@cesium/engine
Version:
CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.
260 lines (240 loc) • 7.79 kB
JavaScript
import Cartesian3 from "../Core/Cartesian3.js";
import combine from "../Core/combine.js";
import defined from "../Core/defined.js";
import ShaderBuilder from "../Renderer/ShaderBuilder.js";
import ShaderDestination from "../Renderer/ShaderDestination.js";
import VoxelUtils from "../Shaders/Voxels/VoxelUtils.js";
import VoxelFS from "../Shaders/Voxels/VoxelFS.js";
import VoxelVS from "../Shaders/Voxels/VoxelVS.js";
import IntersectionUtils from "../Shaders/Voxels/IntersectionUtils.js";
import IntersectDepth from "../Shaders/Voxels/IntersectDepth.js";
import IntersectPlane from "../Shaders/Voxels/IntersectPlane.js";
import IntersectLongitude from "../Shaders/Voxels/IntersectLongitude.js";
import IntersectBox from "../Shaders/Voxels/IntersectBox.js";
import IntersectCylinder from "../Shaders/Voxels/IntersectCylinder.js";
import IntersectEllipsoid from "../Shaders/Voxels/IntersectEllipsoid.js";
import Intersection from "../Shaders/Voxels/Intersection.js";
import convertLocalToBoxUv from "../Shaders/Voxels/convertLocalToBoxUv.js";
import convertLocalToCylinderUv from "../Shaders/Voxels/convertLocalToCylinderUv.js";
import convertLocalToEllipsoidUv from "../Shaders/Voxels/convertLocalToEllipsoidUv.js";
import Octree from "../Shaders/Voxels/Octree.js";
import Megatexture from "../Shaders/Voxels/Megatexture.js";
import VoxelMetadataOrder from "./VoxelMetadataOrder.js";
/**
* Set up render resources, including basic shader code, for rendering
* a Voxel primitive.
* The shader code generated by this function may be modified in later stages.
* @constructor
* @param {VoxelPrimitive} primitive
*
* @private
*/
function VoxelRenderResources(primitive) {
const shaderBuilder = new ShaderBuilder();
/**
* An object used to build a shader incrementally. Each pipeline stage
* may add lines of shader code to this object.
*
* @type {ShaderBuilder}
* @readonly
*
* @private
*/
this.shaderBuilder = shaderBuilder;
// Custom shader uniforms
const customShader = primitive._customShader;
const uniformMap = combine(primitive._uniformMap, customShader.uniformMap);
primitive._uniformMap = uniformMap;
const customShaderUniforms = customShader.uniforms;
for (const uniformName in customShaderUniforms) {
if (customShaderUniforms.hasOwnProperty(uniformName)) {
const uniform = customShaderUniforms[uniformName];
shaderBuilder.addUniform(
uniform.type,
uniformName,
ShaderDestination.FRAGMENT,
);
}
}
// The reason this uniform is added by shader builder is because some of the
// dynamically generated shader code reads from it.
shaderBuilder.addUniform(
"sampler2D",
"u_megatextureTextures[METADATA_COUNT]",
ShaderDestination.FRAGMENT,
);
/**
* A dictionary mapping uniform name to functions that return the uniform
* values.
* @private
* @type {Object<string, Function>}
*/
this.uniformMap = uniformMap;
const clippingPlanes = primitive._clippingPlanes;
const clippingPlanesLength =
defined(clippingPlanes) && clippingPlanes.enabled
? clippingPlanes.length
: 0;
this.clippingPlanes = clippingPlanes;
this.clippingPlanesLength = clippingPlanesLength;
const renderBoundPlanes = primitive._shape.renderBoundPlanes;
const renderBoundPlanesLength = renderBoundPlanes?.length ?? 0;
this.renderBoundPlanes = renderBoundPlanes;
this.renderBoundPlanesLength = renderBoundPlanesLength;
// Build shader
shaderBuilder.addVertexLines([VoxelVS]);
if (primitive.provider.metadataOrder === VoxelMetadataOrder.Y_UP) {
shaderBuilder.addDefine(
"Y_UP_METADATA_ORDER",
undefined,
ShaderDestination.FRAGMENT,
);
}
const shapeType = primitive._provider.shape;
if (shapeType === "BOX") {
shaderBuilder.addDefine("SHAPE_BOX", undefined, ShaderDestination.FRAGMENT);
} else if (shapeType === "CYLINDER") {
shaderBuilder.addDefine(
"SHAPE_CYLINDER",
undefined,
ShaderDestination.FRAGMENT,
);
} else if (shapeType === "ELLIPSOID") {
shaderBuilder.addDefine(
"SHAPE_ELLIPSOID",
undefined,
ShaderDestination.FRAGMENT,
);
}
shaderBuilder.addFragmentLines([
customShader.fragmentShaderText,
"#line 0",
Octree,
VoxelUtils,
Megatexture,
IntersectionUtils,
IntersectPlane,
IntersectDepth,
]);
if (clippingPlanesLength > 0) {
shaderBuilder.addDefine(
"CLIPPING_PLANES",
undefined,
ShaderDestination.FRAGMENT,
);
shaderBuilder.addDefine(
"CLIPPING_PLANES_COUNT",
clippingPlanesLength,
ShaderDestination.FRAGMENT,
);
if (clippingPlanes.unionClippingRegions) {
shaderBuilder.addDefine(
"CLIPPING_PLANES_UNION",
undefined,
ShaderDestination.FRAGMENT,
);
}
}
if (primitive._depthTest) {
shaderBuilder.addDefine(
"DEPTH_TEST",
undefined,
ShaderDestination.FRAGMENT,
);
}
if (shapeType === "BOX") {
shaderBuilder.addFragmentLines([
convertLocalToBoxUv,
IntersectBox,
Intersection,
]);
} else if (shapeType === "CYLINDER") {
shaderBuilder.addFragmentLines([
convertLocalToCylinderUv,
IntersectLongitude,
IntersectCylinder,
Intersection,
]);
} else if (shapeType === "ELLIPSOID") {
shaderBuilder.addFragmentLines([
convertLocalToEllipsoidUv,
IntersectLongitude,
IntersectEllipsoid,
Intersection,
]);
}
shaderBuilder.addFragmentLines([VoxelFS]);
const shape = primitive._shape;
const shapeDefines = shape.shaderDefines;
for (const key in shapeDefines) {
if (shapeDefines.hasOwnProperty(key)) {
let value = shapeDefines[key];
// if value is undefined, don't define it
// if value is true, define it to nothing
if (defined(value)) {
value = value === true ? undefined : value;
shaderBuilder.addDefine(key, value, ShaderDestination.FRAGMENT);
}
}
}
// Count how many intersections the shader will do.
let intersectionCount = shape.shaderMaximumIntersectionsLength;
if (clippingPlanesLength > 0) {
shaderBuilder.addDefine(
"CLIPPING_PLANES_INTERSECTION_INDEX",
intersectionCount,
ShaderDestination.FRAGMENT,
);
if (clippingPlanesLength === 1) {
intersectionCount += 1;
} else if (clippingPlanes.unionClippingRegions) {
intersectionCount += 2;
} else {
intersectionCount += 1;
}
}
if (primitive._depthTest) {
shaderBuilder.addDefine(
"DEPTH_INTERSECTION_INDEX",
intersectionCount,
ShaderDestination.FRAGMENT,
);
intersectionCount += 1;
}
shaderBuilder.addDefine(
"INTERSECTION_COUNT",
intersectionCount,
ShaderDestination.FRAGMENT,
);
// Additional fragment shader defines
if (
!Cartesian3.equals(primitive.paddingBefore, Cartesian3.ZERO) ||
!Cartesian3.equals(primitive.paddingAfter, Cartesian3.ZERO)
) {
shaderBuilder.addDefine("PADDING", undefined, ShaderDestination.FRAGMENT);
}
// Allow reading from log depth texture, but don't write log depth anywhere.
// Note: This needs to be set even if depthTest is off because it affects the
// derived command system.
if (primitive._useLogDepth) {
shaderBuilder.addDefine(
"LOG_DEPTH_READ_ONLY",
undefined,
ShaderDestination.FRAGMENT,
);
}
if (primitive._nearestSampling) {
shaderBuilder.addDefine(
"NEAREST_SAMPLING",
undefined,
ShaderDestination.FRAGMENT,
);
}
const traversal = primitive._traversal;
shaderBuilder.addDefine(
"SAMPLE_COUNT",
`${traversal._sampleCount}`,
ShaderDestination.FRAGMENT,
);
}
export default VoxelRenderResources;