From f248a307e26f780e5fca590755e938fd7b2e6b9c Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sun, 27 Oct 2024 10:50:20 +0100 Subject: [PATCH 1/4] LDrawLoader: Add WebGPU support. --- examples/jsm/loaders/LDrawLoader.js | 158 ++---------------- .../materials/LDrawConditionalLineMaterial.js | 143 ++++++++++++++++ .../LDrawConditionalLineNodeMaterial.js | 114 +++++++++++++ examples/webgl_loader_ldraw.html | 2 + 4 files changed, 275 insertions(+), 142 deletions(-) create mode 100644 examples/jsm/materials/LDrawConditionalLineMaterial.js create mode 100644 examples/jsm/materials/LDrawConditionalLineNodeMaterial.js diff --git a/examples/jsm/loaders/LDrawLoader.js b/examples/jsm/loaders/LDrawLoader.js index a35a50627773bb..e24e34364676e2 100644 --- a/examples/jsm/loaders/LDrawLoader.js +++ b/examples/jsm/loaders/LDrawLoader.js @@ -10,10 +10,7 @@ import { Matrix4, Mesh, MeshStandardMaterial, - ShaderMaterial, SRGBColorSpace, - UniformsLib, - UniformsUtils, Vector3, Ray } from 'three'; @@ -45,140 +42,6 @@ const COLOR_SPACE_LDRAW = SRGBColorSpace; const _tempVec0 = new Vector3(); const _tempVec1 = new Vector3(); -class LDrawConditionalLineMaterial extends ShaderMaterial { - - static get type() { - - return 'LDrawConditionalLineMaterial'; - - } - - constructor( parameters ) { - - super( { - - uniforms: UniformsUtils.merge( [ - UniformsLib.fog, - { - diffuse: { - value: new Color() - }, - opacity: { - value: 1.0 - } - } - ] ), - - vertexShader: /* glsl */` - attribute vec3 control0; - attribute vec3 control1; - attribute vec3 direction; - varying float discardFlag; - - #include - #include - #include - #include - #include - void main() { - #include - - vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); - gl_Position = projectionMatrix * mvPosition; - - // Transform the line segment ends and control points into camera clip space - vec4 c0 = projectionMatrix * modelViewMatrix * vec4( control0, 1.0 ); - vec4 c1 = projectionMatrix * modelViewMatrix * vec4( control1, 1.0 ); - vec4 p0 = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); - vec4 p1 = projectionMatrix * modelViewMatrix * vec4( position + direction, 1.0 ); - - c0.xy /= c0.w; - c1.xy /= c1.w; - p0.xy /= p0.w; - p1.xy /= p1.w; - - // Get the direction of the segment and an orthogonal vector - vec2 dir = p1.xy - p0.xy; - vec2 norm = vec2( -dir.y, dir.x ); - - // Get control point directions from the line - vec2 c0dir = c0.xy - p1.xy; - vec2 c1dir = c1.xy - p1.xy; - - // If the vectors to the controls points are pointed in different directions away - // from the line segment then the line should not be drawn. - float d0 = dot( normalize( norm ), normalize( c0dir ) ); - float d1 = dot( normalize( norm ), normalize( c1dir ) ); - discardFlag = float( sign( d0 ) != sign( d1 ) ); - - #include - #include - #include - } - `, - - fragmentShader: /* glsl */` - uniform vec3 diffuse; - uniform float opacity; - varying float discardFlag; - - #include - #include - #include - #include - #include - void main() { - - if ( discardFlag > 0.5 ) discard; - - #include - vec3 outgoingLight = vec3( 0.0 ); - vec4 diffuseColor = vec4( diffuse, opacity ); - #include - #include - outgoingLight = diffuseColor.rgb; // simple shader - gl_FragColor = vec4( outgoingLight, diffuseColor.a ); - #include - #include - #include - #include - } - `, - - } ); - - Object.defineProperties( this, { - - opacity: { - get: function () { - - return this.uniforms.opacity.value; - - }, - - set: function ( value ) { - - this.uniforms.opacity.value = value; - - } - }, - - color: { - get: function () { - - return this.uniforms.diffuse.value; - - } - } - - } ); - - this.setValues( parameters ); - this.isLDrawConditionalLineMaterial = true; - - } - -} class ConditionalLineSegments extends LineSegments { @@ -1903,19 +1766,19 @@ class LDrawLoader extends Loader { // This object is a map from file names to paths. It agilizes the paths search. If it is not set then files will be searched by trial and error. this.fileMap = {}; - // Initializes the materials library with default materials - this.setMaterials( [] ); - // If this flag is set to true the vertex normals will be smoothed. this.smoothNormals = true; // The path to load parts from the LDraw parts library from. this.partsLibraryPath = ''; + // this material type must be injected via setConditionalLineMaterial() + this.ConditionalLineMaterial = null; + // Material assigned to not available colors for meshes and edges this.missingColorMaterial = new MeshStandardMaterial( { name: Loader.DEFAULT_MATERIAL_NAME, color: 0xFF00FF, roughness: 0.3, metalness: 0 } ); this.missingEdgeColorMaterial = new LineBasicMaterial( { name: Loader.DEFAULT_MATERIAL_NAME, color: 0xFF00FF } ); - this.missingConditionalEdgeColorMaterial = new LDrawConditionalLineMaterial( { name: Loader.DEFAULT_MATERIAL_NAME, fog: true, color: 0xFF00FF } ); + this.missingConditionalEdgeColorMaterial = null; this.edgeMaterialCache.set( this.missingColorMaterial, this.missingEdgeColorMaterial ); this.conditionalEdgeMaterialCache.set( this.missingEdgeColorMaterial, this.missingConditionalEdgeColorMaterial ); @@ -1928,6 +1791,14 @@ class LDrawLoader extends Loader { } + setConditionalLineMaterial( type ) { + + this.ConditionalLineMaterial = type; + this.missingConditionalEdgeColorMaterial = new this.ConditionalLineMaterial( { name: Loader.DEFAULT_MATERIAL_NAME, fog: true, color: 0xFF00FF } ); + return this; + + } + async preloadMaterials( url ) { const fileLoader = new FileLoader( this.manager ); @@ -1964,6 +1835,9 @@ class LDrawLoader extends Loader { fileLoader.setWithCredentials( this.withCredentials ); fileLoader.load( url, text => { + // Initializes the materials library with default materials + this.setMaterials( [] ); + this.partsCache .parseModel( text, this.materialLibrary ) .then( group => { @@ -2391,7 +2265,7 @@ class LDrawLoader extends Loader { edgeMaterial.name = name + ' - Edge'; // This is the material used for conditional edges - const conditionalEdgeMaterial = new LDrawConditionalLineMaterial( { + const conditionalEdgeMaterial = new this.ConditionalLineMaterial( { fog: true, transparent: isTransparent, diff --git a/examples/jsm/materials/LDrawConditionalLineMaterial.js b/examples/jsm/materials/LDrawConditionalLineMaterial.js new file mode 100644 index 00000000000000..bddf68d3da5232 --- /dev/null +++ b/examples/jsm/materials/LDrawConditionalLineMaterial.js @@ -0,0 +1,143 @@ +import { + Color, + ShaderMaterial, + UniformsLib, + UniformsUtils, +} from 'three'; + +class LDrawConditionalLineMaterial extends ShaderMaterial { + + static get type() { + + return 'LDrawConditionalLineMaterial'; + + } + + constructor( parameters ) { + + super( { + + uniforms: UniformsUtils.merge( [ + UniformsLib.fog, + { + diffuse: { + value: new Color() + }, + opacity: { + value: 1.0 + } + } + ] ), + + vertexShader: /* glsl */` + attribute vec3 control0; + attribute vec3 control1; + attribute vec3 direction; + varying float discardFlag; + + #include + #include + #include + #include + #include + void main() { + #include + + vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); + gl_Position = projectionMatrix * mvPosition; + + // Transform the line segment ends and control points into camera clip space + vec4 c0 = projectionMatrix * modelViewMatrix * vec4( control0, 1.0 ); + vec4 c1 = projectionMatrix * modelViewMatrix * vec4( control1, 1.0 ); + vec4 p0 = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); + vec4 p1 = projectionMatrix * modelViewMatrix * vec4( position + direction, 1.0 ); + + c0.xy /= c0.w; + c1.xy /= c1.w; + p0.xy /= p0.w; + p1.xy /= p1.w; + + // Get the direction of the segment and an orthogonal vector + vec2 dir = p1.xy - p0.xy; + vec2 norm = vec2( -dir.y, dir.x ); + + // Get control point directions from the line + vec2 c0dir = c0.xy - p1.xy; + vec2 c1dir = c1.xy - p1.xy; + + // If the vectors to the controls points are pointed in different directions away + // from the line segment then the line should not be drawn. + float d0 = dot( normalize( norm ), normalize( c0dir ) ); + float d1 = dot( normalize( norm ), normalize( c1dir ) ); + discardFlag = float( sign( d0 ) != sign( d1 ) ); + + #include + #include + #include + } + `, + + fragmentShader: /* glsl */` + uniform vec3 diffuse; + uniform float opacity; + varying float discardFlag; + + #include + #include + #include + #include + #include + void main() { + + if ( discardFlag > 0.5 ) discard; + + #include + vec3 outgoingLight = vec3( 0.0 ); + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + outgoingLight = diffuseColor.rgb; // simple shader + gl_FragColor = vec4( outgoingLight, diffuseColor.a ); + #include + #include + #include + #include + } + `, + + } ); + + Object.defineProperties( this, { + + opacity: { + get: function () { + + return this.uniforms.opacity.value; + + }, + + set: function ( value ) { + + this.uniforms.opacity.value = value; + + } + }, + + color: { + get: function () { + + return this.uniforms.diffuse.value; + + } + } + + } ); + + this.setValues( parameters ); + this.isLDrawConditionalLineMaterial = true; + + } + +} + +export { LDrawConditionalLineMaterial }; diff --git a/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js b/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js new file mode 100644 index 00000000000000..98f21a15d6b120 --- /dev/null +++ b/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js @@ -0,0 +1,114 @@ +import { Color } from 'three'; +import { attribute, cameraProjectionMatrix, dot, float, Fn, modelViewMatrix, modelViewProjection, NodeMaterial, normalize, positionGeometry, sign, uniform, varyingProperty, vec2, vec4 } from 'three/tsl'; + +class LDrawConditionalLineMaterial extends NodeMaterial { + + static get type() { + + return 'LDrawConditionalLineMaterial'; + + } + + constructor( parameters ) { + + super(); + + const vertexNode = /*@__PURE__*/ Fn( () => { + + const control0 = attribute( 'control0', 'vec3' ); + const control1 = attribute( 'control1', 'vec3' ); + const direction = attribute( 'direction', 'vec3' ); + + const mvp = cameraProjectionMatrix.mul( modelViewMatrix ); + + // Transform the line segment ends and control points into camera clip space + + const c0 = mvp.mul( vec4( control0, 1 ) ).toVar(); + const c1 = mvp.mul( vec4( control1, 1 ) ).toVar(); + const p0 = mvp.mul( vec4( positionGeometry, 1 ) ).toVar(); + const p1 = mvp.mul( vec4( positionGeometry.add( direction ), 1 ) ).toVar(); + + c0.xy.divAssign( c0.w ); + c1.xy.divAssign( c1.w ); + p0.xy.divAssign( p0.w ); + p1.xy.divAssign( p1.w ); + + // Get the direction of the segment and an orthogonal vector + + const dir = p1.xy.sub( p0.xy ).toVar(); + const norm = vec2( dir.y.negate(), dir.x ).toVar(); + + // Get control point directions from the line + const c0dir = c0.xy.sub( p1.xy ).toVar(); + const c1dir = c1.xy.sub( p1.xy ).toVar(); + + // If the vectors to the controls points are pointed in different directions away + // from the line segment then the line should not be drawn. + const d0 = dot( normalize( norm ), normalize( c0dir ) ).toVar(); + const d1 = dot( normalize( norm ), normalize( c1dir ) ).toVar(); + const discardFlag = sign( d0 ).notEqual( sign( d1 ) ).select( float( 1 ), float( 0 ) ); + + varyingProperty( 'float', 'discardFlag' ).assign( discardFlag ); + + return modelViewProjection(); + + } )(); + + const fragmentNode = /*@__PURE__*/ Fn( () => { + + const discardFlag = varyingProperty( 'float', 'discardFlag' ); + + discardFlag.greaterThan( float( 0.5 ) ).discard(); + + return vec4( 0, 0, 0, this._opacityUniform ); + + } )(); + + this.vertexNode = vertexNode; + this.fragmentNode = fragmentNode; + + this._diffuseUniform = uniform( new Color() ); + this._opacityUniform = uniform( 1 ); + + // + + Object.defineProperties( this, { + + opacity: { + get: function () { + + return this._opacityUniform.value; + + }, + + set: function ( value ) { + + this._opacityUniform.value = value; + + } + }, + + color: { + get: function () { + + return this._diffuseUniform.value; + + }, + + set: function ( value ) { + + this._diffuseUniform.value.copy( value ); + + } + } + + } ); + + this.setValues( parameters ); + this.isLDrawConditionalLineMaterial = true; + + } + +} + +export { LDrawConditionalLineMaterial }; diff --git a/examples/webgl_loader_ldraw.html b/examples/webgl_loader_ldraw.html index 490e020c22ad7a..04a0bd0270655c 100644 --- a/examples/webgl_loader_ldraw.html +++ b/examples/webgl_loader_ldraw.html @@ -40,6 +40,7 @@ import { LDrawLoader } from 'three/addons/loaders/LDrawLoader.js'; import { LDrawUtils } from 'three/addons/utils/LDrawUtils.js'; + import { LDrawConditionalLineMaterial } from 'three/addons/materials/LDrawConditionalLineMaterial.js'; let container, progressBarDiv; @@ -172,6 +173,7 @@ // only smooth when not rendering with flat colors to improve processing time const lDrawLoader = new LDrawLoader(); + lDrawLoader.setConditionalLineMaterial( LDrawConditionalLineMaterial ); lDrawLoader.smoothNormals = guiData.smoothNormals && ! guiData.flatColors; lDrawLoader .setPath( ldrawPath ) From 8e7143b5b14de763e4e8279bb26ad469f94b64ec Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sun, 27 Oct 2024 10:57:30 +0100 Subject: [PATCH 2/4] LDrawLoader: Improve error handling. --- examples/jsm/loaders/LDrawLoader.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/jsm/loaders/LDrawLoader.js b/examples/jsm/loaders/LDrawLoader.js index e24e34364676e2..39bf2c4b511d1d 100644 --- a/examples/jsm/loaders/LDrawLoader.js +++ b/examples/jsm/loaders/LDrawLoader.js @@ -2264,6 +2264,12 @@ class LDrawLoader extends Loader { edgeMaterial.userData.code = code; edgeMaterial.name = name + ' - Edge'; + if ( this.ConditionalLineMaterial === null ) { + + throw new Error( 'THREE.LDrawLoader: ConditionalLineMaterial type must be specificed via .setConditionalLineMaterial().' ); + + } + // This is the material used for conditional edges const conditionalEdgeMaterial = new this.ConditionalLineMaterial( { From 6a8cbdc02b8045d4353b34484baa1e1d4aa21ca7 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sun, 27 Oct 2024 11:02:26 +0100 Subject: [PATCH 3/4] LDrawLoader: Clean up. --- examples/jsm/materials/LDrawConditionalLineNodeMaterial.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js b/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js index 98f21a15d6b120..47f62cf25962f1 100644 --- a/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js +++ b/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js @@ -60,7 +60,7 @@ class LDrawConditionalLineMaterial extends NodeMaterial { discardFlag.greaterThan( float( 0.5 ) ).discard(); - return vec4( 0, 0, 0, this._opacityUniform ); + return vec4( this._diffuseUniform, this._opacityUniform ); } )(); From d9f101e5f98aee0a624d32425eb36a58c28a19c2 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sun, 27 Oct 2024 12:53:03 +0100 Subject: [PATCH 4/4] Update Addons.js --- examples/jsm/Addons.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/jsm/Addons.js b/examples/jsm/Addons.js index 8bbc6f1bd5a941..c1618f784e2cf8 100644 --- a/examples/jsm/Addons.js +++ b/examples/jsm/Addons.js @@ -131,6 +131,8 @@ export * from './loaders/VTKLoader.js'; export * from './loaders/XYZLoader.js'; export * from './materials/MeshGouraudMaterial.js'; +export * from './materials/LDrawConditionalLineMaterial.js'; +export * from './materials/MeshPostProcessingMaterial.js'; export * from './math/Capsule.js'; export * from './math/ColorConverter.js';