123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- import defined from "../Core/defined.js";
- import MetadataType from "./MetadataType.js";
- import ShaderDestination from "../Renderer/ShaderDestination.js";
- /**
- * Update the shader with defines, structs, and functions to handle
- * voxel properties and statistics
- * @function
- *
- * @param {VoxelRenderResources} renderResources
- * @param {VoxelPrimitive} primitive
- *
- * @private
- */
- function processVoxelProperties(renderResources, primitive) {
- const { shaderBuilder } = renderResources;
- const {
- names,
- types,
- componentTypes,
- minimumValues,
- maximumValues,
- } = primitive._provider;
- const attributeLength = types.length;
- const hasStatistics = defined(minimumValues) && defined(maximumValues);
- shaderBuilder.addDefine(
- "METADATA_COUNT",
- attributeLength,
- ShaderDestination.FRAGMENT
- );
- if (hasStatistics) {
- shaderBuilder.addDefine(
- "STATISTICS",
- undefined,
- ShaderDestination.FRAGMENT
- );
- }
- // PropertyStatistics structs
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- const type = types[i];
- const propertyStatisticsStructId = `PropertyStatistics_${name}`;
- const propertyStatisticsStructName = `PropertyStatistics_${name}`;
- shaderBuilder.addStruct(
- propertyStatisticsStructId,
- propertyStatisticsStructName,
- ShaderDestination.FRAGMENT
- );
- const glslType = getGlslType(type);
- shaderBuilder.addStructField(propertyStatisticsStructId, glslType, "min");
- shaderBuilder.addStructField(propertyStatisticsStructId, glslType, "max");
- }
- // Statistics struct
- const statisticsStructId = "Statistics";
- const statisticsStructName = "Statistics";
- const statisticsFieldName = "statistics";
- shaderBuilder.addStruct(
- statisticsStructId,
- statisticsStructName,
- ShaderDestination.FRAGMENT
- );
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- const propertyStructName = `PropertyStatistics_${name}`;
- const propertyFieldName = name;
- shaderBuilder.addStructField(
- statisticsStructId,
- propertyStructName,
- propertyFieldName
- );
- }
- // Metadata struct
- const metadataStructId = "Metadata";
- const metadataStructName = "Metadata";
- const metadataFieldName = "metadata";
- shaderBuilder.addStruct(
- metadataStructId,
- metadataStructName,
- ShaderDestination.FRAGMENT
- );
- shaderBuilder.addStructField(
- metadataStructId,
- statisticsStructName,
- statisticsFieldName
- );
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- const type = types[i];
- const glslType = getGlslType(type);
- shaderBuilder.addStructField(metadataStructId, glslType, name);
- }
- // VoxelProperty structs
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- const type = types[i];
- const glslType = getGlslPartialDerivativeType(type);
- const voxelPropertyStructId = `VoxelProperty_${name}`;
- const voxelPropertyStructName = `VoxelProperty_${name}`;
- shaderBuilder.addStruct(
- voxelPropertyStructId,
- voxelPropertyStructName,
- ShaderDestination.FRAGMENT
- );
- shaderBuilder.addStructField(
- voxelPropertyStructId,
- glslType,
- "partialDerivativeLocal"
- );
- shaderBuilder.addStructField(
- voxelPropertyStructId,
- glslType,
- "partialDerivativeWorld"
- );
- shaderBuilder.addStructField(
- voxelPropertyStructId,
- glslType,
- "partialDerivativeView"
- );
- shaderBuilder.addStructField(
- voxelPropertyStructId,
- glslType,
- "partialDerivativeValid"
- );
- }
- // Voxel struct
- const voxelStructId = "Voxel";
- const voxelStructName = "Voxel";
- const voxelFieldName = "voxel";
- shaderBuilder.addStruct(
- voxelStructId,
- voxelStructName,
- ShaderDestination.FRAGMENT
- );
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- const voxelPropertyStructName = `VoxelProperty_${name}`;
- shaderBuilder.addStructField(voxelStructId, voxelPropertyStructName, name);
- }
- shaderBuilder.addStructField(voxelStructId, "vec3", "positionEC");
- shaderBuilder.addStructField(voxelStructId, "vec3", "positionUv");
- shaderBuilder.addStructField(voxelStructId, "vec3", "positionShapeUv");
- 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
- const fragmentInputStructId = "FragmentInput";
- const fragmentInputStructName = "FragmentInput";
- shaderBuilder.addStruct(
- fragmentInputStructId,
- fragmentInputStructName,
- ShaderDestination.FRAGMENT
- );
- shaderBuilder.addStructField(
- fragmentInputStructId,
- metadataStructName,
- metadataFieldName
- );
- shaderBuilder.addStructField(
- fragmentInputStructId,
- voxelStructName,
- voxelFieldName
- );
- // Properties struct
- const propertiesStructId = "Properties";
- const propertiesStructName = "Properties";
- const propertiesFieldName = "properties";
- shaderBuilder.addStruct(
- propertiesStructId,
- propertiesStructName,
- ShaderDestination.FRAGMENT
- );
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- const type = types[i];
- const glslType = getGlslType(type);
- shaderBuilder.addStructField(propertiesStructId, glslType, name);
- }
- // Fragment shader functions
- // clearProperties function
- {
- const functionId = "clearProperties";
- shaderBuilder.addFunction(
- functionId,
- `${propertiesStructName} clearProperties()`,
- ShaderDestination.FRAGMENT
- );
- shaderBuilder.addFunctionLines(functionId, [
- `${propertiesStructName} ${propertiesFieldName};`,
- ]);
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- const type = types[i];
- const componentType = componentTypes[i];
- const glslType = getGlslType(type, componentType);
- shaderBuilder.addFunctionLines(functionId, [
- `${propertiesFieldName}.${name} = ${glslType}(0.0);`,
- ]);
- }
- shaderBuilder.addFunctionLines(functionId, [
- `return ${propertiesFieldName};`,
- ]);
- }
- // sumProperties function
- {
- const functionId = "sumProperties";
- shaderBuilder.addFunction(
- functionId,
- `${propertiesStructName} sumProperties(${propertiesStructName} propertiesA, ${propertiesStructName} propertiesB)`,
- ShaderDestination.FRAGMENT
- );
- shaderBuilder.addFunctionLines(functionId, [
- `${propertiesStructName} ${propertiesFieldName};`,
- ]);
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- shaderBuilder.addFunctionLines(functionId, [
- `${propertiesFieldName}.${name} = propertiesA.${name} + propertiesB.${name};`,
- ]);
- }
- shaderBuilder.addFunctionLines(functionId, [
- `return ${propertiesFieldName};`,
- ]);
- }
- // scaleProperties function
- {
- const functionId = "scaleProperties";
- shaderBuilder.addFunction(
- functionId,
- `${propertiesStructName} scaleProperties(${propertiesStructName} ${propertiesFieldName}, float scale)`,
- ShaderDestination.FRAGMENT
- );
- shaderBuilder.addFunctionLines(functionId, [
- `${propertiesStructName} scaledProperties = ${propertiesFieldName};`,
- ]);
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- shaderBuilder.addFunctionLines(functionId, [
- `scaledProperties.${name} *= scale;`,
- ]);
- }
- shaderBuilder.addFunctionLines(functionId, [`return scaledProperties;`]);
- }
- // mixProperties
- {
- const functionId = "mixProperties";
- shaderBuilder.addFunction(
- functionId,
- `${propertiesStructName} mixProperties(${propertiesStructName} propertiesA, ${propertiesStructName} propertiesB, float mixFactor)`,
- ShaderDestination.FRAGMENT
- );
- shaderBuilder.addFunctionLines(functionId, [
- `${propertiesStructName} ${propertiesFieldName};`,
- ]);
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- shaderBuilder.addFunctionLines(functionId, [
- `${propertiesFieldName}.${name} = mix(propertiesA.${name}, propertiesB.${name}, mixFactor);`,
- ]);
- }
- shaderBuilder.addFunctionLines(functionId, [
- `return ${propertiesFieldName};`,
- ]);
- }
- // copyPropertiesToMetadata
- {
- const functionId = "copyPropertiesToMetadata";
- shaderBuilder.addFunction(
- functionId,
- `void copyPropertiesToMetadata(in ${propertiesStructName} ${propertiesFieldName}, inout ${metadataStructName} ${metadataFieldName})`,
- ShaderDestination.FRAGMENT
- );
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- shaderBuilder.addFunctionLines(functionId, [
- `${metadataFieldName}.${name} = ${propertiesFieldName}.${name};`,
- ]);
- }
- }
- // setStatistics function
- if (hasStatistics) {
- const functionId = "setStatistics";
- shaderBuilder.addFunction(
- functionId,
- `void setStatistics(inout ${statisticsStructName} ${statisticsFieldName})`,
- ShaderDestination.FRAGMENT
- );
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- const type = types[i];
- const componentCount = MetadataType.getComponentCount(type);
- for (let j = 0; j < componentCount; j++) {
- const glslField = getGlslField(type, j);
- const minimumValue = minimumValues[i][j];
- const maximumValue = maximumValues[i][j];
- shaderBuilder.addFunctionLines(functionId, [
- `${statisticsFieldName}.${name}.min${glslField} = ${getGlslNumberAsFloat(
- minimumValue
- )};`,
- `${statisticsFieldName}.${name}.max${glslField} = ${getGlslNumberAsFloat(
- maximumValue
- )};`,
- ]);
- }
- }
- }
- // getPropertiesFromMegatextureAtUv
- {
- const functionId = "getPropertiesFromMegatextureAtUv";
- shaderBuilder.addFunction(
- functionId,
- `${propertiesStructName} getPropertiesFromMegatextureAtUv(vec2 texcoord)`,
- ShaderDestination.FRAGMENT
- );
- shaderBuilder.addFunctionLines(functionId, [
- `${propertiesStructName} ${propertiesFieldName};`,
- ]);
- for (let i = 0; i < attributeLength; i++) {
- const name = names[i];
- const type = types[i];
- const componentType = componentTypes[i];
- const glslTextureSwizzle = getGlslTextureSwizzle(type, componentType);
- shaderBuilder.addFunctionLines(functionId, [
- `properties.${name} = texture(u_megatextureTextures[${i}], texcoord)${glslTextureSwizzle};`,
- ]);
- }
- shaderBuilder.addFunctionLines(functionId, [
- `return ${propertiesFieldName};`,
- ]);
- }
- }
- /**
- * Converts a {@link MetadataType} to a GLSL type.
- *
- * @function
- *
- * @param {MetadataType} type The {@link MetadataType}.
- * @returns {string} The GLSL type.
- *
- * @private
- */
- function getGlslType(type) {
- if (type === MetadataType.SCALAR) {
- return "float";
- } else if (type === MetadataType.VEC2) {
- return "vec2";
- } else if (type === MetadataType.VEC3) {
- return "vec3";
- } else if (type === MetadataType.VEC4) {
- return "vec4";
- }
- }
- /**
- * Gets the GLSL swizzle when reading data from a texture.
- *
- * @function
- *
- * @param {MetadataType} type The {@link MetadataType}.
- * @returns {string} The GLSL swizzle.
- *
- * @private
- */
- function getGlslTextureSwizzle(type) {
- if (type === MetadataType.SCALAR) {
- return ".r";
- } else if (type === MetadataType.VEC2) {
- return ".ra";
- } else if (type === MetadataType.VEC3) {
- return ".rgb";
- } else if (type === MetadataType.VEC4) {
- return "";
- }
- }
- /**
- * Gets the GLSL type of the partial derivative of {@link MetadataType}.
- *
- * @function
- *
- * @param {MetadataType} type The {@link MetadataType}.
- * @returns {string} The GLSL type.
- *
- * @private
- */
- function getGlslPartialDerivativeType(type) {
- if (type === MetadataType.SCALAR) {
- return "vec3";
- } else if (type === MetadataType.VEC2) {
- return "mat2";
- } else if (type === MetadataType.VEC3) {
- return "mat3";
- } else if (type === MetadataType.VEC4) {
- return "mat4";
- }
- }
- /**
- * GLSL needs to have `.0` at the end of whole number floats or else it's
- * treated like an integer.
- *
- * @function
- *
- * @param {number} number The number to convert.
- * @returns {string} The number as floating point in GLSL.
- *
- * @private
- */
- function getGlslNumberAsFloat(number) {
- let numberString = number.toString();
- if (numberString.indexOf(".") === -1) {
- numberString = `${number}.0`;
- }
- return numberString;
- }
- /**
- * Gets the GLSL field
- *
- * @function
- *
- * @param {MetadataType} type
- * @param {number} index
- * @returns {string}
- *
- * @private
- */
- function getGlslField(type, index) {
- if (type === MetadataType.SCALAR) {
- return "";
- }
- return `[${index}]`;
- }
- export default processVoxelProperties;
|