From 5b793a1d8c2739a0566c13f5d8cd6b4c7f1deb2e Mon Sep 17 00:00:00 2001 From: Apoorva Joshi Date: Thu, 6 Jul 2023 14:06:59 +0200 Subject: [PATCH] WIP implement OpenGL path --- .../lib/mx_pre_convolve_environment.glsl | 11 +-- .../MaterialXGenGlsl/GlslShaderGenerator.cpp | 10 ++- source/MaterialXRenderGlsl/GlslProgram.cpp | 13 +++- source/MaterialXView/RenderPipelineGL.cpp | 68 ++++++++++++++++++- source/MaterialXView/RenderPipelineMetal.mm | 13 ++-- 5 files changed, 98 insertions(+), 17 deletions(-) diff --git a/libraries/pbrlib/genglsl/lib/mx_pre_convolve_environment.glsl b/libraries/pbrlib/genglsl/lib/mx_pre_convolve_environment.glsl index fe05fae8d4..15224df63d 100644 --- a/libraries/pbrlib/genglsl/lib/mx_pre_convolve_environment.glsl +++ b/libraries/pbrlib/genglsl/lib/mx_pre_convolve_environment.glsl @@ -103,12 +103,13 @@ float v_smith_joint_ggx(float NdotL, float NdotV, float alpha, float partLambdaV float lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2); // Simplify visibility term: (2.0 * NdotL * NdotV) / ((4.0 * NdotL * NdotV) * (lambda_v + lambda_l)) - return 0.5 / max(lambdaV + lambdaL, FLT_MIN); + #define EPSILON 0.00001 + return 0.5 / max(lambdaV + lambdaL, EPSILON); } vec3 mx_pre_convolve_environment() { - vec2 uv = gl_FragCoord.xy * pow(2.0, (float)$convolutionMipLevel) / vec2(2048.0, 1024.0); + vec2 uv = gl_FragCoord.xy * pow(2.0, $convolutionMipLevel) / vec2(2048.0, 1024.0); if ($convolutionMipLevel == 0) { return textureLod($envRadiance, uv, 0).rgb; } @@ -117,8 +118,8 @@ vec3 mx_pre_convolve_environment() vec3 N = mx_latlong_map_lookup_inverse(uv); mat3 localToWorld = get_local_frame(N); - const vec3 V = N; - const float NdotV = 1; // Because N == V + vec3 V = N; + float NdotV = 1; // Because N == V float alpha = mx_lod_to_alpha(float($convolutionMipLevel)); float partLambdaV = get_smith_joint_ggx_part_lambda_v(NdotV, alpha); // If we use prefiltering, we can have a smaller sample count, since pre-filtering will reduce @@ -126,7 +127,7 @@ vec3 mx_pre_convolve_environment() // implemented prefiltering yet, so we use a high sample count. int sampleCount = 1597; // Must be a Fibonacci number - float3 lightInt = float3(0.0, 0.0, 0.0); + vec3 lightInt = vec3(0.0, 0.0, 0.0); float cbsdfInt = 0.0; for (int i = 0; i < sampleCount; ++i) diff --git a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp index 6d7d7c4ae1..8396a259e6 100644 --- a/source/MaterialXGenGlsl/GlslShaderGenerator.cpp +++ b/source/MaterialXGenGlsl/GlslShaderGenerator.cpp @@ -557,7 +557,7 @@ void GlslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& c bool lighting = requiresLighting(graph); // Define directional albedo approach - if (lighting || context.getOptions().hwWriteAlbedoTable) + if (lighting || context.getOptions().hwWriteAlbedoTable || context.getOptions().hwWriteEnvPreConvolution) { emitLine("#define DIRECTIONAL_ALBEDO_METHOD " + std::to_string(int(context.getOptions().hwDirectionalAlbedoMethod)), stage, false); emitLineBreak(stage); @@ -598,8 +598,8 @@ void GlslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& c // Emit environment pre-convolution code if (context.getOptions().hwWriteEnvPreConvolution) { - // TODO: Implement this - assert(false); + emitLibraryInclude("pbrlib/genglsl/lib/mx_pre_convolve_environment.glsl", context, stage); + emitLineBreak(stage); } // Set the include file to use for uv transformations, @@ -647,6 +647,10 @@ void GlslShaderGenerator::emitPixelStage(const ShaderGraph& graph, GenContext& c { emitLine(outputSocket->getVariable() + " = vec4(mx_generate_dir_albedo_table(), 1.0)", stage); } + else if (context.getOptions().hwWriteEnvPreConvolution) + { + emitLine(outputSocket->getVariable() + " = vec4(mx_pre_convolve_environment(), 1.0)", stage); + } else { // Add all function calls. diff --git a/source/MaterialXRenderGlsl/GlslProgram.cpp b/source/MaterialXRenderGlsl/GlslProgram.cpp index 900cac0ef1..cad011bb28 100644 --- a/source/MaterialXRenderGlsl/GlslProgram.cpp +++ b/source/MaterialXRenderGlsl/GlslProgram.cpp @@ -578,9 +578,20 @@ void GlslProgram::bindLighting(LightHandlerPtr lightHandler, ImageHandlerPtr ima Matrix44 envRotation = Matrix44::createRotationY(PI) * lightHandler->getLightTransform().getTranspose(); bindUniform(HW::ENV_MATRIX, Value::createValue(envRotation), false); bindUniform(HW::ENV_RADIANCE_SAMPLES, Value::createValue(lightHandler->getEnvSampleCount()), false); + ImagePtr envRadiance = nullptr; + if (lightHandler->getIndirectLighting()) + { + envRadiance = lightHandler->getUsePreConvolvedEnvLighting() ? + lightHandler->getEnvRadianceMapPreConvolved() : + lightHandler->getEnvRadianceMap(); + } + else + { + envRadiance = imageHandler->getZeroImage(); + } ImageMap envImages = { - { HW::ENV_RADIANCE, lightHandler->getIndirectLighting() ? lightHandler->getEnvRadianceMap() : imageHandler->getZeroImage() }, + { HW::ENV_RADIANCE, envRadiance }, { HW::ENV_IRRADIANCE, lightHandler->getIndirectLighting() ? lightHandler->getEnvIrradianceMap() : imageHandler->getZeroImage() } }; for (const auto& env : envImages) diff --git a/source/MaterialXView/RenderPipelineGL.cpp b/source/MaterialXView/RenderPipelineGL.cpp index cacf25f23b..b2ae43aefa 100644 --- a/source/MaterialXView/RenderPipelineGL.cpp +++ b/source/MaterialXView/RenderPipelineGL.cpp @@ -112,8 +112,72 @@ void GLRenderPipeline::updateAlbedoTable(int tableSize) mx::ImagePtr GLRenderPipeline::convolveEnvironment() { - // TODO: Implement this. - return nullptr; + auto& genContext = _viewer->_genContext; + auto& lightHandler = _viewer->_lightHandler; + auto& imageHandler = _viewer->_imageHandler; + mx::GLTextureHandlerPtr glImageHandler = std::dynamic_pointer_cast(imageHandler); + + // Create the convolution shader. + mx::GlslMaterialPtr material = nullptr; + try + { + mx::ShaderPtr hwShader = mx::createEnvPreConvolutionShader(genContext, _viewer->_stdLib, "__ENV_PRE_CONVOLUTION__"); + material = mx::GlslMaterial::create(); + material->generateShader(hwShader); + } + catch (std::exception& e) + { + new ng::MessageDialog(_viewer, ng::MessageDialog::Type::Warning, "Failed to generate convolution shader", e.what()); + return nullptr; + } + + mx::ImagePtr srcTex = lightHandler->getEnvRadianceMap(); + int w = srcTex->getWidth(); + int h = srcTex->getHeight(); + + // Create texture to hold the convolved environment. + mx::ImagePtr outTex = mx::Image::create(w, h, 3, mx::Image::BaseType::HALF, true); + glImageHandler->createRenderResources(outTex, true); // TODO: Is this needed? + + + int i = 0; + while (w > 0 && h > 0) + { + // Create framebuffer + unsigned int framebuffer; + glGenFramebuffers(1, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, outTex->getResourceId(), i); + glViewport(0, 0, w, h); + material->bindShader(); + + // TODO: Can this be moved out of the loop? + // Bind the source texture to attachment 0 + mx::ImageSamplingProperties samplingProperties; + samplingProperties.uaddressMode = mx::ImageSamplingProperties::AddressMode::PERIODIC; + samplingProperties.vaddressMode = mx::ImageSamplingProperties::AddressMode::CLAMP; + samplingProperties.filterType = mx::ImageSamplingProperties::FilterType::LINEAR; + imageHandler->bindImage(srcTex, samplingProperties); + + int textureLocation = glImageHandler->getBoundTextureLocation(srcTex->getResourceId()); + assert(textureLocation >= 0); + material->getProgram()->bindUniform(mx::HW::ENV_RADIANCE, mx::Value::createValue(textureLocation)); + glActiveTexture(GL_TEXTURE0); + + _viewer->renderScreenSpaceQuad(material); + + glDeleteFramebuffers(1, &framebuffer); + + w /= 2; + h /= 2; + i++; + } + + // Clean up. + glViewport(0, 0, _viewer->m_fbsize[0], _viewer->m_fbsize[1]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + + return outTex; } mx::ImagePtr GLRenderPipeline::getShadowMap(int shadowMapSize) diff --git a/source/MaterialXView/RenderPipelineMetal.mm b/source/MaterialXView/RenderPipelineMetal.mm index 7dd614fd98..45bb4f396b 100644 --- a/source/MaterialXView/RenderPipelineMetal.mm +++ b/source/MaterialXView/RenderPipelineMetal.mm @@ -162,14 +162,15 @@ auto& imageHandler = _viewer->_imageHandler; mx::MetalTextureHandlerPtr mtlImageHandler = std::dynamic_pointer_cast(imageHandler); - mx::ImagePtr envMip0 = lightHandler->getEnvRadianceMap(); - int w = envMip0->getWidth(); - int h = envMip0->getHeight(); + mx::ImagePtr srcTex = lightHandler->getEnvRadianceMap(); + int w = srcTex->getWidth(); + int h = srcTex->getHeight(); - mtlImageHandler->createRenderResources(envMip0, true); // Turn mipmaps off + // TODO: Is this needed? + mtlImageHandler->createRenderResources(srcTex, true); // Turn mipmaps off mx::ImagePtr outTex = mx::Image::create(w, h, 3, mx::Image::BaseType::HALF, true); - mtlImageHandler->createRenderResources(outTex, true); + mtlImageHandler->createRenderResources(outTex, true); // TODO: Is this needed? id metalTex = mtlImageHandler->getAssociatedMetalTexture(outTex); @@ -178,7 +179,7 @@ MTL(device), w, h, 4, - mx::Image::BaseType::UINT8, + mx::Image::BaseType::UINT8, // TODO: Should this be HALF? metalTex );