Add existing to tracked
This commit is contained in:
+267
@@ -0,0 +1,267 @@
|
||||
// See Intersection.glsl for the definition of intersectScene
|
||||
// See IntersectionUtils.glsl for the definition of nextIntersection
|
||||
// See convertLocalToBoxUv.glsl, convertLocalToCylinderUv.glsl, or convertLocalToEllipsoidUv.glsl
|
||||
// for the definitions of convertLocalToShapeSpaceDerivative and getTileAndUvCoordinate.
|
||||
// The appropriate functions are selected based on the VoxelPrimitive shape type,
|
||||
// and added to the shader in Scene/VoxelRenderResources.js.
|
||||
// See Octree.glsl for the definitions of TraversalData, SampleData,
|
||||
// traverseOctreeFromBeginning, and traverseOctreeFromExisting
|
||||
// See Megatexture.glsl for the definition of accumulatePropertiesFromMegatexture
|
||||
|
||||
#define STEP_COUNT_MAX 1000 // Harcoded value because GLSL doesn't like variable length loops
|
||||
#if defined(PICKING_VOXEL)
|
||||
#define ALPHA_ACCUM_MAX 0.1
|
||||
#else
|
||||
#define ALPHA_ACCUM_MAX 0.98 // Must be > 0.0 and <= 1.0
|
||||
#endif
|
||||
|
||||
uniform mat4 u_transformPositionViewToLocal;
|
||||
uniform mat3 u_transformDirectionViewToLocal;
|
||||
uniform vec3 u_cameraPositionLocal;
|
||||
uniform vec3 u_cameraDirectionLocal;
|
||||
uniform float u_stepSize;
|
||||
|
||||
#if defined(PICKING)
|
||||
uniform vec4 u_pickColor;
|
||||
#endif
|
||||
|
||||
vec3 getSampleSize(in int level) {
|
||||
vec3 sampleCount = exp2(float(level)) * vec3(u_dimensions);
|
||||
vec3 sampleSizeUv = 1.0 / sampleCount;
|
||||
return scaleShapeUvToShapeSpace(sampleSizeUv);
|
||||
}
|
||||
|
||||
#define MINIMUM_STEP_SCALAR (0.02)
|
||||
#define SHIFT_FRACTION (0.001)
|
||||
|
||||
/**
|
||||
* Given a coordinate within a tile, and sample spacings along a ray through
|
||||
* the coordinate, find the distance to the points where the ray entered and
|
||||
* exited the voxel cell, along with the surface normals at those points.
|
||||
* The surface normals are returned in shape space coordinates.
|
||||
*/
|
||||
RayShapeIntersection getVoxelIntersection(in vec3 tileUv, in vec3 sampleSizeAlongRay) {
|
||||
vec3 voxelCoord = tileUv * vec3(u_dimensions);
|
||||
vec3 directions = sign(sampleSizeAlongRay);
|
||||
vec3 positiveDirections = max(directions, 0.0);
|
||||
vec3 entryCoord = mix(ceil(voxelCoord), floor(voxelCoord), positiveDirections);
|
||||
vec3 exitCoord = entryCoord + directions;
|
||||
|
||||
vec3 distanceFromEntry = -abs((entryCoord - voxelCoord) * sampleSizeAlongRay);
|
||||
float lastEntry = maxComponent(distanceFromEntry);
|
||||
bvec3 isLastEntry = equal(distanceFromEntry, vec3(lastEntry));
|
||||
vec3 entryNormal = -1.0 * vec3(isLastEntry) * directions;
|
||||
vec4 entry = vec4(entryNormal, lastEntry);
|
||||
|
||||
vec3 distanceToExit = abs((exitCoord - voxelCoord) * sampleSizeAlongRay);
|
||||
float firstExit = minComponent(distanceToExit);
|
||||
bvec3 isFirstExit = equal(distanceToExit, vec3(firstExit));
|
||||
vec3 exitNormal = vec3(isFirstExit) * directions;
|
||||
vec4 exit = vec4(exitNormal, firstExit);
|
||||
|
||||
return RayShapeIntersection(entry, exit);
|
||||
}
|
||||
|
||||
vec4 getStepSize(in SampleData sampleData, in Ray viewRay, in RayShapeIntersection shapeIntersection, in mat3 jacobianT, in float currentT) {
|
||||
vec3 gradient = viewRay.dir * jacobianT;
|
||||
vec3 sampleSizeAlongRay = getSampleSize(sampleData.tileCoords.w) / gradient;
|
||||
|
||||
RayShapeIntersection voxelIntersection = getVoxelIntersection(sampleData.tileUv, sampleSizeAlongRay);
|
||||
|
||||
// Transform normal from shape space to Cartesian space to eye space
|
||||
vec3 voxelNormal = jacobianT * voxelIntersection.entry.xyz;
|
||||
voxelNormal = normalize(czm_normal * voxelNormal);
|
||||
|
||||
// Compare with the shape intersection, to choose the appropriate normal
|
||||
vec4 voxelEntry = vec4(voxelNormal, currentT + voxelIntersection.entry.w);
|
||||
vec4 entry = intersectionMax(shapeIntersection.entry, voxelEntry);
|
||||
|
||||
float fixedStep = minComponent(abs(sampleSizeAlongRay)) * u_stepSize;
|
||||
float shift = fixedStep * SHIFT_FRACTION;
|
||||
float dt = voxelIntersection.exit.w + shift;
|
||||
if ((currentT + dt) > shapeIntersection.exit.w) {
|
||||
// Stop at end of shape
|
||||
dt = shapeIntersection.exit.w - currentT + shift;
|
||||
}
|
||||
float stepSize = clamp(dt, fixedStep * MINIMUM_STEP_SCALAR, fixedStep + shift);
|
||||
|
||||
return vec4(entry.xyz, stepSize);
|
||||
}
|
||||
|
||||
vec2 packIntToVec2(int value) {
|
||||
float shifted = float(value) / 255.0;
|
||||
float lowBits = fract(shifted);
|
||||
float highBits = floor(shifted) / 255.0;
|
||||
return vec2(highBits, lowBits);
|
||||
}
|
||||
|
||||
vec2 packFloatToVec2(float value) {
|
||||
float lowBits = fract(value);
|
||||
float highBits = floor(value) / 255.0;
|
||||
return vec2(highBits, lowBits);
|
||||
}
|
||||
|
||||
int getSampleIndex(in SampleData sampleData) {
|
||||
// tileUv = 1.0 is a valid coordinate but sampleIndex = u_inputDimensions is not.
|
||||
// (tileUv = 1.0 corresponds to the far edge of the last sample, at index = u_inputDimensions - 1).
|
||||
// Clamp to [0, voxelDimensions - 0.5) to avoid numerical error before flooring
|
||||
vec3 maxCoordinate = vec3(u_inputDimensions) - vec3(0.5);
|
||||
vec3 inputCoordinate = clamp(sampleData.inputCoordinate, vec3(0.0), maxCoordinate);
|
||||
ivec3 sampleIndex = ivec3(floor(inputCoordinate));
|
||||
// Convert to a 1D index for lookup in a 1D data array
|
||||
return sampleIndex.x + u_inputDimensions.x * (sampleIndex.y + u_inputDimensions.y * sampleIndex.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the view ray at the current fragment, in the local coordinates of the shape.
|
||||
*/
|
||||
Ray getViewRayLocal() {
|
||||
vec4 eyeCoordinates = czm_windowToEyeCoordinates(gl_FragCoord);
|
||||
vec3 origin;
|
||||
vec3 direction;
|
||||
if (czm_orthographicIn3D == 1.0) {
|
||||
eyeCoordinates.z = 0.0;
|
||||
origin = (u_transformPositionViewToLocal * eyeCoordinates).xyz;
|
||||
direction = u_cameraDirectionLocal;
|
||||
} else {
|
||||
origin = u_cameraPositionLocal;
|
||||
direction = u_transformDirectionViewToLocal * normalize(eyeCoordinates.xyz);
|
||||
}
|
||||
return Ray(origin, direction);
|
||||
}
|
||||
|
||||
Ray getViewRayEC() {
|
||||
vec4 eyeCoordinates = czm_windowToEyeCoordinates(gl_FragCoord);
|
||||
vec3 viewPosEC = (czm_orthographicIn3D == 1.0)
|
||||
? vec3(eyeCoordinates.xy, 0.0)
|
||||
: vec3(0.0);
|
||||
vec3 viewDirEC = normalize(eyeCoordinates.xyz);
|
||||
return Ray(viewPosEC, viewDirEC);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
Ray viewRayLocal = getViewRayLocal();
|
||||
Ray viewRayEC = getViewRayEC();
|
||||
|
||||
Intersections ix;
|
||||
vec2 screenCoord = (gl_FragCoord.xy - czm_viewport.xy) / czm_viewport.zw; // [0,1]
|
||||
RayShapeIntersection shapeIntersection = intersectScene(screenCoord, viewRayLocal, viewRayEC, ix);
|
||||
// Exit early if the scene was completely missed.
|
||||
if (shapeIntersection.entry.w == NO_HIT) {
|
||||
discard;
|
||||
}
|
||||
|
||||
float currentT = shapeIntersection.entry.w;
|
||||
float endT = shapeIntersection.exit.w;
|
||||
|
||||
vec3 positionEC = viewRayEC.pos + currentT * viewRayEC.dir;
|
||||
TileAndUvCoordinate tileAndUv = getTileAndUvCoordinate(positionEC);
|
||||
vec3 positionLocal = viewRayLocal.pos + currentT * viewRayLocal.dir;
|
||||
mat3 jacobianT = convertLocalToShapeSpaceDerivative(positionLocal);
|
||||
|
||||
// Traverse the tree from the start position
|
||||
TraversalData traversalData;
|
||||
SampleData sampleDatas[SAMPLE_COUNT];
|
||||
traverseOctreeFromBeginning(tileAndUv, traversalData, sampleDatas);
|
||||
vec4 step = getStepSize(sampleDatas[0], viewRayLocal, shapeIntersection, jacobianT, currentT);
|
||||
|
||||
FragmentInput fragmentInput;
|
||||
#if defined(STATISTICS)
|
||||
setStatistics(fragmentInput.metadataStatistics);
|
||||
#endif
|
||||
|
||||
czm_modelMaterial materialOutput;
|
||||
vec4 colorAccum = vec4(0.0);
|
||||
|
||||
for (int stepCount = 0; stepCount < STEP_COUNT_MAX; ++stepCount) {
|
||||
// Read properties from the megatexture based on the traversal state
|
||||
Properties properties = accumulatePropertiesFromMegatexture(sampleDatas);
|
||||
|
||||
// Prepare the custom shader inputs
|
||||
copyPropertiesToMetadata(properties, fragmentInput.metadata);
|
||||
|
||||
fragmentInput.attributes.positionEC = positionEC;
|
||||
// Re-normalize normals: some shape intersections may have been scaled to encode positive/negative shapes
|
||||
fragmentInput.attributes.normalEC = normalize(step.xyz);
|
||||
|
||||
fragmentInput.voxel.viewDirUv = viewRayLocal.dir;
|
||||
|
||||
fragmentInput.voxel.travelDistance = step.w;
|
||||
fragmentInput.voxel.stepCount = stepCount;
|
||||
fragmentInput.voxel.tileIndex = sampleDatas[0].megatextureIndex;
|
||||
fragmentInput.voxel.sampleIndex = getSampleIndex(sampleDatas[0]);
|
||||
fragmentInput.voxel.distanceToDepthBuffer = ix.distanceToDepthBuffer - currentT;
|
||||
|
||||
// Run the custom shader
|
||||
fragmentMain(fragmentInput, materialOutput);
|
||||
|
||||
// Sanitize the custom shader output
|
||||
vec4 color = vec4(materialOutput.diffuse, materialOutput.alpha);
|
||||
color.rgb = max(color.rgb, vec3(0.0));
|
||||
color.a = clamp(color.a, 0.0, 1.0);
|
||||
|
||||
// Pre-multiplied alpha blend
|
||||
colorAccum += (1.0 - colorAccum.a) * vec4(color.rgb * color.a, color.a);
|
||||
|
||||
// Stop traversing if the alpha has been fully saturated
|
||||
if (colorAccum.a > ALPHA_ACCUM_MAX) {
|
||||
colorAccum.a = ALPHA_ACCUM_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
if (step.w == 0.0) {
|
||||
// Shape is infinitely thin. The ray may have hit the edge of a
|
||||
// foreground voxel. Step ahead slightly to check for more voxels
|
||||
step.w = 0.001;
|
||||
}
|
||||
|
||||
// Keep raymarching
|
||||
currentT += step.w;
|
||||
// Check if there's more intersections.
|
||||
if (currentT > endT) {
|
||||
#if (INTERSECTION_COUNT == 1)
|
||||
break;
|
||||
#else
|
||||
shapeIntersection = nextIntersection(ix);
|
||||
if (shapeIntersection.entry.w == NO_HIT) {
|
||||
break;
|
||||
} else {
|
||||
// Found another intersection. Resume raymarching there
|
||||
currentT = shapeIntersection.entry.w;
|
||||
endT = shapeIntersection.exit.w;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
positionEC = viewRayEC.pos + currentT * viewRayEC.dir;
|
||||
tileAndUv = getTileAndUvCoordinate(positionEC);
|
||||
positionLocal = viewRayLocal.pos + currentT * viewRayLocal.dir;
|
||||
jacobianT = convertLocalToShapeSpaceDerivative(positionLocal);
|
||||
|
||||
// Traverse the tree from the current ray position.
|
||||
// This is similar to traverseOctreeFromBeginning but is faster when the ray is in the same tile as the previous step.
|
||||
traverseOctreeFromExisting(tileAndUv, traversalData, sampleDatas);
|
||||
step = getStepSize(sampleDatas[0], viewRayLocal, shapeIntersection, jacobianT, currentT);
|
||||
}
|
||||
|
||||
// Convert the alpha from [0,ALPHA_ACCUM_MAX] to [0,1]
|
||||
colorAccum.a /= ALPHA_ACCUM_MAX;
|
||||
|
||||
#if defined(PICKING)
|
||||
// If alpha is 0.0 there is nothing to pick
|
||||
if (colorAccum.a == 0.0) {
|
||||
discard;
|
||||
}
|
||||
out_FragColor = u_pickColor;
|
||||
#elif defined(PICKING_VOXEL)
|
||||
// If alpha is 0.0 there is nothing to pick
|
||||
if (colorAccum.a == 0.0) {
|
||||
discard;
|
||||
}
|
||||
vec2 megatextureId = packIntToVec2(sampleDatas[0].megatextureIndex);
|
||||
vec2 sampleIndex = packIntToVec2(getSampleIndex(sampleDatas[0]));
|
||||
out_FragColor = vec4(megatextureId, sampleIndex);
|
||||
#else
|
||||
out_FragColor = colorAccum;
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user