#include "$ENGINE$\DeferredLightPass.bslinc" Technique : inherits("DeferredLightPass") = { Language = "HLSL11"; Pass = { DepthWrite = false; #ifdef INSIDE_GEOMETRY DepthRead = false; Cull = CW; #else DepthRead = true; Cull = CCW; #endif Common = { struct VStoFS { float4 position : SV_POSITION; float4 screenPos : TEXCOORD0; }; }; Vertex = { struct VertexInput { float3 position : POSITION; uint vertexIdx : SV_VERTEXID; }; VStoFS main(VertexInput input) { VStoFS output; float3 worldPosition; uint numSides = gLightGeometry.x; if(numSides > 0) // Generate spot light geometry { uint numSlices = gLightGeometry.y; float radius = gLightGeometry.w; float angle = gLightSpotAnglesAndSqrdInvRadius.x; // Extra scale to ensure edges lie on the circle, not inside it // TODO - These can be precomputed float extraRadiusScale = 1.0f / cos(PI / (float)numSides); float angleTan = tan(angle); float height = radius / angleTan; uint sphereStartIdx = numSides * numSlices; // Cone vertices if (input.vertexIdx < sphereStartIdx) { uint sliceIdx = input.vertexIdx / numSides; uint sideIdx = input.vertexIdx % numSides; float curAngle = sideIdx * 2 * PI / (float)numSides; float sliceOffset = height * sliceIdx / (float)(numSlices - 1); float sliceRadius = sliceOffset * angleTan * extraRadiusScale; float4 localPos = float4(sliceRadius * cos(curAngle), sliceRadius * sin(curAngle), -sliceOffset, 1.0f); worldPosition = (mul(gMatConeTransform, localPos)).xyz; } else // Sphere cap vertices { uint sphereVertexIdx = input.vertexIdx - sphereStartIdx; uint sliceIdx = sphereVertexIdx / numSides; uint sideIdx = sphereVertexIdx % numSides; float curAngle = sideIdx * 2 * PI / (float)numSides; float sliceOffset = radius * sliceIdx / (float)(numSlices - 1); float sliceRadius = sqrt(max(0.0f, radius * radius - sliceOffset * sliceOffset)) * extraRadiusScale; float4 localPos = float4(sliceRadius * cos(curAngle), sliceRadius * sin(curAngle), -height - sliceOffset, 1.0f); worldPosition = (mul(gMatConeTransform, localPos)).xyz; } } else // Scale and position pre-generated sphere geometry { worldPosition = input.position * gLightGeometry.z + gLightPositionAndType.xyz; } output.screenPos = mul(gMatViewProj, float4(worldPosition, 1)); output.position = output.screenPos; return output; } }; Fragment = { float4 main(VStoFS input) : SV_Target0 { float2 correctedPos = input.screenPos.xy / input.screenPos.w; float2 screenUV = correctedPos * gClipToUVScaleOffset.xy + gClipToUVScaleOffset.zw; GBufferData gBufferData = getGBufferData(screenUV); if(gBufferData.worldNormal.w > 0.0f) { // x, y are now in clip space, z, w are in view space // We multiply them by a special inverse view-projection matrix, that had the projection entries that effect // z, w eliminated (since they are already in view space) float4 mixedSpacePos = float4(correctedPos.xy * -gBufferData.depth, gBufferData.depth, 1); float4 worldPosition4D = mul(gMatScreenToWorld, mixedSpacePos); float3 worldPosition = worldPosition4D.xyz / worldPosition4D.w; LightData lightData = getLightData(); return getLighting(worldPosition, screenUV, gBufferData, lightData); } else return float4(0.0f, 0.0f, 0.0f, 0.0f); } }; }; }; Technique : inherits("DeferredLightPass") = { Language = "GLSL"; Pass = { DepthWrite = false; #ifdef INSIDE_GEOMETRY DepthRead = false; Cull = CW; #else DepthRead = true; Cull = CCW; #endif Vertex = { varying vec4 position; varying vec4 screenPos; in vec3 bs_position; in int gl_VertexID; out gl_PerVertex { vec4 gl_Position; }; void main() { vec3 worldPosition; uint numSides = uint(gLightGeometry.x); if(numSides > 0) // Generate spot light geometry { uint numSlices = uint(gLightGeometry.y); float radius = gLightGeometry.w; float angle = gLightSpotAnglesAndSqrdInvRadius.x; // Extra scale to ensure edges lie on the circle, not inside it // TODO - These can be precomputed float extraRadiusScale = 1.0f / cos(PI / float(numSides)); float angleTan = tan(angle); float height = radius / angleTan; uint sphereStartIdx = numSides * numSlices; // Cone vertices if (gl_VertexID < sphereStartIdx) { uint sliceIdx = gl_VertexID / numSides; uint sideIdx = gl_VertexID % numSides; float curAngle = float(sideIdx) * 2 * PI / float(numSides); float sliceOffset = height * sliceIdx / float(numSlices - 1); float sliceRadius = sliceOffset * angleTan * extraRadiusScale; vec4 localPos = vec4(sliceRadius * cos(curAngle), sliceRadius * sin(curAngle), -sliceOffset, 1.0f); worldPosition = (gMatConeTransform * localPos).xyz; } else // Sphere cap vertices { uint sphereVertexIdx = gl_VertexID - sphereStartIdx; uint sliceIdx = sphereVertexIdx / numSides; uint sideIdx = sphereVertexIdx % numSides; float curAngle = float(sideIdx) * 2 * PI / float(numSides); float sliceOffset = radius * sliceIdx / float(numSlices - 1); float sliceRadius = sqrt(max(0.0f, radius * radius - sliceOffset * sliceOffset)) * extraRadiusScale; vec4 localPos = vec4(sliceRadius * cos(curAngle), sliceRadius * sin(curAngle), -height - sliceOffset, 1.0f); worldPosition = (gMatConeTransform * localPos).xyz; } } else // Scale and position pre-generated sphere geometry { worldPosition = bs_position * gLightGeometry.z + gLightPositionAndType.xyz; } screenPos = gMatViewProj * vec4(worldPosition, 1); position = screenPos; gl_Position = position; } }; Fragment = { in vec4 position; in vec4 screenPos; out vec4 fragColor; void main() { vec2 correctedPos = screenPos.xy / screenPos.w; vec2 screenUV = correctedPos * gClipToUVScaleOffset.xy + gClipToUVScaleOffset.zw; GBufferData gBufferData = getGBufferData(screenUV); if(gBufferData.worldNormal.w > 0.0f) { // x, y are now in clip space, z, w are in view space // We multiply them by a special inverse view-projection matrix, that had the projection entries that effect // z, w eliminated (since they are already in view space) vec4 mixedSpacePos = vec4(correctedPos.xy * -gBufferData.depth, gBufferData.depth, 1); vec4 worldPosition4D = gMatScreenToWorld * mixedSpacePos; vec3 worldPosition = worldPosition4D.xyz / worldPosition4D.w; LightData lightData = getLightData(); fragColor = getLighting(worldPosition, screenUV, gBufferData, lightData); } else fragColor = vec4(0.0f, 0.0f, 0.0f, 0.0f); } }; }; };