Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,11 @@ export const enum GreasedLineMeshColorDistributionType {
* Options for GreasedLineMaterial
*/
export interface GreasedLineMaterialOptions {
/**
* Force the greased lines to compile to glsl even on WebGPU engines.
* False by default. This is mostly meant for backward compatibility.
*/
forceGLSL?: boolean;
/**
* Line width. If sizeAttenuation os false scene units will be used for width.
* Defaults to 0.1 if @see sizeAttenuation is false, or to 1 if it's true.
Expand Down
240 changes: 61 additions & 179 deletions packages/dev/core/src/Materials/GreasedLine/greasedLinePluginMaterial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ import { MaterialDefines } from "../materialDefines";
import type { AbstractMesh } from "../../Meshes/abstractMesh";
import type { BaseTexture } from "../Textures/baseTexture";
import { RegisterClass } from "../../Misc/typeStore";
import { ShaderLanguage } from "../shaderLanguage";

import type { GreasedLineMaterialOptions, IGreasedLineMaterial } from "./greasedLineMaterialInterfaces";
import { GreasedLineMeshColorDistributionType, GreasedLineMeshColorMode } from "./greasedLineMaterialInterfaces";
import { GreasedLineMaterialDefaults } from "./greasedLineMaterialDefaults";
import { GreasedLineTools } from "../../Misc/greasedLineTools";
import { GetCustomCode as getCustomCodeGLSL } from "./greasedLinePluginMaterialShadersGLSL";
import { GetCustomCode as getCustomCodeWGSL } from "./greasedLinePluginMaterialShadersWGSL";

/**
* @internal
Expand Down Expand Up @@ -58,6 +62,12 @@ export class GreasedLinePluginMaterial extends MaterialPluginBase implements IGr
*/
public static readonly 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.
*/
public static ForceGLSL = false;

/**
* Whether to use the colors option to colorize the line
*/
Expand Down Expand Up @@ -120,11 +130,22 @@ export class GreasedLinePluginMaterial extends MaterialPluginBase implements IGr

private _engine: AbstractEngine;

private _forceGLSL = false;

/**
* 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
*/
public override isCompatible(_shaderLanguage: ShaderLanguage): boolean {
return true;
}

/**
* Creates a new instance of the GreasedLinePluginMaterial
* @param material base material for the plugin
* @param scene the scene
* @param options plugin options
* @param material Base material for the plugin
* @param scene The scene
* @param options Plugin options
*/
constructor(material: Material, scene?: Scene, options?: GreasedLineMaterialOptions) {
options = options || {
Expand All @@ -137,7 +158,9 @@ export class GreasedLinePluginMaterial extends MaterialPluginBase implements IGr
defines.GREASED_LINE_COLOR_DISTRIBUTION_TYPE_LINE = options.colorDistributionType === 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);
super(material, GreasedLinePluginMaterial.GREASED_LINE_MATERIAL_NAME, 200, defines, true, true);

this._forceGLSL = options?.forceGLSL || GreasedLinePluginMaterial.ForceGLSL;

this._scene = scene ?? material.getScene();
this._engine = this._scene.getEngine();
Expand Down Expand Up @@ -174,8 +197,6 @@ export class GreasedLinePluginMaterial extends MaterialPluginBase implements IGr
this._engine.onDisposeObservable.add(() => {
GreasedLineTools.DisposeEmptyColorsTexture();
});

this._enable(true); // always enabled
}

/**
Expand Down Expand Up @@ -215,9 +236,10 @@ export class GreasedLinePluginMaterial extends MaterialPluginBase implements IGr

/**
* Get the shader uniforms
* @param shaderLanguage The shader language to use
* @returns uniforms
*/
override getUniforms() {
override getUniforms(shaderLanguage = ShaderLanguage.GLSL) {
const ubo = [
{ name: "grl_singleColor", size: 3, type: "vec3" },
{ name: "grl_textureSize", size: 2, type: "vec2" },
Expand All @@ -228,20 +250,31 @@ export class GreasedLinePluginMaterial extends MaterialPluginBase implements IGr
ubo.push({ name: "grl_projection", size: 16, type: "mat4" }, { name: "grl_aspect_resolution_lineWidth", size: 4, type: "vec4" });
}

if (shaderLanguage === ShaderLanguage.WGSL) {
ubo.push({
name: "viewProjection",
size: 16,
type: "mat4",
});
}

return {
ubo,
vertex: this._cameraFacing
vertex:
this._cameraFacing && this._isGLSL(shaderLanguage)
? `
uniform vec4 grl_aspect_resolution_lineWidth;
uniform mat4 grl_projection;
`
: "",
fragment: this._isGLSL(shaderLanguage)
? `
uniform vec4 grl_aspect_resolution_lineWidth;
uniform mat4 grl_projection;
`
uniform vec4 grl_dashOptions;
uniform vec2 grl_textureSize;
uniform vec4 grl_colorMode_visibility_colorsWidth_useColors;
uniform vec3 grl_singleColor;
`
: "",
fragment: `
uniform vec4 grl_dashOptions;
uniform vec2 grl_textureSize;
uniform vec4 grl_colorMode_visibility_colorsWidth_useColors;
uniform vec3 grl_singleColor;
`,
};
}

Expand All @@ -257,14 +290,8 @@ export class GreasedLinePluginMaterial extends MaterialPluginBase implements IGr
*/
override bindForSubMesh(uniformBuffer: UniformBuffer) {
if (this._cameraFacing) {
const activeCamera = this._scene.activeCamera;

if (activeCamera) {
const projection = activeCamera.getProjectionMatrix();
uniformBuffer.updateMatrix("grl_projection", projection);
} else {
throw Error("GreasedLinePluginMaterial requires an active camera.");
}
uniformBuffer.updateMatrix("grl_projection", this._scene.getProjectionMatrix());
uniformBuffer.updateMatrix("viewProjection", this._scene.getTransformMatrix());

const resolutionLineWidth = TmpVectors.Vector4[0];
resolutionLineWidth.x = this._aspect;
Expand Down Expand Up @@ -321,163 +348,14 @@ export class GreasedLinePluginMaterial extends MaterialPluginBase implements IGr
/**
* Get shader code
* @param shaderType vertex/fragment
* @param shaderLanguage GLSL or WGSL
* @returns shader code
*/
override getCustomCode(shaderType: string): Nullable<{ [pointName: string]: string }> {
if (shaderType === "vertex") {
const obj: any = {
// eslint-disable-next-line @typescript-eslint/naming-convention
CUSTOM_VERTEX_DEFINITIONS: `
attribute float grl_widths;
attribute vec3 grl_offsets;
attribute float grl_colorPointers;
varying float grlCounters;
varying float grlColorPointer;

#ifdef GREASED_LINE_CAMERA_FACING
attribute vec4 grl_previousAndSide;
attribute vec4 grl_nextAndCounters;

vec2 grlFix( vec4 i, float aspect ) {
vec2 res = i.xy / i.w;
res.x *= aspect;
return res;
}
#else
attribute vec3 grl_slopes;
attribute float grl_counters;
#endif
`,
// eslint-disable-next-line @typescript-eslint/naming-convention
CUSTOM_VERTEX_UPDATE_POSITION: `
#ifdef GREASED_LINE_CAMERA_FACING
vec3 grlPositionOffset = grl_offsets;
positionUpdated += grlPositionOffset;
#else
positionUpdated = (positionUpdated + grl_offsets) + (grl_slopes * grl_widths);
#endif
`,
// eslint-disable-next-line @typescript-eslint/naming-convention
CUSTOM_VERTEX_MAIN_END: `
grlColorPointer = grl_colorPointers;

#ifdef GREASED_LINE_CAMERA_FACING

float grlAspect = grl_aspect_resolution_lineWidth.x;
float grlBaseWidth = grl_aspect_resolution_lineWidth.w;


vec3 grlPrevious = grl_previousAndSide.xyz;
float grlSide = grl_previousAndSide.w;

vec3 grlNext = grl_nextAndCounters.xyz;
grlCounters = grl_nextAndCounters.w;

mat4 grlMatrix = viewProjection * finalWorld;
vec4 grlFinalPosition = grlMatrix * vec4( positionUpdated , 1.0 );
vec4 grlPrevPos = grlMatrix * vec4( grlPrevious + grlPositionOffset, 1.0 );
vec4 grlNextPos = grlMatrix * vec4( grlNext + grlPositionOffset, 1.0 );

vec2 grlCurrentP = grlFix( grlFinalPosition, grlAspect );
vec2 grlPrevP = grlFix( grlPrevPos, grlAspect );
vec2 grlNextP = grlFix( grlNextPos, grlAspect );

float grlWidth = grlBaseWidth * grl_widths;

vec2 grlDir;
if( grlNextP == grlCurrentP ) grlDir = normalize( grlCurrentP - grlPrevP );
else if( grlPrevP == grlCurrentP ) grlDir = normalize( grlNextP - grlCurrentP );
else {
vec2 grlDir1 = normalize( grlCurrentP - grlPrevP );
vec2 grlDir2 = normalize( grlNextP - grlCurrentP );
grlDir = normalize( grlDir1 + grlDir2 );
}
vec4 grlNormal = vec4( -grlDir.y, grlDir.x, 0., 1. );
#ifdef GREASED_LINE_RIGHT_HANDED_COORDINATE_SYSTEM
grlNormal.xy *= -.5 * grlWidth;
#else
grlNormal.xy *= .5 * grlWidth;
#endif

grlNormal *= grl_projection;

#ifdef GREASED_LINE_SIZE_ATTENUATION
grlNormal.xy *= grlFinalPosition.w;
grlNormal.xy /= ( vec4( grl_aspect_resolution_lineWidth.yz, 0., 1. ) * grl_projection ).xy;
#endif

grlFinalPosition.xy += grlNormal.xy * grlSide;
gl_Position = grlFinalPosition;

vPositionW = vec3(grlFinalPosition);
#else
grlCounters = grl_counters;
#endif
`,
};
this._cameraFacing && (obj["!gl_Position\\=viewProjection\\*worldPos;"] = "//"); // not needed for camera facing GRL
return obj;
override getCustomCode(shaderType: string, shaderLanguage = ShaderLanguage.GLSL): Nullable<{ [pointName: string]: string }> {
if (this._isGLSL(shaderLanguage)) {
return getCustomCodeGLSL(shaderType, this._cameraFacing);
}

if (shaderType === "fragment") {
return {
// eslint-disable-next-line @typescript-eslint/naming-convention
CUSTOM_FRAGMENT_DEFINITIONS: `
varying float grlCounters;
varying float grlColorPointer;
uniform sampler2D grl_colors;
`,
// eslint-disable-next-line @typescript-eslint/naming-convention
CUSTOM_FRAGMENT_MAIN_END: `
float grlColorMode = grl_colorMode_visibility_colorsWidth_useColors.x;
float grlVisibility = grl_colorMode_visibility_colorsWidth_useColors.y;
float grlColorsWidth = grl_colorMode_visibility_colorsWidth_useColors.z;
float grlUseColors = grl_colorMode_visibility_colorsWidth_useColors.w;

float grlUseDash = grl_dashOptions.x;
float grlDashArray = grl_dashOptions.y;
float grlDashOffset = grl_dashOptions.z;
float grlDashRatio = grl_dashOptions.w;

gl_FragColor.a *= step(grlCounters, grlVisibility);
if( gl_FragColor.a == 0. ) discard;

if(grlUseDash == 1.){
gl_FragColor.a *= ceil(mod(grlCounters + grlDashOffset, grlDashArray) - (grlDashArray * grlDashRatio));
if (gl_FragColor.a == 0.) discard;
}

#ifdef GREASED_LINE_HAS_COLOR
if (grlColorMode == ${GreasedLineMeshColorMode.COLOR_MODE_SET}.) {
gl_FragColor.rgb = grl_singleColor;
} else if (grlColorMode == ${GreasedLineMeshColorMode.COLOR_MODE_ADD}.) {
gl_FragColor.rgb += grl_singleColor;
} else if (grlColorMode == ${GreasedLineMeshColorMode.COLOR_MODE_MULTIPLY}.) {
gl_FragColor.rgb *= grl_singleColor;
}
#else
if (grlUseColors == 1.) {
#ifdef GREASED_LINE_COLOR_DISTRIBUTION_TYPE_LINE
vec4 grlColor = texture2D(grl_colors, vec2(grlCounters, 0.), 0.);
#else
vec2 lookup = vec2(fract(grlColorPointer / grl_textureSize.x), 1.0 - floor(grlColorPointer / grl_textureSize.x) / max(grl_textureSize.y - 1.0, 1.0));
vec4 grlColor = texture2D(grl_colors, lookup, 0.0);
#endif
if (grlColorMode == ${GreasedLineMeshColorMode.COLOR_MODE_SET}.) {
gl_FragColor = grlColor;
} else if (grlColorMode == ${GreasedLineMeshColorMode.COLOR_MODE_ADD}.) {
gl_FragColor += grlColor;
} else if (grlColorMode == ${GreasedLineMeshColorMode.COLOR_MODE_MULTIPLY}.) {
gl_FragColor *= grlColor;
}
}
#endif

`,
};
}

return null;
return getCustomCodeWGSL(shaderType, this._cameraFacing);
}

/**
Expand Down Expand Up @@ -730,6 +608,10 @@ export class GreasedLinePluginMaterial extends MaterialPluginBase implements IGr

dest.markAllDefinesAsDirty();
}

private _isGLSL(shaderLanguage: ShaderLanguage) {
return shaderLanguage === ShaderLanguage.GLSL || this._forceGLSL;
}
}

RegisterClass(`BABYLON.${GreasedLinePluginMaterial.GREASED_LINE_MATERIAL_NAME}`, GreasedLinePluginMaterial);
Loading