diff --git a/samples/03_model_render/model/BoxTexturedNonPowerOfTwo.glb b/samples/03_model_render/model/BoxTexturedNonPowerOfTwo.glb new file mode 100644 index 0000000..a5ffb78 --- /dev/null +++ b/samples/03_model_render/model/BoxTexturedNonPowerOfTwo.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:624621d7885bb418ac64e99c994b45634a32c87caeefae67b06c5c0531c57115 +size 4696 diff --git a/samples/03_model_render/model/MetalRoughSpheres.glb b/samples/03_model_render/model/MetalRoughSpheres.glb new file mode 100644 index 0000000..3437cc6 --- /dev/null +++ b/samples/03_model_render/model/MetalRoughSpheres.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:450c05557b0823a10835e32c05caf77a7b175eba94516555c1c9bb084f563f01 +size 11221356 diff --git a/samples/03_model_render/model_render.cpp b/samples/03_model_render/model_render.cpp index 42fb9df..3597ee5 100644 --- a/samples/03_model_render/model_render.cpp +++ b/samples/03_model_render/model_render.cpp @@ -372,6 +372,7 @@ main(int, char **) bool rotating = false; bool lockToScreen = true; bool showDiffuse = false; + bool useDiffuse = true; i32 height = Cast(internalResolution.height); f32 camPitch = glm::degrees(cameraController.m_Pitch); f32 camYaw = glm::degrees(cameraController.m_Yaw); @@ -446,7 +447,11 @@ main(int, char **) { cameraController.SetPosition(camPosition); } + gui::Separator(); + gui::Text("IBL"); gui::Checkbox("Show DiffIrr", &showDiffuse); + gui::Checkbox("Use DiffIrr", &useDiffuse); + gui::Separator(); gui::Checkbox("Rotate", &rotating); gui::PopItemWidth(); if (gui::Button("Exit")) @@ -559,6 +564,18 @@ main(int, char **) cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof texCube, &texCube); pcbOffset += sizeof texCube; } + if (useDiffuse) + { + cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof diffuseIrr, + &diffuseIrr); + pcbOffset += sizeof diffuseIrr; + } + else + { + TextureHandle invalid; + cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof invalid, &invalid); + pcbOffset += sizeof invalid; + } static_assert(sizeof texCube == sizeof diffuseIrr); cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, pcbOffset, sizeof lightManager.m_MetaInfo, &lightManager.m_MetaInfo); diff --git a/samples/03_model_render/pipeline_utils.cpp b/samples/03_model_render/pipeline_utils.cpp index 53179d2..d4a409c 100644 --- a/samples/03_model_render/pipeline_utils.cpp +++ b/samples/03_model_render/pipeline_utils.cpp @@ -57,7 +57,7 @@ CreatePipeline(const Device *device, vk::Format attachmentFormat, const GpuResou vk::PushConstantRange pushConstantRange = { .stageFlags = vk::ShaderStageFlagBits::eAll, .offset = 0, - .size = 40, + .size = 44, }; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { @@ -206,7 +206,7 @@ CreateBackgroundPipeline(const Device *device, vk::Format attachmentFormat, cons vk::PushConstantRange pushConstantRange = { .stageFlags = vk::ShaderStageFlagBits::eAll, .offset = 0, - .size = 40, + .size = 44, }; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { diff --git a/samples/03_model_render/shader/graphics_structs.hlsli b/samples/03_model_render/shader/graphics_structs.hlsli index 4f45bfa..c305415 100644 --- a/samples/03_model_render/shader/graphics_structs.hlsli +++ b/samples/03_model_render/shader/graphics_structs.hlsli @@ -16,6 +16,7 @@ struct Block uint MaterialBufferHandle; uint NodeBufferHandle; uint EnvCubeHandle; + uint DiffuseIrradianceHandle; uint LightHandle; uint PointLightIndexer; uint DirectionalLightIndexer; diff --git a/samples/03_model_render/shader/model.ps.hlsl b/samples/03_model_render/shader/model.ps.hlsl index f9b5e2b..17bc179 100644 --- a/samples/03_model_render/shader/model.ps.hlsl +++ b/samples/03_model_render/shader/model.ps.hlsl @@ -10,7 +10,7 @@ struct FS_Input struct FS_Output { - float4 ColorTarget : SV_Target0; + float4 ColorTarget : SV_Target0; }; float4 GetAlbedo(float2 UV, float4 InColor) @@ -21,6 +21,13 @@ float4 GetAlbedo(float2 UV, float4 InColor) return AlbedoFactor * InColor * (AlbedoTexId != INVALID_HANDLE ? Textures[AlbedoTexId].Sample(ImmutableSamplers[AlbedoTexId], UV) : 1.0f.xxxx); } +float GetOcclusion(float2 UV) +{ + uint OcclusionTexId = MaterialsBuffer[PushConstant.MaterialBufferHandle][PushConstant.MaterialIdx].OcclusionTex; + + return OcclusionTexId != INVALID_HANDLE ? Textures[OcclusionTexId].Sample(ImmutableSamplers[OcclusionTexId], UV).r : 1.0f; +} + float3 GetEmissive(float2 UV) { float3 EmissionFactor = (float3) MaterialsBuffer[PushConstant.MaterialBufferHandle][PushConstant.MaterialIdx].EmissionFactor; @@ -61,6 +68,15 @@ float2 GetMetalRough(float2 UV) return MetalRoughFactors * (MetalRoughTexId != INVALID_HANDLE ? Textures[MetalRoughTexId].Sample(ImmutableSamplers[MetalRoughTexId], UV).bg : 1.0f.xx); // Metal is B, Rough is G. } +float3 SampleIrradiance(float3 Direction) +{ + if (PushConstant.DiffuseIrradianceHandle != INVALID_HANDLE) + { + return TextureCubes[PushConstant.DiffuseIrradianceHandle].Sample(ImmutableSamplers[PushConstant.DiffuseIrradianceHandle], Direction).rgb; + } + return 0.04f.xxx; +} + float TrowbridgeReitzGGX(float3 Normal, float3 Halfway, float Roughness) { float Coeff = Roughness * Roughness; @@ -100,6 +116,12 @@ float3 FresnelSchlick(float cosine, float3 F_0) return F_0 + (1.0f - F_0) * pow(clamp(1.0f - cosine, 0.0f, 1.0f), 5.0f); // Clamp to avoid artifacts. } +// Sebastian Lagarde +float3 FresnelSchlickRoughness(float cosine, float3 F_0, float Roughness) +{ + return F_0 + (max((1.0f - Roughness).xxx, F_0) - F_0) * pow(clamp(1.0f - cosine, 0.0f, 1.0f), 5.0f); // Clamp to avoid artifacts. +} + float3 GetPBRContrib(float3 Albedo, float3 LightColor, float3 ViewDir, float3 Normal, float Metallic, float Roughness, float3 F_0, float3 LightDir, float LightDistance) { float Attenuation = 1.0f / (LightDistance * LightDistance); // TODO: Controlled Attenuation @@ -113,18 +135,18 @@ float3 GetPBRContrib(float3 Albedo, float3 LightColor, float3 ViewDir, float3 No float NormalDistribution = TrowbridgeReitzGGX(Normal, Halfway, Roughness); float Geometry = GeometrySmith(NdotV, NdotL, Roughness); - float3 Fresnel = FresnelSchlick(CosineFactor, F_0); + float3 Fresnel = FresnelSchlickRoughness(CosineFactor, F_0, Roughness); float3 Numerator = (NormalDistribution * Geometry) * Fresnel; float Denominator = 4.0f * NdotV * NdotL; - float3 Specular = Numerator / max(Denominator, 0.00001); + float3 Specular = Numerator / (Denominator + 0.00001f); float3 K_Specular = Fresnel; float3 K_Diffuse = 1.0f.xxx - K_Specular; K_Diffuse *= 1.0f - Metallic; - return NdotL * Radiance * ((K_Diffuse * Albedo / PI) + Specular); + return NdotL * Radiance * (K_Diffuse * Albedo / PI + Specular); } float3 GetPointLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal) @@ -144,7 +166,6 @@ float3 GetPointLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, // TODO: Cite float3 F_0 = 0.04f.xxx; F_0 = lerp(F_0, Albedo, Metallic); - float3 LightAmp = float3(23.47f, 21.31f, 20.79f); // TODO: Get rid float3 Contrib = 0.0f; for (uint i = 0; i < Count; ++i) @@ -167,7 +188,7 @@ float3 GetPointLightInfluence(float3 Albedo, float2 MetalRough, float3 Position, float G = (Light.Color & 0x00FF0000) >> 16; float B = (Light.Color & 0x0000FF00) >> 8; - float3 LightColor = LightAmp * Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255 + float3 LightColor = Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255 Contrib += GetPBRContrib(Albedo, LightColor, ViewDir, Normal, Metallic, Roughness, F_0, LightDir, LightDistance); } @@ -192,7 +213,6 @@ float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Pos // TODO: Cite float3 F_0 = 0.04f.xxx; F_0 = lerp(F_0, Albedo, Metallic); - float3 LightAmp = float3(23.47f, 21.31f, 20.79f); // TODO: Get rid float3 Contrib = 0.0f; for (uint i = 0; i < Count; ++i) @@ -209,7 +229,7 @@ float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Pos float G = (Light.Color & 0x00FF0000) >> 16; float B = (Light.Color & 0x0000FF00) >> 8; - float3 LightColor = LightAmp * Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255 + float3 LightColor = Light.Intensity * float3(R, G, B) * 0.00392156862f; // 0.00392156862 = 1/255 Contrib += GetPBRContrib(Albedo, LightColor, ViewDir, Normal, Metallic, Roughness, F_0, LightDir, 1.0f); } @@ -217,12 +237,27 @@ float3 GetDirectionalLightInfluence(float3 Albedo, float2 MetalRough, float3 Pos return Contrib; } +float3 GetAmbientInfluence(float3 Albedo, float2 MetalRough, float3 Position, float3 Normal, float Occlusion) +{ + float3 ViewDir = normalize(Camera.Position.xyz - Position); + float CosineFactor = max(dot(Normal, ViewDir), 0.0f); // TODO: Is Normal or is it Halfway? + + float3 F_0 = 0.04f.xxx; + F_0 = lerp(F_0, Albedo, MetalRough.r); + float3 K_Specular = FresnelSchlickRoughness(CosineFactor, F_0, MetalRough.g); + float3 K_Diffuse = 1.0f.xxx - K_Specular; + + K_Diffuse *= 1.0f - MetalRough.r; // Metals don't have diffuse/refractions. + + float3 DiffuseIrradiance = K_Diffuse * Albedo * SampleIrradiance(Normal) * Occlusion; + + return DiffuseIrradiance; +} + FS_Output main(FS_Input StageInput) { FS_Output Output; - float3 Ambient = float3(0.02f, 0.02f, 0.02f); - // TODO: This should be invalid on the CPU side. if (PushConstant.MaterialIdx < 0) { @@ -238,7 +273,12 @@ FS_Output main(FS_Input StageInput) float Alpha = AlbedoAlpha.a; float2 MetalRough = GetMetalRough(StageInput.InUV0); float3 Emission = GetEmissive(StageInput.InUV0); - float3 Color = GetDirectionalLightInfluence(Albedo, MetalRough, Position, Normal) + GetPointLightInfluence(Albedo, MetalRough, Position, Normal); + float Occlusion = GetOcclusion(StageInput.InUV0); + + float3 DirectionalLightLum = GetDirectionalLightInfluence(Albedo, MetalRough, Position, Normal); + float3 PointLighLum = GetPointLightInfluence(Albedo, MetalRough, Position, Normal); + float3 AmbientLum = GetAmbientInfluence(Albedo, MetalRough, Position, Normal, Occlusion); + float3 Color = DirectionalLightLum + PointLighLum + AmbientLum; Output.ColorTarget = float4(Uncharted2Tonemap(Color + Emission), Alpha); return Output;