2
0
Эх сурвалжийг харах

Merge pull request #36 from godlikepanos/box_refl_probes

Make reflection probes AABBs
Panagiotis Christopoulos Charitos 7 жил өмнө
parent
commit
96ce34210b

+ 18 - 198
samples/sponza/assets/scene.lua

@@ -5,15 +5,6 @@ local node
 local inst
 local inst
 local lcomp
 local lcomp
 
 
-node = scene:newSectorNode("Cube0", "assets/Cube.ankimesh")
-trf = Transform.new()
-trf:setOrigin(Vec4.new(0, 10.6707, 0, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
 node = scene:newParticleEmitterNode("particles0", "assets/fire.ankipart")
 node = scene:newParticleEmitterNode("particles0", "assets/fire.ankipart")
 trf = Transform.new()
 trf = Transform.new()
 trf:setOrigin(Vec4.new(-10.7851, 2.17929, 2.47133, 0))
 trf:setOrigin(Vec4.new(-10.7851, 2.17929, 2.47133, 0))
@@ -86,252 +77,81 @@ trf:setRotation(rot)
 trf:setScale(0.259678)
 trf:setScale(0.259678)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
 
-node = scene:newReflectionProbeNode("reflprobe0", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(18.0683, 2.49039, 6.66315, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe1", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(8.05931, 2.49039, 6.66315, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe2", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(-1.43904, 2.49039, 6.66315, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe3", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(-11.1261, 2.49039, 6.66315, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe4", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(-19.0274, 2.49039, 6.66315, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe5", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(-19.0274, 2.49039, -8.62114, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe6", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(-11.1261, 2.49039, -8.62114, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe7", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(-1.43904, 2.49039, -8.62114, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe8", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(8.05931, 2.49039, -8.62114, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe9", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(18.0683, 2.49039, -8.62114, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe10", 7.13881)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(18.9426, 2.49039, -0.625299, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe11", 7.13881)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(8.47687, 2.49039, -0.625299, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe12", 7.13881)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(-1.45483, 2.49039, -0.625299, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe13", 7.13881)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(-11.5838, 2.49039, -0.625299, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe14", 7.13881)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(-19.8456, 2.49039, -0.625299, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe15", 7.13881)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(-19.8456, 11.1297, -0.625299, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe16", 7.13881)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(18.9426, 11.1297, -0.625299, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe17", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(18.0683, 11.1297, -8.62114, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe18", 6.82732)
-trf = Transform.new()
-trf:setOrigin(Vec4.new(8.05931, 11.1297, -8.62114, 0))
-rot = Mat3x4.new()
-rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
-trf:setRotation(rot)
-trf:setScale(1)
-node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
-
-node = scene:newReflectionProbeNode("reflprobe19", 6.82732)
+node = scene:newReflectionProbeNode("reflprobe0", Vec4.new(-24.8339, -3.89695, -4.12719, 0), Vec4.new(24.8339, 3.89695, 4.12719, 0))
 trf = Transform.new()
 trf = Transform.new()
-trf:setOrigin(Vec4.new(-1.43904, 11.1297, -8.62114, 0))
+trf:setOrigin(Vec4.new(-1.00211, 3.65293, -7.63218, 0))
 rot = Mat3x4.new()
 rot = Mat3x4.new()
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 trf:setRotation(rot)
 trf:setRotation(rot)
 trf:setScale(1)
 trf:setScale(1)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
 
-node = scene:newReflectionProbeNode("reflprobe20", 6.82732)
+node = scene:newReflectionProbeNode("reflprobe1", Vec4.new(-24.8339, -4.2659, -4.12719, 0), Vec4.new(24.8339, 4.2659, 4.12719, 0))
 trf = Transform.new()
 trf = Transform.new()
-trf:setOrigin(Vec4.new(-11.1261, 11.1297, -8.62114, 0))
+trf:setOrigin(Vec4.new(-1.00211, 11.4761, -7.63218, 0))
 rot = Mat3x4.new()
 rot = Mat3x4.new()
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 trf:setRotation(rot)
 trf:setRotation(rot)
 trf:setScale(1)
 trf:setScale(1)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
 
-node = scene:newReflectionProbeNode("reflprobe21", 6.82732)
+node = scene:newReflectionProbeNode("reflprobe2", Vec4.new(-24.8339, -4.2659, -4.12719, 0), Vec4.new(24.8339, 4.2659, 4.12719, 0))
 trf = Transform.new()
 trf = Transform.new()
-trf:setOrigin(Vec4.new(-19.0274, 11.1297, -8.62114, 0))
+trf:setOrigin(Vec4.new(-1.00211, 19.8704, -7.63218, 0))
 rot = Mat3x4.new()
 rot = Mat3x4.new()
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 trf:setRotation(rot)
 trf:setRotation(rot)
 trf:setScale(1)
 trf:setScale(1)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
 
-node = scene:newReflectionProbeNode("reflprobe22", 6.82732)
+node = scene:newReflectionProbeNode("reflprobe3", Vec4.new(-24.8339, -4.2659, -4.12719, 0), Vec4.new(24.8339, 4.2659, 4.12719, 0))
 trf = Transform.new()
 trf = Transform.new()
-trf:setOrigin(Vec4.new(-19.0274, 11.1297, 6.66315, 0))
+trf:setOrigin(Vec4.new(-1.00211, 19.8704, -0.0445416, 0))
 rot = Mat3x4.new()
 rot = Mat3x4.new()
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 trf:setRotation(rot)
 trf:setRotation(rot)
 trf:setScale(1)
 trf:setScale(1)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
 
-node = scene:newReflectionProbeNode("reflprobe23", 6.82732)
+node = scene:newReflectionProbeNode("reflprobe4", Vec4.new(-24.8339, -4.2659, -4.12719, 0), Vec4.new(24.8339, 4.2659, 4.12719, 0))
 trf = Transform.new()
 trf = Transform.new()
-trf:setOrigin(Vec4.new(-11.1261, 11.1297, 6.66315, 0))
+trf:setOrigin(Vec4.new(-1.00211, 11.4761, -0.0445416, 0))
 rot = Mat3x4.new()
 rot = Mat3x4.new()
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 trf:setRotation(rot)
 trf:setRotation(rot)
 trf:setScale(1)
 trf:setScale(1)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
 
-node = scene:newReflectionProbeNode("reflprobe24", 6.82732)
+node = scene:newReflectionProbeNode("reflprobe5", Vec4.new(-24.8339, -3.89695, -4.12719, 0), Vec4.new(24.8339, 3.89695, 4.12719, 0))
 trf = Transform.new()
 trf = Transform.new()
-trf:setOrigin(Vec4.new(-1.43904, 11.1297, 6.66315, 0))
+trf:setOrigin(Vec4.new(-1.00211, 3.65293, -0.0445416, 0))
 rot = Mat3x4.new()
 rot = Mat3x4.new()
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 trf:setRotation(rot)
 trf:setRotation(rot)
 trf:setScale(1)
 trf:setScale(1)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
 
-node = scene:newReflectionProbeNode("reflprobe25", 6.82732)
+node = scene:newReflectionProbeNode("reflprobe6", Vec4.new(-24.8339, -3.89695, -4.12719, 0), Vec4.new(24.8339, 3.89695, 4.12719, 0))
 trf = Transform.new()
 trf = Transform.new()
-trf:setOrigin(Vec4.new(8.05931, 11.1297, 6.66315, 0))
+trf:setOrigin(Vec4.new(-1.00211, 3.65293, 6.48553, 0))
 rot = Mat3x4.new()
 rot = Mat3x4.new()
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 trf:setRotation(rot)
 trf:setRotation(rot)
 trf:setScale(1)
 trf:setScale(1)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
 
-node = scene:newReflectionProbeNode("reflprobe26", 6.82732)
+node = scene:newReflectionProbeNode("reflprobe7", Vec4.new(-24.8339, -4.2659, -4.12719, 0), Vec4.new(24.8339, 4.2659, 4.12719, 0))
 trf = Transform.new()
 trf = Transform.new()
-trf:setOrigin(Vec4.new(18.0683, 11.1297, 6.66315, 0))
+trf:setOrigin(Vec4.new(-1.00211, 11.4761, 6.48553, 0))
 rot = Mat3x4.new()
 rot = Mat3x4.new()
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 trf:setRotation(rot)
 trf:setRotation(rot)
 trf:setScale(1)
 trf:setScale(1)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
 
-node = scene:newReflectionProbeNode("reflprobe27", 35.9169)
+node = scene:newReflectionProbeNode("reflprobe8", Vec4.new(-24.8339, -4.2659, -4.12719, 0), Vec4.new(24.8339, 4.2659, 4.12719, 0))
 trf = Transform.new()
 trf = Transform.new()
-trf:setOrigin(Vec4.new(0, 9.57409, -0.625299, 0))
+trf:setOrigin(Vec4.new(-1.00211, 19.8704, 6.48553, 0))
 rot = Mat3x4.new()
 rot = Mat3x4.new()
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
 trf:setRotation(rot)
 trf:setRotation(rot)

+ 10 - 3
shaders/ForwardShadingUpscale.ankiprog

@@ -23,7 +23,8 @@ http://www.anki3d.org/LICENSE
 #include <shaders/Common.glsl>
 #include <shaders/Common.glsl>
 #include <shaders/Functions.glsl>
 #include <shaders/Functions.glsl>
 
 
-#define BLUE_NOISE 1
+#define EXPENSIVE_PASS 0
+#define BLUE_NOISE 0
 
 
 layout(location = 0) in Vec2 in_uv;
 layout(location = 0) in Vec2 in_uv;
 
 
@@ -38,13 +39,19 @@ layout(ANKI_TEX_BINDING(0, 3)) uniform sampler2DArray u_noiseTex;
 
 
 layout(ANKI_UBO_BINDING(0, 0)) uniform u0_
 layout(ANKI_UBO_BINDING(0, 0)) uniform u0_
 {
 {
-	Vec4 u_linearizeCfPad2;
+	Vec4 u_linearizeCfFarPad1;
 };
 };
 
 
 void main()
 void main()
 {
 {
+#if EXPENSIVE_PASS
 	out_color =
 	out_color =
-		bilateralUpsample(u_depthFullTex, u_depthHalfTex, u_fsRt, 1.0 / Vec2(SRC_SIZE), in_uv, u_linearizeCfPad2.xy);
+		bilateralUpsample(u_depthFullTex, u_depthHalfTex, u_fsRt, 1.0 / Vec2(SRC_SIZE), in_uv, u_linearizeCfFarPad1.xy);
+#else
+	const F32 thresholdMeters = 5.0 / 100.0; // 5 centimeters
+	F32 threshold = thresholdMeters / u_linearizeCfFarPad1.z;
+	out_color = nearestDepthUpscale(in_uv, u_depthFullTex, u_depthHalfTex, u_fsRt, u_linearizeCfFarPad1.xy, threshold);
+#endif
 
 
 #if BLUE_NOISE
 #if BLUE_NOISE
 	Vec3 blueNoise = texture(u_noiseTex, Vec3(FB_SIZE / Vec2(NOISE_TEX_SIZE) * in_uv, 0.0), 0.0).rgb;
 	Vec3 blueNoise = texture(u_noiseTex, Vec3(FB_SIZE / Vec2(NOISE_TEX_SIZE) * in_uv, 0.0), 0.0).rgb;

+ 28 - 4
shaders/Functions.glsl

@@ -46,6 +46,12 @@ F32 linearizeDepthOptimal(in F32 depth, in F32 a, in F32 b)
 	return 1.0 / (a + b / depth);
 	return 1.0 / (a + b / depth);
 }
 }
 
 
+// This is the optimal linearizeDepth where a=(n-f)/n and b=f/n
+Vec4 linearizeDepthOptimal(in Vec4 depths, in F32 a, in F32 b)
+{
+	return 1.0 / (a + b / depths);
+}
+
 // Project a vector by knowing only the non zero values of a perspective matrix
 // Project a vector by knowing only the non zero values of a perspective matrix
 Vec4 projectPerspective(in Vec4 vec, in F32 m00, in F32 m11, in F32 m22, in F32 m23)
 Vec4 projectPerspective(in Vec4 vec, in F32 m00, in F32 m11, in F32 m22, in F32 m23)
 {
 {
@@ -78,17 +84,22 @@ F32 rand(Vec2 n)
 	return 0.5 + 0.5 * fract(sin(dot(n, Vec2(12.9898, 78.233))) * 43758.5453);
 	return 0.5 + 0.5 * fract(sin(dot(n, Vec2(12.9898, 78.233))) * 43758.5453);
 }
 }
 
 
-Vec3 nearestDepthUpscale(Vec2 uv, sampler2D depthFull, sampler2D depthHalf, sampler2D colorTex, F32 depthThreshold)
+Vec4 nearestDepthUpscale(
+	Vec2 uv, sampler2D depthFull, sampler2D depthHalf, sampler2D colorTex, Vec2 linearDepthCf, F32 depthThreshold)
 {
 {
 	F32 fullDepth = texture(depthFull, uv).r;
 	F32 fullDepth = texture(depthFull, uv).r;
+	fullDepth = linearizeDepthOptimal(fullDepth, linearDepthCf.x, linearDepthCf.y);
+
 	Vec4 halfDepths = textureGather(depthHalf, uv, 0);
 	Vec4 halfDepths = textureGather(depthHalf, uv, 0);
+	halfDepths = linearizeDepthOptimal(halfDepths, linearDepthCf.x, linearDepthCf.y);
+
 	Vec4 diffs = abs(Vec4(fullDepth) - halfDepths);
 	Vec4 diffs = abs(Vec4(fullDepth) - halfDepths);
-	Vec3 color;
+	Vec4 color;
 
 
 	if(all(lessThan(diffs, Vec4(depthThreshold))))
 	if(all(lessThan(diffs, Vec4(depthThreshold))))
 	{
 	{
 		// No major discontinuites, sample with bilinear
 		// No major discontinuites, sample with bilinear
-		color = texture(colorTex, uv).rgb;
+		color = texture(colorTex, uv);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -96,6 +107,7 @@ Vec3 nearestDepthUpscale(Vec2 uv, sampler2D depthFull, sampler2D depthHalf, samp
 		Vec4 r = textureGather(colorTex, uv, 0);
 		Vec4 r = textureGather(colorTex, uv, 0);
 		Vec4 g = textureGather(colorTex, uv, 1);
 		Vec4 g = textureGather(colorTex, uv, 1);
 		Vec4 b = textureGather(colorTex, uv, 2);
 		Vec4 b = textureGather(colorTex, uv, 2);
+		Vec4 a = textureGather(colorTex, uv, 3);
 
 
 		F32 minDiff = diffs.x;
 		F32 minDiff = diffs.x;
 		U32 comp = 0;
 		U32 comp = 0;
@@ -117,7 +129,7 @@ Vec3 nearestDepthUpscale(Vec2 uv, sampler2D depthFull, sampler2D depthHalf, samp
 			comp = 3;
 			comp = 3;
 		}
 		}
 
 
-		color = Vec3(r[comp], g[comp], b[comp]);
+		color = Vec4(r[comp], g[comp], b[comp], a[comp]);
 	}
 	}
 
 
 	return color;
 	return color;
@@ -354,4 +366,16 @@ F32 cubeCoordSolidAngle(Vec2 norm, F32 cubeFaceSize)
 	return areaElement(v0.x, v0.y) - areaElement(v0.x, v1.y) - areaElement(v1.x, v0.y) + areaElement(v1.x, v1.y);
 	return areaElement(v0.x, v0.y) - areaElement(v0.x, v1.y) - areaElement(v1.x, v0.y) + areaElement(v1.x, v1.y);
 }
 }
 
 
+/// Intersect a ray against an AABB. The ray is inside the AABB. The function returns the distance 'a' where the
+/// intersection point is rayOrigin + rayDir * a
+/// https://community.arm.com/graphics/b/blog/posts/reflections-based-on-local-cubemaps-in-unity
+F32 rayAabbIntersectionInside(Vec3 rayOrigin, Vec3 rayDir, Vec3 aabbMin, Vec3 aabbMax)
+{
+	Vec3 intersectMaxPointPlanes = (aabbMax - rayOrigin) / rayDir;
+	Vec3 intersectMinPointPlanes = (aabbMin - rayOrigin) / rayDir;
+	Vec3 largestParams = max(intersectMaxPointPlanes, intersectMinPointPlanes);
+	F32 distToIntersect = min(min(largestParams.x, largestParams.y), largestParams.z);
+	return distToIntersect;
+}
+
 #endif
 #endif

+ 33 - 0
shaders/LightFunctions.glsl

@@ -191,4 +191,37 @@ F32 computeAttenuationFactor(F32 lightRadius, Vec3 frag2Light)
 	return att * att;
 	return att * att;
 }
 }
 
 
+// Given the probe properties trace a ray inside the probe and find the cube tex coordinates to sample
+Vec3 intersectProbe(Vec3 fragPos, // Ray origin
+	Vec3 rayDir, // Ray direction
+	Vec3 probeAabbMin,
+	Vec3 probeAabbMax,
+	Vec3 probeOrigin // Cubemap origin
+)
+{
+	// Compute the intersection point
+	F32 intresectionDist = rayAabbIntersectionInside(fragPos, rayDir, probeAabbMin, probeAabbMax);
+	Vec3 intersectionPoint = fragPos + intresectionDist * rayDir;
+
+	// Compute the cubemap vector
+	return intersectionPoint - probeOrigin;
+}
+
+// Compute a weight (factor) of fragPos against some probe's bounds. The weight will be zero when fragPos is close to
+// AABB bounds and 1.0 at fadeDistance and less.
+F32 computeProbeBlendWeight(Vec3 fragPos, // Doesn't need to be inside the AABB
+	Vec3 probeAabbMin,
+	Vec3 probeAabbMax,
+	F32 fadeDistance)
+{
+	// Compute the min distance of fragPos from the edges of the AABB
+	Vec3 distFromMin = fragPos - probeAabbMin;
+	Vec3 distFromMax = probeAabbMax - fragPos;
+	Vec3 minDistVec = min(distFromMin, distFromMax);
+	F32 minDist = min(minDistVec.x, min(minDistVec.y, minDistVec.z));
+
+	// Use saturate because minDist might be negative.
+	return saturate(minDist / fadeDistance);
+}
+
 #endif
 #endif

+ 2 - 2
shaders/LightShading.ankiprog

@@ -117,7 +117,7 @@ void main()
 
 
 		LIGHTING_COMMON_BRDF();
 		LIGHTING_COMMON_BRDF();
 
 
-		if(light.m_diffuseColorTileSize.w >= 0.0)
+		ANKI_BRANCH if(light.m_diffuseColorTileSize.w >= 0.0)
 		{
 		{
 			F32 shadow = computeShadowFactorOmni(frag2Light, 
 			F32 shadow = computeShadowFactorOmni(frag2Light, 
 				light.m_radiusPad1.x, 
 				light.m_radiusPad1.x, 
@@ -143,7 +143,7 @@ void main()
 			l, light.m_outerCosInnerCos.x, light.m_outerCosInnerCos.y, light.m_lightDirRadius.xyz);
 			l, light.m_outerCosInnerCos.x, light.m_outerCosInnerCos.y, light.m_lightDirRadius.xyz);
 
 
 		F32 shadowmapLayerIdx = light.m_diffuseColorShadowmapId.w;
 		F32 shadowmapLayerIdx = light.m_diffuseColorShadowmapId.w;
-		if(shadowmapLayerIdx >= 0.0)
+		ANKI_BRANCH if(shadowmapLayerIdx >= 0.0)
 		{
 		{
 			F32 shadow = computeShadowFactorSpot(
 			F32 shadow = computeShadowFactorSpot(
 				light.m_texProjectionMat, worldPos, light.m_lightDirRadius.w, u_shadowTex);
 				light.m_texProjectionMat, worldPos, light.m_lightDirRadius.w, u_shadowTex);

+ 24 - 24
shaders/Reflections.ankiprog

@@ -174,36 +174,36 @@ void readReflectionsAndIrradianceFromProbes(
 
 
 	F32 reflLod = F32(IR_MIPMAP_COUNT - 1u) * roughness;
 	F32 reflLod = F32(IR_MIPMAP_COUNT - 1u) * roughness;
 
 
+	F32 totalBlendWeight = EPSILON;
+
 	// Check proxy
 	// Check proxy
 	U32 count = u_lightIndices[idxOffset++];
 	U32 count = u_lightIndices[idxOffset++];
 	ANKI_LOOP while(count-- != 0)
 	ANKI_LOOP while(count-- != 0)
 	{
 	{
 		ReflectionProbe probe = u_reflectionProbes[u_lightIndices[idxOffset++]];
 		ReflectionProbe probe = u_reflectionProbes[u_lightIndices[idxOffset++]];
-
-		F32 R2 = probe.m_positionRadiusSq.w;
-		Vec3 center = probe.m_positionRadiusSq.xyz;
-
-		// Get distance from the center of the probe
-		Vec3 f = worldPos - center;
-
-		// Cubemap UV in view space
-		Vec3 uv = computeCubemapVecAccurate(reflDir, R2, f);
-
-		// Read!
-		F32 cubemapIndex = probe.m_cubemapIndexPad3.x;
-		Vec3 c = textureLod(u_reflectionsTex, Vec4(uv, cubemapIndex), reflLod).rgb;
-
-		// Combine (lerp) with previous color
-		F32 d = dot(f, f);
-		F32 factor = d / R2;
-		factor = min(factor, 1.0);
-		specIndirect = mix(c, specIndirect, factor);
-
-		// Do the same for diffuse
-		uv = computeCubemapVecAccurate(normal, R2, f);
-		Vec3 id = textureLod(u_irradianceTex, Vec4(uv, cubemapIndex), 0.0).rgb;
-		diffIndirect = mix(id, diffIndirect, factor);
+		Vec3 aabbMin = probe.m_aabbMinPad1.xyz;
+		Vec3 aabbMax = probe.m_aabbMaxPad1.xyz;
+		Vec3 probeOrigin = probe.m_positionCubemapIndex.xyz;
+		F32 cubemapIndex = probe.m_positionCubemapIndex.w;
+
+		// Compute blend weight
+		F32 blendWeight = computeProbeBlendWeight(worldPos, aabbMin, aabbMax, 0.2);
+		totalBlendWeight += blendWeight;
+		
+		// Sample reflections
+		Vec3 cubeUv = intersectProbe(worldPos, reflDir, aabbMin, aabbMax, probeOrigin);
+		Vec3 c = textureLod(u_reflectionsTex, Vec4(cubeUv, cubemapIndex), reflLod).rgb;
+		specIndirect += c * blendWeight;
+		
+		// Sample irradiance
+		cubeUv = intersectProbe(worldPos, normal, aabbMin, aabbMax, probeOrigin);
+		c = textureLod(u_irradianceTex, Vec4(cubeUv, cubemapIndex), 0.0).rgb;
+		diffIndirect += c * blendWeight;
 	}
 	}
+
+	// Normalize the colors
+	specIndirect /= totalBlendWeight;
+	diffIndirect /= totalBlendWeight;
 }
 }
 
 
 void main()
 void main()

+ 3 - 5
shaders/glsl_cpp_common/ClusteredShading.h

@@ -52,11 +52,9 @@ const U32 SIZEOF_SPOT_LIGHT = 4 * SIZEOF_VEC4 + SIZEOF_MAT4;
 // Representation of a reflection probe
 // Representation of a reflection probe
 struct ReflectionProbe
 struct ReflectionProbe
 {
 {
-	// Position of the prove in view space. Radius of probe squared
-	Vec4 m_positionRadiusSq;
-
-	// Slice in u_reflectionsTex vector.
-	Vec4 m_cubemapIndexPad3;
+	Vec4 m_positionCubemapIndex; // xyz: Position of the prove in view space. w: Slice in u_reflectionsTex vector.
+	Vec4 m_aabbMinPad1;
+	Vec4 m_aabbMaxPad1;
 };
 };
 const U32 SIZEOF_REFLECTION_PROBE = 2 * SIZEOF_VEC4;
 const U32 SIZEOF_REFLECTION_PROBE = 2 * SIZEOF_VEC4;
 
 

+ 1 - 0
src/anki/renderer/ForwardShading.cpp

@@ -134,6 +134,7 @@ void ForwardShading::drawUpscale(const RenderingContext& ctx, RenderPassWorkCont
 	Vec4* linearDepth = allocateAndBindUniforms<Vec4*>(sizeof(Vec4), cmdb, 0, 0);
 	Vec4* linearDepth = allocateAndBindUniforms<Vec4*>(sizeof(Vec4), cmdb, 0, 0);
 	computeLinearizeDepthOptimal(
 	computeLinearizeDepthOptimal(
 		ctx.m_renderQueue->m_cameraNear, ctx.m_renderQueue->m_cameraFar, linearDepth->x(), linearDepth->y());
 		ctx.m_renderQueue->m_cameraNear, ctx.m_renderQueue->m_cameraFar, linearDepth->x(), linearDepth->y());
+	linearDepth->z() = ctx.m_renderQueue->m_cameraFar;
 
 
 	rgraphCtx.bindTextureAndSampler(0,
 	rgraphCtx.bindTextureAndSampler(0,
 		0,
 		0,

+ 15 - 19
src/anki/renderer/LightBin.cpp

@@ -81,27 +81,22 @@ public:
 		m_index = i;
 		m_index = i;
 	}
 	}
 
 
-	F32 getProbeRadius() const
+	void setProbeVolume(F32 v)
 	{
 	{
-		return F32(m_probeRadius) / F32(MAX_U16) * F32(MAX_PROBE_RADIUS);
-	}
-
-	void setProbeRadius(F32 r)
-	{
-		ANKI_ASSERT(r < MAX_PROBE_RADIUS);
-		m_probeRadius = r / F32(MAX_PROBE_RADIUS) * F32(MAX_U16);
+		ANKI_ASSERT(v < MAX_PROBE_VOLUME);
+		m_probeVolume = v / F32(MAX_PROBE_VOLUME) * F32(MAX_U16);
 	}
 	}
 
 
 	Bool operator<(const ClusterProbeIndex& b) const
 	Bool operator<(const ClusterProbeIndex& b) const
 	{
 	{
-		ANKI_ASSERT(m_probeRadius > 0 && b.m_probeRadius > 0);
-		return (m_probeRadius != b.m_probeRadius) ? (m_probeRadius > b.m_probeRadius) : (m_index < b.m_index);
+		ANKI_ASSERT(m_probeVolume > 0 && b.m_probeVolume > 0);
+		return (m_probeVolume != b.m_probeVolume) ? (m_probeVolume > b.m_probeVolume) : (m_index < b.m_index);
 	}
 	}
 
 
 private:
 private:
-	static const U MAX_PROBE_RADIUS = 1000;
+	static const U MAX_PROBE_VOLUME = 1000;
 	U16 m_index;
 	U16 m_index;
-	U16 m_probeRadius;
+	U16 m_probeVolume;
 };
 };
 
 
 /// WARNING: Keep it as small as possible. The number of clusters is huge
 /// WARNING: Keep it as small as possible. The number of clusters is huge
@@ -716,17 +711,16 @@ void LightBin::writeAndBinProbe(
 {
 {
 	// Write it
 	// Write it
 	ReflectionProbe probe;
 	ReflectionProbe probe;
-	probe.m_positionRadiusSq = Vec4(probeEl.m_worldPosition, probeEl.m_radius * probeEl.m_radius);
-	probe.m_cubemapIndexPad3 = Vec4(probeEl.m_textureArrayIndex, 0.0f, 0.0f, 0.0f);
+	probe.m_positionCubemapIndex = Vec4(probeEl.m_worldPosition, probeEl.m_textureArrayIndex);
+	probe.m_aabbMinPad1 = probeEl.m_aabbMin.xyz0();
+	probe.m_aabbMaxPad1 = probeEl.m_aabbMax.xyz0();
 
 
 	U idx = ctx.m_probeCount.fetchAdd(1);
 	U idx = ctx.m_probeCount.fetchAdd(1);
 	ctx.m_probes[idx] = probe;
 	ctx.m_probes[idx] = probe;
 
 
 	// Bin it
 	// Bin it
-	Sphere sphere(probeEl.m_worldPosition.xyz0(), probeEl.m_radius);
-	Aabb box;
-	sphere.computeAabb(box);
-	m_clusterer.bin(sphere, box, testResult);
+	Aabb box(probeEl.m_aabbMin, probeEl.m_aabbMax);
+	m_clusterer.bin(box, box, testResult);
 
 
 	auto it = testResult.getClustersBegin();
 	auto it = testResult.getClustersBegin();
 	auto end = testResult.getClustersEnd();
 	auto end = testResult.getClustersEnd();
@@ -742,7 +736,9 @@ void LightBin::writeAndBinProbe(
 
 
 		i = cluster.m_probeCount.fetchAdd(1) % MAX_PROBES_PER_CLUSTER;
 		i = cluster.m_probeCount.fetchAdd(1) % MAX_PROBES_PER_CLUSTER;
 		cluster.m_probeIds[i].setIndex(idx);
 		cluster.m_probeIds[i].setIndex(idx);
-		cluster.m_probeIds[i].setProbeRadius(probeEl.m_radius);
+
+		Vec3 edges = probeEl.m_aabbMax - probeEl.m_aabbMin;
+		cluster.m_probeIds[i].setProbeVolume(edges.x() * edges.y() * edges.z());
 	}
 	}
 }
 }
 
 

+ 2 - 1
src/anki/renderer/RenderQueue.h

@@ -120,7 +120,8 @@ public:
 	void* m_userData;
 	void* m_userData;
 	U64 m_uuid;
 	U64 m_uuid;
 	Vec3 m_worldPosition;
 	Vec3 m_worldPosition;
-	F32 m_radius;
+	Vec3 m_aabbMin;
+	Vec3 m_aabbMax;
 	Array<RenderQueue*, 6> m_renderQueues;
 	Array<RenderQueue*, 6> m_renderQueues;
 	U32 m_textureArrayIndex; ///< Renderer internal.
 	U32 m_textureArrayIndex; ///< Renderer internal.
 };
 };

+ 22 - 15
src/anki/scene/ReflectionProbeNode.cpp

@@ -46,7 +46,7 @@ ReflectionProbeNode::~ReflectionProbeNode()
 {
 {
 }
 }
 
 
-Error ReflectionProbeNode::init(F32 radius)
+Error ReflectionProbeNode::init(const Vec4& aabbMinLSpace, const Vec4& aabbMaxLSpace)
 {
 {
 	// Move component first
 	// Move component first
 	newComponent<MoveComponent>(this);
 	newComponent<MoveComponent>(this);
@@ -55,28 +55,28 @@ Error ReflectionProbeNode::init(F32 radius)
 	newComponent<ReflectionProbeMoveFeedbackComponent>(this);
 	newComponent<ReflectionProbeMoveFeedbackComponent>(this);
 
 
 	// The frustum components
 	// The frustum components
-	const F32 ang = toRad(90.0);
+	const F32 ang = toRad(90.0f);
 	const F32 zNear = FRUSTUM_NEAR_PLANE;
 	const F32 zNear = FRUSTUM_NEAR_PLANE;
 
 
 	Mat3 rot;
 	Mat3 rot;
 
 
-	rot = Mat3(Euler(0.0, -PI / 2.0, 0.0)) * Mat3(Euler(0.0, 0.0, PI));
+	rot = Mat3(Euler(0.0f, -PI / 2.0f, 0.0f)) * Mat3(Euler(0.0f, 0.0f, PI));
 	m_cubeSides[0].m_localTrf.setRotation(Mat3x4(rot));
 	m_cubeSides[0].m_localTrf.setRotation(Mat3x4(rot));
-	rot = Mat3(Euler(0.0, PI / 2.0, 0.0)) * Mat3(Euler(0.0, 0.0, PI));
+	rot = Mat3(Euler(0.0f, PI / 2.0f, 0.0f)) * Mat3(Euler(0.0f, 0.0f, PI));
 	m_cubeSides[1].m_localTrf.setRotation(Mat3x4(rot));
 	m_cubeSides[1].m_localTrf.setRotation(Mat3x4(rot));
-	rot = Mat3(Euler(PI / 2.0, 0.0, 0.0));
+	rot = Mat3(Euler(PI / 2.0f, 0.0f, 0.0f));
 	m_cubeSides[2].m_localTrf.setRotation(Mat3x4(rot));
 	m_cubeSides[2].m_localTrf.setRotation(Mat3x4(rot));
-	rot = Mat3(Euler(-PI / 2.0, 0.0, 0.0));
+	rot = Mat3(Euler(-PI / 2.0f, 0.0f, 0.0f));
 	m_cubeSides[3].m_localTrf.setRotation(Mat3x4(rot));
 	m_cubeSides[3].m_localTrf.setRotation(Mat3x4(rot));
-	rot = Mat3(Euler(0.0, PI, 0.0)) * Mat3(Euler(0.0, 0.0, PI));
+	rot = Mat3(Euler(0.0f, PI, 0.0f)) * Mat3(Euler(0.0f, 0.0f, PI));
 	m_cubeSides[4].m_localTrf.setRotation(Mat3x4(rot));
 	m_cubeSides[4].m_localTrf.setRotation(Mat3x4(rot));
-	rot = Mat3(Euler(0.0, 0.0, PI));
+	rot = Mat3(Euler(0.0f, 0.0f, PI));
 	m_cubeSides[5].m_localTrf.setRotation(Mat3x4(rot));
 	m_cubeSides[5].m_localTrf.setRotation(Mat3x4(rot));
 
 
 	for(U i = 0; i < 6; ++i)
 	for(U i = 0; i < 6; ++i)
 	{
 	{
-		m_cubeSides[i].m_localTrf.setOrigin(Vec4(0.0));
-		m_cubeSides[i].m_localTrf.setScale(1.0);
+		m_cubeSides[i].m_localTrf.setOrigin(Vec4(0.0f));
+		m_cubeSides[i].m_localTrf.setScale(1.0f);
 
 
 		m_cubeSides[i].m_frustum.setAll(ang, ang, zNear, EFFECTIVE_DISTANCE);
 		m_cubeSides[i].m_frustum.setAll(ang, ang, zNear, EFFECTIVE_DISTANCE);
 		m_cubeSides[i].m_frustum.resetTransform(m_cubeSides[i].m_localTrf);
 		m_cubeSides[i].m_frustum.resetTransform(m_cubeSides[i].m_localTrf);
@@ -87,13 +87,16 @@ Error ReflectionProbeNode::init(F32 radius)
 	}
 	}
 
 
 	// Spatial component
 	// Spatial component
-	m_spatialSphere.setCenter(Vec4(0.0));
-	m_spatialSphere.setRadius(radius);
-	newComponent<SpatialComponent>(this, &m_spatialSphere);
+	m_aabbMinLSpace = aabbMinLSpace.xyz();
+	m_aabbMaxLSpace = aabbMaxLSpace.xyz();
+	m_spatialAabb.setMin(aabbMinLSpace);
+	m_spatialAabb.setMax(aabbMaxLSpace);
+	newComponent<SpatialComponent>(this, &m_spatialAabb);
 
 
 	// Reflection probe comp
 	// Reflection probe comp
 	ReflectionProbeComponent* reflc = newComponent<ReflectionProbeComponent>(this);
 	ReflectionProbeComponent* reflc = newComponent<ReflectionProbeComponent>(this);
-	reflc->setRadius(radius);
+	reflc->setPosition(Vec4(0.0f));
+	reflc->setBoundingBox(aabbMinLSpace, aabbMaxLSpace);
 
 
 	return Error::NONE;
 	return Error::NONE;
 }
 }
@@ -120,11 +123,15 @@ void ReflectionProbeNode::onMoveUpdate(MoveComponent& move)
 	SpatialComponent& sp = getComponent<SpatialComponent>();
 	SpatialComponent& sp = getComponent<SpatialComponent>();
 	sp.markForUpdate();
 	sp.markForUpdate();
 	sp.setSpatialOrigin(move.getWorldTransform().getOrigin());
 	sp.setSpatialOrigin(move.getWorldTransform().getOrigin());
-	m_spatialSphere.setCenter(move.getWorldTransform().getOrigin());
+	const Vec3 aabbMinWSpace = m_aabbMinLSpace + move.getWorldTransform().getOrigin().xyz();
+	const Vec3 aabbMaxWSpace = m_aabbMaxLSpace + move.getWorldTransform().getOrigin().xyz();
+	m_spatialAabb.setMin(aabbMinWSpace);
+	m_spatialAabb.setMax(aabbMaxWSpace);
 
 
 	// Update the refl comp
 	// Update the refl comp
 	ReflectionProbeComponent& reflc = getComponent<ReflectionProbeComponent>();
 	ReflectionProbeComponent& reflc = getComponent<ReflectionProbeComponent>();
 	reflc.setPosition(move.getWorldTransform().getOrigin());
 	reflc.setPosition(move.getWorldTransform().getOrigin());
+	reflc.setBoundingBox(aabbMinWSpace.xyz0(), aabbMaxWSpace.xyz0());
 }
 }
 
 
 Error ReflectionProbeNode::frameUpdate(Second prevUpdateTime, Second crntTime)
 Error ReflectionProbeNode::frameUpdate(Second prevUpdateTime, Second crntTime)

+ 4 - 15
src/anki/scene/ReflectionProbeNode.h

@@ -32,19 +32,7 @@ public:
 
 
 	~ReflectionProbeNode();
 	~ReflectionProbeNode();
 
 
-	ANKI_USE_RESULT Error init(F32 radius);
-
-	U getCubemapArrayIndex() const
-	{
-		ANKI_ASSERT(m_cubemapArrayIdx < 0xFF);
-		return m_cubemapArrayIdx;
-	}
-
-	void setCubemapArrayIndex(U cubemapArrayIdx)
-	{
-		ANKI_ASSERT(cubemapArrayIdx < 0xFF);
-		m_cubemapArrayIdx = cubemapArrayIdx;
-	}
+	ANKI_USE_RESULT Error init(const Vec4& aabbMinLSpace, const Vec4& aabbMaxLSpace);
 
 
 	ANKI_USE_RESULT Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
 	ANKI_USE_RESULT Error frameUpdate(Second prevUpdateTime, Second crntTime) override;
 
 
@@ -57,8 +45,9 @@ private:
 	};
 	};
 
 
 	Array<CubeSide, 6> m_cubeSides;
 	Array<CubeSide, 6> m_cubeSides;
-	Sphere m_spatialSphere;
-	U8 m_cubemapArrayIdx = 0xFF; ///< Used by the renderer
+	Vec3 m_aabbMinLSpace = Vec3(+1.0f);
+	Vec3 m_aabbMaxLSpace = Vec3(-1.0f);
+	Aabb m_spatialAabb;
 
 
 	void onMoveUpdate(MoveComponent& move);
 	void onMoveUpdate(MoveComponent& move);
 };
 };

+ 20 - 30
src/anki/scene/components/ReflectionProbeComponent.h

@@ -25,67 +25,57 @@ public:
 	{
 	{
 	}
 	}
 
 
-	const Vec4& getPosition() const
+	Vec4 getPosition() const
 	{
 	{
-		return m_pos;
+		return m_pos.xyz0();
 	}
 	}
 
 
 	void setPosition(const Vec4& pos)
 	void setPosition(const Vec4& pos)
 	{
 	{
-		m_pos = pos.xyz0();
+		m_pos = pos.xyz();
 	}
 	}
 
 
-	F32 getRadius() const
+	void setBoundingBox(const Vec4& min, const Vec4& max)
 	{
 	{
-		ANKI_ASSERT(m_radius > 0.0);
-		return m_radius;
+		m_aabbMin = min.xyz();
+		m_aabbMax = max.xyz();
 	}
 	}
 
 
-	void setRadius(F32 radius)
+	Vec4 getBoundingBoxMin() const
 	{
 	{
-		ANKI_ASSERT(radius > 0.0);
-		m_radius = radius;
+		return m_aabbMin.xyz0();
 	}
 	}
 
 
-	Bool getMarkedForRendering() const
-	{
-		return m_markedForRendering;
-	}
-
-	void setMarkedForRendering(Bool render)
+	Vec4 getBoundingBoxMax() const
 	{
 	{
-		m_markedForRendering = render;
+		return m_aabbMax.xyz0();
 	}
 	}
 
 
-	void setTextureArrayIndex(U idx)
-	{
-		m_textureArrayIndex = idx;
-	}
-
-	U getTextureArrayIndex() const
+	Bool getMarkedForRendering() const
 	{
 	{
-		ANKI_ASSERT(m_textureArrayIndex < MAX_U16);
-		return m_textureArrayIndex;
+		return m_markedForRendering;
 	}
 	}
 
 
 	void setupReflectionProbeQueueElement(ReflectionProbeQueueElement& el) const
 	void setupReflectionProbeQueueElement(ReflectionProbeQueueElement& el) const
 	{
 	{
+		ANKI_ASSERT(m_aabbMin < m_aabbMax);
+		ANKI_ASSERT(m_pos > m_aabbMin && m_pos < m_aabbMax);
 		el.m_feedbackCallback = reflectionProbeQueueElementFeedbackCallback;
 		el.m_feedbackCallback = reflectionProbeQueueElementFeedbackCallback;
 		el.m_userData = const_cast<ReflectionProbeComponent*>(this);
 		el.m_userData = const_cast<ReflectionProbeComponent*>(this);
 		el.m_uuid = getUuid();
 		el.m_uuid = getUuid();
-		el.m_worldPosition = m_pos.xyz();
-		el.m_radius = m_radius;
+		el.m_worldPosition = m_pos;
+		el.m_aabbMin = m_aabbMin;
+		el.m_aabbMax = m_aabbMax;
 		el.m_textureArrayIndex = MAX_U32;
 		el.m_textureArrayIndex = MAX_U32;
 		el.m_drawCallback = debugDrawCallback;
 		el.m_drawCallback = debugDrawCallback;
 	}
 	}
 
 
 private:
 private:
-	Vec4 m_pos = Vec4(0.0);
-	F32 m_radius = 0.0;
+	Vec3 m_pos = Vec3(0.0f);
+	Vec3 m_aabbMin = Vec3(+1.0f);
+	Vec3 m_aabbMax = Vec3(-1.0f);
 	Bool8 m_markedForRendering = false;
 	Bool8 m_markedForRendering = false;
 
 
-	U16 m_textureArrayIndex = MAX_U16; ///< Used by the renderer
-
 	static void reflectionProbeQueueElementFeedbackCallback(Bool fillRenderQueuesOnNextFrame, void* userData)
 	static void reflectionProbeQueueElementFeedbackCallback(Bool fillRenderQueuesOnNextFrame, void* userData)
 	{
 	{
 		ANKI_ASSERT(userData);
 		ANKI_ASSERT(userData);

+ 14 - 4
src/anki/script/Scene.cpp

@@ -3107,7 +3107,7 @@ static inline int pwrapSceneGraphnewReflectionProbeNode(lua_State* l)
 	PtrSize size;
 	PtrSize size;
 	(void)size;
 	(void)size;
 
 
-	LuaBinder::checkArgsCount(l, 3);
+	LuaBinder::checkArgsCount(l, 4);
 
 
 	// Get "this" as "self"
 	// Get "this" as "self"
 	if(LuaBinder::checkUserData(l, 1, classnameSceneGraph, -7754439619132389154, ud))
 	if(LuaBinder::checkUserData(l, 1, classnameSceneGraph, -7754439619132389154, ud))
@@ -3124,14 +3124,24 @@ static inline int pwrapSceneGraphnewReflectionProbeNode(lua_State* l)
 		return -1;
 		return -1;
 	}
 	}
 
 
-	F32 arg1;
-	if(LuaBinder::checkNumber(l, 3, arg1))
+	if(LuaBinder::checkUserData(l, 3, "Vec4", 6804478823655046386, ud))
+	{
+		return -1;
+	}
+
+	Vec4* iarg1 = ud->getData<Vec4>();
+	const Vec4& arg1(*iarg1);
+
+	if(LuaBinder::checkUserData(l, 4, "Vec4", 6804478823655046386, ud))
 	{
 	{
 		return -1;
 		return -1;
 	}
 	}
 
 
+	Vec4* iarg2 = ud->getData<Vec4>();
+	const Vec4& arg2(*iarg2);
+
 	// Call the method
 	// Call the method
-	ReflectionProbeNode* ret = newSceneNode<ReflectionProbeNode>(self, arg0, arg1);
+	ReflectionProbeNode* ret = newSceneNode<ReflectionProbeNode>(self, arg0, arg1, arg2);
 
 
 	// Push return value
 	// Push return value
 	if(ANKI_UNLIKELY(ret == nullptr))
 	if(ANKI_UNLIKELY(ret == nullptr))

+ 3 - 2
src/anki/script/Scene.xml

@@ -369,10 +369,11 @@ static SceneGraph* getSceneGraph(lua_State* l)
 					<return>ParticleEmitterNode*</return>
 					<return>ParticleEmitterNode*</return>
 				</method>
 				</method>
 				<method name="newReflectionProbeNode">
 				<method name="newReflectionProbeNode">
-					<overrideCall><![CDATA[ReflectionProbeNode* ret = newSceneNode<ReflectionProbeNode>(self, arg0, arg1);]]></overrideCall>
+					<overrideCall><![CDATA[ReflectionProbeNode* ret = newSceneNode<ReflectionProbeNode>(self, arg0, arg1, arg2);]]></overrideCall>
 					<args>
 					<args>
 						<arg>const CString&amp;</arg>
 						<arg>const CString&amp;</arg>
-						<arg>F32</arg>
+						<arg>const Vec4&amp;</arg>
+						<arg>const Vec4&amp;</arg>
 					</args>
 					</args>
 					<return>ReflectionProbeNode*</return>
 					<return>ReflectionProbeNode*</return>
 				</method>
 				</method>

+ 9 - 4
tools/scene/Exporter.cpp

@@ -819,9 +819,12 @@ void Exporter::visitNode(const aiNode* ainode)
 				aiMatrix4x4 trf = toAnkiMatrix(ainode->mTransformation);
 				aiMatrix4x4 trf = toAnkiMatrix(ainode->mTransformation);
 				probe.m_position = aiVector3D(trf.a4, trf.b4, trf.c4);
 				probe.m_position = aiVector3D(trf.a4, trf.b4, trf.c4);
 
 
-				aiVector3D zAxis(trf.a3, trf.b3, trf.c3);
-				float scale = zAxis.Length();
-				probe.m_radius = scale;
+				aiVector3D scale(trf.a1, trf.b2, trf.c3);
+				assert(scale.x > 0.0f && scale.y > 0.0f && scale.z > 0.0f);
+
+				aiVector3D half = scale;
+				probe.m_aabbMin = probe.m_position - half - probe.m_position;
+				probe.m_aabbMax = probe.m_position + half - probe.m_position;
 
 
 				m_reflectionProbes.push_back(probe);
 				m_reflectionProbes.push_back(probe);
 
 
@@ -1049,7 +1052,9 @@ void Exporter::exportAll()
 	for(const ReflectionProbe& probe : m_reflectionProbes)
 	for(const ReflectionProbe& probe : m_reflectionProbes)
 	{
 	{
 		std::string name = "reflprobe" + std::to_string(i);
 		std::string name = "reflprobe" + std::to_string(i);
-		file << "\nnode = scene:newReflectionProbeNode(\"" << name << "\", " << probe.m_radius << ")\n";
+		file << "\nnode = scene:newReflectionProbeNode(\"" << name << "\", Vec4.new(" << probe.m_aabbMin.x << ", "
+			 << probe.m_aabbMin.y << ", " << probe.m_aabbMin.z << ", 0), Vec4.new(" << probe.m_aabbMax.x << ", "
+			 << probe.m_aabbMax.y << ", " << probe.m_aabbMax.z << ", 0))\n";
 
 
 		aiMatrix4x4 trf;
 		aiMatrix4x4 trf;
 		aiMatrix4x4::Translation(probe.m_position, trf);
 		aiMatrix4x4::Translation(probe.m_position, trf);

+ 2 - 1
tools/scene/Exporter.h

@@ -74,7 +74,8 @@ class ReflectionProbe
 {
 {
 public:
 public:
 	aiVector3D m_position;
 	aiVector3D m_position;
-	float m_radius;
+	aiVector3D m_aabbMin;
+	aiVector3D m_aabbMax;
 };
 };
 
 
 class ReflectionProxy
 class ReflectionProxy