From e840f61942ea48ff78bb076c3a55573a166a3485 Mon Sep 17 00:00:00 2001 From: turanszkij Date: Tue, 14 May 2019 21:30:56 +0100 Subject: [PATCH] shader refactors --- Editor/MaterialWindow.cpp | 3 + WickedEngine/bvh_classificationCS.hlsl | 20 +- WickedEngine/captureImpostorPS_albedo.hlsl | 15 +- WickedEngine/captureImpostorPS_normal.hlsl | 10 +- WickedEngine/captureImpostorPS_surface.hlsl | 19 +- WickedEngine/lightingHF.hlsli | 605 +++++++++++--------- WickedEngine/objectDS.hlsl | 11 +- WickedEngine/objectHF.hlsli | 68 ++- WickedEngine/objectInputLayoutHF.hlsli | 36 +- WickedEngine/objectPS_hologram.hlsl | 17 +- WickedEngine/objectPS_voxelizer.hlsl | 17 +- WickedEngine/raySceneIntersectHF.hlsli | 56 +- WickedEngine/shadowPS_transparent.hlsl | 35 +- WickedEngine/shadowPS_water.hlsl | 41 +- WickedEngine/wiGPUBVH.cpp | 12 +- WickedEngine/wiRenderer.cpp | 12 +- WickedEngine/wiVersion.cpp | 2 +- 17 files changed, 573 insertions(+), 406 deletions(-) diff --git a/Editor/MaterialWindow.cpp b/Editor/MaterialWindow.cpp index e754db12d..c018156ca 100644 --- a/Editor/MaterialWindow.cpp +++ b/Editor/MaterialWindow.cpp @@ -882,6 +882,9 @@ void MaterialWindow::SetEntity(Entity entity) ss << material->uvset_surfaceMap; texture_surface_uvset_Field->SetText(ss.str()); ss.str(""); + ss << material->uvset_displacementMap; + texture_displacement_uvset_Field->SetText(ss.str()); + ss.str(""); ss << material->uvset_emissiveMap; texture_emissive_uvset_Field->SetText(ss.str()); ss.str(""); diff --git a/WickedEngine/bvh_classificationCS.hlsl b/WickedEngine/bvh_classificationCS.hlsl index 48bd5ce63..01202f810 100644 --- a/WickedEngine/bvh_classificationCS.hlsl +++ b/WickedEngine/bvh_classificationCS.hlsl @@ -95,13 +95,13 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex) float4 pos_nor2 = asfloat(meshVertexBuffer_POS.Load4(i2 * xTraceBVHMeshVertexPOSStride)); uint nor_u = asuint(pos_nor0.w); - uint materialIndex; + uint subsetIndex; float3 nor0; { nor0.x = (float)((nor_u >> 0) & 0x000000FF) / 255.0f * 2.0f - 1.0f; nor0.y = (float)((nor_u >> 8) & 0x000000FF) / 255.0f * 2.0f - 1.0f; nor0.z = (float)((nor_u >> 16) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - materialIndex = (nor_u >> 24) & 0x000000FF; + subsetIndex = (nor_u >> 24) & 0x000000FF; } nor_u = asuint(pos_nor1.w); float3 nor1; @@ -122,6 +122,8 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex) // Transform triangle into world space and store: float4x4 WORLD = xTraceBVHWorld; + const uint materialIndex = xTraceBVHMaterialOffset + subsetIndex; + TracedRenderingMaterial material = materialBuffer[materialIndex]; BVHMeshTriangle prim; prim.v0 = mul(WORLD, float4(pos_nor0.xyz, 1)).xyz; @@ -130,20 +132,18 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex) prim.n0 = mul((float3x3)WORLD, nor0); prim.n1 = mul((float3x3)WORLD, nor1); prim.n2 = mul((float3x3)WORLD, nor2); - prim.u0 = float4(meshVertexBuffer_UV0[i0], meshVertexBuffer_UV1[i0]); - prim.u1 = float4(meshVertexBuffer_UV0[i1], meshVertexBuffer_UV1[i1]); - prim.u2 = float4(meshVertexBuffer_UV0[i2], meshVertexBuffer_UV1[i2]); - prim.materialIndex = xTraceBVHMaterialOffset + materialIndex; + prim.u0 = float4(meshVertexBuffer_UV0[i0] * material.texMulAdd.xy + material.texMulAdd.zw, meshVertexBuffer_UV1[i0]); + prim.u1 = float4(meshVertexBuffer_UV0[i1] * material.texMulAdd.xy + material.texMulAdd.zw, meshVertexBuffer_UV1[i1]); + prim.u2 = float4(meshVertexBuffer_UV0[i2] * material.texMulAdd.xy + material.texMulAdd.zw, meshVertexBuffer_UV1[i2]); + prim.materialIndex = materialIndex; - TracedRenderingMaterial mat = materialBuffer[prim.materialIndex]; - - float4 color = xTraceBVHInstanceColor * mat.baseColor; + float4 color = xTraceBVHInstanceColor * material.baseColor; prim.c0 = color; prim.c1 = color; prim.c2 = color; [branch] - if (mat.useVertexColors) + if (material.useVertexColors) { prim.c0 *= meshVertexBuffer_COL[i0]; prim.c1 *= meshVertexBuffer_COL[i1]; diff --git a/WickedEngine/captureImpostorPS_albedo.hlsl b/WickedEngine/captureImpostorPS_albedo.hlsl index d91668ad3..eaac217ee 100644 --- a/WickedEngine/captureImpostorPS_albedo.hlsl +++ b/WickedEngine/captureImpostorPS_albedo.hlsl @@ -2,9 +2,18 @@ float4 main(PixelInputType input) : SV_Target0 { - const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; - float4 color = xBaseColorMap.Sample(sampler_objectshader, UV_baseColorMap); - color.rgb = DEGAMMA(color.rgb); + float4 color; + [branch] + if (g_xMat_uvset_baseColorMap >= 0) + { + const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; + color = xBaseColorMap.Sample(sampler_objectshader, UV_baseColorMap); + color.rgb = DEGAMMA(color.rgb); + } + else + { + color = 1; + } color *= input.color; ALPHATEST(color.a); color.a = 1; diff --git a/WickedEngine/captureImpostorPS_normal.hlsl b/WickedEngine/captureImpostorPS_normal.hlsl index 412dc0125..3a391011d 100644 --- a/WickedEngine/captureImpostorPS_normal.hlsl +++ b/WickedEngine/captureImpostorPS_normal.hlsl @@ -7,9 +7,13 @@ float4 main(PixelInputType input) : SV_Target0 float3x3 TBN = compute_tangent_frame(N, P, input.uvsets.xy); - float3 bumpColor; - const float2 UV_normalMap = g_xMat_uvset_normalMap == 0 ? input.uvsets.xy : input.uvsets.zw; - NormalMapping(UV_normalMap, P, N, TBN, bumpColor); + [branch] + if (g_xMat_uvset_normalMap >= 0) + { + float3 bumpColor; + const float2 UV_normalMap = g_xMat_uvset_normalMap == 0 ? input.uvsets.xy : input.uvsets.zw; + NormalMapping(UV_normalMap, P, N, TBN, bumpColor); + } return float4(N * 0.5f + 0.5f, 1); } diff --git a/WickedEngine/captureImpostorPS_surface.hlsl b/WickedEngine/captureImpostorPS_surface.hlsl index 1b9338654..20d8d2dc1 100644 --- a/WickedEngine/captureImpostorPS_surface.hlsl +++ b/WickedEngine/captureImpostorPS_surface.hlsl @@ -2,12 +2,21 @@ float4 main(PixelInputType input) : SV_Target0 { - const float2 UV_surfaceMap = g_xMat_uvset_surfaceMap == 0 ? input.uvsets.xy : input.uvsets.zw; - float4 surface_occlusion_roughness_metallic_reflectance = xSurfaceMap.Sample(sampler_objectshader, UV_surfaceMap); - - if (g_xMat_specularGlossinessWorkflow) + float4 surface_occlusion_roughness_metallic_reflectance; + [branch] + if (g_xMat_uvset_surfaceMap >= 0) { - ConvertToSpecularGlossiness(surface_occlusion_roughness_metallic_reflectance); + const float2 UV_surfaceMap = g_xMat_uvset_surfaceMap == 0 ? input.uvsets.xy : input.uvsets.zw; + surface_occlusion_roughness_metallic_reflectance = xSurfaceMap.Sample(sampler_objectshader, UV_surfaceMap); + + if (g_xMat_specularGlossinessWorkflow) + { + ConvertToSpecularGlossiness(surface_occlusion_roughness_metallic_reflectance); + } + } + else + { + surface_occlusion_roughness_metallic_reflectance = 1; } float4 surface; diff --git a/WickedEngine/lightingHF.hlsli b/WickedEngine/lightingHF.hlsli index f303a12c1..4ef2ae772 100644 --- a/WickedEngine/lightingHF.hlsli +++ b/WickedEngine/lightingHF.hlsli @@ -92,61 +92,69 @@ inline float3 shadowCascade(float4 shadowPos, float2 ShTex, float shadowKernel, inline void DirectionalLight(in ShaderEntityType light, in Surface surface, inout Lighting lighting) { - float3 lightColor = light.GetColor().rgb*light.energy; - float3 L = light.directionWS.xyz; SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); - float3 sh = max(surfaceToLight.NdotL, 0).xxx; - [branch] - if (light.IsCastingShadow()) + if (surfaceToLight.NdotL > 0) { - // calculate shadow map texcoords: - float4 ShPos[3]; - ShPos[0] = mul(float4(surface.P, 1), MatrixArray[light.GetShadowMatrixIndex() + 0]); - ShPos[1] = mul(float4(surface.P, 1), MatrixArray[light.GetShadowMatrixIndex() + 1]); - ShPos[2] = mul(float4(surface.P, 1), MatrixArray[light.GetShadowMatrixIndex() + 2]); - float3 ShTex[3]; - ShTex[0] = ShPos[0].xyz * float3(0.5f, -0.5f, 0.5f) + 0.5f; - ShTex[1] = ShPos[1].xyz * float3(0.5f, -0.5f, 0.5f) + 0.5f; - ShTex[2] = ShPos[2].xyz * float3(0.5f, -0.5f, 0.5f) + 0.5f; + float3 sh = surfaceToLight.NdotL.xxx; - // determine the main shadow cascade: - int cascade = -1; - [loop] - for (uint i = 0; i < 3; ++i) - { - cascade = is_saturated(ShTex[i]) ? i : cascade; - } - - // if we are within any cascade, sample shadow maps: +#ifndef DISABLE_SHADOWMAPS [branch] - if (cascade >= 0) + if (light.IsCastingShadow()) { - const float3 cascadeBlend = abs(ShTex[cascade] * 2 - 1); - const int2 cascades = uint2(cascade, cascade - 1); - float3 shadows[2] = { float3(1,1,1), float3(1,1,1) }; + // calculate shadow map texcoords: + float4 ShPos[3]; + ShPos[0] = mul(float4(surface.P, 1), MatrixArray[light.GetShadowMatrixIndex() + 0]); + ShPos[1] = mul(float4(surface.P, 1), MatrixArray[light.GetShadowMatrixIndex() + 1]); + ShPos[2] = mul(float4(surface.P, 1), MatrixArray[light.GetShadowMatrixIndex() + 2]); + float3 ShTex[3]; + ShTex[0] = ShPos[0].xyz * float3(0.5f, -0.5f, 0.5f) + 0.5f; + ShTex[1] = ShPos[1].xyz * float3(0.5f, -0.5f, 0.5f) + 0.5f; + ShTex[2] = ShPos[2].xyz * float3(0.5f, -0.5f, 0.5f) + 0.5f; - // main shadow cascade sampling: - shadows[0] = shadowCascade(ShPos[cascades[0]], ShTex[cascades[0]].xy, light.shadowKernel, light.shadowBias, light.GetShadowMapIndex() + cascades[0]); - - // fallback shadow cascade sampling (far cascade has no fallback, so avoid sampling): - [branch] - if (cascades[1] >= 0) + // determine the main shadow cascade: + int cascade = -1; + [loop] + for (uint i = 0; i < 3; ++i) { - shadows[1] = shadowCascade(ShPos[cascades[1]], ShTex[cascades[1]].xy, light.shadowKernel, light.shadowBias, light.GetShadowMapIndex() + cascades[1]); + cascade = is_saturated(ShTex[i]) ? i : cascade; + } + + // if we are within any cascade, sample shadow maps: + [branch] + if (cascade >= 0) + { + const float3 cascadeBlend = abs(ShTex[cascade] * 2 - 1); + const int2 cascades = uint2(cascade, cascade - 1); + float3 shadows[2] = { float3(1,1,1), float3(1,1,1) }; + + // main shadow cascade sampling: + shadows[0] = shadowCascade(ShPos[cascades[0]], ShTex[cascades[0]].xy, light.shadowKernel, light.shadowBias, light.GetShadowMapIndex() + cascades[0]); + + // fallback shadow cascade sampling (far cascade has no fallback, so avoid sampling): + [branch] + if (cascades[1] >= 0) + { + shadows[1] = shadowCascade(ShPos[cascades[1]], ShTex[cascades[1]].xy, light.shadowKernel, light.shadowBias, light.GetShadowMapIndex() + cascades[1]); + } + + // blend the cascades: + sh *= lerp(shadows[0], shadows[1], pow(max(cascadeBlend.x, max(cascadeBlend.y, cascadeBlend.z)), 4)); } - // blend the cascades: - sh *= lerp(shadows[0], shadows[1], pow(max(cascadeBlend.x, max(cascadeBlend.y, cascadeBlend.z)), 4)); } +#endif // DISABLE_SHADOWMAPS + [branch] + if (any(sh)) + { + float3 lightColor = light.GetColor().rgb * light.energy * sh; + lighting.direct.diffuse += max(0.0f, lightColor * BRDF_GetDiffuse(surface, surfaceToLight)); + lighting.direct.specular += max(0.0f, lightColor * BRDF_GetSpecular(surface, surfaceToLight)); + } } - lightColor *= sh; - - lighting.direct.diffuse += max(0.0f, lightColor * BRDF_GetDiffuse(surface, surfaceToLight)); - lighting.direct.specular += max(0.0f, lightColor * BRDF_GetSpecular(surface, surfaceToLight)); } inline void PointLight(in ShaderEntityType light, in Surface surface, inout Lighting lighting) { @@ -159,26 +167,34 @@ inline void PointLight(in ShaderEntityType light, in Surface surface, inout Ligh { L /= dist; - float3 lightColor = light.GetColor().rgb*light.energy; - SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); - const float range2 = light.range * light.range; - const float att = saturate(1.0 - (dist2 / range2)); - const float attenuation = att * att; - lightColor *= attenuation; - - float sh = max(surfaceToLight.NdotL, 0); -#ifndef DISABLE_SHADOWMAPS [branch] - if (light.IsCastingShadow()) { - sh *= texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.GetShadowMapIndex()), 1 - dist / light.range * (1 - light.shadowBias)).r; - } -#endif - lightColor *= sh; + if (surfaceToLight.NdotL > 0) + { + float sh = surfaceToLight.NdotL; - lighting.direct.diffuse += max(0.0f, lightColor * BRDF_GetDiffuse(surface, surfaceToLight)); - lighting.direct.specular += max(0.0f, lightColor * BRDF_GetSpecular(surface, surfaceToLight)); +#ifndef DISABLE_SHADOWMAPS + [branch] + if (light.IsCastingShadow()) { + sh *= texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.GetShadowMapIndex()), 1 - dist / light.range * (1 - light.shadowBias)).r; + } +#endif // DISABLE_SHADOWMAPS + + [branch] + if (sh > 0) + { + float3 lightColor = light.GetColor().rgb * light.energy * sh; + + const float range2 = light.range * light.range; + const float att = saturate(1.0 - (dist2 / range2)); + const float attenuation = att * att; + lightColor *= attenuation; + + lighting.direct.diffuse += max(0.0f, lightColor * BRDF_GetDiffuse(surface, surfaceToLight)); + lighting.direct.specular += max(0.0f, lightColor * BRDF_GetSpecular(surface, surfaceToLight)); + } + } } } inline void SpotLight(in ShaderEntityType light, in Surface surface, inout Lighting lighting) @@ -192,39 +208,49 @@ inline void SpotLight(in ShaderEntityType light, in Surface surface, inout Light { L /= dist; - float3 lightColor = light.GetColor().rgb*light.energy; - - const float SpotFactor = dot(L, light.directionWS); - const float spotCutOff = light.coneAngleCos; + SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); [branch] - if (SpotFactor > spotCutOff) + if (surfaceToLight.NdotL > 0) { - SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); + const float SpotFactor = dot(L, light.directionWS); + const float spotCutOff = light.coneAngleCos; - const float range2 = light.range * light.range; - const float att = saturate(1.0 - (dist2 / range2)); - float attenuation = att * att; - attenuation *= saturate((1.0 - (1.0 - SpotFactor) * 1.0 / (1.0 - spotCutOff))); - lightColor *= attenuation; - - float3 sh = max(surfaceToLight.NdotL, 0).xxx; [branch] - if (light.IsCastingShadow()) + if (SpotFactor > spotCutOff) { - float4 ShPos = mul(float4(surface.P, 1), MatrixArray[light.GetShadowMatrixIndex() + 0]); - ShPos.xyz /= ShPos.w; - float2 ShTex = ShPos.xy * float2(0.5f, -0.5f) + float2(0.5f, 0.5f); + float3 sh = surfaceToLight.NdotL.xxx; + +#ifndef DISABLE_SHADOWMAPS [branch] - if (is_saturated(ShTex)) + if (light.IsCastingShadow()) { - sh *= shadowCascade(ShPos, ShTex.xy, light.shadowKernel, light.shadowBias, light.GetShadowMapIndex()); + float4 ShPos = mul(float4(surface.P, 1), MatrixArray[light.GetShadowMatrixIndex() + 0]); + ShPos.xyz /= ShPos.w; + float2 ShTex = ShPos.xy * float2(0.5f, -0.5f) + float2(0.5f, 0.5f); + [branch] + if (is_saturated(ShTex)) + { + sh *= shadowCascade(ShPos, ShTex.xy, light.shadowKernel, light.shadowBias, light.GetShadowMapIndex()); + } + } +#endif // DISABLE_SHADOWMAPS + + [branch] + if (any(sh)) + { + float3 lightColor = light.GetColor().rgb * light.energy * sh; + + const float range2 = light.range * light.range; + const float att = saturate(1.0 - (dist2 / range2)); + float attenuation = att * att; + attenuation *= saturate((1.0 - (1.0 - SpotFactor) * 1.0 / (1.0 - spotCutOff))); + lightColor *= attenuation; + + lighting.direct.diffuse += max(0.0f, lightColor * BRDF_GetDiffuse(surface, surfaceToLight)); + lighting.direct.specular += max(0.0f, lightColor * BRDF_GetSpecular(surface, surfaceToLight)); } } - lightColor *= sh; - - lighting.direct.diffuse += max(0.0f, lightColor * BRDF_GetDiffuse(surface, surfaceToLight)); - lighting.direct.specular += max(0.0f, lightColor * BRDF_GetSpecular(surface, surfaceToLight)); } } } @@ -400,275 +426,304 @@ inline void SphereLight(in ShaderEntityType light, in Surface surface, inout Lig float3 Lunormalized = light.positionWS - surface.P; float dist = length(Lunormalized); float3 L = Lunormalized / dist; - - float sqrDist = dot(Lunormalized, Lunormalized); - - float cosTheta = clamp(dot(surface.N, L), -0.999, 0.999); // Clamp to avoid edge case - // We need to prevent the object penetrating into the surface - // and we must avoid divide by 0, thus the 0.9999f - float sqrLightRadius = light.GetRadius() * light.GetRadius(); - float sinSigmaSqr = min(sqrLightRadius / sqrDist, 0.9999f); - float fLight = illuminanceSphereOrDisk(cosTheta, sinSigmaSqr); + float fLight = 1; #ifndef DISABLE_SHADOWMAPS [branch] if (light.IsCastingShadow()) { - fLight *= texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.GetShadowMapIndex()), 1 - dist / light.range * (1 - light.shadowBias)).r; + fLight = texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.GetShadowMapIndex()), 1 - dist / light.range * (1 - light.shadowBias)).r; } #endif - - // We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection + [branch] + if (fLight > 0) { - float3 r = surface.R; - r = getSpecularDominantDirArea(surface.N, r, surface.roughness); + float sqrDist = dot(Lunormalized, Lunormalized); - float3 centerToRay = dot(Lunormalized, r) * r - Lunormalized; - float3 closestPoint = Lunormalized + centerToRay * saturate(light.GetRadius() / length(centerToRay)); - L = normalize(closestPoint); + float cosTheta = clamp(dot(surface.N, L), -0.999, 0.999); // Clamp to avoid edge case + // We need to prevent the object penetrating into the surface + // and we must avoid divide by 0, thus the 0.9999f + float sqrLightRadius = light.GetRadius() * light.GetRadius(); + float sinSigmaSqr = min(sqrLightRadius / sqrDist, 0.9999f); + fLight *= illuminanceSphereOrDisk(cosTheta, sinSigmaSqr); + + [branch] + if (fLight > 0) + { + // We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection + { + float3 r = surface.R; + r = getSpecularDominantDirArea(surface.N, r, surface.roughness); + + float3 centerToRay = dot(Lunormalized, r) * r - Lunormalized; + float3 closestPoint = Lunormalized + centerToRay * saturate(light.GetRadius() / length(centerToRay)); + L = normalize(closestPoint); + } + + float3 lightColor = light.GetColor().rgb * light.energy * fLight; + + + SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); + + lighting.direct.specular += max(0, lightColor * BRDF_GetSpecular(surface, surfaceToLight)); + lighting.direct.diffuse += max(0, lightColor / PI); + } } - - float3 lightColor = light.GetColor().rgb*light.energy; - - - SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); - - lighting.direct.specular += max(0, lightColor * BRDF_GetSpecular(surface, surfaceToLight) * fLight); - lighting.direct.diffuse += max(0, lightColor * fLight / PI); } inline void DiscLight(in ShaderEntityType light, in Surface surface, inout Lighting lighting) { float3 Lunormalized = light.positionWS - surface.P; float dist = length(Lunormalized); float3 L = Lunormalized / dist; - - float sqrDist = dot(Lunormalized, Lunormalized); - - float3 lightPlaneNormal = light.GetFront(); - - float cosTheta = clamp(dot(surface.N, L), -0.999, 0.999); - float sqrLightRadius = light.GetRadius() * light.GetRadius(); - // Do not let the surface penetrate the light - float sinSigmaSqr = sqrLightRadius / (sqrLightRadius + max(sqrLightRadius, sqrDist)); - // Multiply by saturate(dot(planeNormal , -L)) to better match ground truth. - float fLight = illuminanceSphereOrDisk(cosTheta, sinSigmaSqr) - * saturate(dot(lightPlaneNormal, -L)); + float fLight = 1; #ifndef DISABLE_SHADOWMAPS [branch] if (light.IsCastingShadow()) { - fLight *= texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.GetShadowMapIndex()), 1 - dist / light.range * (1 - light.shadowBias)).r; + fLight = texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.GetShadowMapIndex()), 1 - dist / light.range * (1 - light.shadowBias)).r; } #endif - // We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection + [branch] + if (fLight > 0) { - float3 r = surface.R; - r = getSpecularDominantDirArea(surface.N, r, surface.roughness); + float sqrDist = dot(Lunormalized, Lunormalized); - float t = Trace_plane(surface.P, r, light.positionWS, lightPlaneNormal); - float3 p = surface.P + r*t; - float3 centerToRay = p - light.positionWS; - float3 closestPoint = Lunormalized + centerToRay * saturate(light.GetRadius() / length(centerToRay)); - L = normalize(closestPoint); + float3 lightPlaneNormal = light.GetFront(); + + float cosTheta = clamp(dot(surface.N, L), -0.999, 0.999); + float sqrLightRadius = light.GetRadius() * light.GetRadius(); + // Do not let the surface penetrate the light + float sinSigmaSqr = sqrLightRadius / (sqrLightRadius + max(sqrLightRadius, sqrDist)); + // Multiply by saturate(dot(planeNormal , -L)) to better match ground truth. + fLight *= illuminanceSphereOrDisk(cosTheta, sinSigmaSqr) * saturate(dot(lightPlaneNormal, -L)); + + [branch] + if (fLight > 0) + { + // We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection + { + float3 r = surface.R; + r = getSpecularDominantDirArea(surface.N, r, surface.roughness); + + float t = Trace_plane(surface.P, r, light.positionWS, lightPlaneNormal); + float3 p = surface.P + r * t; + float3 centerToRay = p - light.positionWS; + float3 closestPoint = Lunormalized + centerToRay * saturate(light.GetRadius() / length(centerToRay)); + L = normalize(closestPoint); + } + + float3 lightColor = light.GetColor().rgb * light.energy * fLight; + + SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); + + lighting.direct.specular += max(0, lightColor * BRDF_GetSpecular(surface, surfaceToLight)); + lighting.direct.diffuse += max(0, lightColor / PI); + } } - - float3 lightColor = light.GetColor().rgb*light.energy; - - SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); - - lighting.direct.specular += max(0, lightColor * BRDF_GetSpecular(surface, surfaceToLight) * fLight); - lighting.direct.diffuse += max(0, lightColor * fLight / PI); } inline void RectangleLight(in ShaderEntityType light, in Surface surface, inout Lighting lighting) { float3 L = light.positionWS - surface.P; float dist = length(L); L /= dist; - - - float3 lightPlaneNormal = light.GetFront(); - float3 lightLeft = light.GetRight(); - float3 lightUp = light.GetUp(); - float lightWidth = light.GetWidth(); - float lightHeight = light.GetHeight(); - float3 worldPos = surface.P; - float3 worldNormal = surface.N; - - - float fLight = 0; - float halfWidth = lightWidth * 0.5; - float halfHeight = lightHeight * 0.5; - float3 p0 = light.positionWS + lightLeft * -halfWidth + lightUp * halfHeight; - float3 p1 = light.positionWS + lightLeft * -halfWidth + lightUp * -halfHeight; - - float3 p2 = light.positionWS + lightLeft * halfWidth + lightUp * -halfHeight; - float3 p3 = light.positionWS + lightLeft * halfWidth + lightUp * halfHeight; - float solidAngle = RectangleSolidAngle(worldPos, p0, p1, p2, p3); - - if (dot(worldPos - light.positionWS, lightPlaneNormal) > 0) - { - fLight = solidAngle * 0.2 * ( - saturate(dot(normalize(p0 - worldPos), worldNormal)) + - saturate(dot(normalize(p1 - worldPos), worldNormal)) + - saturate(dot(normalize(p2 - worldPos), worldNormal)) + - saturate(dot(normalize(p3 - worldPos), worldNormal)) + - saturate(dot(normalize(light.positionWS - worldPos), worldNormal))); - } - fLight = max(0, fLight); + float fLight = 1; #ifndef DISABLE_SHADOWMAPS [branch] if (light.IsCastingShadow()) { - fLight *= texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.GetShadowMapIndex()), 1 - dist / light.range * (1 - light.shadowBias)).r; + fLight = texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.GetShadowMapIndex()), 1 - dist / light.range * (1 - light.shadowBias)).r; } #endif - - // We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection + [branch] + if (fLight > 0) { - float3 r = surface.R; - r = getSpecularDominantDirArea(surface.N, r, surface.roughness); + float3 lightPlaneNormal = light.GetFront(); + float3 lightLeft = light.GetRight(); + float3 lightUp = light.GetUp(); + float lightWidth = light.GetWidth(); + float lightHeight = light.GetHeight(); + float3 worldPos = surface.P; + float3 worldNormal = surface.N; - float traced = Trace_rectangle(surface.P, r, p0, p1, p2, p3); - [branch] - if (traced > 0) + float halfWidth = lightWidth * 0.5; + float halfHeight = lightHeight * 0.5; + float3 p0 = light.positionWS + lightLeft * -halfWidth + lightUp * halfHeight; + float3 p1 = light.positionWS + lightLeft * -halfWidth + lightUp * -halfHeight; + + float3 p2 = light.positionWS + lightLeft * halfWidth + lightUp * -halfHeight; + float3 p3 = light.positionWS + lightLeft * halfWidth + lightUp * halfHeight; + float solidAngle = RectangleSolidAngle(worldPos, p0, p1, p2, p3); + + if (dot(worldPos - light.positionWS, lightPlaneNormal) > 0) { - // Trace succeeded so the light vector L is the reflection vector itself - L = r; + fLight *= solidAngle * 0.2 * ( + saturate(dot(normalize(p0 - worldPos), worldNormal)) + + saturate(dot(normalize(p1 - worldPos), worldNormal)) + + saturate(dot(normalize(p2 - worldPos), worldNormal)) + + saturate(dot(normalize(p3 - worldPos), worldNormal)) + + saturate(dot(normalize(light.positionWS - worldPos), worldNormal))); } else { - // The trace didn't succeed, so we need to find the closest point to the ray on the rectangle + fLight = 0; + } - // We find the intersection point on the plane of the rectangle - float3 tracedPlane = surface.P + r * Trace_plane(surface.P, r, light.positionWS, lightPlaneNormal); - - // Then find the closest point along the edges of the rectangle (edge = segment) - float3 PC[4] = { - ClosestPointOnSegment(p0, p1, tracedPlane), - ClosestPointOnSegment(p1, p2, tracedPlane), - ClosestPointOnSegment(p2, p3, tracedPlane), - ClosestPointOnSegment(p3, p0, tracedPlane), - }; - float dist[4] = { - distance(PC[0], tracedPlane), - distance(PC[1], tracedPlane), - distance(PC[2], tracedPlane), - distance(PC[3], tracedPlane), - }; - - float3 min = PC[0]; - float minDist = dist[0]; - [unroll] - for (uint iLoop = 1; iLoop < 4; iLoop++) + [branch] + if (fLight > 0) + { + // We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection { - if (dist[iLoop] < minDist) + float3 r = surface.R; + r = getSpecularDominantDirArea(surface.N, r, surface.roughness); + + float traced = Trace_rectangle(surface.P, r, p0, p1, p2, p3); + + [branch] + if (traced > 0) { - minDist = dist[iLoop]; - min = PC[iLoop]; + // Trace succeeded so the light vector L is the reflection vector itself + L = r; } + else + { + // The trace didn't succeed, so we need to find the closest point to the ray on the rectangle + + // We find the intersection point on the plane of the rectangle + float3 tracedPlane = surface.P + r * Trace_plane(surface.P, r, light.positionWS, lightPlaneNormal); + + // Then find the closest point along the edges of the rectangle (edge = segment) + float3 PC[4] = { + ClosestPointOnSegment(p0, p1, tracedPlane), + ClosestPointOnSegment(p1, p2, tracedPlane), + ClosestPointOnSegment(p2, p3, tracedPlane), + ClosestPointOnSegment(p3, p0, tracedPlane), + }; + float dist[4] = { + distance(PC[0], tracedPlane), + distance(PC[1], tracedPlane), + distance(PC[2], tracedPlane), + distance(PC[3], tracedPlane), + }; + + float3 min = PC[0]; + float minDist = dist[0]; + [unroll] + for (uint iLoop = 1; iLoop < 4; iLoop++) + { + if (dist[iLoop] < minDist) + { + minDist = dist[iLoop]; + min = PC[iLoop]; + } + } + + L = min - surface.P; + } + L = normalize(L); // TODO: Is it necessary? } - L = min - surface.P; + float3 lightColor = light.GetColor().rgb * light.energy * fLight; + + SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); + + lighting.direct.specular += max(0, lightColor * BRDF_GetSpecular(surface, surfaceToLight)); + lighting.direct.diffuse += max(0, lightColor / PI); } - L = normalize(L); // TODO: Is it necessary? } - - float3 lightColor = light.GetColor().rgb*light.energy; - - SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); - - lighting.direct.specular += max(0, lightColor * BRDF_GetSpecular(surface, surfaceToLight) * fLight); - lighting.direct.diffuse += max(0, lightColor * fLight / PI); } inline void TubeLight(in ShaderEntityType light, in Surface surface, inout Lighting lighting) { float3 Lunormalized = light.positionWS - surface.P; float dist = length(Lunormalized); float3 L = Lunormalized / dist; - - float sqrDist = dot(Lunormalized, Lunormalized); - - float3 lightLeft = light.GetRight(); - float lightWidth = light.GetWidth(); - float3 worldPos = surface.P; - float3 worldNormal = surface.N; - - - float3 P0 = light.positionWS - lightLeft*lightWidth*0.5f; - float3 P1 = light.positionWS + lightLeft*lightWidth*0.5f; - - // The sphere is placed at the nearest point on the segment. - // The rectangular plane is define by the following orthonormal frame: - float3 forward = normalize(ClosestPointOnLine(P0, P1, worldPos) - worldPos); - float3 left = lightLeft; - float3 up = cross(lightLeft, forward); - - float3 p0 = light.positionWS - left * (0.5 * lightWidth) + light.GetRadius() * up; - float3 p1 = light.positionWS - left * (0.5 * lightWidth) - light.GetRadius() * up; - float3 p2 = light.positionWS + left * (0.5 * lightWidth) - light.GetRadius() * up; - float3 p3 = light.positionWS + left * (0.5 * lightWidth) + light.GetRadius() * up; - - - float solidAngle = RectangleSolidAngle(worldPos, p0, p1, p2, p3); - - float fLight = solidAngle * 0.2 * ( - saturate(dot(normalize(p0 - worldPos), worldNormal)) + - saturate(dot(normalize(p1 - worldPos), worldNormal)) + - saturate(dot(normalize(p2 - worldPos), worldNormal)) + - saturate(dot(normalize(p3 - worldPos), worldNormal)) + - saturate(dot(normalize(light.positionWS - worldPos), worldNormal))); - - // We then add the contribution of the sphere - float3 spherePosition = ClosestPointOnSegment(P0, P1, worldPos); - float3 sphereUnormL = spherePosition - worldPos; - float3 sphereL = normalize(sphereUnormL); - float sqrSphereDistance = dot(sphereUnormL, sphereUnormL); - - float fLightSphere = PI * saturate(dot(sphereL, worldNormal)) * - ((light.GetRadius() * light.GetRadius()) / sqrSphereDistance); - - fLight += fLightSphere; - - fLight = max(0, fLight); + float fLight = 1; #ifndef DISABLE_SHADOWMAPS [branch] if (light.IsCastingShadow()) { - fLight *= texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.GetShadowMapIndex()), 1 - dist / light.range * (1 - light.shadowBias)).r; + fLight = texture_shadowarray_cube.SampleCmpLevelZero(sampler_cmp_depth, float4(-L, light.GetShadowMapIndex()), 1 - dist / light.range * (1 - light.shadowBias)).r; } #endif - - // We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection + [branch] + if (fLight > 0) { - float3 r = surface.R; - r = getSpecularDominantDirArea(surface.N, r, surface.roughness); + float sqrDist = dot(Lunormalized, Lunormalized); - // First, the closest point to the ray on the segment - float3 L0 = P0 - surface.P; - float3 L1 = P1 - surface.P; - float3 Ld = L1 - L0; + float3 lightLeft = light.GetRight(); + float lightWidth = light.GetWidth(); + float3 worldPos = surface.P; + float3 worldNormal = surface.N; - float t = dot(r, L0) * dot(r, Ld) - dot(L0, Ld); - t /= dot(Ld, Ld) - sqr(dot(r, Ld)); - L = (L0 + saturate(t) * Ld); + float3 P0 = light.positionWS - lightLeft * lightWidth*0.5f; + float3 P1 = light.positionWS + lightLeft * lightWidth*0.5f; - // Then I place a sphere on that point and calculate the lisght vector like for sphere light. - float3 centerToRay = dot(L, r) * r - L; - float3 closestPoint = L + centerToRay * saturate(light.GetRadius() / length(centerToRay)); - L = normalize(closestPoint); + // The sphere is placed at the nearest point on the segment. + // The rectangular plane is define by the following orthonormal frame: + float3 forward = normalize(ClosestPointOnLine(P0, P1, worldPos) - worldPos); + float3 left = lightLeft; + float3 up = cross(lightLeft, forward); + + float3 p0 = light.positionWS - left * (0.5 * lightWidth) + light.GetRadius() * up; + float3 p1 = light.positionWS - left * (0.5 * lightWidth) - light.GetRadius() * up; + float3 p2 = light.positionWS + left * (0.5 * lightWidth) - light.GetRadius() * up; + float3 p3 = light.positionWS + left * (0.5 * lightWidth) + light.GetRadius() * up; + + + float solidAngle = RectangleSolidAngle(worldPos, p0, p1, p2, p3); + + fLight *= solidAngle * 0.2 * ( + saturate(dot(normalize(p0 - worldPos), worldNormal)) + + saturate(dot(normalize(p1 - worldPos), worldNormal)) + + saturate(dot(normalize(p2 - worldPos), worldNormal)) + + saturate(dot(normalize(p3 - worldPos), worldNormal)) + + saturate(dot(normalize(light.positionWS - worldPos), worldNormal))); + + // We then add the contribution of the sphere + float3 spherePosition = ClosestPointOnSegment(P0, P1, worldPos); + float3 sphereUnormL = spherePosition - worldPos; + float3 sphereL = normalize(sphereUnormL); + float sqrSphereDistance = dot(sphereUnormL, sphereUnormL); + + float fLightSphere = PI * saturate(dot(sphereL, worldNormal)) * ((light.GetRadius() * light.GetRadius()) / sqrSphereDistance); + fLight += fLightSphere; + + [branch] + if (fLight > 0) + { + // We approximate L by the closest point on the reflection ray to the light source (representative point technique) to achieve a nice looking specular reflection + { + float3 r = surface.R; + r = getSpecularDominantDirArea(surface.N, r, surface.roughness); + + // First, the closest point to the ray on the segment + float3 L0 = P0 - surface.P; + float3 L1 = P1 - surface.P; + float3 Ld = L1 - L0; + + float t = dot(r, L0) * dot(r, Ld) - dot(L0, Ld); + t /= dot(Ld, Ld) - sqr(dot(r, Ld)); + + L = (L0 + saturate(t) * Ld); + + // Then I place a sphere on that point and calculate the lisght vector like for sphere light. + float3 centerToRay = dot(L, r) * r - L; + float3 closestPoint = L + centerToRay * saturate(light.GetRadius() / length(centerToRay)); + L = normalize(closestPoint); + } + + float3 lightColor = light.GetColor().rgb * light.energy * fLight; + + SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); + + lighting.direct.specular += max(0, lightColor * BRDF_GetSpecular(surface, surfaceToLight)); + lighting.direct.diffuse += max(0, lightColor / PI); + } } - - float3 lightColor = light.GetColor().rgb*light.energy; - - SurfaceToLight surfaceToLight = CreateSurfaceToLight(surface, L); - - lighting.direct.specular += max(0, lightColor * BRDF_GetSpecular(surface, surfaceToLight) * fLight); - lighting.direct.diffuse += max(0, lightColor * fLight / PI); } diff --git a/WickedEngine/objectDS.hlsl b/WickedEngine/objectDS.hlsl index a23b43e2a..d268eec12 100644 --- a/WickedEngine/objectDS.hlsl +++ b/WickedEngine/objectDS.hlsl @@ -124,10 +124,13 @@ PixelInputType main(ConstantOutputType input, float3 uvwCoord : SV_DomainLocatio vertexNormal = PhongNormal(fU, fV, fW, input); // Displacement - const float2 UV_displacementMap = g_xMat_uvset_displacementMap == 0 ? vertexUvsets.xy : vertexUvsets.zw; - float3 displacement = 1 - xDisplacementMap.SampleLevel(sampler_linear_wrap, UV_displacementMap, 0).rrr; - displacement *= vertexNormal.xyz; - displacement *= -g_xMat_displacementMapping; + float3 displacement = -g_xMat_displacementMapping * vertexNormal.xyz; + [branch] + if (g_xMat_uvset_displacementMap >= 0) + { + const float2 UV_displacementMap = g_xMat_uvset_displacementMap == 0 ? vertexUvsets.xy : vertexUvsets.zw; + displacement *= 1 - xDisplacementMap.SampleLevel(sampler_linear_wrap, UV_displacementMap, 0).rrr; + } vertexPosition.xyz += displacement; vertexPositionPrev.xyz += displacement; diff --git a/WickedEngine/objectHF.hlsli b/WickedEngine/objectHF.hlsli index e6c121422..d9779f8ca 100644 --- a/WickedEngine/objectHF.hlsli +++ b/WickedEngine/objectHF.hlsli @@ -752,9 +752,18 @@ GBUFFEROutputType_Thin main(PIXELINPUT input) ParallaxOcclusionMapping(input.uvsets, surface.V, TBN); #endif // POM - const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; - float4 color = xBaseColorMap.Sample(sampler_objectshader, UV_baseColorMap); - color.rgb = DEGAMMA(color.rgb); + float4 color; + [branch] + if (g_xMat_uvset_baseColorMap >= 0) + { + const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; + color = xBaseColorMap.Sample(sampler_objectshader, UV_baseColorMap); + color.rgb = DEGAMMA(color.rgb); + } + else + { + color = 1; + } color *= input.color; ALPHATEST(color.a); @@ -783,21 +792,31 @@ GBUFFEROutputType_Thin main(PIXELINPUT input) NormalMapping(UV_normalMap, surface.P, surface.N, TBN, bumpColor); #endif // NORMALMAP - const float2 UV_surfaceMap = g_xMat_uvset_surfaceMap == 0 ? input.uvsets.xy : input.uvsets.zw; - float4 surface_occlusion_roughness_metallic_reflectance = xSurfaceMap.Sample(sampler_objectshader, UV_surfaceMap); - if (g_xMat_occlusion_primary == 0) + // Surface map: + float4 surface_occlusion_roughness_metallic_reflectance; + [branch] + if (g_xMat_uvset_surfaceMap >= 0) { - surface_occlusion_roughness_metallic_reflectance.r = 1; - } - - if (g_xMat_specularGlossinessWorkflow) - { - ConvertToSpecularGlossiness(surface_occlusion_roughness_metallic_reflectance); + const float2 UV_surfaceMap = g_xMat_uvset_surfaceMap == 0 ? input.uvsets.xy : input.uvsets.zw; + surface_occlusion_roughness_metallic_reflectance = xSurfaceMap.Sample(sampler_objectshader, UV_surfaceMap); + if (g_xMat_occlusion_primary == 0) + { + surface_occlusion_roughness_metallic_reflectance.r = 1; + } + if (g_xMat_specularGlossinessWorkflow) + { + ConvertToSpecularGlossiness(surface_occlusion_roughness_metallic_reflectance); + } + } + else + { + surface_occlusion_roughness_metallic_reflectance = 1; } + // Emissive map: float4 emissiveColor; [branch] - if (g_xMat_emissiveColor.a > 0) + if (g_xMat_emissiveColor.a > 0 && g_xMat_uvset_emissiveMap >= 0) { const float2 UV_emissiveMap = g_xMat_uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; emissiveColor = xEmissiveMap.Sample(sampler_objectshader, UV_emissiveMap); @@ -809,29 +828,30 @@ GBUFFEROutputType_Thin main(PIXELINPUT input) emissiveColor = 0; } - float occlusion = 1; - if (g_xMat_occlusion_secondary) + // Secondary occlusion map: + [branch] + if (g_xMat_occlusion_secondary && g_xMat_uvset_occlusionMap >= 0) { const float2 UV_occlusionMap = g_xMat_uvset_occlusionMap == 0 ? input.uvsets.xy : input.uvsets.zw; - occlusion = xOcclusionMap.Sample(sampler_objectshader, UV_occlusionMap).r; + surface_occlusion_roughness_metallic_reflectance.r *= xOcclusionMap.Sample(sampler_objectshader, UV_occlusionMap).r; } - #ifndef SIMPLE_INPUT #ifndef ENVMAPRENDERING #ifndef TRANSPARENT const float ssao = xSSAO.SampleLevel(sampler_linear_clamp, ReprojectedScreenCoord, 0).r; - occlusion *= ssao; + surface_occlusion_roughness_metallic_reflectance.r *= ssao; #endif // TRANSPARENT #endif // ENVMAPRENDERING #endif // SIMPLE_INPUT + surface = CreateSurface( surface.P, surface.N, surface.V, color, - surface_occlusion_roughness_metallic_reflectance.r * occlusion, + surface_occlusion_roughness_metallic_reflectance.r, g_xMat_roughness * surface_occlusion_roughness_metallic_reflectance.g, g_xMat_metalness * surface_occlusion_roughness_metallic_reflectance.b, g_xMat_reflectance * surface_occlusion_roughness_metallic_reflectance.a, @@ -851,9 +871,13 @@ GBUFFEROutputType_Thin main(PIXELINPUT input) float2 bumpColor0 = 0; float2 bumpColor1 = 0; float2 bumpColor2 = 0; - const float2 UV_normalMap = g_xMat_uvset_normalMap == 0 ? input.uvsets.xy : input.uvsets.zw; - bumpColor0 = 2.0f * xNormalMap.Sample(sampler_objectshader, UV_normalMap - g_xMat_texMulAdd.ww).rg - 1.0f; - bumpColor1 = 2.0f * xNormalMap.Sample(sampler_objectshader, UV_normalMap + g_xMat_texMulAdd.zw).rg - 1.0f; + [branch] + if (g_xMat_uvset_normalMap >= 0) + { + const float2 UV_normalMap = g_xMat_uvset_normalMap == 0 ? input.uvsets.xy : input.uvsets.zw; + bumpColor0 = 2.0f * xNormalMap.Sample(sampler_objectshader, UV_normalMap - g_xMat_texMulAdd.ww).rg - 1.0f; + bumpColor1 = 2.0f * xNormalMap.Sample(sampler_objectshader, UV_normalMap + g_xMat_texMulAdd.zw).rg - 1.0f; + } bumpColor2 = xWaterRipples.Sample(sampler_objectshader, ScreenCoord).rg; bumpColor = float3(bumpColor0 + bumpColor1 + bumpColor2, 1) * g_xMat_refractionIndex; surface.N = normalize(lerp(surface.N, mul(normalize(bumpColor), TBN), g_xMat_normalMapStrength)); diff --git a/WickedEngine/objectInputLayoutHF.hlsli b/WickedEngine/objectInputLayoutHF.hlsli index 31614cbe2..4501b3513 100644 --- a/WickedEngine/objectInputLayoutHF.hlsli +++ b/WickedEngine/objectInputLayoutHF.hlsli @@ -71,7 +71,7 @@ struct VertexSurface float2 atlas; float4 color; float3 normal; - uint materialIndex; + uint subsetIndex; float4 prevPos; }; inline VertexSurface MakeVertexSurfaceFromInput(Input_Object_POS input) @@ -82,11 +82,11 @@ inline VertexSurface MakeVertexSurfaceFromInput(Input_Object_POS input) surface.color = g_xMat_baseColor * input.inst.color; - uint normal_wind_matID = asuint(input.pos.w); - surface.normal.x = (float)((normal_wind_matID >> 0) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - surface.normal.y = (float)((normal_wind_matID >> 8) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - surface.normal.z = (float)((normal_wind_matID >> 16) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - surface.materialIndex = (normal_wind_matID >> 24) & 0x000000FF; + uint normal_subsetIndex = asuint(input.pos.w); + surface.normal.x = (float)((normal_subsetIndex >> 0) & 0x000000FF) / 255.0f * 2.0f - 1.0f; + surface.normal.y = (float)((normal_subsetIndex >> 8) & 0x000000FF) / 255.0f * 2.0f - 1.0f; + surface.normal.z = (float)((normal_subsetIndex >> 16) & 0x000000FF) / 255.0f * 2.0f - 1.0f; + surface.subsetIndex = (normal_subsetIndex >> 24) & 0x000000FF; return surface; } @@ -98,13 +98,13 @@ inline VertexSurface MakeVertexSurfaceFromInput(Input_Object_POS_TEX input) surface.color = g_xMat_baseColor * input.inst.color; - uint normal_wind_matID = asuint(input.pos.w); - surface.normal.x = (float)((normal_wind_matID >> 0) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - surface.normal.y = (float)((normal_wind_matID >> 8) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - surface.normal.z = (float)((normal_wind_matID >> 16) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - surface.materialIndex = (normal_wind_matID >> 24) & 0x000000FF; + uint normal_subsetIndex = asuint(input.pos.w); + surface.normal.x = (float)((normal_subsetIndex >> 0) & 0x000000FF) / 255.0f * 2.0f - 1.0f; + surface.normal.y = (float)((normal_subsetIndex >> 8) & 0x000000FF) / 255.0f * 2.0f - 1.0f; + surface.normal.z = (float)((normal_subsetIndex >> 16) & 0x000000FF) / 255.0f * 2.0f - 1.0f; + surface.subsetIndex = (normal_subsetIndex >> 24) & 0x000000FF; - surface.uvsets = float4(input.uv0, input.uv1) * g_xMat_texMulAdd.xyxy + g_xMat_texMulAdd.zwzw; + surface.uvsets = float4(input.uv0 * g_xMat_texMulAdd.xy + g_xMat_texMulAdd.zw, input.uv1); return surface; } @@ -121,13 +121,13 @@ inline VertexSurface MakeVertexSurfaceFromInput(Input_Object_ALL input) surface.color *= input.col; } - uint normal_wind_matID = asuint(input.pos.w); - surface.normal.x = (float)((normal_wind_matID >> 0) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - surface.normal.y = (float)((normal_wind_matID >> 8) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - surface.normal.z = (float)((normal_wind_matID >> 16) & 0x000000FF) / 255.0f * 2.0f - 1.0f; - surface.materialIndex = (normal_wind_matID >> 24) & 0x000000FF; + uint normal_subsetIndex = asuint(input.pos.w); + surface.normal.x = (float)((normal_subsetIndex >> 0) & 0x000000FF) / 255.0f * 2.0f - 1.0f; + surface.normal.y = (float)((normal_subsetIndex >> 8) & 0x000000FF) / 255.0f * 2.0f - 1.0f; + surface.normal.z = (float)((normal_subsetIndex >> 16) & 0x000000FF) / 255.0f * 2.0f - 1.0f; + surface.subsetIndex = (normal_subsetIndex >> 24) & 0x000000FF; - surface.uvsets = float4(input.uv0, input.uv1) * g_xMat_texMulAdd.xyxy + g_xMat_texMulAdd.zwzw; + surface.uvsets = float4(input.uv0 * g_xMat_texMulAdd.xy + g_xMat_texMulAdd.zw, input.uv1); surface.atlas = input.atl * input.instAtlas.atlasMulAdd.xy + input.instAtlas.atlasMulAdd.zw; diff --git a/WickedEngine/objectPS_hologram.hlsl b/WickedEngine/objectPS_hologram.hlsl index 14d66ce1b..759f9a191 100644 --- a/WickedEngine/objectPS_hologram.hlsl +++ b/WickedEngine/objectPS_hologram.hlsl @@ -2,10 +2,19 @@ float4 main(PixelInputType input) : SV_TARGET { - const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; - float4 color = xBaseColorMap.Sample(sampler_objectshader, UV_baseColorMap); - color.rgb = DEGAMMA(color.rgb); - color.rgb = max(color.r, max(color.g, color.b)); + float4 color; + [branch] + if (g_xMat_uvset_baseColorMap >= 0) + { + const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; + color = xBaseColorMap.Sample(sampler_objectshader, UV_baseColorMap); + color.rgb = DEGAMMA(color.rgb); + color.rgb = max(color.r, max(color.g, color.b)); + } + else + { + color = 1; + } color *= input.color; float time = g_xFrame_Time; diff --git a/WickedEngine/objectPS_voxelizer.hlsl b/WickedEngine/objectPS_voxelizer.hlsl index 3b5305107..ed4030356 100644 --- a/WickedEngine/objectPS_voxelizer.hlsl +++ b/WickedEngine/objectPS_voxelizer.hlsl @@ -23,14 +23,23 @@ void main(PSInput input) [branch] if (is_saturated(uvw)) { - const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; - float4 baseColor = xBaseColorMap.Sample(sampler_linear_wrap, UV_baseColorMap); - baseColor.rgb = DEGAMMA(baseColor.rgb); + float4 baseColor; + [branch] + if (g_xMat_uvset_baseColorMap >= 0) + { + const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; + baseColor = xBaseColorMap.Sample(sampler_linear_wrap, UV_baseColorMap); + baseColor.rgb = DEGAMMA(baseColor.rgb); + } + else + { + baseColor = 1; + } baseColor *= input.color; float4 color = baseColor; float4 emissiveColor; [branch] - if (g_xMat_emissiveColor.a > 0) + if (g_xMat_emissiveColor.a > 0 && g_xMat_uvset_emissiveMap >= 0) { const float2 UV_emissiveMap = g_xMat_uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; emissiveColor = xEmissiveMap.Sample(sampler_linear_wrap, UV_emissiveMap); diff --git a/WickedEngine/raySceneIntersectHF.hlsli b/WickedEngine/raySceneIntersectHF.hlsli index 62d28780d..d3e95fe53 100644 --- a/WickedEngine/raySceneIntersectHF.hlsli +++ b/WickedEngine/raySceneIntersectHF.hlsli @@ -294,36 +294,52 @@ inline float3 Shade(inout Ray ray, inout RayHit hit, inout float seed, in float2 hit.color = tri.c0 * w + tri.c1 * u + tri.c2 * v; hit.materialIndex = tri.materialIndex; - TracedRenderingMaterial mat = materialBuffer[hit.materialIndex]; + TracedRenderingMaterial material = materialBuffer[hit.materialIndex]; hit.uvsets = frac(hit.uvsets); // emulate wrap - const float2 UV_baseColorMap = mat.uvset_baseColorMap == 0 ? hit.uvsets.xy : hit.uvsets.zw; - float4 baseColorMap = materialTextureAtlas.SampleLevel(sampler_linear_clamp, UV_baseColorMap * mat.baseColorAtlasMulAdd.xy + mat.baseColorAtlasMulAdd.zw, 0); - - const float2 UV_surfaceMap = mat.uvset_surfaceMap == 0 ? hit.uvsets.xy : hit.uvsets.zw; - float4 surface_occlusion_roughness_metallic_reflectance = materialTextureAtlas.SampleLevel(sampler_linear_clamp, UV_surfaceMap * mat.surfaceMapAtlasMulAdd.xy + mat.surfaceMapAtlasMulAdd.zw, 0); - - if (mat.specularGlossinessWorkflow) + float4 baseColor; + [branch] + if (material.uvset_baseColorMap >= 0) { - ConvertToSpecularGlossiness(surface_occlusion_roughness_metallic_reflectance); + const float2 UV_baseColorMap = material.uvset_baseColorMap == 0 ? hit.uvsets.xy : hit.uvsets.zw; + baseColor = materialTextureAtlas.SampleLevel(sampler_linear_clamp, UV_baseColorMap * material.baseColorAtlasMulAdd.xy + material.baseColorAtlasMulAdd.zw, 0); + baseColor.rgb = DEGAMMA(baseColor.rgb); + } + else + { + baseColor = 1; + } + baseColor *= hit.color; + + float4 surface_occlusion_roughness_metallic_reflectance; + [branch] + if (material.uvset_surfaceMap >= 0) + { + const float2 UV_surfaceMap = material.uvset_surfaceMap == 0 ? hit.uvsets.xy : hit.uvsets.zw; + surface_occlusion_roughness_metallic_reflectance = materialTextureAtlas.SampleLevel(sampler_linear_clamp, UV_surfaceMap * material.surfaceMapAtlasMulAdd.xy + material.surfaceMapAtlasMulAdd.zw, 0); + if (material.specularGlossinessWorkflow) + { + ConvertToSpecularGlossiness(surface_occlusion_roughness_metallic_reflectance); + } + } + else + { + surface_occlusion_roughness_metallic_reflectance = 1; } - float4 baseColor = baseColorMap; - baseColor.rgb = DEGAMMA(baseColor.rgb); - baseColor *= hit.color; - float roughness = mat.roughness * surface_occlusion_roughness_metallic_reflectance.g; - float metalness = mat.metalness * surface_occlusion_roughness_metallic_reflectance.b; - float reflectance = mat.reflectance * surface_occlusion_roughness_metallic_reflectance.a; + float roughness = material.roughness * surface_occlusion_roughness_metallic_reflectance.g; + float metalness = material.metalness * surface_occlusion_roughness_metallic_reflectance.b; + float reflectance = material.reflectance * surface_occlusion_roughness_metallic_reflectance.a; roughness = sqr(roughness); // convert linear roughness to cone aperture float4 emissiveColor; [branch] - if (mat.emissiveColor.a > 0) + if (material.emissiveColor.a > 0 && material.uvset_emissiveMap >= 0) { - const float2 UV_emissiveMap = mat.uvset_emissiveMap == 0 ? hit.uvsets.xy : hit.uvsets.zw; - emissiveColor = materialTextureAtlas.SampleLevel(sampler_linear_clamp, UV_emissiveMap * mat.emissiveMapAtlasMulAdd.xy + mat.emissiveMapAtlasMulAdd.zw, 0); + const float2 UV_emissiveMap = material.uvset_emissiveMap == 0 ? hit.uvsets.xy : hit.uvsets.zw; + emissiveColor = materialTextureAtlas.SampleLevel(sampler_linear_clamp, UV_emissiveMap * material.emissiveMapAtlasMulAdd.xy + material.emissiveMapAtlasMulAdd.zw, 0); emissiveColor.rgb = DEGAMMA(emissiveColor.rgb); - emissiveColor *= mat.emissiveColor; + emissiveColor *= material.emissiveColor; } else { @@ -340,7 +356,7 @@ inline float3 Shade(inout Ray ray, inout RayHit hit, inout float seed, in float2 if (roulette < refractChance) { // Refraction - float3 R = refract(ray.direction, hit.N, 1 - mat.refractionIndex); + float3 R = refract(ray.direction, hit.N, 1 - material.refractionIndex); ray.direction = lerp(R, SampleHemisphere(R, seed, pixel), roughness); ray.energy *= lerp(baseColor.rgb, 1, refractChance); diff --git a/WickedEngine/shadowPS_transparent.hlsl b/WickedEngine/shadowPS_transparent.hlsl index 8f33725a5..8cf2e2528 100644 --- a/WickedEngine/shadowPS_transparent.hlsl +++ b/WickedEngine/shadowPS_transparent.hlsl @@ -12,9 +12,18 @@ float4 main(VertextoPixel input) : SV_TARGET { float2 pixel = input.pos.xy; - const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; - float4 color = xBaseColorMap.Sample(sampler_objectshader, UV_baseColorMap); - color.rgb = DEGAMMA(color.rgb); + float4 color; + [branch] + if (g_xMat_uvset_baseColorMap >= 0) + { + const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; + color = xBaseColorMap.Sample(sampler_objectshader, UV_baseColorMap); + color.rgb = DEGAMMA(color.rgb); + } + else + { + color = 1; + } color *= input.color; ALPHATEST(color.a); float opacity = color.a; @@ -22,15 +31,19 @@ float4 main(VertextoPixel input) : SV_TARGET color.rgb *= 1 - opacity; // Use the alpha channel for refraction caustics effect: - float3 bumpColor; + [branch] + if (g_xMat_uvset_normalMap >= 0) + { + float3 bumpColor; - const float2 UV_normalMap = g_xMat_uvset_normalMap == 0 ? input.uvsets.xy : input.uvsets.zw; - bumpColor = float3(2.0f * xNormalMap.Sample(sampler_objectshader, UV_normalMap - g_xMat_texMulAdd.ww).rg - 1.0f, 1); - bumpColor.rg *= g_xMat_refractionIndex; - bumpColor.rg *= g_xMat_normalMapStrength; - bumpColor = normalize(max(bumpColor, float3(0, 0, 0.0001f))); - - color.a = 1 - saturate(dot(bumpColor, float3(0, 0, 1))); + const float2 UV_normalMap = g_xMat_uvset_normalMap == 0 ? input.uvsets.xy : input.uvsets.zw; + bumpColor = float3(2.0f * xNormalMap.Sample(sampler_objectshader, UV_normalMap - g_xMat_texMulAdd.ww).rg - 1.0f, 1); + bumpColor.rg *= g_xMat_refractionIndex; + bumpColor.rg *= g_xMat_normalMapStrength; + bumpColor = normalize(max(bumpColor, float3(0, 0, 0.0001f))); + + color.a = 1 - saturate(dot(bumpColor, float3(0, 0, 1))); + } return color; } diff --git a/WickedEngine/shadowPS_water.hlsl b/WickedEngine/shadowPS_water.hlsl index 950d92a3a..0f7f4f87e 100644 --- a/WickedEngine/shadowPS_water.hlsl +++ b/WickedEngine/shadowPS_water.hlsl @@ -12,9 +12,18 @@ float4 main(VertextoPixel input) : SV_TARGET { float2 pixel = input.pos.xy; - const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; - float4 color = xBaseColorMap.Sample(sampler_objectshader, UV_baseColorMap); - color.rgb = DEGAMMA(color.rgb); + float4 color; + [branch] + if (g_xMat_uvset_baseColorMap >= 0) + { + const float2 UV_baseColorMap = g_xMat_uvset_baseColorMap == 0 ? input.uvsets.xy : input.uvsets.zw; + color = xBaseColorMap.Sample(sampler_objectshader, UV_baseColorMap); + color.rgb = DEGAMMA(color.rgb); + } + else + { + color = 1; + } color *= input.color; ALPHATEST(color.a); float opacity = color.a; @@ -25,19 +34,23 @@ float4 main(VertextoPixel input) : SV_TARGET color.rgb = 1; // Use the alpha channel for refraction caustics effect: - float3 bumpColor; + [branch] + if (g_xMat_uvset_normalMap >= 0) + { + float3 bumpColor; - float2 bumpColor0 = 0; - float2 bumpColor1 = 0; - float2 bumpColor2 = 0; - const float2 UV_normalMap = g_xMat_uvset_normalMap == 0 ? input.uvsets.xy : input.uvsets.zw; - bumpColor0 = 2.0f * xNormalMap.Sample(sampler_objectshader, UV_normalMap - g_xMat_texMulAdd.ww).rg - 1.0f; - bumpColor1 = 2.0f * xNormalMap.Sample(sampler_objectshader, UV_normalMap + g_xMat_texMulAdd.zw).rg - 1.0f; - bumpColor = float3(bumpColor0 + bumpColor1 + bumpColor2, 1) * g_xMat_refractionIndex; - bumpColor.rg *= g_xMat_normalMapStrength; - bumpColor = normalize(max(bumpColor, float3(0, 0, 0.0001f))); + float2 bumpColor0 = 0; + float2 bumpColor1 = 0; + float2 bumpColor2 = 0; + const float2 UV_normalMap = g_xMat_uvset_normalMap == 0 ? input.uvsets.xy : input.uvsets.zw; + bumpColor0 = 2.0f * xNormalMap.Sample(sampler_objectshader, UV_normalMap - g_xMat_texMulAdd.ww).rg - 1.0f; + bumpColor1 = 2.0f * xNormalMap.Sample(sampler_objectshader, UV_normalMap + g_xMat_texMulAdd.zw).rg - 1.0f; + bumpColor = float3(bumpColor0 + bumpColor1 + bumpColor2, 1) * g_xMat_refractionIndex; + bumpColor.rg *= g_xMat_normalMapStrength; + bumpColor = normalize(max(bumpColor, float3(0, 0, 0.0001f))); - color.a = 1 - saturate(abs(dot(bumpColor, float3(0, 0, 1)))); + color.a = 1 - saturate(abs(dot(bumpColor, float3(0, 0, 1)))); + } return color; } diff --git a/WickedEngine/wiGPUBVH.cpp b/WickedEngine/wiGPUBVH.cpp index 5a38605b5..86b4878a8 100644 --- a/WickedEngine/wiGPUBVH.cpp +++ b/WickedEngine/wiGPUBVH.cpp @@ -154,12 +154,12 @@ void wiGPUBVH::UpdateGlobalMaterialResources(const Scene& scene, GRAPHICSTHREAD global_material.parallaxOcclusionMapping = material.parallaxOcclusionMapping; global_material.displacementMapping = material.displacementMapping; global_material.useVertexColors = material.IsUsingVertexColors() ? 1 : 0; - global_material.uvset_baseColorMap = material.uvset_baseColorMap; - global_material.uvset_surfaceMap = material.uvset_surfaceMap; - global_material.uvset_normalMap = material.uvset_normalMap; - global_material.uvset_displacementMap = material.uvset_displacementMap; - global_material.uvset_emissiveMap = material.uvset_emissiveMap; - global_material.uvset_occlusionMap = material.uvset_occlusionMap; + global_material.uvset_baseColorMap = material.baseColorMap == nullptr ? -1 : material.uvset_baseColorMap; + global_material.uvset_surfaceMap = material.surfaceMap == nullptr ? -1 : material.uvset_surfaceMap; + global_material.uvset_normalMap = material.normalMap == nullptr ? -1 : material.uvset_normalMap; + global_material.uvset_displacementMap = material.displacementMap == nullptr ? -1 : material.uvset_displacementMap; + global_material.uvset_emissiveMap = material.emissiveMap == nullptr ? -1 : material.uvset_emissiveMap; + global_material.uvset_occlusionMap = material.occlusionMap == nullptr ? -1 : material.uvset_occlusionMap; global_material.specularGlossinessWorkflow = material.IsUsingSpecularGlossinessWorkflow() ? 1 : 0; global_material.occlusion_primary = material.IsOcclusionEnabled_Primary() ? 1 : 0; global_material.occlusion_secondary = material.IsOcclusionEnabled_Secondary() ? 1 : 0; diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index e5d53a7f8..dc82eaa16 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -3842,12 +3842,12 @@ void UpdateRenderData(GRAPHICSTHREAD threadID) materialGPUData.g_xMat_parallaxOcclusionMapping = material.parallaxOcclusionMapping; materialGPUData.g_xMat_displacementMapping = material.displacementMapping; materialGPUData.g_xMat_useVertexColors = material.IsUsingVertexColors() ? 1 : 0; - materialGPUData.g_xMat_uvset_baseColorMap = material.uvset_baseColorMap; - materialGPUData.g_xMat_uvset_surfaceMap = material.uvset_surfaceMap; - materialGPUData.g_xMat_uvset_normalMap = material.uvset_normalMap; - materialGPUData.g_xMat_uvset_displacementMap = material.uvset_displacementMap; - materialGPUData.g_xMat_uvset_emissiveMap = material.uvset_emissiveMap; - materialGPUData.g_xMat_uvset_occlusionMap = material.uvset_occlusionMap; + materialGPUData.g_xMat_uvset_baseColorMap = material.baseColorMap == nullptr ? -1 : material.uvset_baseColorMap; + materialGPUData.g_xMat_uvset_surfaceMap = material.surfaceMap == nullptr ? -1 : material.uvset_surfaceMap; + materialGPUData.g_xMat_uvset_normalMap = material.normalMap == nullptr ? -1 : material.uvset_normalMap; + materialGPUData.g_xMat_uvset_displacementMap = material.displacementMap == nullptr ? -1 : material.uvset_displacementMap; + materialGPUData.g_xMat_uvset_emissiveMap = material.emissiveMap == nullptr ? -1 : material.uvset_emissiveMap; + materialGPUData.g_xMat_uvset_occlusionMap = material.occlusionMap == nullptr ? -1 : material.uvset_occlusionMap; materialGPUData.g_xMat_specularGlossinessWorkflow = material.IsUsingSpecularGlossinessWorkflow() ? 1 : 0; materialGPUData.g_xMat_occlusion_primary = material.IsOcclusionEnabled_Primary() ? 1 : 0; materialGPUData.g_xMat_occlusion_secondary = material.IsOcclusionEnabled_Secondary() ? 1 : 0; diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index ce7fd8bcf..70094a2bb 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates const int minor = 26; // minor bug fixes, alterations, refactors, updates - const int revision = 24; + const int revision = 25; long GetVersion()