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.

532 lines 21.5 kB
import { RawTexture } from "../Textures/rawTexture.js"; import { MaterialPluginBase } from "../materialPluginBase.js"; import { Vector2, TmpVectors } from "../../Maths/math.vector.js"; import { MaterialDefines } from "../materialDefines.js"; import { RegisterClass } from "../../Misc/typeStore.js"; import { GreasedLineMaterialDefaults } from "./greasedLineMaterialDefaults.js"; import { GreasedLineTools } from "../../Misc/greasedLineTools.js"; import { GetCustomCode as getCustomCodeGLSL } from "./greasedLinePluginMaterialShadersGLSL.js"; import { GetCustomCode as getCustomCodeWGSL } from "./greasedLinePluginMaterialShadersWGSL.js"; /** * @internal */ export class MaterialGreasedLineDefines extends MaterialDefines { constructor() { super(...arguments); /** * The material has a color option specified */ // eslint-disable-next-line @typescript-eslint/naming-convention this.GREASED_LINE_HAS_COLOR = false; /** * The material's size attenuation optiom */ // eslint-disable-next-line @typescript-eslint/naming-convention this.GREASED_LINE_SIZE_ATTENUATION = false; /** * The type of color distribution is set to line this value equals to true. */ // eslint-disable-next-line @typescript-eslint/naming-convention this.GREASED_LINE_COLOR_DISTRIBUTION_TYPE_LINE = false; /** * True if scene is in right handed coordinate system. */ // eslint-disable-next-line @typescript-eslint/naming-convention this.GREASED_LINE_RIGHT_HANDED_COORDINATE_SYSTEM = false; /** * True if the line is in camera facing mode */ // eslint-disable-next-line @typescript-eslint/naming-convention this.GREASED_LINE_CAMERA_FACING = true; /** * True if the line uses offsets */ // eslint-disable-next-line @typescript-eslint/naming-convention this.GREASED_LINE_USE_OFFSETS = false; } } /** * GreasedLinePluginMaterial for GreasedLineMesh/GreasedLineRibbonMesh. * Use the GreasedLineBuilder.CreateGreasedLineMaterial function to create and instance of this class. */ export class GreasedLinePluginMaterial extends MaterialPluginBase { /** * Gets a boolean indicating that the plugin is compatible with a given shader language * @param _shaderLanguage The shader language to use * @returns true if the plugin is compatible with the shader language. Return always true since both GLSL and WGSL are supported */ isCompatible(_shaderLanguage) { return true; } /** * Creates a new instance of the GreasedLinePluginMaterial * @param material Base material for the plugin * @param scene The scene * @param options Plugin options */ constructor(material, scene, options) { options = options || { color: GreasedLineMaterialDefaults.DEFAULT_COLOR, }; const defines = new MaterialGreasedLineDefines(); defines.GREASED_LINE_HAS_COLOR = !!options.color && !options.useColors; defines.GREASED_LINE_SIZE_ATTENUATION = options.sizeAttenuation ?? false; defines.GREASED_LINE_COLOR_DISTRIBUTION_TYPE_LINE = options.colorDistributionType === 1 /* GreasedLineMeshColorDistributionType.COLOR_DISTRIBUTION_TYPE_LINE */; defines.GREASED_LINE_RIGHT_HANDED_COORDINATE_SYSTEM = (scene ?? material.getScene()).useRightHandedSystem; defines.GREASED_LINE_CAMERA_FACING = options.cameraFacing ?? true; super(material, GreasedLinePluginMaterial.GREASED_LINE_MATERIAL_NAME, 200, defines, true, true); /** * You can provide a colorsTexture to use instead of one generated from the 'colors' option */ this.colorsTexture = null; this._forceGLSL = false; this._forceGLSL = options?.forceGLSL || GreasedLinePluginMaterial.ForceGLSL; this._scene = scene ?? material.getScene(); this._engine = this._scene.getEngine(); this._cameraFacing = options.cameraFacing ?? true; this.visibility = options.visibility ?? 1; this.useDash = options.useDash ?? false; this.dashRatio = options.dashRatio ?? 0.5; this.dashOffset = options.dashOffset ?? 0; this.width = options.width ? options.width : options.sizeAttenuation ? GreasedLineMaterialDefaults.DEFAULT_WIDTH_ATTENUATED : GreasedLineMaterialDefaults.DEFAULT_WIDTH; this._sizeAttenuation = options.sizeAttenuation ?? false; this.colorMode = options.colorMode ?? 0 /* GreasedLineMeshColorMode.COLOR_MODE_SET */; this._color = options.color ?? null; this.useColors = options.useColors ?? false; this._colorsDistributionType = options.colorDistributionType ?? 0 /* GreasedLineMeshColorDistributionType.COLOR_DISTRIBUTION_TYPE_SEGMENT */; this.colorsSampling = options.colorsSampling ?? RawTexture.NEAREST_NEAREST; this._colors = options.colors ?? null; this.dashCount = options.dashCount ?? 1; // calculate the _dashArray value, call the setter this.resolution = options.resolution ?? new Vector2(this._engine.getRenderWidth(), this._engine.getRenderHeight()); // calculate aspect call the setter if (options.colorsTexture) { this.colorsTexture = options.colorsTexture; // colorsTexture from options takes precedence } else { if (this._colors) { this.colorsTexture = GreasedLineTools.CreateColorsTexture(`${material.name}-colors-texture`, this._colors, this.colorsSampling, this._scene); } else { this._color = this._color ?? GreasedLineMaterialDefaults.DEFAULT_COLOR; GreasedLineTools.PrepareEmptyColorsTexture(this._scene); } } this._engine.onDisposeObservable.add(() => { GreasedLineTools.DisposeEmptyColorsTexture(); }); } /** * Get the shader attributes * @param attributes array which will be filled with the attributes */ getAttributes(attributes) { attributes.push("grl_offsets"); attributes.push("grl_widths"); attributes.push("grl_colorPointers"); attributes.push("grl_counters"); if (this._cameraFacing) { attributes.push("grl_previousAndSide"); attributes.push("grl_nextAndCounters"); } else { attributes.push("grl_slopes"); } } /** * Get the shader samplers * @param samplers */ getSamplers(samplers) { samplers.push("grl_colors"); } /** * Get the shader textures * @param activeTextures array which will be filled with the textures */ getActiveTextures(activeTextures) { if (this.colorsTexture) { activeTextures.push(this.colorsTexture); } } /** * Get the shader uniforms * @param shaderLanguage The shader language to use * @returns uniforms */ getUniforms(shaderLanguage = 0 /* ShaderLanguage.GLSL */) { const ubo = [ { name: "grl_singleColor", size: 3, type: "vec3" }, { name: "grl_textureSize", size: 2, type: "vec2" }, { name: "grl_dashOptions", size: 4, type: "vec4" }, { name: "grl_colorMode_visibility_colorsWidth_useColors", size: 4, type: "vec4" }, ]; if (this._cameraFacing) { ubo.push({ name: "grl_projection", size: 16, type: "mat4" }, { name: "grl_aspect_resolution_lineWidth", size: 4, type: "vec4" }); } if (shaderLanguage === 1 /* ShaderLanguage.WGSL */) { ubo.push({ name: "viewProjection", size: 16, type: "mat4", }); } return { ubo, vertex: this._cameraFacing && this._isGLSL(shaderLanguage) ? ` uniform vec4 grl_aspect_resolution_lineWidth; uniform mat4 grl_projection; ` : "", fragment: this._isGLSL(shaderLanguage) ? ` uniform vec4 grl_dashOptions; uniform vec2 grl_textureSize; uniform vec4 grl_colorMode_visibility_colorsWidth_useColors; uniform vec3 grl_singleColor; ` : "", }; } // only getter, it doesn't make sense to use this plugin on a mesh other than GreasedLineMesh // and it doesn't make sense to disable it on the mesh get isEnabled() { return true; } /** * Bind the uniform buffer * @param uniformBuffer */ bindForSubMesh(uniformBuffer) { if (this._cameraFacing) { uniformBuffer.updateMatrix("grl_projection", this._scene.getProjectionMatrix()); if (!this._isGLSL(this._material.shaderLanguage)) { uniformBuffer.updateMatrix("viewProjection", this._scene.getTransformMatrix()); } const resolutionLineWidth = TmpVectors.Vector4[0]; resolutionLineWidth.x = this._aspect; resolutionLineWidth.y = this._resolution.x; resolutionLineWidth.z = this._resolution.y; resolutionLineWidth.w = this.width; uniformBuffer.updateVector4("grl_aspect_resolution_lineWidth", resolutionLineWidth); } const dashOptions = TmpVectors.Vector4[0]; dashOptions.x = GreasedLineTools.BooleanToNumber(this.useDash); dashOptions.y = this._dashArray; dashOptions.z = this.dashOffset; dashOptions.w = this.dashRatio; uniformBuffer.updateVector4("grl_dashOptions", dashOptions); const colorModeVisibilityColorsWidthUseColors = TmpVectors.Vector4[1]; colorModeVisibilityColorsWidthUseColors.x = this.colorMode; colorModeVisibilityColorsWidthUseColors.y = this.visibility; colorModeVisibilityColorsWidthUseColors.z = this.colorsTexture ? this.colorsTexture.getSize().width : 0; colorModeVisibilityColorsWidthUseColors.w = GreasedLineTools.BooleanToNumber(this.useColors); uniformBuffer.updateVector4("grl_colorMode_visibility_colorsWidth_useColors", colorModeVisibilityColorsWidthUseColors); if (this._color) { uniformBuffer.updateColor3("grl_singleColor", this._color); } const texture = this.colorsTexture ?? GreasedLineMaterialDefaults.EmptyColorsTexture; uniformBuffer.setTexture("grl_colors", texture); uniformBuffer.updateFloat2("grl_textureSize", texture?.getSize().width ?? 1, texture?.getSize().height ?? 1); } /** * Prepare the defines * @param defines * @param _scene * @param mesh */ prepareDefines(defines, _scene, mesh) { defines.GREASED_LINE_HAS_COLOR = !!this.color && !this.useColors; defines.GREASED_LINE_SIZE_ATTENUATION = this._sizeAttenuation; defines.GREASED_LINE_COLOR_DISTRIBUTION_TYPE_LINE = this._colorsDistributionType === 1 /* GreasedLineMeshColorDistributionType.COLOR_DISTRIBUTION_TYPE_LINE */; defines.GREASED_LINE_RIGHT_HANDED_COORDINATE_SYSTEM = _scene.useRightHandedSystem; defines.GREASED_LINE_CAMERA_FACING = this._cameraFacing; defines.GREASED_LINE_USE_OFFSETS = !!mesh.offsets; } /** * Get the class name * @returns class name */ getClassName() { return GreasedLinePluginMaterial.GREASED_LINE_MATERIAL_NAME; } /** * Get shader code * @param shaderType vertex/fragment * @param shaderLanguage GLSL or WGSL * @returns shader code */ getCustomCode(shaderType, shaderLanguage = 0 /* ShaderLanguage.GLSL */) { if (this._isGLSL(shaderLanguage)) { return getCustomCodeGLSL(shaderType, this._cameraFacing); } return getCustomCodeWGSL(shaderType, this._cameraFacing); } /** * Disposes the plugin material. */ dispose() { this.colorsTexture?.dispose(); super.dispose(); } /** * Returns the colors used to colorize the line */ get colors() { return this._colors; } /** * Sets the colors used to colorize the line */ set colors(value) { this.setColors(value); } /** * Creates or updates the colors texture * @param colors color table RGBA * @param lazy if lazy, the colors are not updated * @param forceNewTexture force creation of a new texture */ setColors(colors, lazy = false, forceNewTexture = false) { const origColorsCount = this._colors?.length ?? 0; this._colors = colors; if (colors === null || colors.length === 0) { this.colorsTexture?.dispose(); return; } if (lazy && !forceNewTexture) { return; } if (this.colorsTexture && origColorsCount === colors.length && !forceNewTexture) { const colorArray = GreasedLineTools.Color3toRGBAUint8(colors); this.colorsTexture.update(colorArray); } else { this.colorsTexture?.dispose(); this.colorsTexture = GreasedLineTools.CreateColorsTexture(`${this._material.name}-colors-texture`, colors, this.colorsSampling, this._scene); } } /** * Updates the material. Use when material created in lazy mode. */ updateLazy() { if (this._colors) { this.setColors(this._colors, false, true); } } /** * Gets the number of dashes in the line */ get dashCount() { return this._dashCount; } /** * Sets the number of dashes in the line * @param value dash */ set dashCount(value) { this._dashCount = value; this._dashArray = 1 / value; } /** * If set to true the line will be rendered always with the same width regardless how far it is located from the camera. * Not supported for non camera facing lines. */ get sizeAttenuation() { return this._sizeAttenuation; } /** * Turn on/off size attenuation of the width option and widths array. * Not supported for non camera facing lines. * @param value If set to true the line will be rendered always with the same width regardless how far it is located from the camera. */ set sizeAttenuation(value) { this._sizeAttenuation = value; this.markAllDefinesAsDirty(); } /** * Gets the color of the line */ get color() { return this._color; } /** * Sets the color of the line * @param value Color3 or null to clear the color. You need to clear the color if you use colors and useColors = true */ set color(value) { this.setColor(value); } /** * Sets the color of the line. If set the whole line will be mixed with this color according to the colorMode option. * @param value color * @param doNotMarkDirty if true, the material will not be marked as dirty */ setColor(value, doNotMarkDirty = false) { if ((this._color === null && value !== null) || (this._color !== null && value === null)) { this._color = value; if (!doNotMarkDirty) { this.markAllDefinesAsDirty(); } } else { this._color = value; } } /** * Gets the color distributiopn type */ get colorsDistributionType() { return this._colorsDistributionType; } /** * Sets the color distribution type * @see GreasedLineMeshColorDistributionType * @param value color distribution type */ set colorsDistributionType(value) { this._colorsDistributionType = value; this.markAllDefinesAsDirty(); } /** * Gets the resolution */ get resolution() { return this._resolution; } /** * Sets the resolution * @param value resolution of the screen for GreasedLine */ set resolution(value) { this._aspect = value.x / value.y; this._resolution = value; } /** * Serializes this plugin material * @returns serializationObjec */ serialize() { const serializationObject = super.serialize(); const greasedLineMaterialOptions = { colorDistributionType: this._colorsDistributionType, colorsSampling: this.colorsSampling, colorMode: this.colorMode, dashCount: this._dashCount, dashOffset: this.dashOffset, dashRatio: this.dashRatio, resolution: this._resolution, sizeAttenuation: this._sizeAttenuation, useColors: this.useColors, useDash: this.useDash, visibility: this.visibility, width: this.width, }; if (this._colors) { greasedLineMaterialOptions.colors = this._colors; } if (this._color) { greasedLineMaterialOptions.color = this._color; } serializationObject.greasedLineMaterialOptions = greasedLineMaterialOptions; return serializationObject; } /** * Parses a serialized objects * @param source serialized object * @param scene scene * @param rootUrl root url for textures */ parse(source, scene, rootUrl) { super.parse(source, scene, rootUrl); const greasedLineMaterialOptions = source.greasedLineMaterialOptions; this.colorsTexture?.dispose(); if (greasedLineMaterialOptions.color) { this.setColor(greasedLineMaterialOptions.color, true); } if (greasedLineMaterialOptions.colorDistributionType) { this.colorsDistributionType = greasedLineMaterialOptions.colorDistributionType; } if (greasedLineMaterialOptions.colors) { this.colors = greasedLineMaterialOptions.colors; } if (greasedLineMaterialOptions.colorsSampling) { this.colorsSampling = greasedLineMaterialOptions.colorsSampling; } if (greasedLineMaterialOptions.colorMode) { this.colorMode = greasedLineMaterialOptions.colorMode; } if (greasedLineMaterialOptions.useColors) { this.useColors = greasedLineMaterialOptions.useColors; } if (greasedLineMaterialOptions.visibility) { this.visibility = greasedLineMaterialOptions.visibility; } if (greasedLineMaterialOptions.useDash) { this.useDash = greasedLineMaterialOptions.useDash; } if (greasedLineMaterialOptions.dashCount) { this.dashCount = greasedLineMaterialOptions.dashCount; } if (greasedLineMaterialOptions.dashRatio) { this.dashRatio = greasedLineMaterialOptions.dashRatio; } if (greasedLineMaterialOptions.dashOffset) { this.dashOffset = greasedLineMaterialOptions.dashOffset; } if (greasedLineMaterialOptions.width) { this.width = greasedLineMaterialOptions.width; } if (greasedLineMaterialOptions.sizeAttenuation) { this.sizeAttenuation = greasedLineMaterialOptions.sizeAttenuation; } if (greasedLineMaterialOptions.resolution) { this.resolution = greasedLineMaterialOptions.resolution; } if (this.colors) { this.colorsTexture = GreasedLineTools.CreateColorsTexture(`${this._material.name}-colors-texture`, this.colors, this.colorsSampling, scene); } else { GreasedLineTools.PrepareEmptyColorsTexture(scene); } this.markAllDefinesAsDirty(); } /** * Makes a duplicate of the current configuration into another one. * @param plugin define the config where to copy the info */ copyTo(plugin) { const dest = plugin; dest.colorsTexture?.dispose(); if (this._colors) { dest.colorsTexture = GreasedLineTools.CreateColorsTexture(`${dest._material.name}-colors-texture`, this._colors, dest.colorsSampling, this._scene); } dest.setColor(this.color, true); dest.colorsDistributionType = this.colorsDistributionType; dest.colorsSampling = this.colorsSampling; dest.colorMode = this.colorMode; dest.useColors = this.useColors; dest.visibility = this.visibility; dest.useDash = this.useDash; dest.dashCount = this.dashCount; dest.dashRatio = this.dashRatio; dest.dashOffset = this.dashOffset; dest.width = this.width; dest.sizeAttenuation = this.sizeAttenuation; dest.resolution = this.resolution; dest.markAllDefinesAsDirty(); } _isGLSL(shaderLanguage) { return shaderLanguage === 0 /* ShaderLanguage.GLSL */ || this._forceGLSL; } } /** * Plugin name */ GreasedLinePluginMaterial.GREASED_LINE_MATERIAL_NAME = "GreasedLinePluginMaterial"; /** * Force all the greased lines to compile to glsl even on WebGPU engines. * False by default. This is mostly meant for backward compatibility. */ GreasedLinePluginMaterial.ForceGLSL = false; RegisterClass(`BABYLON.${GreasedLinePluginMaterial.GREASED_LINE_MATERIAL_NAME}`, GreasedLinePluginMaterial); //# sourceMappingURL=greasedLinePluginMaterial.js.map