Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorporate updates for voxel lighting #11122

Merged
merged 22 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/engine/Source/Scene/VoxelRenderResources.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ function VoxelRenderResources(primitive) {
shaderBuilder.addFragmentLines([
customShader.fragmentShaderText,
"#line 0",
IntersectionUtils,
Octree,
IntersectionUtils,
Megatexture,
]);

Expand Down
1 change: 1 addition & 0 deletions packages/engine/Source/Scene/buildVoxelDrawCommands.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ function buildVoxelDrawCommands(primitive, context) {
renderState: renderState,
shaderProgram: shaderProgram,
uniformMap: renderResources.uniformMap,
modelMatrix: primitive._compoundModelMatrix,
pass: Pass.VOXELS,
executeInClosestFrustum: true,
owner: this,
Expand Down
1 change: 1 addition & 0 deletions packages/engine/Source/Scene/processVoxelProperties.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ function processVoxelProperties(renderResources, primitive) {
shaderBuilder.addStructField(voxelStructId, "vec3", "positionUvLocal");
shaderBuilder.addStructField(voxelStructId, "vec3", "viewDirUv");
shaderBuilder.addStructField(voxelStructId, "vec3", "viewDirWorld");
shaderBuilder.addStructField(voxelStructId, "vec3", "surfaceNormal");
shaderBuilder.addStructField(voxelStructId, "float", "travelDistance");

// FragmentInput struct
Expand Down
28 changes: 20 additions & 8 deletions packages/engine/Source/Shaders/Voxels/IntersectBox.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,17 @@ Box constructVoxelBox(in ivec4 octreeCoords, in vec3 tileUv)
return Box(p0, p1);
}

vec3 getBoxNormal(in Box box, in Ray ray, in float t)
{
vec3 hitPoint = ray.pos + t * ray.dir;
vec3 lower = step(hitPoint, box.p0);
vec3 upper = step(box.p1, hitPoint);
return normalize(upper - lower);
}

// Find the distances along a ray at which the ray intersects an axis-aligned box
// See https://tavianator.com/2011/ray_box.html
vec2 intersectBox(in Ray ray, in Box box)
RayShapeIntersection intersectBox(in Ray ray, in Box box)
{
// Consider the box as the intersection of the space between 3 pairs of parallel planes
// Compute the distance along the ray to each plane
Expand All @@ -44,18 +52,22 @@ vec2 intersectBox(in Ray ray, in Box box)
vec3 exits = max(t0, t1);

// The actual box intersection points are the furthest entry and the closest exit
float entry = max(max(entries.x, entries.y), entries.z);
float exit = min(min(exits.x, exits.y), exits.z);
float entryT = max(max(entries.x, entries.y), entries.z);
float exitT = min(min(exits.x, exits.y), exits.z);

vec3 entryNormal = getBoxNormal(box, ray, entryT - RAY_SHIFT);
vec3 exitNormal = getBoxNormal(box, ray, exitT + RAY_SHIFT);

if (entry > exit) {
return vec2(NO_HIT);
if (entryT > exitT) {
entryT = NO_HIT;
exitT = NO_HIT;
}

return vec2(entry, exit);
return RayShapeIntersection(vec4(entryNormal, entryT), vec4(exitNormal, exitT));
}

void intersectShape(in Ray ray, inout Intersections ix)
{
vec2 entryExit = intersectBox(ray, Box(u_renderMinBounds, u_renderMaxBounds));
setIntersectionPair(ix, BOX_INTERSECTION_INDEX, entryExit);
RayShapeIntersection intersection = intersectBox(ray, Box(u_renderMinBounds, u_renderMaxBounds));
setShapeIntersection(ix, BOX_INTERSECTION_INDEX, intersection);
}
66 changes: 37 additions & 29 deletions packages/engine/Source/Shaders/Voxels/IntersectClippingPlanes.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,68 @@ uniform sampler2D u_clippingPlanesTexture;
uniform mat4 u_clippingPlanesMatrix;

// Plane is in Hessian Normal Form
vec2 intersectPlane(in Ray ray, in vec4 plane) {
vec3 o = ray.pos;
vec3 d = ray.dir;
vec4 intersectPlane(in Ray ray, in vec4 plane) {
vec3 n = plane.xyz; // normal
float w = plane.w; // -dot(pointOnPlane, normal)

float a = dot(o, n);
float b = dot(d, n);
float a = dot(ray.pos, n);
float b = dot(ray.dir, n);
float t = -(w + a) / b;

if (dot(d, n) > 0.0) {
return vec2(t, +INF_HIT);
} else {
return vec2(-INF_HIT, t);
}
return vec4(n, t);
}

void intersectClippingPlanes(in Ray ray, inout Intersections ix) {
vec4 backSide = vec4(-ray.dir, -INF_HIT);
vec4 farSide = vec4(ray.dir, +INF_HIT);
RayShapeIntersection clippingVolume;

#if (CLIPPING_PLANES_COUNT == 1)
// Union and intersection are the same when there's one clipping plane, and the code
// is more simplified.
vec4 planeUv = getClippingPlane(u_clippingPlanesTexture, 0, u_clippingPlanesMatrix);
vec2 intersection = intersectPlane(ray, planeUv);
setIntersectionPair(ix, CLIPPING_PLANES_INTERSECTION_INDEX, intersection);
vec4 intersection = intersectPlane(ray, planeUv);
bool reflects = dot(ray.dir, intersection.xyz) < 0.0;
clippingVolume.entry = reflects ? backSide : intersection;
clippingVolume.exit = reflects ? intersection : farSide;
setShapeIntersection(ix, CLIPPING_PLANES_INTERSECTION_INDEX, clippingVolume);
#elif defined(CLIPPING_PLANES_UNION)
float minPositiveT = +INF_HIT;
float maxNegativeT = -INF_HIT;
vec4 firstTransmission = vec4(ray.dir, +INF_HIT);
vec4 lastReflection = vec4(-ray.dir, -INF_HIT);
for (int i = 0; i < CLIPPING_PLANES_COUNT; i++) {
vec4 planeUv = getClippingPlane(u_clippingPlanesTexture, i, u_clippingPlanesMatrix);
vec2 intersection = intersectPlane(ray, planeUv);
if (intersection.y == +INF_HIT) {
minPositiveT = min(minPositiveT, intersection.x);
vec4 intersection = intersectPlane(ray, planeUv);
if (dot(ray.dir, planeUv.xyz) > 0.0) {
firstTransmission = intersection.w <= firstTransmission.w ? intersection : firstTransmission;
} else {
maxNegativeT = max(maxNegativeT, intersection.y);
lastReflection = intersection.w >= lastReflection.w ? intersection : lastReflection;
}
}
setIntersectionPair(ix, CLIPPING_PLANES_INTERSECTION_INDEX + 0, vec2(-INF_HIT, maxNegativeT));
setIntersectionPair(ix, CLIPPING_PLANES_INTERSECTION_INDEX + 1, vec2(minPositiveT, +INF_HIT));
clippingVolume.entry = backSide;
clippingVolume.exit = lastReflection;
setShapeIntersection(ix, CLIPPING_PLANES_INTERSECTION_INDEX + 0, clippingVolume);
clippingVolume.entry = firstTransmission;
clippingVolume.exit = farSide;
setShapeIntersection(ix, CLIPPING_PLANES_INTERSECTION_INDEX + 1, clippingVolume);
#else // intersection
float maxPositiveT = -INF_HIT;
float minNegativeT = +INF_HIT;
vec4 lastTransmission = vec4(ray.dir, -INF_HIT);
vec4 firstReflection = vec4(-ray.dir, +INF_HIT);
for (int i = 0; i < CLIPPING_PLANES_COUNT; i++) {
vec4 planeUv = getClippingPlane(u_clippingPlanesTexture, i, u_clippingPlanesMatrix);
vec2 intersection = intersectPlane(ray, planeUv);
if (intersection.y == +INF_HIT) {
maxPositiveT = max(maxPositiveT, intersection.x);
vec4 intersection = intersectPlane(ray, planeUv);
if (dot(ray.dir, planeUv.xyz) > 0.0) {
lastTransmission = intersection.w > lastTransmission.w ? intersection : lastTransmission;
} else {
minNegativeT = min(minNegativeT, intersection.y);
firstReflection = intersection.w < firstReflection.w ? intersection: firstReflection;
}
}
if (maxPositiveT < minNegativeT) {
setIntersectionPair(ix, CLIPPING_PLANES_INTERSECTION_INDEX, vec2(maxPositiveT, minNegativeT));
if (lastTransmission.w < firstReflection.w) {
clippingVolume.entry = lastTransmission;
clippingVolume.exit = firstReflection;
} else {
setIntersectionPair(ix, CLIPPING_PLANES_INTERSECTION_INDEX, vec2(NO_HIT));
clippingVolume.entry = vec4(-ray.dir, NO_HIT);
clippingVolume.exit = vec4(ray.dir, NO_HIT);
}
setShapeIntersection(ix, CLIPPING_PLANES_INTERSECTION_INDEX, clippingVolume);
#endif
}
20 changes: 10 additions & 10 deletions packages/engine/Source/Shaders/Voxels/Intersection.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
// Scene/VoxelRenderResources.js.
// See also IntersectClippingPlane.glsl and IntersectDepth.glsl.
// See IntersectionUtils.glsl for the definitions of Ray, NO_HIT,
// getIntersectionPair, initializeIntersections, nextIntersection.
// getFirstIntersection, initializeIntersections, nextIntersection.

/* Intersection defines (set in Scene/VoxelRenderResources.js)
#define INTERSECTION_COUNT ###
*/

vec2 intersectScene(in vec2 screenCoord, in Ray ray, out Intersections ix) {
RayShapeIntersection intersectScene(in vec2 screenCoord, in Ray ray, out Intersections ix) {
// Do a ray-shape intersection to find the exact starting and ending points.
intersectShape(ray, ix);

// Exit early if the positive shape was completely missed or behind the ray.
vec2 entryExitT = getIntersectionPair(ix, 0);
if (entryExitT.x == NO_HIT) {
RayShapeIntersection intersection = getFirstIntersection(ix);
if (intersection.entry.w == NO_HIT) {
// Positive shape was completely missed - so exit early.
return vec2(NO_HIT);
return intersection;
}

// Clipping planes
Expand All @@ -36,17 +36,17 @@ vec2 intersectScene(in vec2 screenCoord, in Ray ray, out Intersections ix) {
#if (INTERSECTION_COUNT > 1)
initializeIntersections(ix);
for (int i = 0; i < INTERSECTION_COUNT; ++i) {
entryExitT = nextIntersection(ix);
if (entryExitT.y > 0.0) {
intersection = nextIntersection(ix);
if (intersection.exit.w > 0.0) {
// Set start to 0.0 when ray is inside the shape.
entryExitT.x = max(entryExitT.x, 0.0);
intersection.entry.w = max(intersection.entry.w, 0.0);
break;
}
}
#else
// Set start to 0.0 when ray is inside the shape.
entryExitT.x = max(entryExitT.x, 0.0);
intersection.entry.w = max(intersection.entry.w, 0.0);
#endif

return entryExitT;
return intersection;
}
Loading