From 206d1c0157c338de485cedd06a89bf6029cc9255 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Sat, 29 Jun 2024 21:50:33 -0700 Subject: [PATCH] shader error fallback --- interface/resources/shaders/errorShader.frag | 30 +++++++++++++++++++ .../resources/shaders/errorSkyboxShader.frag | 7 +++++ .../procedural/src/procedural/Procedural.cpp | 19 +++++++++++- .../procedural/src/procedural/Procedural.h | 5 ++++ .../src/procedural/ProceduralSkybox.cpp | 2 ++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 interface/resources/shaders/errorShader.frag create mode 100644 interface/resources/shaders/errorSkyboxShader.frag diff --git a/interface/resources/shaders/errorShader.frag b/interface/resources/shaders/errorShader.frag new file mode 100644 index 0000000000..acfd23505e --- /dev/null +++ b/interface/resources/shaders/errorShader.frag @@ -0,0 +1,30 @@ +vec3 getErrorColor() { + vec3 positionWS = iWorldOrientation * (_positionMS.xyz * iWorldScale) + iWorldPosition; + float checkSize = 0.1; + vec3 edges = round(mod(positionWS, vec3(checkSize)) / checkSize); + float checkerboard = mod(edges.x + edges.y + edges.z, 2.0); + return mix(vec3(1, 0, 1), vec3(0.0), checkerboard); +} + +// version 1 +vec3 getProceduralColor() { + return getErrorColor(); +} + +// version 2 +float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + diffuse = getErrorColor(); + return 1.0; +} + +// version 3 +float getProceduralFragment(inout ProceduralFragment data) { + data.emissive = getErrorColor(); + return 1.0; +} + +// version 4 +float getProceduralFragmentWithPosition(inout ProceduralFragmentWithPosition data) { + data.emissive = getErrorColor(); + return 1.0; +} diff --git a/interface/resources/shaders/errorSkyboxShader.frag b/interface/resources/shaders/errorSkyboxShader.frag new file mode 100644 index 0000000000..1c9b333ae5 --- /dev/null +++ b/interface/resources/shaders/errorSkyboxShader.frag @@ -0,0 +1,7 @@ +vec3 getSkyboxColor() { + vec3 normal = normalize(_normal); + float checkSize = 0.1; + vec3 edges = round(mod(normal, vec3(checkSize)) / checkSize); + float checkerboard = mod(edges.x + edges.y + edges.z, 2.0); + return mix(vec3(1, 0, 1), vec3(0.0), checkerboard); +} diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 66dde1ca56..91b949e280 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -377,6 +377,16 @@ void Procedural::prepare(gpu::Batch& batch, _proceduralPipelines[key] = gpu::Pipeline::create(program, key.isTransparent() ? _transparentState : _opaqueState); + if (_errorFallbackFragmentSource.isEmpty()) { + QFile file(_errorFallbackFragmentPath); + file.open(QIODevice::ReadOnly); + _errorFallbackFragmentSource = QTextStream(&file).readAll(); + } + fragmentSource.replacements[PROCEDURAL_BLOCK] = _errorFallbackFragmentSource.toStdString(); + gpu::ShaderPointer errorFragmentShader = gpu::Shader::createPixel(fragmentSource); + gpu::ShaderPointer errorProgram = gpu::Shader::createProgram(vertexShader, errorFragmentShader); + _errorPipelines[key] = gpu::Pipeline::create(errorProgram, _opaqueState); + _lastCompile = usecTimestampNow(); if (_firstCompile == 0) { _firstCompile = _lastCompile; @@ -385,8 +395,13 @@ void Procedural::prepare(gpu::Batch& batch, recompiledShader = true; } + gpu::PipelinePointer finalPipeline = recompiledShader ? _proceduralPipelines[key] : pipeline->second; + if (!finalPipeline || finalPipeline->getProgram()->compilationHasFailed()) { + finalPipeline = _errorPipelines[key]; + } + // FIXME: need to handle forward rendering - batch.setPipeline(recompiledShader ? _proceduralPipelines[key] : pipeline->second); + batch.setPipeline(finalPipeline); bool recreateUniforms = _shaderDirty || _uniformsDirty || recompiledShader || _prevKey != key; if (recreateUniforms) { @@ -533,4 +548,6 @@ void graphics::ProceduralMaterial::initializeProcedural() { // FIXME: Setup proper uniform slots and use correct pipelines for forward rendering _procedural._opaqueFragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_procedural); _procedural._transparentFragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_procedural_translucent); + + _procedural._errorFallbackFragmentPath = ":" + QUrl("qrc:///shaders/errorShader.frag").path(); } \ No newline at end of file diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 39c619c687..3b78563b40 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -124,6 +124,8 @@ public: gpu::Shader::Source _opaqueFragmentSource; gpu::Shader::Source _transparentFragmentSource; + QString _errorFallbackFragmentSource; + gpu::StatePointer _opaqueState { std::make_shared() }; gpu::StatePointer _transparentState { std::make_shared() }; @@ -176,11 +178,14 @@ protected: bool _shaderDirty { true }; bool _uniformsDirty { true }; + QString _errorFallbackFragmentPath; + // Rendering objects UniformLambdas _uniforms; NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS]; std::unordered_map _proceduralPipelines; + std::unordered_map _errorPipelines; StandardInputs _standardInputs; gpu::BufferPointer _standardInputsBuffer; diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 432e02fe10..5cbf11f298 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -22,6 +22,8 @@ ProceduralSkybox::ProceduralSkybox(uint64_t created) : graphics::Skybox(), _crea _procedural._vertexSource = shader::Source::get(shader::graphics::vertex::skybox); _procedural._opaqueFragmentSource = shader::Source::get(shader::procedural::fragment::proceduralSkybox); + _procedural._errorFallbackFragmentPath = ":" + QUrl("qrc:///shaders/errorSkyboxShader.frag").path(); + _procedural.setDoesFade(false); // Adjust the pipeline state for background using the stencil test