Add existing to tracked
This commit is contained in:
+398
@@ -0,0 +1,398 @@
|
||||
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 glslType = getGlslType(types[i]);
|
||||
const propertyStatisticsStructId = `PropertyStatistics_${name}`;
|
||||
const propertyStatisticsStructName = `PropertyStatistics_${name}`;
|
||||
shaderBuilder.addStruct(
|
||||
propertyStatisticsStructId,
|
||||
propertyStatisticsStructName,
|
||||
ShaderDestination.FRAGMENT,
|
||||
);
|
||||
shaderBuilder.addStructField(propertyStatisticsStructId, glslType, "min");
|
||||
shaderBuilder.addStructField(propertyStatisticsStructId, glslType, "max");
|
||||
}
|
||||
|
||||
// MetadataStatistics struct
|
||||
const metadataStatisticsStructId = "MetadataStatistics";
|
||||
const metadataStatisticsStructName = "MetadataStatistics";
|
||||
const metadataStatisticsFieldName = "metadataStatistics";
|
||||
shaderBuilder.addStruct(
|
||||
metadataStatisticsStructId,
|
||||
metadataStatisticsStructName,
|
||||
ShaderDestination.FRAGMENT,
|
||||
);
|
||||
for (let i = 0; i < attributeLength; i++) {
|
||||
const name = names[i];
|
||||
const propertyStructName = `PropertyStatistics_${name}`;
|
||||
const propertyFieldName = name;
|
||||
shaderBuilder.addStructField(
|
||||
metadataStatisticsStructId,
|
||||
propertyStructName,
|
||||
propertyFieldName,
|
||||
);
|
||||
}
|
||||
|
||||
// Metadata struct
|
||||
const metadataStructId = "Metadata";
|
||||
const metadataStructName = "Metadata";
|
||||
const metadataFieldName = "metadata";
|
||||
shaderBuilder.addStruct(
|
||||
metadataStructId,
|
||||
metadataStructName,
|
||||
ShaderDestination.FRAGMENT,
|
||||
);
|
||||
for (let i = 0; i < attributeLength; i++) {
|
||||
const glslType = getGlslType(types[i]);
|
||||
shaderBuilder.addStructField(metadataStructId, glslType, names[i]);
|
||||
}
|
||||
|
||||
// Attributes struct
|
||||
const attributesStructId = "Attributes";
|
||||
const attributesStructName = "Attributes";
|
||||
const attributesFieldName = "attributes";
|
||||
shaderBuilder.addStruct(
|
||||
attributesStructId,
|
||||
attributesStructName,
|
||||
ShaderDestination.FRAGMENT,
|
||||
);
|
||||
shaderBuilder.addStructField(attributesStructId, "vec3", "positionEC");
|
||||
shaderBuilder.addStructField(attributesStructId, "vec3", "normalEC");
|
||||
|
||||
// Voxel struct
|
||||
const voxelStructId = "Voxel";
|
||||
const voxelStructName = "Voxel";
|
||||
const voxelFieldName = "voxel";
|
||||
shaderBuilder.addStruct(
|
||||
voxelStructId,
|
||||
voxelStructName,
|
||||
ShaderDestination.FRAGMENT,
|
||||
);
|
||||
shaderBuilder.addStructField(voxelStructId, "vec3", "viewDirUv");
|
||||
shaderBuilder.addStructField(voxelStructId, "float", "travelDistance");
|
||||
shaderBuilder.addStructField(voxelStructId, "int", "stepCount");
|
||||
shaderBuilder.addStructField(voxelStructId, "int", "tileIndex");
|
||||
shaderBuilder.addStructField(voxelStructId, "int", "sampleIndex");
|
||||
shaderBuilder.addStructField(voxelStructId, "float", "distanceToDepthBuffer");
|
||||
|
||||
// FragmentInput struct
|
||||
const fragmentInputStructId = "FragmentInput";
|
||||
const fragmentInputStructName = "FragmentInput";
|
||||
shaderBuilder.addStruct(
|
||||
fragmentInputStructId,
|
||||
fragmentInputStructName,
|
||||
ShaderDestination.FRAGMENT,
|
||||
);
|
||||
shaderBuilder.addStructField(
|
||||
fragmentInputStructId,
|
||||
metadataStatisticsStructName,
|
||||
metadataStatisticsFieldName,
|
||||
);
|
||||
shaderBuilder.addStructField(
|
||||
fragmentInputStructId,
|
||||
metadataStructName,
|
||||
metadataFieldName,
|
||||
);
|
||||
shaderBuilder.addStructField(
|
||||
fragmentInputStructId,
|
||||
attributesStructName,
|
||||
attributesFieldName,
|
||||
);
|
||||
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 glslType = getGlslType(types[i]);
|
||||
shaderBuilder.addStructField(propertiesStructId, glslType, names[i]);
|
||||
}
|
||||
|
||||
// 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 glslType = getGlslType(types[i], componentTypes[i]);
|
||||
shaderBuilder.addFunctionLines(functionId, [
|
||||
`${propertiesFieldName}.${names[i]} = ${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++) {
|
||||
shaderBuilder.addFunctionLines(functionId, [
|
||||
`scaledProperties.${names[i]} *= 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 ${metadataStatisticsStructName} ${metadataStatisticsFieldName})`,
|
||||
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];
|
||||
if (!defined(minimumValue) || !defined(maximumValue)) {
|
||||
continue;
|
||||
}
|
||||
shaderBuilder.addFunctionLines(functionId, [
|
||||
`${metadataStatisticsFieldName}.${name}.min${glslField} = ${getGlslNumberAsFloat(
|
||||
minimumValue,
|
||||
)};`,
|
||||
`${metadataStatisticsFieldName}.${name}.max${glslField} = ${getGlslNumberAsFloat(
|
||||
maximumValue,
|
||||
)};`,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getPropertiesFromMegatextureAtUv
|
||||
{
|
||||
const functionId = "getPropertiesFromMegatextureAtUv";
|
||||
shaderBuilder.addFunction(
|
||||
functionId,
|
||||
`${propertiesStructName} getPropertiesFromMegatextureAtUv(vec3 texcoord)`,
|
||||
ShaderDestination.FRAGMENT,
|
||||
);
|
||||
shaderBuilder.addFunctionLines(functionId, [
|
||||
`${propertiesStructName} ${propertiesFieldName};`,
|
||||
]);
|
||||
for (let i = 0; i < attributeLength; i++) {
|
||||
const type = types[i];
|
||||
const componentType = componentTypes[i];
|
||||
const glslTextureSwizzle = getGlslTextureSwizzle(type, componentType);
|
||||
shaderBuilder.addFunctionLines(functionId, [
|
||||
`properties.${names[i]} = 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 "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
Reference in New Issue
Block a user