diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index 04f7eac4b..9fac0e954 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -89,6 +89,10 @@ namespace Nz #include }; + const UInt8 r_mathDepthModule[] = { + #include + }; + // Passes const UInt8 r_gammaCorrectionPass[] = { #include @@ -487,6 +491,7 @@ namespace Nz RegisterEmbedShaderModule(r_mathColorModule); RegisterEmbedShaderModule(r_mathConstantsModule); RegisterEmbedShaderModule(r_mathCookTorrancePBRModule); + RegisterEmbedShaderModule(r_mathDepthModule); RegisterEmbedShaderModule(r_phongMaterialShader); RegisterEmbedShaderModule(r_physicallyBasedMaterialShader); RegisterEmbedShaderModule(r_skinningDataModule); diff --git a/src/Nazara/Graphics/Resources/Shaders/BasicMaterial.nzsl b/src/Nazara/Graphics/Resources/Shaders/BasicMaterial.nzsl index ddbc7d3df..30ce0a87c 100644 --- a/src/Nazara/Graphics/Resources/Shaders/BasicMaterial.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/BasicMaterial.nzsl @@ -72,7 +72,7 @@ external [tag("SkeletalData")] skeletalData: uniform[SkeletalData] } -struct VertToFrag +struct VertOut { [location(0)] worldPos: vec3[f32], [location(1), cond(HasUV)] uv: vec2[f32], @@ -87,7 +87,7 @@ struct FragOut [builtin(frag_depth), cond(DistanceDepth)] fragdepth: f32 } -fn ComputeColor(input: VertToFrag) -> vec4[f32] +fn ComputeColor(input: VertOut) -> vec4[f32] { let color = settings.BaseColor; @@ -103,19 +103,20 @@ fn ComputeColor(input: VertToFrag) -> vec4[f32] const if (HasAlphaTexture) color.w *= MaterialAlphaMap.Sample(input.uv).x; - return color; -} - -[entry(frag), cond(!DepthPass || AlphaTest)] -fn main(input: VertToFrag) -> FragOut -{ - let color = ComputeColor(input); const if (AlphaTest) { if (color.w < settings.AlphaThreshold) discard; } + return color; +} + +[entry(frag), cond(!DepthPass || AlphaTest)] +fn FragMain(input: VertOut) -> FragOut +{ + let color = ComputeColor(input); + let output: FragOut; output.RenderTarget0 = color; return output; @@ -124,14 +125,9 @@ fn main(input: VertToFrag) -> FragOut // Shadow passes entries [entry(frag), cond(DepthPass && DistanceDepth)] [depth_write(replace)] -fn main(input: VertToFrag) -> FragOut +fn FragDepthDist(input: VertOut) -> FragOut { let color = ComputeColor(input); - const if (AlphaTest) - { - if (color.w < settings.AlphaThreshold) - discard; - } let output: FragOut; output.RenderTarget0 = color; @@ -143,11 +139,9 @@ fn main(input: VertToFrag) -> FragOut } [entry(frag), cond(DepthPass && AlphaTest && !DistanceDepth)] -fn main(input: VertToFrag) -> FragOut +fn FragDepth(input: VertOut) -> FragOut { let color = ComputeColor(input); - if (color.w < settings.AlphaThreshold) - discard; let output: FragOut; output.RenderTarget0 = color; @@ -155,7 +149,7 @@ fn main(input: VertToFrag) -> FragOut } [entry(frag), cond(DepthPass && !AlphaTest && !DistanceDepth)] -fn main() {} //< dummy +fn FragDepthNoAlpha() {} //< dummy // Vertex stage struct VertIn @@ -189,7 +183,7 @@ struct VertIn } [entry(vert), cond(Billboard)] -fn billboardMain(input: VertIn) -> VertToFrag +fn VertBillboard(input: VertIn) -> VertOut { let size = input.billboardSizeRot.xy; let sinCos = input.billboardSizeRot.zw; @@ -209,7 +203,7 @@ fn billboardMain(input: VertIn) -> VertToFrag let worldPosition = instanceData.worldMatrix * vec4[f32](vertexPos, 1.0); - let output: VertToFrag; + let output: VertOut; output.worldPos = worldPosition.xyz; output.position = viewerData.viewProjMatrix * worldPosition; @@ -223,7 +217,7 @@ fn billboardMain(input: VertIn) -> VertToFrag } [entry(vert), cond(!Billboard)] -fn main(input: VertIn) -> VertToFrag +fn VertMain(input: VertIn) -> VertOut { let pos: vec3[f32]; @@ -251,7 +245,7 @@ fn main(input: VertIn) -> VertToFrag let worldPosition = instanceData.worldMatrix * vec4[f32](pos, 1.0); - let output: VertToFrag; + let output: VertOut; output.worldPos = worldPosition.xyz; output.position = viewerData.viewProjMatrix * worldPosition; diff --git a/src/Nazara/Graphics/Resources/Shaders/Modules/Math/Depth.nzsl b/src/Nazara/Graphics/Resources/Shaders/Modules/Math/Depth.nzsl new file mode 100644 index 000000000..7e3ca1d36 --- /dev/null +++ b/src/Nazara/Graphics/Resources/Shaders/Modules/Math/Depth.nzsl @@ -0,0 +1,8 @@ +[nzsl_version("1.0")] +module Math.Depth; + +[export] +fn LinearizeDepth(depth: f32, zNear: f32, zFar: f32) -> f32 +{ + return zNear * zFar / (zFar + depth * (zNear - zFar)); +} diff --git a/src/Nazara/Graphics/Resources/Shaders/PhongMaterial.nzsl b/src/Nazara/Graphics/Resources/Shaders/PhongMaterial.nzsl index dba2848fa..29ea98df1 100644 --- a/src/Nazara/Graphics/Resources/Shaders/PhongMaterial.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/PhongMaterial.nzsl @@ -111,7 +111,7 @@ external [tag("ShadowMapsSpot")] shadowMapsSpot: array[depth_sampler2D[f32], MaxLightCount], } -struct VertToFrag +struct VertOut { [location(0)] worldPos: vec3[f32], [location(1), cond(HasUV)] uv: vec2[f32], @@ -129,21 +129,7 @@ struct FragOut [builtin(frag_depth), cond(DistanceDepth)] fragdepth: f32, } -fn LinearizeDepth(depth: f32, zNear: f32, zFar: f32) -> f32 -{ - return zNear * zFar / (zFar + depth * (zNear - zFar)); -} - -// http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/ -fn GetSlopeScaledBias(normal: vec3[f32], lightDir: vec3[f32]) -> f32 -{ - let cosAlpha = clamp(dot(normal, lightDir), 0.0, 1.0); - let sinAlpha = sqrt(1.0 - cosAlpha * cosAlpha); // sin(acos(L*N)) - let tanAlpha = sinAlpha / cosAlpha; // tan(acos(L*N)) - return tanAlpha; -} - -fn ComputeColor(input: VertToFrag) -> vec4[f32] +fn ComputeColor(input: VertOut) -> vec4[f32] { let color = settings.BaseColor; @@ -159,115 +145,119 @@ fn ComputeColor(input: VertToFrag) -> vec4[f32] const if (HasAlphaTexture) color.w *= MaterialAlphaMap.Sample(input.uv).x; - return color; -} - -[entry(frag), cond(!DepthPass)] -fn main(input: VertToFrag) -> FragOut -{ - let color = ComputeColor(input); const if (AlphaTest) { if (color.w < settings.AlphaThreshold) discard; } - const if (HasLighting) + return color; +} + +[cond(HasLighting)] +fn ComputeLighting(color: vec3[f32], input: VertOut) -> vec3[f32] +{ + let lightAmbient = vec3[f32](0.0, 0.0, 0.0); + let lightDiffuse = vec3[f32](0.0, 0.0, 0.0); + let lightSpecular = vec3[f32](0.0, 0.0, 0.0); + + let eyeVec = normalize(viewerData.eyePosition - input.worldPos); + + let normal: vec3[f32]; + const if (HasNormalMapping) { - let lightAmbient = vec3[f32](0.0, 0.0, 0.0); - let lightDiffuse = vec3[f32](0.0, 0.0, 0.0); - let lightSpecular = vec3[f32](0.0, 0.0, 0.0); + let N = normalize(input.normal); + let T = normalize(input.tangent); + let B = cross(N, T); + let tbnMatrix = mat3[f32](T, B, N); - let eyeVec = normalize(viewerData.eyePosition - input.worldPos); - - let normal: vec3[f32]; - const if (HasNormalMapping) - { - let N = normalize(input.normal); - let T = normalize(input.tangent); - let B = cross(N, T); - let tbnMatrix = mat3[f32](T, B, N); - - normal = normalize(tbnMatrix * (MaterialNormalMap.Sample(input.uv).xyz * 2.0 - vec3[f32](1.0, 1.0, 1.0))); - } - else - normal = normalize(input.normal); - - for lightIndex in u32(0) -> lightData.directionalLightCount - { - let light = lightData.directionalLights[lightIndex]; - - let lambert = max(dot(normal, -light.direction), 0.0); - - let reflection = reflect(light.direction, normal); - let specFactor = max(dot(reflection, eyeVec), 0.0); - specFactor = pow(specFactor, settings.Shininess); - - let shadowFactor = ComputeDirectionalLightShadow(light, shadowMapsDirectional[lightIndex], input.worldPos, lambert, viewerData.viewMatrix); - - lightAmbient += shadowFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb; - lightDiffuse += shadowFactor * lambert * light.color.rgb * light.diffuseFactor; - lightSpecular += shadowFactor * specFactor * light.color.rgb; - } - - for lightIndex in u32(0) -> lightData.pointLightCount - { - let light = lightData.pointLights[lightIndex]; - - let lightToPos = input.worldPos - light.position; - let dist = length(lightToPos); - let lightToPosNorm = lightToPos / max(dist, 0.0001); - - let attenuationFactor = max(1.0 - dist * light.invRadius, 0.0); - let lambert = clamp(dot(normal, -lightToPosNorm), 0.0, 1.0); - - let reflection = reflect(lightToPosNorm, normal); - let specFactor = max(dot(reflection, eyeVec), 0.0); - specFactor = pow(specFactor, settings.Shininess); - - let shadowFactor = ComputePointLightShadow(light, shadowMapsPoint[lightIndex], dist, lightToPosNorm); - - lightAmbient += attenuationFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb; - lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * light.diffuseFactor; - lightSpecular += shadowFactor * attenuationFactor * specFactor * light.color.rgb; - } - - for lightIndex in u32(0) -> lightData.spotLightCount - { - let light = lightData.spotLights[lightIndex]; - - let lightToPos = input.worldPos - light.position; - let dist = length(lightToPos); - let lightToPosNorm = lightToPos / max(dist, 0.0001); - - let curAngle = dot(light.direction, lightToPosNorm); - let innerMinusOuterAngle = light.innerAngle - light.outerAngle; - - let attenuationFactor = max(1.0 - dist * light.invRadius, 0.0); - attenuationFactor *= max((curAngle - light.outerAngle) / innerMinusOuterAngle, 0.0); - - let lambert = clamp(dot(normal, -lightToPosNorm), 0.0, 1.0); - - let reflection = reflect(lightToPosNorm, normal); - let specFactor = max(dot(reflection, eyeVec), 0.0); - specFactor = pow(specFactor, settings.Shininess); - - let shadowFactor = ComputeSpotLightShadow(light, shadowMapsSpot[lightIndex], input.worldPos, lambert); - - lightAmbient += attenuationFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb; - lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * light.diffuseFactor; - lightSpecular += shadowFactor * attenuationFactor * specFactor * light.color.rgb; - } - - lightSpecular *= settings.SpecularColor.rgb; - - const if (HasSpecularTexture) - lightSpecular *= MaterialSpecularMap.Sample(input.uv).rgb; - - let lightColor = lightAmbient + lightDiffuse + lightSpecular; - - color.rgb *= lightColor; + normal = normalize(tbnMatrix * (MaterialNormalMap.Sample(input.uv).xyz * 2.0 - vec3[f32](1.0, 1.0, 1.0))); } + else + normal = normalize(input.normal); + + for lightIndex in u32(0) -> lightData.directionalLightCount + { + let light = lightData.directionalLights[lightIndex]; + + let lambert = max(dot(normal, -light.direction), 0.0); + + let reflection = reflect(light.direction, normal); + let specFactor = max(dot(reflection, eyeVec), 0.0); + specFactor = pow(specFactor, settings.Shininess); + + let shadowFactor = ComputeDirectionalLightShadow(light, shadowMapsDirectional[lightIndex], input.worldPos, lambert, viewerData.viewMatrix); + + lightAmbient += shadowFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb; + lightDiffuse += shadowFactor * lambert * light.color.rgb * light.diffuseFactor; + lightSpecular += shadowFactor * specFactor * light.color.rgb; + } + + for lightIndex in u32(0) -> lightData.pointLightCount + { + let light = lightData.pointLights[lightIndex]; + + let lightToPos = input.worldPos - light.position; + let dist = length(lightToPos); + let lightToPosNorm = lightToPos / max(dist, 0.0001); + + let attenuationFactor = max(1.0 - dist * light.invRadius, 0.0); + let lambert = clamp(dot(normal, -lightToPosNorm), 0.0, 1.0); + + let reflection = reflect(lightToPosNorm, normal); + let specFactor = max(dot(reflection, eyeVec), 0.0); + specFactor = pow(specFactor, settings.Shininess); + + let shadowFactor = ComputePointLightShadow(light, shadowMapsPoint[lightIndex], dist, lightToPosNorm); + + lightAmbient += attenuationFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb; + lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * light.diffuseFactor; + lightSpecular += shadowFactor * attenuationFactor * specFactor * light.color.rgb; + } + + for lightIndex in u32(0) -> lightData.spotLightCount + { + let light = lightData.spotLights[lightIndex]; + + let lightToPos = input.worldPos - light.position; + let dist = length(lightToPos); + let lightToPosNorm = lightToPos / max(dist, 0.0001); + + let curAngle = dot(light.direction, lightToPosNorm); + let innerMinusOuterAngle = light.innerAngle - light.outerAngle; + + let attenuationFactor = max(1.0 - dist * light.invRadius, 0.0); + attenuationFactor *= max((curAngle - light.outerAngle) / innerMinusOuterAngle, 0.0); + + let lambert = clamp(dot(normal, -lightToPosNorm), 0.0, 1.0); + + let reflection = reflect(lightToPosNorm, normal); + let specFactor = max(dot(reflection, eyeVec), 0.0); + specFactor = pow(specFactor, settings.Shininess); + + let shadowFactor = ComputeSpotLightShadow(light, shadowMapsSpot[lightIndex], input.worldPos, lambert); + + lightAmbient += attenuationFactor * light.color.rgb * light.ambientFactor * settings.AmbientColor.rgb; + lightDiffuse += shadowFactor * attenuationFactor * lambert * light.color.rgb * light.diffuseFactor; + lightSpecular += shadowFactor * attenuationFactor * specFactor * light.color.rgb; + } + + lightSpecular *= settings.SpecularColor.rgb; + + const if (HasSpecularTexture) + lightSpecular *= MaterialSpecularMap.Sample(input.uv).rgb; + + let lightColor = lightAmbient + lightDiffuse + lightSpecular; + return color * lightColor; +} + +[entry(frag), cond(!DepthPass)] +fn FragMain(input: VertOut) -> FragOut +{ + let color = ComputeColor(input); + + const if (HasLighting) + color.rgb = ComputeLighting(color.rgb, input); let output: FragOut; output.RenderTarget0 = color; @@ -278,14 +268,9 @@ fn main(input: VertToFrag) -> FragOut // Shadow passes entries [entry(frag), cond(DepthPass && DistanceDepth)] [depth_write(replace)] -fn main(input: VertToFrag) -> FragOut +fn FragDepthDist(input: VertOut) -> FragOut { let color = ComputeColor(input); - const if (AlphaTest) - { - if (color.w < settings.AlphaThreshold) - discard; - } let output: FragOut; output.RenderTarget0 = color; @@ -297,11 +282,9 @@ fn main(input: VertToFrag) -> FragOut } [entry(frag), cond(DepthPass && AlphaTest && !DistanceDepth)] -fn main(input: VertToFrag) -> FragOut +fn FragDepth(input: VertOut) -> FragOut { let color = ComputeColor(input); - if (color.w < settings.AlphaThreshold) - discard; let output: FragOut; output.RenderTarget0 = color; @@ -309,7 +292,7 @@ fn main(input: VertToFrag) -> FragOut } [entry(frag), cond(DepthPass && !AlphaTest && !DistanceDepth)] -fn main() {} //< dummy +fn FragDepthNoAlpha() {} //< dummy // Vertex stage struct VertIn @@ -346,7 +329,7 @@ struct VertIn } [entry(vert), cond(Billboard)] -fn billboardMain(input: VertIn) -> VertToFrag +fn billboardMain(input: VertIn) -> VertOut { let size = input.billboardSizeRot.xy; let sinCos = input.billboardSizeRot.zw; @@ -364,7 +347,7 @@ fn billboardMain(input: VertIn) -> VertToFrag vertexPos += cameraRight * rotatedPosition.x; vertexPos += cameraUp * rotatedPosition.y; - let output: VertToFrag; + let output: VertOut; output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](vertexPos, 1.0); const if (HasColor) @@ -377,7 +360,7 @@ fn billboardMain(input: VertIn) -> VertToFrag } [entry(vert), cond(!Billboard)] -fn main(input: VertIn) -> VertToFrag +fn main(input: VertIn) -> VertOut { let pos: vec3[f32]; const if (HasNormal) let normal: vec3[f32]; @@ -419,7 +402,7 @@ fn main(input: VertIn) -> VertToFrag let worldPosition = instanceData.worldMatrix * vec4[f32](pos, 1.0); - let output: VertToFrag; + let output: VertOut; output.worldPos = worldPosition.xyz; output.position = viewerData.viewProjMatrix * worldPosition; diff --git a/src/Nazara/Graphics/Resources/Shaders/PhysicallyBasedMaterial.nzsl b/src/Nazara/Graphics/Resources/Shaders/PhysicallyBasedMaterial.nzsl index 20f189fb6..73f1b419d 100644 --- a/src/Nazara/Graphics/Resources/Shaders/PhysicallyBasedMaterial.nzsl +++ b/src/Nazara/Graphics/Resources/Shaders/PhysicallyBasedMaterial.nzsl @@ -104,7 +104,8 @@ external [tag("ShadowMapsSpot")] shadowMapsSpot: array[depth_sampler2D[f32], MaxLightCount], } -struct VertToFrag +[export] +struct VertOut { [location(0)] worldPos: vec3[f32], [location(1), cond(HasUV)] uv: vec2[f32], @@ -124,7 +125,8 @@ struct FragOut [builtin(frag_depth), cond(DistanceDepth)] fragdepth: f32, } -fn ComputeColor(input: VertToFrag) -> vec4[f32] +[export] +fn ComputeColor(input: VertOut) -> vec4[f32] { let color = settings.BaseColor; @@ -140,136 +142,132 @@ fn ComputeColor(input: VertToFrag) -> vec4[f32] const if (HasAlphaTexture) color.w *= MaterialAlphaMap.Sample(input.uv).x; - return color; -} - -[entry(frag), cond(!DepthPass)] -fn main(input: VertToFrag) -> FragOut -{ - let color = ComputeColor(input); const if (AlphaTest) { if (color.w < settings.AlphaThreshold) discard; } - const if (HasNormal && !DepthPass) + return color; +} + +[export, cond(HasNormal)] +fn ComputeLighting(color: vec3[f32], input: VertOut) -> vec3[f32] +{ + let lightRadiance = vec3[f32](0.0, 0.0, 0.0); + + let eyeVec = normalize(viewerData.eyePosition - input.worldPos); + + let normal: vec3[f32]; + const if (HasNormalMapping) { - let lightRadiance = vec3[f32](0.0, 0.0, 0.0); + let N = normalize(input.normal); + let T = normalize(input.tangent); + let B = cross(N, T); + let tbnMatrix = mat3[f32](T, B, N); - let eyeVec = normalize(viewerData.eyePosition - input.worldPos); - - let normal: vec3[f32]; - const if (HasNormalMapping) - { - let N = normalize(input.normal); - let T = normalize(input.tangent); - let B = cross(N, T); - let tbnMatrix = mat3[f32](T, B, N); - - normal = normalize(tbnMatrix * (MaterialNormalMap.Sample(input.uv).xyz * 2.0 - vec3[f32](1.0, 1.0, 1.0))); - } - else - normal = normalize(input.normal); - - let albedo = color.xyz; - let metallic: f32; - let roughness: f32; - - const if (HasMetallicTexture) - metallic = MaterialMetallicMap.Sample(input.uv).x; - else - metallic = 0.0; - - const if (HasRoughnessTexture) - roughness = MaterialRoughnessMap.Sample(input.uv).x; - else - roughness = 0.8; - - let F0 = vec3[f32](0.04, 0.04, 0.04); - F0 = albedo * metallic + F0 * (1.0 - metallic); - - let albedoFactor = albedo / Pi; - - for lightIndex in u32(0) -> lightData.directionalLightCount - { - let light = lightData.directionalLights[lightIndex]; - - let lambert = max(dot(normal, -light.direction), 0.0); - - let shadowFactor = ComputeDirectionalLightShadow(light, shadowMapsDirectional[lightIndex], input.worldPos, lambert, viewerData.viewMatrix); - let radiance = ComputeLightRadiance(light.color.rgb, -light.direction, 1.0, albedoFactor, eyeVec, F0, normal, metallic, roughness); - - lightRadiance += shadowFactor * radiance; - } - - for lightIndex in u32(0) -> lightData.pointLightCount - { - let light = lightData.pointLights[lightIndex]; - - let lightToPos = input.worldPos - light.position; - let dist = length(lightToPos); - - let attenuation = max(1.0 - dist * light.invRadius, 0.0); - let lightToPosNorm = lightToPos / max(dist, 0.0001); - - let shadowFactor = ComputePointLightShadow(light, shadowMapsPoint[lightIndex], dist, lightToPosNorm); - let radiance = ComputeLightRadiance(light.color.rgb, lightToPosNorm, attenuation, albedoFactor, eyeVec, F0, normal, metallic, roughness); - - lightRadiance += shadowFactor * radiance; - } - - for lightIndex in u32(0) -> lightData.spotLightCount - { - let light = lightData.spotLights[lightIndex]; - - let lightToPos = input.worldPos - light.position; - let dist = length(lightToPos); - let lightToPosNorm = lightToPos / max(dist, 0.0001); - - let curAngle = dot(light.direction, lightToPosNorm); - let innerMinusOuterAngle = light.innerAngle - light.outerAngle; - - let attenuation = max(1.0 - dist * light.invRadius, 0.0); - attenuation *= max((curAngle - light.outerAngle) / innerMinusOuterAngle, 0.0); - - let lambert = clamp(dot(normal, -lightToPosNorm), 0.0, 1.0); - - let shadowFactor = ComputeSpotLightShadow(light, shadowMapsSpot[lightIndex], input.worldPos, lambert); - let radiance = ComputeLightRadiance(light.color.rgb, lightToPosNorm, attenuation, albedoFactor, eyeVec, F0, normal, metallic, roughness); - - lightRadiance += shadowFactor * radiance; - } - - let ambient = (0.0001).rrr * albedo; - - let color = ambient + lightRadiance * color.rgb; - color = color / (color + vec3[f32](1.0, 1.0, 1.0)); - color = pow(color, (1.0 / 2.2).xxx); - - let output: FragOut; - output.RenderTarget0 = vec4[f32](color, 1.0); - return output; + normal = normalize(tbnMatrix * (MaterialNormalMap.Sample(input.uv).xyz * 2.0 - vec3[f32](1.0, 1.0, 1.0))); } else + normal = normalize(input.normal); + + let albedo = color.xyz; + let metallic: f32; + let roughness: f32; + + const if (HasMetallicTexture) + metallic = MaterialMetallicMap.Sample(input.uv).x; + else + metallic = 0.0; + + const if (HasRoughnessTexture) + roughness = MaterialRoughnessMap.Sample(input.uv).x; + else + roughness = 0.8; + + let F0 = vec3[f32](0.04, 0.04, 0.04); + F0 = albedo * metallic + F0 * (1.0 - metallic); + + let albedoFactor = albedo / Pi; + + for lightIndex in u32(0) -> lightData.directionalLightCount { - let output: FragOut; - output.RenderTarget0 = color; - return output; + let light = lightData.directionalLights[lightIndex]; + + let lambert = max(dot(normal, -light.direction), 0.0); + + let shadowFactor = ComputeDirectionalLightShadow(light, shadowMapsDirectional[lightIndex], input.worldPos, lambert, viewerData.viewMatrix); + let radiance = ComputeLightRadiance(light.color.rgb, -light.direction, 1.0, albedoFactor, eyeVec, F0, normal, metallic, roughness); + + lightRadiance += shadowFactor * radiance; } + + for lightIndex in u32(0) -> lightData.pointLightCount + { + let light = lightData.pointLights[lightIndex]; + + let lightToPos = input.worldPos - light.position; + let dist = length(lightToPos); + + let attenuation = max(1.0 - dist * light.invRadius, 0.0); + let lightToPosNorm = lightToPos / max(dist, 0.0001); + + let shadowFactor = ComputePointLightShadow(light, shadowMapsPoint[lightIndex], dist, lightToPosNorm); + let radiance = ComputeLightRadiance(light.color.rgb, lightToPosNorm, attenuation, albedoFactor, eyeVec, F0, normal, metallic, roughness); + + lightRadiance += shadowFactor * radiance; + } + + for lightIndex in u32(0) -> lightData.spotLightCount + { + let light = lightData.spotLights[lightIndex]; + + let lightToPos = input.worldPos - light.position; + let dist = length(lightToPos); + let lightToPosNorm = lightToPos / max(dist, 0.0001); + + let curAngle = dot(light.direction, lightToPosNorm); + let innerMinusOuterAngle = light.innerAngle - light.outerAngle; + + let attenuation = max(1.0 - dist * light.invRadius, 0.0); + attenuation *= max((curAngle - light.outerAngle) / innerMinusOuterAngle, 0.0); + + let lambert = clamp(dot(normal, -lightToPosNorm), 0.0, 1.0); + + let shadowFactor = ComputeSpotLightShadow(light, shadowMapsSpot[lightIndex], input.worldPos, lambert); + let radiance = ComputeLightRadiance(light.color.rgb, lightToPosNorm, attenuation, albedoFactor, eyeVec, F0, normal, metallic, roughness); + + lightRadiance += shadowFactor * radiance; + } + + let ambient = (0.0001).rrr * albedo; + + let finalColor = ambient + lightRadiance * color; + finalColor = finalColor / (finalColor + vec3[f32](1.0, 1.0, 1.0)); + finalColor = pow(finalColor, (1.0 / 2.2).xxx); //< WTF? + + return finalColor; +} + +[export, entry(frag), cond(!DepthPass)] +fn FragMain(input: VertOut) -> FragOut +{ + let color = ComputeColor(input); + + const if (HasNormal) + color.rgb = ComputeLighting(color.rgb, input); + + let output: FragOut; + output.RenderTarget0 = color; + return output; } // Shadow passes entries [entry(frag), cond(DepthPass && DistanceDepth)] [depth_write(replace)] -fn main(input: VertToFrag) -> FragOut +fn FragDepthDist(input: VertOut) -> FragOut { let color = ComputeColor(input); - const if (AlphaTest) - { - if (color.w < settings.AlphaThreshold) - discard; - } let output: FragOut; output.RenderTarget0 = color; @@ -281,11 +279,9 @@ fn main(input: VertToFrag) -> FragOut } [entry(frag), cond(DepthPass && AlphaTest && !DistanceDepth)] -fn main(input: VertToFrag) -> FragOut +fn FragDepth(input: VertOut) -> FragOut { let color = ComputeColor(input); - if (color.w < settings.AlphaThreshold) - discard; let output: FragOut; output.RenderTarget0 = color; @@ -293,7 +289,7 @@ fn main(input: VertToFrag) -> FragOut } [entry(frag), cond(DepthPass && !AlphaTest && !DistanceDepth)] -fn main() {} //< dummy +fn FragDepthNoAlpha() {} //< dummy // Vertex stage struct VertIn @@ -330,7 +326,7 @@ struct VertIn } [entry(vert), cond(Billboard)] -fn billboardMain(input: VertIn) -> VertToFrag +fn VertBillboard(input: VertIn) -> VertOut { let size = input.billboardSizeRot.xy; let sinCos = input.billboardSizeRot.zw; @@ -348,12 +344,12 @@ fn billboardMain(input: VertIn) -> VertToFrag vertexPos += cameraRight * rotatedPosition.x; vertexPos += cameraUp * rotatedPosition.y; - let output: VertToFrag; + let output: VertOut; output.position = viewerData.viewProjMatrix * instanceData.worldMatrix * vec4[f32](vertexPos, 1.0); - + const if (HasColor) output.color = input.billboardColor; - + const if (HasUV) output.uv = input.pos.xy + vec2[f32](0.5, 0.5); @@ -361,7 +357,7 @@ fn billboardMain(input: VertIn) -> VertToFrag } [entry(vert), cond(!Billboard)] -fn main(input: VertIn) -> VertToFrag +fn VertMain(input: VertIn) -> VertOut { let pos: vec3[f32]; const if (HasNormal) let normal: vec3[f32]; @@ -403,7 +399,7 @@ fn main(input: VertIn) -> VertToFrag let worldPosition = instanceData.worldMatrix * vec4[f32](pos, 1.0); - let output: VertToFrag; + let output: VertOut; output.worldPos = worldPosition.xyz; output.position = viewerData.viewProjMatrix * worldPosition; diff --git a/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp b/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp index c7374efed..31039086c 100644 --- a/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp +++ b/src/Nazara/OpenGLRenderer/OpenGLShaderModule.cpp @@ -170,9 +170,11 @@ namespace Nz m_states = states; m_states.sanitized = true; //< Shader is always sanitized (because of keywords) -#ifdef NAZARA_PLATFORM_WEB - m_states.optimize = true; //< Always remove unused code with emscripten (prevents errors on draw calls when no buffer is bound on a unused binding) -#endif + /* + Always remove dead code with OpenGL (prevents errors on draw calls when no buffer is bound on a unused binding), + also prevents compilation failure because of functions using discard in a vertex shader + */ + m_states.optimize = true; nzsl::Ast::SanitizeVisitor::Options options = nzsl::GlslWriter::GetSanitizeOptions(); options.optionValues = states.optionValues;