diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index a705b61cd3..1b5b8bccaf 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -38,18 +38,10 @@ ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Pare // FIXME: Setup proper uniform slots and use correct pipelines for forward rendering _procedural._opaqueFragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::simple); _procedural._transparentFragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::simple_transparent); - _procedural._opaqueState->setCullMode(gpu::State::CULL_NONE); - _procedural._opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL); + + // TODO: move into Procedural.cpp PrepareStencil::testMaskDrawShape(*_procedural._opaqueState); - _procedural._opaqueState->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _procedural._transparentState->setCullMode(gpu::State::CULL_BACK); - _procedural._transparentState->setDepthTest(true, true, gpu::LESS_EQUAL); PrepareStencil::testMask(*_procedural._transparentState); - _procedural._transparentState->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } bool ShapeEntityRenderer::needsRenderUpdate() const { @@ -212,7 +204,10 @@ ShapeKey ShapeEntityRenderer::getShapeKey() { return builder.build(); } else { ShapeKey::Builder builder; - if (_procedural.isReady()) { + bool proceduralReady = resultWithReadLock([&] { + return _procedural.isReady(); + }); + if (proceduralReady) { builder.withOwnPipeline(); } if (isTransparent()) { @@ -242,7 +237,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { if (_procedural.isReady()) { outColor = _procedural.getColor(outColor); outColor.a *= _procedural.isFading() ? Interpolate::calculateFadeRatio(_procedural.getFadeStartTime()) : 1.0f; - _procedural.prepare(batch, _position, _dimensions, _orientation, outColor); + _procedural.prepare(batch, _position, _dimensions, _orientation, ProceduralProgramKey(outColor.a < 1.0f)); proceduralRender = true; } } diff --git a/libraries/gpu/src/gpu/Pipeline.h b/libraries/gpu/src/gpu/Pipeline.h index 28f7fe106e..b46226182a 100755 --- a/libraries/gpu/src/gpu/Pipeline.h +++ b/libraries/gpu/src/gpu/Pipeline.h @@ -38,8 +38,6 @@ protected: StatePointer _state; Pipeline(); - Pipeline(const Pipeline& pipeline); // deep copy of the sysmem shader - Pipeline& operator=(const Pipeline& pipeline); // deep copy of the sysmem texture }; typedef Pipeline::Pointer PipelinePointer; diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 7095732d53..a124d4e8be 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -39,8 +39,10 @@ static const std::string PROCEDURAL_BLOCK = "//PROCEDURAL_BLOCK"; static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION"; bool operator==(const ProceduralData& a, const ProceduralData& b) { - return ((a.version == b.version) && (a.shaderUrl == b.shaderUrl) && (a.uniforms == b.uniforms) && - (a.channels == b.channels)); + return ((a.version == b.version) && + (a.shaderUrl == b.shaderUrl) && + (a.uniforms == b.uniforms) && + (a.channels == b.channels)); } QJsonValue ProceduralData::getProceduralData(const QString& proceduralJson) { @@ -57,9 +59,9 @@ QJsonValue ProceduralData::getProceduralData(const QString& proceduralJson) { return doc.object()[PROCEDURAL_USER_DATA_KEY]; } -ProceduralData ProceduralData::parse(const QString& userDataJson) { +ProceduralData ProceduralData::parse(const QString& proceduralData) { ProceduralData result; - result.parse(getProceduralData(userDataJson).toObject()); + result.parse(getProceduralData(proceduralData).toObject()); return result; } @@ -73,7 +75,7 @@ void ProceduralData::parse(const QJsonObject& proceduralData) { if (versionJson.isDouble()) { version = (uint8_t)(floor(versionJson.toDouble())); // invalid version - if (!(version == 1 || version == 2)) { + if (!(version == 1 || version == 2 || version == 3)) { return; } } else { @@ -102,20 +104,27 @@ void ProceduralData::parse(const QJsonObject& proceduralData) { //} Procedural::Procedural() { - _transparentState->setCullMode(gpu::State::CULL_NONE); + _opaqueState->setCullMode(gpu::State::CULL_BACK); + _opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL); + _opaqueState->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + _transparentState->setCullMode(gpu::State::CULL_BACK); _transparentState->setDepthTest(true, true, gpu::LESS_EQUAL); - _transparentState->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + _transparentState->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); _standardInputsBuffer = std::make_shared(sizeof(StandardInputs), nullptr); } void Procedural::setProceduralData(const ProceduralData& proceduralData) { + std::lock_guard lock(_mutex); if (proceduralData == _data) { return; } - _dirty = true; _enabled = false; if (proceduralData.version != _data.version) { @@ -124,6 +133,10 @@ void Procedural::setProceduralData(const ProceduralData& proceduralData) { } if (proceduralData.uniforms != _data.uniforms) { + // If the uniform keys changed, we need to recreate the whole shader to handle the reflection + if (proceduralData.uniforms.keys() != _data.uniforms.keys()) { + _shaderDirty = true; + } _data.uniforms = proceduralData.uniforms; _uniformsDirty = true; } @@ -147,16 +160,14 @@ void Procedural::setProceduralData(const ProceduralData& proceduralData) { if (proceduralData.shaderUrl != _data.shaderUrl) { _data.shaderUrl = proceduralData.shaderUrl; - _shaderDirty = true; const auto& shaderUrl = _data.shaderUrl; + + _shaderDirty = true; _networkShader.reset(); _shaderPath.clear(); + _shaderSource.clear(); - if (shaderUrl.isEmpty()) { - return; - } - - if (!shaderUrl.isValid()) { + if (shaderUrl.isEmpty() || !shaderUrl.isValid()) { return; } @@ -180,6 +191,8 @@ bool Procedural::isReady() const { return false; #endif + std::lock_guard lock(_mutex); + if (!_enabled) { return false; } @@ -209,10 +222,11 @@ bool Procedural::isReady() const { } void Procedural::prepare(gpu::Batch& batch, - const glm::vec3& position, - const glm::vec3& size, - const glm::quat& orientation, - const glm::vec4& color) { + const glm::vec3& position, + const glm::vec3& size, + const glm::quat& orientation, + const ProceduralProgramKey key) { + std::lock_guard lock(_mutex); _entityDimensions = size; _entityPosition = position; _entityOrientation = glm::mat3_cast(orientation); @@ -225,62 +239,56 @@ void Procedural::prepare(gpu::Batch& batch, _shaderDirty = true; _shaderModified = lastModified; } - } else if (_networkShader && _networkShader->isLoaded()) { + } else if (_shaderSource.isEmpty() && _networkShader && _networkShader->isLoaded()) { _shaderSource = _networkShader->_source; + _shaderDirty = true; } - if (!_opaquePipeline || !_transparentPipeline || _shaderDirty) { + if (_shaderDirty) { + _proceduralPipelines.clear(); + } + + auto& pipeline = _proceduralPipelines.find(key); + bool recompiledShader = false; + if (pipeline == _proceduralPipelines.end()) { if (!_vertexShader) { _vertexShader = gpu::Shader::createVertex(_vertexSource); } + gpu::Shader::Source& fragmentSource = (key.isTransparent() && _transparentFragmentSource.valid()) ? _transparentFragmentSource : _opaqueFragmentSource; + // Build the fragment shader - _opaqueFragmentSource.replacements.clear(); - if (_data.version == 1) { - _opaqueFragmentSource.replacements[PROCEDURAL_VERSION] = "#define PROCEDURAL_V1 1"; - } else if (_data.version == 2) { - _opaqueFragmentSource.replacements[PROCEDURAL_VERSION] = "#define PROCEDURAL_V2 1"; - } - _opaqueFragmentSource.replacements[PROCEDURAL_BLOCK] = _shaderSource.toStdString(); - _transparentFragmentSource.replacements = _opaqueFragmentSource.replacements; + fragmentSource.replacements.clear(); + fragmentSource.replacements[PROCEDURAL_VERSION] = "#define PROCEDURAL_V" + std::to_string(_data.version); + fragmentSource.replacements[PROCEDURAL_BLOCK] = _shaderSource.toStdString(); // Set any userdata specified uniforms int customSlot = procedural::slot::uniform::Custom; for (const auto& key : _data.uniforms.keys()) { std::string uniformName = key.toLocal8Bit().data(); - _opaqueFragmentSource.reflection.uniforms[uniformName] = customSlot; - _transparentFragmentSource.reflection.uniforms[uniformName] = customSlot; + fragmentSource.reflection.uniforms[uniformName] = customSlot; ++customSlot; } // Leave this here for debugging - // qCDebug(procedural) << "FragmentShader:\n" << fragmentShaderSource.c_str(); + //qCDebug(proceduralLog) << "FragmentShader:\n" << fragmentSource.getSource(shader::Dialect::glsl450, shader::Variant::Mono).c_str(); + + gpu::ShaderPointer fragmentShader = gpu::Shader::createPixel(fragmentSource); + gpu::ShaderPointer program = gpu::Shader::createProgram(_vertexShader, fragmentShader); + + _proceduralPipelines[key] = gpu::Pipeline::create(program, key.isTransparent() ? _transparentState : _opaqueState); - // TODO: THis is a simple fix, we need a cleaner way to provide the "hosting" program for procedural custom shaders to be defined together with the required bindings. - _opaqueFragmentShader = gpu::Shader::createPixel(_opaqueFragmentSource); - _opaqueShader = gpu::Shader::createProgram(_vertexShader, _opaqueFragmentShader); - _opaquePipeline = gpu::Pipeline::create(_opaqueShader, _opaqueState); - if (_transparentFragmentSource.valid()) { - _transparentFragmentShader = gpu::Shader::createPixel(_transparentFragmentSource); - _transparentShader = gpu::Shader::createProgram(_vertexShader, _transparentFragmentShader); - _transparentPipeline = gpu::Pipeline::create(_transparentShader, _transparentState); - } else { - _transparentFragmentShader = _opaqueFragmentShader; - _transparentShader = _opaqueShader; - _transparentPipeline = _opaquePipeline; - } _start = usecTimestampNow(); _frameCount = 0; + recompiledShader = true; } - bool transparent = color.a < 1.0f; - batch.setPipeline(transparent ? _transparentPipeline : _opaquePipeline); + batch.setPipeline(_proceduralPipelines[key]); - if (_shaderDirty || _uniformsDirty || _prevTransparent != transparent) { - setupUniforms(transparent); + if (_shaderDirty || _uniformsDirty) { + setupUniforms(); } - _prevTransparent = transparent; _shaderDirty = _uniformsDirty = false; for (auto lambda : _uniforms) { @@ -290,8 +298,7 @@ void Procedural::prepare(gpu::Batch& batch, static gpu::Sampler sampler; static std::once_flag once; std::call_once(once, [&] { - gpu::Sampler::Desc desc; - desc._filter = gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR; + sampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR); }); for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { @@ -301,19 +308,17 @@ void Procedural::prepare(gpu::Batch& batch, gpuTexture->setSampler(sampler); gpuTexture->setAutoGenerateMips(true); } - batch.setResourceTexture((gpu::uint32)i, gpuTexture); + batch.setResourceTexture(procedural::slot::texture::Channel0 + i, gpuTexture); } } } -void Procedural::setupUniforms(bool transparent) { +void Procedural::setupUniforms() { _uniforms.clear(); - auto customUniformCount = _data.uniforms.keys().size(); // Set any userdata specified uniforms - for (int i = 0; i < customUniformCount; ++i) { - int slot = procedural::slot::uniform::Custom + i; - QString key = _data.uniforms.keys().at(i); + int slot = procedural::slot::uniform::Custom; + for (const auto& key : _data.uniforms.keys()) { std::string uniformName = key.toLocal8Bit().data(); QJsonValue value = _data.uniforms[key]; if (value.isDouble()) { @@ -360,6 +365,7 @@ void Procedural::setupUniforms(bool transparent) { } } } + slot++; } _uniforms.push_back([=](gpu::Batch& batch) { @@ -398,7 +404,7 @@ void Procedural::setupUniforms(bool transparent) { }); } -glm::vec4 Procedural::getColor(const glm::vec4& entityColor) { +glm::vec4 Procedural::getColor(const glm::vec4& entityColor) const { if (_data.version == 1) { return glm::vec4(1); } diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 781ac25249..3e10678ba7 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -7,8 +7,6 @@ // #pragma once -#ifndef hifi_RenderableProcedrualItem_h -#define hifi_RenderableProcedrualItem_h #include @@ -32,7 +30,6 @@ const size_t MAX_PROCEDURAL_TEXTURE_CHANNELS{ 4 }; struct ProceduralData { static QJsonValue getProceduralData(const QString& proceduralJson); static ProceduralData parse(const QString& userDataJson); - // This should only be called from the render thread, as it shares data with Procedural::prepare void parse(const QJsonObject&); // Rendering object descriptions, from userData @@ -42,10 +39,40 @@ struct ProceduralData { QJsonArray channels; }; +class ProceduralProgramKey { +public: + enum FlagBit { + IS_TRANSPARENT = 0, + NUM_FLAGS + }; + + typedef std::bitset Flags; + + Flags _flags; + + bool isTransparent() const { return _flags[IS_TRANSPARENT]; } + + ProceduralProgramKey(bool transparent = false) { + if (transparent) { + _flags.set(IS_TRANSPARENT); + } + } +}; +namespace std { + template <> + struct hash { + size_t operator()(const ProceduralProgramKey& key) const { + return std::hash>()(key._flags); + } + }; +} +inline bool operator==(const ProceduralProgramKey& a, const ProceduralProgramKey& b) { + return a._flags == b._flags; +} +inline bool operator!=(const ProceduralProgramKey& a, const ProceduralProgramKey& b) { + return a._flags != b._flags; +} -// WARNING with threaded rendering it is the RESPONSIBILITY OF THE CALLER to ensure that -// calls to `setProceduralData` happen on the main thread and that calls to `ready` and `prepare` -// are treated atomically, and that they cannot happen concurrently with calls to `setProceduralData` // FIXME better encapsulation // FIXME better mechanism for extending to things rendered using shaders other than simple.slv struct Procedural { @@ -55,10 +82,9 @@ public: bool isReady() const; bool isEnabled() const { return _enabled; } - void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, const glm::vec4& color = glm::vec4(1)); - const gpu::ShaderPointer& getOpaqueShader() const { return _opaqueShader; } + void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, const glm::quat& orientation, const ProceduralProgramKey key = ProceduralProgramKey()); - glm::vec4 getColor(const glm::vec4& entityColor); + glm::vec4 getColor(const glm::vec4& entityColor) const; quint64 getFadeStartTime() const { return _fadeStartTime; } bool isFading() const { return _doesFade && _isFading; } void setIsFading(bool isFading) { _isFading = isFading; } @@ -108,22 +134,19 @@ protected: QString _shaderPath; quint64 _shaderModified { 0 }; NetworkShaderPointer _networkShader; - bool _dirty { false }; bool _shaderDirty { true }; bool _uniformsDirty { true }; // Rendering objects UniformLambdas _uniforms; NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS]; - gpu::PipelinePointer _opaquePipeline; - gpu::PipelinePointer _transparentPipeline; + + std::unordered_map _proceduralPipelines; + + gpu::ShaderPointer _vertexShader; + StandardInputs _standardInputs; gpu::BufferPointer _standardInputsBuffer; - gpu::ShaderPointer _vertexShader; - gpu::ShaderPointer _opaqueFragmentShader; - gpu::ShaderPointer _transparentFragmentShader; - gpu::ShaderPointer _opaqueShader; - gpu::ShaderPointer _transparentShader; // Entity metadata glm::vec3 _entityDimensions; @@ -131,14 +154,11 @@ protected: glm::mat3 _entityOrientation; private: - // This should only be called from the render thread, as it shares data with Procedural::prepare - void setupUniforms(bool transparent); + void setupUniforms(); mutable quint64 _fadeStartTime { 0 }; mutable bool _hasStartedFade { false }; mutable bool _isFading { false }; bool _doesFade { true }; - bool _prevTransparent { false }; + mutable std::mutex _mutex; }; - -#endif diff --git a/libraries/procedural/src/procedural/ProceduralCommon.slh b/libraries/procedural/src/procedural/ProceduralCommon.slh index d515a79e22..ab8d74bdfa 100644 --- a/libraries/procedural/src/procedural/ProceduralCommon.slh +++ b/libraries/procedural/src/procedural/ProceduralCommon.slh @@ -8,11 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include gpu/Transform.slh@> <@include gpu/Noise.slh@> <@include procedural/ShaderConstants.h@> - -<$declareStandardCameraTransform()$> LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL0) uniform sampler2D iChannel0; LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL1) uniform sampler2D iChannel1; @@ -59,6 +56,19 @@ LAYOUT_STD140(binding=0) uniform standardInputsBuffer { #define iChannelResolution standardInputs.channelResolution #define iWorldOrientation standardInputs.worldOrientation +struct ProceduralFragmentData { + vec3 position; + vec3 normal; + vec3 diffuse; + vec3 specular; + vec3 emissive; + float alpha; + float roughness; + float metallic; + float occlusion; + float scattering; +}; + // Unimplemented uniforms // Resolution doesn't make sense in the VR context const vec3 iResolution = vec3(1.0); @@ -69,8 +79,6 @@ const float iSampleRate = 1.0; // No support for video input const vec4 iChannelTime = vec4(0.0); -#define PROCEDURAL 1 - //PROCEDURAL_VERSION // hack comment for extra whitespace diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index ea5be23eb8..211f6ca0a2 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -35,7 +35,6 @@ bool ProceduralSkybox::empty() { void ProceduralSkybox::clear() { // Parse and prepare a procedural with no shaders to release textures parse(QString()); - _procedural.isReady(); Skybox::clear(); } diff --git a/libraries/render-utils/src/forward_simple.slf b/libraries/render-utils/src/forward_simple.slf index 9c86f9dff1..677c369033 100644 --- a/libraries/render-utils/src/forward_simple.slf +++ b/libraries/render-utils/src/forward_simple.slf @@ -14,9 +14,9 @@ <@include DefaultMaterials.slh@> <@include ForwardGlobalLight.slh@> -<@include gpu/Transform.slh@> - <$declareEvalSkyboxGlobalColor()$> + +<@include gpu/Transform.slh@> <$declareStandardCameraTransform()$> // the interpolated normal diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index dac01aac89..c0bb021c2d 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -14,6 +14,9 @@ <@include DeferredBufferWrite.slh@> +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + <@include render-utils/ShaderConstants.h@> // the interpolated normal @@ -45,27 +48,64 @@ float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float s return 1.0; } +float getProceduralFragment(inout ProceduralFragmentData proceduralData) { + return 1.0; +} + //PROCEDURAL_BLOCK_END #line 2030 void main(void) { vec3 normal = normalize(_normalWS.xyz); vec3 diffuse = _color.rgb; + float roughness = DEFAULT_ROUGHNESS; + float metallic = DEFAULT_METALLIC; + vec3 emissive = DEFAULT_EMISSIVE; + float occlusion = DEFAULT_OCCLUSION; + float scattering = DEFAULT_SCATTERING; + + float emissiveAmount = 0.0; + +#if defined(PROCEDURAL_V1) + diffuse = getProceduralColor().rgb; + emissiveAmount = 1.0; + emissive = vec3(1.0); +#elif defined(PROCEDURAL_V2) vec3 specular = DEFAULT_SPECULAR; float shininess = DEFAULT_SHININESS; - float emissiveAmount = 0.0; - -#ifdef PROCEDURAL - -#ifdef PROCEDURAL_V1 - diffuse = getProceduralColor().rgb; - // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline - //diffuse = pow(diffuse, vec3(2.2)); - emissiveAmount = 1.0; -#else emissiveAmount = getProceduralColors(diffuse, specular, shininess); -#endif + roughness = max(0.0, 1.0 - shininess / 128.0); + metallic = length(specular); + emissive = vec3(clamp(emissiveAmount, 0.0, 1.0)); +#elif defined(PROCEDURAL_V3) + TransformCamera cam = getTransformCamera(); + vec4 position = cam._viewInverse * _positionES; + ProceduralFragmentData proceduralData = { + position.xyz, + normal, + vec3(0.0), + DEFAULT_SPECULAR, + DEFAULT_EMISSIVE, + 1.0, + DEFAULT_ROUGHNESS, + DEFAULT_METALLIC, + DEFAULT_OCCLUSION, + DEFAULT_SCATTERING + }; + emissiveAmount = getProceduralFragment(proceduralData); + normal = proceduralData.normal; + diffuse = proceduralData.diffuse; + roughness = proceduralData.roughness; + metallic = proceduralData.metallic; + emissive = proceduralData.emissive; + occlusion = proceduralData.occlusion; + scattering = proceduralData.scattering; + position = vec4(proceduralData.position, 1.0); + vec4 posClip = cam._projection * (cam._view * position); + float far = gl_DepthRange.far; + float near = gl_DepthRange.near; + gl_FragDepth = 0.5 * ((far - near) * posClip.z / posClip.w + near + far); #endif if (emissiveAmount > 0.0) { @@ -73,18 +113,18 @@ void main(void) { normal, 1.0, diffuse, - max(0.0, 1.0 - shininess / 128.0), - DEFAULT_METALLIC, - vec3(clamp(emissiveAmount, 0.0, 1.0))); + roughness, + metallic, + emissive); } else { packDeferredFragment( normal, 1.0, diffuse, - max(0.0, 1.0 - shininess / 128.0), - length(specular), - DEFAULT_EMISSIVE, - DEFAULT_OCCLUSION, - DEFAULT_SCATTERING); + roughness, + metallic, + emissive, + occlusion, + scattering); } } diff --git a/libraries/render-utils/src/simple_transparent.slf b/libraries/render-utils/src/simple_transparent.slf index 0e29ed7470..bafec462db 100644 --- a/libraries/render-utils/src/simple_transparent.slf +++ b/libraries/render-utils/src/simple_transparent.slf @@ -16,6 +16,9 @@ <@include DeferredGlobalLight.slh@> <$declareEvalGlobalLightingAlphaBlendedWithHaze()$> +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + <@include render-utils/ShaderConstants.h@> // the interpolated normal @@ -50,46 +53,86 @@ float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float s return 1.0; } +float getProceduralFragment(inout ProceduralFragmentData proceduralData) { + return 1.0; +} + //PROCEDURAL_BLOCK_END #line 2030 void main(void) { vec3 normal = normalize(_normalWS.xyz); vec3 diffuse = _color.rgb; - vec3 specular = DEFAULT_SPECULAR; - float shininess = DEFAULT_SHININESS; + float alpha = _color.a; + float occlusion = DEFAULT_OCCLUSION; + vec3 fresnel = DEFAULT_FRESNEL; + float metallic = DEFAULT_METALLIC; + vec3 emissive = DEFAULT_EMISSIVE; + float roughness = DEFAULT_ROUGHNESS; + float emissiveAmount = 0.0; - -#ifdef PROCEDURAL + + TransformCamera cam = getTransformCamera(); + vec3 posEye = _positionES.xyz; #ifdef PROCEDURAL_V1 diffuse = getProceduralColor().rgb; - // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline - //diffuse = pow(diffuse, vec3(2.2)); emissiveAmount = 1.0; -#else + emissive = vec3(1.0); +#elif defined(PROCEDURAL_V2) + vec3 specular = DEFAULT_SPECULAR; + float shininess = DEFAULT_SHININESS; emissiveAmount = getProceduralColors(diffuse, specular, shininess); -#endif + roughness = max(0.0, 1.0 - shininess / 128.0); + metallic = length(specular); + emissive = vec3(clamp(emissiveAmount, 0.0, 1.0)); +#elif defined(PROCEDURAL_V3) + vec4 position = cam._viewInverse * _positionES; + ProceduralFragmentData proceduralData = { + position.xyz, + normal, + vec3(0.0), + DEFAULT_SPECULAR, + DEFAULT_EMISSIVE, + 1.0, + DEFAULT_ROUGHNESS, + DEFAULT_METALLIC, + DEFAULT_OCCLUSION, + DEFAULT_SCATTERING + }; + emissiveAmount = getProceduralFragment(proceduralData); + position = vec4(proceduralData.position, 1.0); + vec4 posEye4 = cam._view * position; + posEye = vec3(posEye4); + occlusion = proceduralData.occlusion; + normal = proceduralData.normal; + diffuse = proceduralData.diffuse; + alpha = proceduralData.alpha; + fresnel = proceduralData.specular; + metallic = proceduralData.metallic; + emissive = proceduralData.emissive; + roughness = proceduralData.roughness; + vec4 posClip = cam._projection * posEye4; + float far = gl_DepthRange.far; + float near = gl_DepthRange.near; + gl_FragDepth = 0.5 * ((far - near) * posClip.z / posClip.w + near + far); #endif - TransformCamera cam = getTransformCamera(); - vec3 fragPosition = _positionES.xyz; - if (emissiveAmount > 0.0) { - _fragColor0 = vec4(diffuse, _color.a); + _fragColor0 = vec4(diffuse, alpha); } else { _fragColor0 = vec4(evalGlobalLightingAlphaBlendedWithHaze( cam._viewInverse, 1.0, - DEFAULT_OCCLUSION, - fragPosition, + occlusion, + posEye, normal, diffuse, - DEFAULT_FRESNEL, - length(specular), - DEFAULT_EMISSIVE, - max(0.0, 1.0 - shininess / 128.0), _color.a), - _color.a); + fresnel, + metallic, + emissive, + roughness, alpha), + alpha); } }