View source
class ClusterLightOcclusion
package h3d.shader.pbr
extends Shader
import h3d.shader.pbr.ClusterCull
@:directlyUsed@:src({ @global var camera:{ var view : Mat4; var proj : Mat4; var invProj : Mat4; @const var reverseDepth : Bool}; @param var lightInfos:Buffer<Vec4,4096>; @param var lightVisible:RWBuffer<Int>; @param var hzb:Sampler2D; @param var hzbSize:Vec2; var POINT_LIGHT_STRIDE:Int = 2; var SPOT_LIGHT_STRIDE:Int = 3; var CAPSULE_LIGHT_STRIDE:Int = 3; var RECT_LIGHT_STRIDE:Int = 6; @param var pointLightOffset:Int; @param var pointCount:Int; @param var spotLightOffset:Int; @param var spotCount:Int; @param var capsuleLightOffset:Int; @param var capsuleCount:Int; @param var rectLightOffset:Int; @param var rectCount:Int; function rangeFromInv4(invRange4:Float):Float { return pow(invRange4, -0.25) * 1.001; }; function farDepth(ndcMin:Vec2, ndcMax:Vec2):Float { var pixelMin = vec2(ndcMin.x * 0.5 + 0.5, 0.5 - ndcMax.y * 0.5) * hzbSize; var pixelMax = vec2(ndcMax.x * 0.5 + 0.5, 0.5 - ndcMin.y * 0.5) * hzbSize; var size = max(pixelMax - pixelMin, vec2(1.0)); var lod = max(0.0, ceil(log2(max(size.x, size.y))) - 1.0); var texel = exp2(lod); var mipSize = max(vec2(1.0), floor(hzbSize / texel)); var texelMin = ivec2(clamp(floor(pixelMin / texel), vec2(0.0), mipSize - 1.0)); var texelMax = ivec2(clamp(ceil(pixelMax / texel) - 1.0, vec2(0.0), mipSize - 1.0)); var depth = camera.reverseDepth ? 1.0 : 0.0; for (y in texelMin.y ... texelMax.y + 1) for (x in texelMin.x ... texelMax.x + 1) { var d = hzb.fetchLod(ivec2(x, y), int(lod)).x; depth = camera.reverseDepth ? min(depth, d) : max(depth, d); }; var p = vec4(0.0, 0.0, depth, 1.0) * camera.invProj; return p.z / p.w; }; function sphereVisible(center:Vec3, radius:Float):Bool { var c = (vec4(center, 1.0) * camera.view).xyz; var visible = true; if (c.z - radius > 1e-3) { var ndcMin = vec2(1e30); var ndcMax = vec2(-1e30); for (k in 0 ... 8) { var corner = c + vec3(float((k & 1) * 2 - 1), float(((k >> 1) & 1) * 2 - 1), float(((k >> 2) & 1) * 2 - 1)) * radius; var p = vec4(corner, 1.0) * camera.proj; ndcMin = min(ndcMin, p.xy / p.w); ndcMax = max(ndcMax, p.xy / p.w); }; ndcMin = max(ndcMin, vec2(-1.0)); ndcMax = min(ndcMax, vec2(1.0)); if (ndcMin.x < ndcMax.x && ndcMin.y < ndcMax.y) visible = c.z - radius <= farDepth(ndcMin, ndcMax) * 1.001; }; return visible; }; function main() { setLayout(64, 1, 1); var id = computeVar.globalInvocation.x; var total = pointCount + spotCount + capsuleCount + rectCount; if (id >= total) return; var center = vec3(0.0); var radius = 0.0; if (id < pointCount) { var i = pointLightOffset + id * POINT_LIGHT_STRIDE; center = lightInfos[i + 1].xyz; radius = rangeFromInv4(lightInfos[i + 1].a); } else if (id < pointCount + spotCount) { var i = spotLightOffset + (id - pointCount) * SPOT_LIGHT_STRIDE; center = lightInfos[i + 1].xyz; radius = lightInfos[i + 2].a * 1.001; } else if (id < pointCount + spotCount + capsuleCount) { var i = capsuleLightOffset + (id - pointCount - spotCount) * CAPSULE_LIGHT_STRIDE; center = lightInfos[i + 1].xyz; radius = rangeFromInv4(lightInfos[i + 1].a) + lightInfos[i].a; } else { var i = rectLightOffset + (id - pointCount - spotCount - capsuleCount) * RECT_LIGHT_STRIDE; center = lightInfos[i + 1].xyz; radius = lightInfos[i + 2].a * 1.001 + length(vec2(lightInfos[i].b, lightInfos[i].a)); }; lightVisible[id] = sphereVisible(center, radius) ? 1 : 0; }; })@:build(hxsl.Macros.buildShader())@:autoBuild(hxsl.Macros.buildShader())Constructor
Variables
Methods
Inherited Variables
Inherited Methods
Defined by Shader
setPriority(v:Int):Void
Shader priority should only be changed before the shader is added to a material.
