diff --git a/src/quick3d/qdemonsceneenvironment.h b/src/quick3d/qdemonsceneenvironment.h index 104c2aa520d7c063dd0eb75bfc9bbe45758c9b5a..e98110b5a4643867b8fee3dcef33c60830b64662 100644 --- a/src/quick3d/qdemonsceneenvironment.h +++ b/src/quick3d/qdemonsceneenvironment.h @@ -59,7 +59,8 @@ public: enum QDemonEnvironmentBackgroundTypes { Transparent = 0, Unspecified, - Color + Color, + SkyBox }; Q_ENUM(QDemonEnvironmentBackgroundTypes) diff --git a/src/runtimerender/graphobjects/qdemonrenderlayer.h b/src/runtimerender/graphobjects/qdemonrenderlayer.h index 978e0cfd1ce6652ea060a94362efc69ce2c49eb2..7f170f9eb73c24fe45e3933777c41c26a8b34d8c 100644 --- a/src/runtimerender/graphobjects/qdemonrenderlayer.h +++ b/src/runtimerender/graphobjects/qdemonrenderlayer.h @@ -77,7 +77,9 @@ struct Q_DEMONRUNTIMERENDER_EXPORT QDemonRenderLayer : public QDemonRenderNode enum class Background : quint8 { Transparent = 0, - Unspecified, Color + Unspecified, + Color, + SkyBox }; enum class BlendMode : quint8 diff --git a/src/runtimerender/rendererimpl/qdemonrendererimpl.h b/src/runtimerender/rendererimpl/qdemonrendererimpl.h index 781c24b85f193e90502ea85948f83f5e945a762b..ead798cd67f8d5fbd4311e90514aa988f8351191 100644 --- a/src/runtimerender/rendererimpl/qdemonrendererimpl.h +++ b/src/runtimerender/rendererimpl/qdemonrendererimpl.h @@ -132,6 +132,7 @@ class Q_DEMONRUNTIMERENDER_EXPORT QDemonRendererImpl : public QDemonRendererInte QDemonRef<QDemonRenderableDepthPrepassShader> m_depthTessLinearPrepassShaderDisplaced; QDemonRef<QDemonRenderableDepthPrepassShader> m_depthTessPhongPrepassShader; QDemonRef<QDemonRenderableDepthPrepassShader> m_depthTessNPatchPrepassShader; + QDemonRef<QDemonSkyBoxShader> m_skyBoxShader; QDemonRef<QDemonDefaultAoPassShader> m_defaultAoPassShader; QDemonRef<QDemonDefaultAoPassShader> m_fakeDepthShader; QDemonRef<QDemonDefaultAoPassShader> m_fakeCubemapDepthShader; @@ -295,6 +296,7 @@ public: QDemonRef<QDemonShaderGeneratorGeneratedShader> getShader(QDemonSubsetRenderable &inRenderable, const TShaderFeatureSet &inFeatureSet); + QDemonRef<QDemonSkyBoxShader> getSkyBoxShader(); QDemonRef<QDemonDefaultAoPassShader> getDefaultAoPassShader(TShaderFeatureSet inFeatureSet); QDemonRef<QDemonDefaultAoPassShader> getFakeDepthShader(TShaderFeatureSet inFeatureSet); QDemonRef<QDemonDefaultAoPassShader> getFakeCubeDepthShader(TShaderFeatureSet inFeatureSet); diff --git a/src/runtimerender/rendererimpl/qdemonrendererimpllayerrenderdata.cpp b/src/runtimerender/rendererimpl/qdemonrendererimpllayerrenderdata.cpp index e5ef481089973aedc8461c3ce94cfbac7f316086..aac33cfc9c7d0aa1b911b54a4e6bf36de8d437c2 100644 --- a/src/runtimerender/rendererimpl/qdemonrendererimpllayerrenderdata.cpp +++ b/src/runtimerender/rendererimpl/qdemonrendererimpllayerrenderdata.cpp @@ -212,6 +212,57 @@ QDemonRenderFrameBufferAttachment QDemonLayerRenderData::getFramebufferDepthAtta return fmt; } +void QDemonLayerRenderData::renderClearPass() +{ + QDemonStackPerfTimer ___timer(renderer->demonContext()->performanceTimer(), Q_FUNC_INFO); + if (camera == nullptr) + return; + + renderer->beginLayerRender(*this); + + auto theContext = renderer->context(); + if (layer.background == QDemonRenderLayer::Background::SkyBox) { + theContext->setDepthTestEnabled(false); // Draw to every pixel + theContext->setDepthWriteEnabled(false); // Depth will be cleared in a separate step + QDemonRef<QDemonSkyBoxShader> shader = renderer->getSkyBoxShader(); + theContext->setActiveShader(shader->shader); + // Setup constants + shader->projection.set(camera->projection); + shader->viewMatrix.set(camera->globalTransform); + shader->skyboxTexture.set(layer.lightProbe->m_textureData.m_texture.data()); + renderer->renderQuad(); + } + + QDemonRenderClearFlags clearFlags = 0; + if (!layer.flags.testFlag(QDemonRenderLayer::Flag::LayerEnableDepthPrePass)) { + clearFlags |= QDemonRenderClearValues::Depth; + clearFlags |= QDemonRenderClearValues::Stencil; + // Enable depth write for the clear below + theContext->setDepthWriteEnabled(true); + } + + if (layer.background == QDemonRenderLayer::Background::SkyBox) { + theContext->clear(clearFlags); + } else if (layer.background == QDemonRenderLayer::Background::Color) { + clearFlags |= QDemonRenderClearValues::Color; + QDemonRenderContextScopedProperty<QVector4D> __clearColor(*theContext, + &QDemonRenderContext::clearColor, + &QDemonRenderContext::setClearColor, + QVector4D(layer.clearColor, 1.0f)); + theContext->clear(clearFlags); + } else { + if (layerPrepResult->flags.requiresTransparentClear()) { + clearFlags |= QDemonRenderClearValues::Color; + QDemonRenderContextScopedProperty<QVector4D> __clearColor(*theContext, + &QDemonRenderContext::clearColor, + &QDemonRenderContext::setClearColor, + QVector4D(0.0, 0.0, 0.0, 0.0f)); + theContext->clear(clearFlags); + } + } + renderer->endLayerRender(); +} + void QDemonLayerRenderData::renderAoPass() { renderer->beginLayerDepthPassRender(*this); @@ -1122,6 +1173,9 @@ void QDemonLayerRenderData::renderToViewport() &layer); } } else { + startProfiling("Clear pass", false); + renderClearPass(); + endProfiling("Clear pass"); if (layer.flags.testFlag(QDemonRenderLayer::Flag::LayerEnableDepthPrePass)) { startProfiling("Depth pass", false); @@ -1630,7 +1684,9 @@ void QDemonLayerRenderData::runnableRenderToViewport(const QDemonRef<QDemonRende // Then we can't possible affect the resulting render target. bool needsToRender = layer.firstEffect != nullptr || opaqueObjects.empty() == false || anyCompletelyNonTransparentObjects(transparentObjects) || usesOffscreenRenderer() - || m_layerWidgetTexture.getTexture() || m_boundingRectColor.hasValue() || layer.background == QDemonRenderLayer::Background::Color; + || m_layerWidgetTexture.getTexture() || m_boundingRectColor.hasValue() + || layer.background == QDemonRenderLayer::Background::Color + || layer.background == QDemonRenderLayer::Background::SkyBox; if (needsToRender == false) return; @@ -1657,29 +1713,6 @@ void QDemonLayerRenderData::runnableRenderToViewport(const QDemonRef<QDemonRende theContext->setViewport(layerPrepResult->viewport().toRect()); theContext->setScissorTestEnabled(true); theContext->setScissorRect(layerPrepResult->scissor().toRect()); - - QDemonRenderClearFlags clearFlags = QDemonRenderClearValues::Color; - if (!layer.flags.testFlag(QDemonRenderLayer::Flag::LayerEnableDepthPrePass)) { - clearFlags |= (QDemonRenderClearValues::Depth); - clearFlags |= (QDemonRenderClearValues::Stencil); - // enable depth write for the clear below - theContext->setDepthWriteEnabled(true); - } - if (layer.background == QDemonRenderLayer::Background::Color) { - QDemonRenderContextScopedProperty<QVector4D> __clearColor(*theContext, - &QDemonRenderContext::clearColor, - &QDemonRenderContext::setClearColor, - QVector4D(layer.clearColor, 1.0f)); - theContext->clear(clearFlags); - } else { - if (thePrepResult.flags.requiresTransparentClear()) { - QDemonRenderContextScopedProperty<QVector4D> __clearColor(*theContext, - &QDemonRenderContext::clearColor, - &QDemonRenderContext::setClearColor, - QVector4D(0.0, 0.0, 0.0, 0.0f)); - theContext->clear(clearFlags); - } - } renderToViewport(); } else { // First, render the layer along with whatever progressive AA is appropriate. diff --git a/src/runtimerender/rendererimpl/qdemonrendererimpllayerrenderdata.h b/src/runtimerender/rendererimpl/qdemonrendererimpllayerrenderdata.h index 04e88827baee45853045769eb8b6cdedf34c9647..ab79cd136fe3f200e90bec928094b49d5dd8700f 100644 --- a/src/runtimerender/rendererimpl/qdemonrendererimpllayerrenderdata.h +++ b/src/runtimerender/rendererimpl/qdemonrendererimpllayerrenderdata.h @@ -104,6 +104,7 @@ struct QDemonLayerRenderData : public QDemonLayerRenderPreparationData // Render this layer assuming viewport and RT are setup. Just renders exactly this item // no effects. + void renderClearPass(); void renderDepthPass(bool inEnableTransparentDepthWrite = false); void renderAoPass(); void renderFakeDepthMapPass(QDemonRenderTexture2D *theDepthTex, QDemonRenderTextureCube *theDepthCube); diff --git a/src/runtimerender/rendererimpl/qdemonrendererimplshaders.cpp b/src/runtimerender/rendererimpl/qdemonrendererimplshaders.cpp index ae78706eb3424026c22f4ed31db1a682679fe0f8..810ab64b51e5c3158b8beee4f5b1a256b7a46033 100644 --- a/src/runtimerender/rendererimpl/qdemonrendererimplshaders.cpp +++ b/src/runtimerender/rendererimpl/qdemonrendererimplshaders.cpp @@ -1545,6 +1545,76 @@ QDemonRef<QDemonRenderableDepthPrepassShader> QDemonRendererImpl::getDepthTessNP return m_depthTessNPatchPrepassShader; } +QDemonRef<QDemonSkyBoxShader> QDemonRendererImpl::getSkyBoxShader() +{ + if (!m_skyBoxShader) { + QDemonRef<QDemonShaderCache> theCache = m_demonContext->shaderCache(); + QByteArray name = "fullscreen skybox shader"; + QDemonRef<QDemonRenderShaderProgram> skyBoxShaderProgram = theCache->getProgram(name, TShaderFeatureSet()); + if (!skyBoxShaderProgram) { + QDemonRef<QDemonShaderProgramGeneratorInterface> theGenerator(getProgramGenerator()); + theGenerator->beginProgram(); + QDemonShaderStageGeneratorInterface &vertexGenerator(*theGenerator->getStage(QDemonShaderGeneratorStage::Vertex)); + QDemonShaderStageGeneratorInterface &fragmentGenerator(*theGenerator->getStage(QDemonShaderGeneratorStage::Fragment)); + + vertexGenerator.addIncoming("attr_pos", "vec3"); + + vertexGenerator.addOutgoing("eye_direction", "vec3"); + + vertexGenerator.addUniform("view_matrix", "mat4"); + vertexGenerator.addUniform("projection", "mat4"); + + vertexGenerator.append("void main() {"); + vertexGenerator.append("\tgl_Position = vec4(attr_pos, 1.0);"); + vertexGenerator.append("\tmat4 inverseProjection = inverse(projection);"); + vertexGenerator.append("\tvec3 unprojected = (inverseProjection * gl_Position).xyz;"); + vertexGenerator.append("\teye_direction = normalize(mat3(view_matrix) * unprojected);"); + vertexGenerator.append("}"); + + fragmentGenerator.addInclude("customMaterial.glsllib"); // Needed for PI, PI_TWO + + fragmentGenerator.addUniform("skybox_image", "sampler2D"); + fragmentGenerator.addUniform("output_color", "vec3"); + + fragmentGenerator.append("void main() {"); + + // Ideally, we would just reuse getProbeSampleUV like this, but that leads to issues + // with incorrect texture gradients because we're drawing on a quad and not a sphere. + // See explanation below. + // fragmentGenerator.addInclude("sampleProbe.glsllib"); + // fragmentGenerator.append("\tgl_FragColor = texture2D(skybox_image, getProbeSampleUV(eye, vec4(1.0, 0.0, 0.0, 1.0), vec2(0,0)));"); + + // nlerp direction vector, not entirely correct, but simple/efficient + fragmentGenerator.append("\tvec3 eye = normalize(eye_direction);"); + + // Equirectangular textures project longitude and latitude to the xy plane + fragmentGenerator.append("\tfloat longitude = atan(eye.x, eye.z) / PI_TWO + 0.5;"); + fragmentGenerator.append("\tfloat latitude = asin(eye.y) / PI + 0.5;"); + fragmentGenerator.append("\tvec2 uv = vec2(longitude, latitude);"); + + // Because of the non-standard projection, the texture lookup for normal texture + // filtering is messed up. Make this somewhat better by manually setting the gradients. + // Right now, they're set to 0,0, but ideally, we would derive the correct gradient + // function mathematically. + // TODO: Alternatively, we could check if it's possible to disable some of the texture + // filtering just for the skybox part. + fragmentGenerator.append("\tgl_FragColor = textureGrad(skybox_image, uv, vec2(0), vec2(0));"); + fragmentGenerator.append("}"); + + // No flags enabled + skyBoxShaderProgram = theGenerator->compileGeneratedShader(name, QDemonShaderCacheProgramFlags(), TShaderFeatureSet()); + } + + if (skyBoxShaderProgram) { + m_skyBoxShader = QDemonRef<QDemonSkyBoxShader>( + new QDemonSkyBoxShader(skyBoxShaderProgram, context())); + } else { + m_skyBoxShader = QDemonRef<QDemonSkyBoxShader>(); + } + } + return m_skyBoxShader; +} + QDemonRef<QDemonDefaultAoPassShader> QDemonRendererImpl::getDefaultAoPassShader(TShaderFeatureSet inFeatureSet) { if (m_defaultAoPassShader.isNull()) { diff --git a/src/runtimerender/rendererimpl/qdemonrendererimplshaders.h b/src/runtimerender/rendererimpl/qdemonrendererimplshaders.h index c5ac1b89c89cb184d66d640a7c7f496dfd8106b7..93bdd5e9f16991a1f31d8dc544a71d5a5a39c753 100644 --- a/src/runtimerender/rendererimpl/qdemonrendererimplshaders.h +++ b/src/runtimerender/rendererimpl/qdemonrendererimplshaders.h @@ -180,6 +180,25 @@ struct QDemonRenderableDepthPrepassShader ~QDemonRenderableDepthPrepassShader() {} }; +struct QDemonSkyBoxShader +{ + QAtomicInt ref; + QDemonRef<QDemonRenderShaderProgram> shader; + QDemonRenderCachedShaderProperty<QMatrix4x4> viewMatrix; + QDemonRenderCachedShaderProperty<QMatrix4x4> projection; + QDemonRenderCachedShaderProperty<QDemonRenderTexture2D *> skyboxTexture; + + QDemonSkyBoxShader(QDemonRef<QDemonRenderShaderProgram> inShader, QDemonRef<QDemonRenderContext> inContext) + : shader(inShader) + , viewMatrix("view_matrix", inShader) + , projection("projection", inShader) + , skyboxTexture("skybox_image", inShader) + { + Q_UNUSED(inContext) + } + ~QDemonSkyBoxShader() = default; +}; + struct QDemonDefaultAoPassShader { QAtomicInt ref;