UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

259 lines (248 loc) 11.5 kB
import { RawTexture3D } from "../Materials/Textures/rawTexture3D.js"; import { MaterialPluginBase } from "../Materials/materialPluginBase.js"; /** * Material plugin to add hardware accelerated lattice support * @see [webgl2](https://playground.babylonjs.com/#HBZD72#5) * @see [webgpu](https://playground.babylonjs.com/#HBZD72#6) */ export class LatticePluginMaterial extends MaterialPluginBase { /** * Create a new LatticePluginMaterial * @param lattice defines the lattice this plugin is associated with * @param material defines the material this plugin is associated with */ constructor(lattice, material) { super(material, "Lattice", 200); this._lattice = lattice; this.refreshData(); // let's enable it by default this._enable(true); } /** * Get the class name of the plugin * @returns the string "LatticePluginMaterial" */ getClassName() { return "LatticePluginMaterial"; } /** * Defines if the plugin supports the specified shader language * @param shaderLanguage defines the shader language to check * @returns true if supported, false otherwise */ isCompatible(shaderLanguage) { switch (shaderLanguage) { case 0 /* ShaderLanguage.GLSL */: case 1 /* ShaderLanguage.WGSL */: return true; default: return false; } } /** * Must be called when the lattice data was updated */ refreshData() { const length = this._lattice.resolutionX * this._lattice.resolutionY * this._lattice.resolutionZ * 4; if (!this._latticeData || this._latticeData.length !== length) { this._latticeData = new Float32Array(length); } for (let i = 0; i < this._lattice.resolutionX; i++) { for (let j = 0; j < this._lattice.resolutionY; j++) { for (let k = 0; k < this._lattice.resolutionZ; k++) { const control = this._lattice.data[i][j][k]; const index = i + this._lattice.resolutionX * (j + this._lattice.resolutionY * k); control.toArray(this._latticeData, index * 4); } } } if (!this._latticeDataTexture || this._latticeDataTexture.width !== this._lattice.resolutionX || this._latticeDataTexture.height !== this._lattice.resolutionY || this._latticeDataTexture.depth !== this._lattice.resolutionZ) { if (this._latticeDataTexture) { this._latticeDataTexture.dispose(); } this._latticeDataTexture = new RawTexture3D(this._latticeData, this._lattice.resolutionX, this._lattice.resolutionY, this._lattice.resolutionZ, 5, this._material.getScene(), false, false, 1, 1); } else { this._latticeDataTexture.update(this._latticeData); } } /** * Gets the description of the uniforms to add to the ubo (if engine supports ubos) or to inject directly in the vertex/fragment shaders (if engine does not support ubos) * @param shaderLanguage The shader language to use. * @returns the description of the uniforms */ getUniforms(shaderLanguage = 0 /* ShaderLanguage.GLSL */) { if (shaderLanguage === 1 /* ShaderLanguage.WGSL */) { // For webgpu we only define the UBO with the correct type and size. return { ubo: [ { name: "lattice_cellSize", size: 3, type: "vec3" }, { name: "lattice_min", size: 3, type: "vec3" }, { name: "lattice_max", size: 3, type: "vec3" }, { name: "lattice_resolution", size: 3, type: "vec3" }, { name: "lattice_position", size: 3, type: "vec3" }, ], }; } return { // first, define the UBO with the correct type and size. ubo: [ { name: "lattice_cellSize", size: 3, type: "vec3" }, { name: "lattice_min", size: 3, type: "vec3" }, { name: "lattice_max", size: 3, type: "vec3" }, { name: "lattice_resolution", size: 3, type: "vec3" }, { name: "lattice_position", size: 3, type: "vec3" }, ], // now, on the vertex shader, add the uniform itself in case uniform buffers are not supported by the engine vertex: ` uniform vec3 lattice_cellSize; uniform vec3 lattice_min; uniform vec3 lattice_max; uniform vec3 lattice_resolution; uniform vec3 lattice_position; `, }; } /** * Binds the material data. * @param uniformBuffer defines the Uniform buffer to fill in. */ bindForSubMesh(uniformBuffer) { this._lattice.updateInternals(); uniformBuffer.updateVector3("lattice_cellSize", this._lattice.cellSize); uniformBuffer.updateVector3("lattice_min", this._lattice.min); uniformBuffer.updateVector3("lattice_max", this._lattice.max); uniformBuffer.updateFloat3("lattice_resolution", this._lattice.resolutionX, this._lattice.resolutionY, this._lattice.resolutionZ); uniformBuffer.updateVector3("lattice_position", this._lattice.position); uniformBuffer.setTexture("latticeData", this._latticeDataTexture); } /** * Gets the samplers used by the plugin. * @param samplers list that the sampler names should be added to. */ getSamplers(samplers) { samplers.push("latticeData"); } _prepareCode(shaderLanguage = 0 /* ShaderLanguage.GLSL */) { if (this._code) { return this._code; } let code = ` if (positionUpdated.x >= lattice_min.x && positionUpdated.x <= lattice_max.x && positionUpdated.y >= lattice_min.y && positionUpdated.y <= lattice_max.y && positionUpdated.z >= lattice_min.z && positionUpdated.z <= lattice_max.z) { // Map vertex position to lattice local coordinates vec3d localPos = vec3c((positionUpdated.x - lattice_min.x) / lattice_cellSize.x, (positionUpdated.y - lattice_min.y) / lattice_cellSize.y, (positionUpdated.z - lattice_min.z) / lattice_cellSize.z); // Get integer lattice indices intd i0 = intc(floor(localPos.x)); intd j0 = intc(floor(localPos.y)); intd k0 = intc(floor(localPos.z)); intd resX = intc(lattice_resolution.x) - 1; intd resY = intc(lattice_resolution.y) - 1; intd resZ = intc(lattice_resolution.z) - 1; intd i1 = min(i0 + 1, resX); intd j1 = min(j0 + 1, resY); intd k1 = min(k0 + 1, resZ); // Compute interpolation weights floatd tx = localPos.x - floatc(i0); floatd ty = localPos.y - floatc(j0); floatd tz = localPos.z - floatc(k0); // Ensure indices are within bounds intd ii0 = clamp(i0, 0, resX); intd jj0 = clamp(j0, 0, resY); intd kk0 = clamp(k0, 0, resZ); intd ii1 = clamp(i1, 0, resX); intd jj1 = clamp(j1, 0, resY); intd kk1 = clamp(k1, 0, resZ); // Get lattice control points vec3d p000 = texelFetch(latticeData, ivec3c(ii0, jj0, kk0), 0).rgb; vec3d p100 = texelFetch(latticeData, ivec3c(ii1, jj0, kk0), 0).rgb; vec3d p010 = texelFetch(latticeData, ivec3c(ii0, jj1, kk0), 0).rgb; vec3d p110 = texelFetch(latticeData, ivec3c(ii1, jj1, kk0), 0).rgb; vec3d p001 = texelFetch(latticeData, ivec3c(ii0, jj0, kk1), 0).rgb; vec3d p101 = texelFetch(latticeData, ivec3c(ii1, jj0, kk1), 0).rgb; vec3d p011 = texelFetch(latticeData, ivec3c(ii0, jj1, kk1), 0).rgb; vec3d p111 = texelFetch(latticeData, ivec3c(ii1, jj1, kk1), 0).rgb; // Trilinear interpolation vec3d p00 = mix(p000, p100, tx); vec3d p01 = mix(p001, p101, tx); vec3d p10 = mix(p010, p110, tx); vec3d p11 = mix(p011, p111, tx); vec3d p0 = mix(p00, p10, ty); vec3d p1 = mix(p01, p11, ty); vec3d deformedPos = mix(p0, p1, tz); positionUpdated = deformedPos + lattice_position; }; `; if (shaderLanguage === 1 /* ShaderLanguage.WGSL */) { code = ` let lattice_min = uniforms.lattice_min; let lattice_max = uniforms.lattice_max; let lattice_resolution = uniforms.lattice_resolution; let lattice_position = uniforms.lattice_position; let lattice_cellSize = uniforms.lattice_cellSize; ` + code; code = code.replace(/ivec3c/g, "vec3i"); code = code.replace(/vec3d/g, "var"); code = code.replace(/vec3c/g, "vec3f"); code = code.replace(/intd/g, "var"); code = code.replace(/intc/g, "i32"); code = code.replace(/floatd/g, "var"); code = code.replace(/floatc/g, "f32"); code = code.replace(/texelFetch/g, "textureLoad"); } else { code = code.replace(/ivec3c/g, "ivec3"); code = code.replace(/vec3d/g, "vec3"); code = code.replace(/vec3c/g, "vec3"); code = code.replace(/intd/g, "int"); code = code.replace(/intc/g, "int"); code = code.replace(/floatd/g, "float"); code = code.replace(/floatc/g, "float"); } this._code = code; return this._code; } /** * Returns a list of custom shader code fragments to customize the shader. * @param shaderType "vertex" or "fragment" * @param shaderLanguage The shader language to use. * @returns null if no code to be added, or a list of pointName =\> code. */ getCustomCode(shaderType, shaderLanguage = 0 /* ShaderLanguage.GLSL */) { if (shaderType === "vertex") { // we're adding this specific code at the end of the main() function if (shaderLanguage === 1 /* ShaderLanguage.WGSL */) { return { CUSTOM_VERTEX_DEFINITIONS: ` var latticeData: texture_3d<f32>; `, CUSTOM_VERTEX_UPDATE_POSITION: this._prepareCode(shaderLanguage), }; } return { CUSTOM_VERTEX_DEFINITIONS: ` precision highp sampler3D; uniform sampler3D latticeData; `, CUSTOM_VERTEX_UPDATE_POSITION: this._prepareCode(shaderLanguage), }; } // for other shader types we're not doing anything, return null return null; } /** * Disposes the resources of the material. */ dispose() { if (this._latticeDataTexture) { this._latticeDataTexture.dispose(); this._latticeDataTexture = null; } } } //# sourceMappingURL=lattice.material.js.map