first commit

This commit is contained in:
2026-06-24 09:48:54 +02:00
commit 41e62ddcad
33739 changed files with 4266226 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
import { Material } from './Material.js';
import { Color } from '../math/Color.js';
class LineBasicMaterial extends Material {
constructor( parameters ) {
super();
this.isLineBasicMaterial = true;
this.type = 'LineBasicMaterial';
this.color = new Color( 0xffffff );
this.map = null;
this.linewidth = 1;
this.linecap = 'round';
this.linejoin = 'round';
this.fog = true;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.linewidth = source.linewidth;
this.linecap = source.linecap;
this.linejoin = source.linejoin;
this.fog = source.fog;
return this;
}
}
export { LineBasicMaterial };
+34
View File
@@ -0,0 +1,34 @@
import { LineBasicMaterial } from './LineBasicMaterial.js';
class LineDashedMaterial extends LineBasicMaterial {
constructor( parameters ) {
super();
this.isLineDashedMaterial = true;
this.type = 'LineDashedMaterial';
this.scale = 1;
this.dashSize = 3;
this.gapSize = 1;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.scale = source.scale;
this.dashSize = source.dashSize;
this.gapSize = source.gapSize;
return this;
}
}
export { LineDashedMaterial };
+531
View File
@@ -0,0 +1,531 @@
import { Color } from '../math/Color.js';
import { EventDispatcher } from '../core/EventDispatcher.js';
import { FrontSide, NormalBlending, LessEqualDepth, AddEquation, OneMinusSrcAlphaFactor, SrcAlphaFactor, AlwaysStencilFunc, KeepStencilOp } from '../constants.js';
import { generateUUID } from '../math/MathUtils.js';
let _materialId = 0;
class Material extends EventDispatcher {
constructor() {
super();
this.isMaterial = true;
Object.defineProperty( this, 'id', { value: _materialId ++ } );
this.uuid = generateUUID();
this.name = '';
this.type = 'Material';
this.blending = NormalBlending;
this.side = FrontSide;
this.vertexColors = false;
this.opacity = 1;
this.transparent = false;
this.alphaHash = false;
this.blendSrc = SrcAlphaFactor;
this.blendDst = OneMinusSrcAlphaFactor;
this.blendEquation = AddEquation;
this.blendSrcAlpha = null;
this.blendDstAlpha = null;
this.blendEquationAlpha = null;
this.blendColor = new Color( 0, 0, 0 );
this.blendAlpha = 0;
this.depthFunc = LessEqualDepth;
this.depthTest = true;
this.depthWrite = true;
this.stencilWriteMask = 0xff;
this.stencilFunc = AlwaysStencilFunc;
this.stencilRef = 0;
this.stencilFuncMask = 0xff;
this.stencilFail = KeepStencilOp;
this.stencilZFail = KeepStencilOp;
this.stencilZPass = KeepStencilOp;
this.stencilWrite = false;
this.clippingPlanes = null;
this.clipIntersection = false;
this.clipShadows = false;
this.shadowSide = null;
this.colorWrite = true;
this.precision = null; // override the renderer's default precision for this material
this.polygonOffset = false;
this.polygonOffsetFactor = 0;
this.polygonOffsetUnits = 0;
this.dithering = false;
this.alphaToCoverage = false;
this.premultipliedAlpha = false;
this.forceSinglePass = false;
this.visible = true;
this.toneMapped = true;
this.userData = {};
this.version = 0;
this._alphaTest = 0;
}
get alphaTest() {
return this._alphaTest;
}
set alphaTest( value ) {
if ( this._alphaTest > 0 !== value > 0 ) {
this.version ++;
}
this._alphaTest = value;
}
// onBeforeRender and onBeforeCompile only supported in WebGLRenderer
onBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {}
onBeforeCompile( /* shaderobject, renderer */ ) {}
customProgramCacheKey() {
return this.onBeforeCompile.toString();
}
setValues( values ) {
if ( values === undefined ) return;
for ( const key in values ) {
const newValue = values[ key ];
if ( newValue === undefined ) {
console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` );
continue;
}
const currentValue = this[ key ];
if ( currentValue === undefined ) {
console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` );
continue;
}
if ( currentValue && currentValue.isColor ) {
currentValue.set( newValue );
} else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {
currentValue.copy( newValue );
} else {
this[ key ] = newValue;
}
}
}
toJSON( meta ) {
const isRootObject = ( meta === undefined || typeof meta === 'string' );
if ( isRootObject ) {
meta = {
textures: {},
images: {}
};
}
const data = {
metadata: {
version: 4.6,
type: 'Material',
generator: 'Material.toJSON'
}
};
// standard Material serialization
data.uuid = this.uuid;
data.type = this.type;
if ( this.name !== '' ) data.name = this.name;
if ( this.color && this.color.isColor ) data.color = this.color.getHex();
if ( this.roughness !== undefined ) data.roughness = this.roughness;
if ( this.metalness !== undefined ) data.metalness = this.metalness;
if ( this.sheen !== undefined ) data.sheen = this.sheen;
if ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex();
if ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness;
if ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();
if ( this.emissiveIntensity !== undefined && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;
if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
if ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;
if ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex();
if ( this.shininess !== undefined ) data.shininess = this.shininess;
if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
if ( this.clearcoatMap && this.clearcoatMap.isTexture ) {
data.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;
}
if ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {
data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;
}
if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
}
if ( this.dispersion !== undefined ) data.dispersion = this.dispersion;
if ( this.iridescence !== undefined ) data.iridescence = this.iridescence;
if ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR;
if ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange;
if ( this.iridescenceMap && this.iridescenceMap.isTexture ) {
data.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid;
}
if ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) {
data.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid;
}
if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy;
if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation;
if ( this.anisotropyMap && this.anisotropyMap.isTexture ) {
data.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid;
}
if ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;
if ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;
if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;
if ( this.lightMap && this.lightMap.isTexture ) {
data.lightMap = this.lightMap.toJSON( meta ).uuid;
data.lightMapIntensity = this.lightMapIntensity;
}
if ( this.aoMap && this.aoMap.isTexture ) {
data.aoMap = this.aoMap.toJSON( meta ).uuid;
data.aoMapIntensity = this.aoMapIntensity;
}
if ( this.bumpMap && this.bumpMap.isTexture ) {
data.bumpMap = this.bumpMap.toJSON( meta ).uuid;
data.bumpScale = this.bumpScale;
}
if ( this.normalMap && this.normalMap.isTexture ) {
data.normalMap = this.normalMap.toJSON( meta ).uuid;
data.normalMapType = this.normalMapType;
data.normalScale = this.normalScale.toArray();
}
if ( this.displacementMap && this.displacementMap.isTexture ) {
data.displacementMap = this.displacementMap.toJSON( meta ).uuid;
data.displacementScale = this.displacementScale;
data.displacementBias = this.displacementBias;
}
if ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;
if ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;
if ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;
if ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;
if ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid;
if ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid;
if ( this.envMap && this.envMap.isTexture ) {
data.envMap = this.envMap.toJSON( meta ).uuid;
if ( this.combine !== undefined ) data.combine = this.combine;
}
if ( this.envMapRotation !== undefined ) data.envMapRotation = this.envMapRotation.toArray();
if ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;
if ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity;
if ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio;
if ( this.gradientMap && this.gradientMap.isTexture ) {
data.gradientMap = this.gradientMap.toJSON( meta ).uuid;
}
if ( this.transmission !== undefined ) data.transmission = this.transmission;
if ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid;
if ( this.thickness !== undefined ) data.thickness = this.thickness;
if ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid;
if ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance;
if ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex();
if ( this.size !== undefined ) data.size = this.size;
if ( this.shadowSide !== null ) data.shadowSide = this.shadowSide;
if ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;
if ( this.blending !== NormalBlending ) data.blending = this.blending;
if ( this.side !== FrontSide ) data.side = this.side;
if ( this.vertexColors === true ) data.vertexColors = true;
if ( this.opacity < 1 ) data.opacity = this.opacity;
if ( this.transparent === true ) data.transparent = true;
if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc;
if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst;
if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation;
if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha;
if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha;
if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha;
if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex();
if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha;
if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc;
if ( this.depthTest === false ) data.depthTest = this.depthTest;
if ( this.depthWrite === false ) data.depthWrite = this.depthWrite;
if ( this.colorWrite === false ) data.colorWrite = this.colorWrite;
if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask;
if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc;
if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef;
if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask;
if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail;
if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail;
if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass;
if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite;
// rotation (SpriteMaterial)
if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation;
if ( this.polygonOffset === true ) data.polygonOffset = true;
if ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;
if ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;
if ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth;
if ( this.dashSize !== undefined ) data.dashSize = this.dashSize;
if ( this.gapSize !== undefined ) data.gapSize = this.gapSize;
if ( this.scale !== undefined ) data.scale = this.scale;
if ( this.dithering === true ) data.dithering = true;
if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;
if ( this.alphaHash === true ) data.alphaHash = true;
if ( this.alphaToCoverage === true ) data.alphaToCoverage = true;
if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true;
if ( this.forceSinglePass === true ) data.forceSinglePass = true;
if ( this.wireframe === true ) data.wireframe = true;
if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;
if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;
if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;
if ( this.flatShading === true ) data.flatShading = true;
if ( this.visible === false ) data.visible = false;
if ( this.toneMapped === false ) data.toneMapped = false;
if ( this.fog === false ) data.fog = false;
if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;
// TODO: Copied from Object3D.toJSON
function extractFromCache( cache ) {
const values = [];
for ( const key in cache ) {
const data = cache[ key ];
delete data.metadata;
values.push( data );
}
return values;
}
if ( isRootObject ) {
const textures = extractFromCache( meta.textures );
const images = extractFromCache( meta.images );
if ( textures.length > 0 ) data.textures = textures;
if ( images.length > 0 ) data.images = images;
}
return data;
}
clone() {
return new this.constructor().copy( this );
}
copy( source ) {
this.name = source.name;
this.blending = source.blending;
this.side = source.side;
this.vertexColors = source.vertexColors;
this.opacity = source.opacity;
this.transparent = source.transparent;
this.blendSrc = source.blendSrc;
this.blendDst = source.blendDst;
this.blendEquation = source.blendEquation;
this.blendSrcAlpha = source.blendSrcAlpha;
this.blendDstAlpha = source.blendDstAlpha;
this.blendEquationAlpha = source.blendEquationAlpha;
this.blendColor.copy( source.blendColor );
this.blendAlpha = source.blendAlpha;
this.depthFunc = source.depthFunc;
this.depthTest = source.depthTest;
this.depthWrite = source.depthWrite;
this.stencilWriteMask = source.stencilWriteMask;
this.stencilFunc = source.stencilFunc;
this.stencilRef = source.stencilRef;
this.stencilFuncMask = source.stencilFuncMask;
this.stencilFail = source.stencilFail;
this.stencilZFail = source.stencilZFail;
this.stencilZPass = source.stencilZPass;
this.stencilWrite = source.stencilWrite;
const srcPlanes = source.clippingPlanes;
let dstPlanes = null;
if ( srcPlanes !== null ) {
const n = srcPlanes.length;
dstPlanes = new Array( n );
for ( let i = 0; i !== n; ++ i ) {
dstPlanes[ i ] = srcPlanes[ i ].clone();
}
}
this.clippingPlanes = dstPlanes;
this.clipIntersection = source.clipIntersection;
this.clipShadows = source.clipShadows;
this.shadowSide = source.shadowSide;
this.colorWrite = source.colorWrite;
this.precision = source.precision;
this.polygonOffset = source.polygonOffset;
this.polygonOffsetFactor = source.polygonOffsetFactor;
this.polygonOffsetUnits = source.polygonOffsetUnits;
this.dithering = source.dithering;
this.alphaTest = source.alphaTest;
this.alphaHash = source.alphaHash;
this.alphaToCoverage = source.alphaToCoverage;
this.premultipliedAlpha = source.premultipliedAlpha;
this.forceSinglePass = source.forceSinglePass;
this.visible = source.visible;
this.toneMapped = source.toneMapped;
this.userData = JSON.parse( JSON.stringify( source.userData ) );
return this;
}
dispose() {
this.dispatchEvent( { type: 'dispose' } );
}
set needsUpdate( value ) {
if ( value === true ) this.version ++;
}
onBuild( /* shaderobject, renderer */ ) {
console.warn( 'Material: onBuild() has been removed.' ); // @deprecated, r166
}
}
export { Material };
+39
View File
@@ -0,0 +1,39 @@
import { ShadowMaterial } from './ShadowMaterial.js';
import { SpriteMaterial } from './SpriteMaterial.js';
import { RawShaderMaterial } from './RawShaderMaterial.js';
import { ShaderMaterial } from './ShaderMaterial.js';
import { PointsMaterial } from './PointsMaterial.js';
import { MeshPhysicalMaterial } from './MeshPhysicalMaterial.js';
import { MeshStandardMaterial } from './MeshStandardMaterial.js';
import { MeshPhongMaterial } from './MeshPhongMaterial.js';
import { MeshToonMaterial } from './MeshToonMaterial.js';
import { MeshNormalMaterial } from './MeshNormalMaterial.js';
import { MeshLambertMaterial } from './MeshLambertMaterial.js';
import { MeshDepthMaterial } from './MeshDepthMaterial.js';
import { MeshDistanceMaterial } from './MeshDistanceMaterial.js';
import { MeshBasicMaterial } from './MeshBasicMaterial.js';
import { MeshMatcapMaterial } from './MeshMatcapMaterial.js';
import { LineDashedMaterial } from './LineDashedMaterial.js';
import { LineBasicMaterial } from './LineBasicMaterial.js';
import { Material } from './Material.js';
export {
ShadowMaterial,
SpriteMaterial,
RawShaderMaterial,
ShaderMaterial,
PointsMaterial,
MeshPhysicalMaterial,
MeshStandardMaterial,
MeshPhongMaterial,
MeshToonMaterial,
MeshNormalMaterial,
MeshLambertMaterial,
MeshDepthMaterial,
MeshDistanceMaterial,
MeshBasicMaterial,
MeshMatcapMaterial,
LineDashedMaterial,
LineBasicMaterial,
Material
};
+84
View File
@@ -0,0 +1,84 @@
import { Material } from './Material.js';
import { MultiplyOperation } from '../constants.js';
import { Color } from '../math/Color.js';
import { Euler } from '../math/Euler.js';
class MeshBasicMaterial extends Material {
constructor( parameters ) {
super();
this.isMeshBasicMaterial = true;
this.type = 'MeshBasicMaterial';
this.color = new Color( 0xffffff ); // emissive
this.map = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.specularMap = null;
this.alphaMap = null;
this.envMap = null;
this.envMapRotation = new Euler();
this.combine = MultiplyOperation;
this.reflectivity = 1;
this.refractionRatio = 0.98;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.fog = true;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.specularMap = source.specularMap;
this.alphaMap = source.alphaMap;
this.envMap = source.envMap;
this.envMapRotation.copy( source.envMapRotation );
this.combine = source.combine;
this.reflectivity = source.reflectivity;
this.refractionRatio = source.refractionRatio;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.fog = source.fog;
return this;
}
}
export { MeshBasicMaterial };
+54
View File
@@ -0,0 +1,54 @@
import { Material } from './Material.js';
import { BasicDepthPacking } from '../constants.js';
class MeshDepthMaterial extends Material {
constructor( parameters ) {
super();
this.isMeshDepthMaterial = true;
this.type = 'MeshDepthMaterial';
this.depthPacking = BasicDepthPacking;
this.map = null;
this.alphaMap = null;
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.depthPacking = source.depthPacking;
this.map = source.map;
this.alphaMap = source.alphaMap;
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
return this;
}
}
export { MeshDepthMaterial };
+43
View File
@@ -0,0 +1,43 @@
import { Material } from './Material.js';
class MeshDistanceMaterial extends Material {
constructor( parameters ) {
super();
this.isMeshDistanceMaterial = true;
this.type = 'MeshDistanceMaterial';
this.map = null;
this.alphaMap = null;
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.map = source.map;
this.alphaMap = source.alphaMap;
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
return this;
}
}
export { MeshDistanceMaterial };
+119
View File
@@ -0,0 +1,119 @@
import { MultiplyOperation, TangentSpaceNormalMap } from '../constants.js';
import { Material } from './Material.js';
import { Vector2 } from '../math/Vector2.js';
import { Color } from '../math/Color.js';
import { Euler } from '../math/Euler.js';
class MeshLambertMaterial extends Material {
constructor( parameters ) {
super();
this.isMeshLambertMaterial = true;
this.type = 'MeshLambertMaterial';
this.color = new Color( 0xffffff ); // diffuse
this.map = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.emissive = new Color( 0x000000 );
this.emissiveIntensity = 1.0;
this.emissiveMap = null;
this.bumpMap = null;
this.bumpScale = 1;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.specularMap = null;
this.alphaMap = null;
this.envMap = null;
this.envMapRotation = new Euler();
this.combine = MultiplyOperation;
this.reflectivity = 1;
this.refractionRatio = 0.98;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.flatShading = false;
this.fog = true;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.emissive.copy( source.emissive );
this.emissiveMap = source.emissiveMap;
this.emissiveIntensity = source.emissiveIntensity;
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.specularMap = source.specularMap;
this.alphaMap = source.alphaMap;
this.envMap = source.envMap;
this.envMapRotation.copy( source.envMapRotation );
this.combine = source.combine;
this.reflectivity = source.reflectivity;
this.refractionRatio = source.refractionRatio;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.flatShading = source.flatShading;
this.fog = source.fog;
return this;
}
}
export { MeshLambertMaterial };
+81
View File
@@ -0,0 +1,81 @@
import { TangentSpaceNormalMap } from '../constants.js';
import { Material } from './Material.js';
import { Vector2 } from '../math/Vector2.js';
import { Color } from '../math/Color.js';
class MeshMatcapMaterial extends Material {
constructor( parameters ) {
super();
this.isMeshMatcapMaterial = true;
this.defines = { 'MATCAP': '' };
this.type = 'MeshMatcapMaterial';
this.color = new Color( 0xffffff ); // diffuse
this.matcap = null;
this.map = null;
this.bumpMap = null;
this.bumpScale = 1;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.alphaMap = null;
this.flatShading = false;
this.fog = true;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.defines = { 'MATCAP': '' };
this.color.copy( source.color );
this.matcap = source.matcap;
this.map = source.map;
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.alphaMap = source.alphaMap;
this.flatShading = source.flatShading;
this.fog = source.fog;
return this;
}
}
export { MeshMatcapMaterial };
+61
View File
@@ -0,0 +1,61 @@
import { TangentSpaceNormalMap } from '../constants.js';
import { Material } from './Material.js';
import { Vector2 } from '../math/Vector2.js';
class MeshNormalMaterial extends Material {
constructor( parameters ) {
super();
this.isMeshNormalMaterial = true;
this.type = 'MeshNormalMaterial';
this.bumpMap = null;
this.bumpScale = 1;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.flatShading = false;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.flatShading = source.flatShading;
return this;
}
}
export { MeshNormalMaterial };
+123
View File
@@ -0,0 +1,123 @@
import { MultiplyOperation, TangentSpaceNormalMap } from '../constants.js';
import { Material } from './Material.js';
import { Vector2 } from '../math/Vector2.js';
import { Color } from '../math/Color.js';
import { Euler } from '../math/Euler.js';
class MeshPhongMaterial extends Material {
constructor( parameters ) {
super();
this.isMeshPhongMaterial = true;
this.type = 'MeshPhongMaterial';
this.color = new Color( 0xffffff ); // diffuse
this.specular = new Color( 0x111111 );
this.shininess = 30;
this.map = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.emissive = new Color( 0x000000 );
this.emissiveIntensity = 1.0;
this.emissiveMap = null;
this.bumpMap = null;
this.bumpScale = 1;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.specularMap = null;
this.alphaMap = null;
this.envMap = null;
this.envMapRotation = new Euler();
this.combine = MultiplyOperation;
this.reflectivity = 1;
this.refractionRatio = 0.98;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.flatShading = false;
this.fog = true;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.specular.copy( source.specular );
this.shininess = source.shininess;
this.map = source.map;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.emissive.copy( source.emissive );
this.emissiveMap = source.emissiveMap;
this.emissiveIntensity = source.emissiveIntensity;
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.specularMap = source.specularMap;
this.alphaMap = source.alphaMap;
this.envMap = source.envMap;
this.envMapRotation.copy( source.envMapRotation );
this.combine = source.combine;
this.reflectivity = source.reflectivity;
this.refractionRatio = source.refractionRatio;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.flatShading = source.flatShading;
this.fog = source.fog;
return this;
}
}
export { MeshPhongMaterial };
+244
View File
@@ -0,0 +1,244 @@
import { Vector2 } from '../math/Vector2.js';
import { MeshStandardMaterial } from './MeshStandardMaterial.js';
import { Color } from '../math/Color.js';
import { clamp } from '../math/MathUtils.js';
class MeshPhysicalMaterial extends MeshStandardMaterial {
constructor( parameters ) {
super();
this.isMeshPhysicalMaterial = true;
this.defines = {
'STANDARD': '',
'PHYSICAL': ''
};
this.type = 'MeshPhysicalMaterial';
this.anisotropyRotation = 0;
this.anisotropyMap = null;
this.clearcoatMap = null;
this.clearcoatRoughness = 0.0;
this.clearcoatRoughnessMap = null;
this.clearcoatNormalScale = new Vector2( 1, 1 );
this.clearcoatNormalMap = null;
this.ior = 1.5;
Object.defineProperty( this, 'reflectivity', {
get: function () {
return ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) );
},
set: function ( reflectivity ) {
this.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity );
}
} );
this.iridescenceMap = null;
this.iridescenceIOR = 1.3;
this.iridescenceThicknessRange = [ 100, 400 ];
this.iridescenceThicknessMap = null;
this.sheenColor = new Color( 0x000000 );
this.sheenColorMap = null;
this.sheenRoughness = 1.0;
this.sheenRoughnessMap = null;
this.transmissionMap = null;
this.thickness = 0;
this.thicknessMap = null;
this.attenuationDistance = Infinity;
this.attenuationColor = new Color( 1, 1, 1 );
this.specularIntensity = 1.0;
this.specularIntensityMap = null;
this.specularColor = new Color( 1, 1, 1 );
this.specularColorMap = null;
this._anisotropy = 0;
this._clearcoat = 0;
this._dispersion = 0;
this._iridescence = 0;
this._sheen = 0.0;
this._transmission = 0;
this.setValues( parameters );
}
get anisotropy() {
return this._anisotropy;
}
set anisotropy( value ) {
if ( this._anisotropy > 0 !== value > 0 ) {
this.version ++;
}
this._anisotropy = value;
}
get clearcoat() {
return this._clearcoat;
}
set clearcoat( value ) {
if ( this._clearcoat > 0 !== value > 0 ) {
this.version ++;
}
this._clearcoat = value;
}
get iridescence() {
return this._iridescence;
}
set iridescence( value ) {
if ( this._iridescence > 0 !== value > 0 ) {
this.version ++;
}
this._iridescence = value;
}
get dispersion() {
return this._dispersion;
}
set dispersion( value ) {
if ( this._dispersion > 0 !== value > 0 ) {
this.version ++;
}
this._dispersion = value;
}
get sheen() {
return this._sheen;
}
set sheen( value ) {
if ( this._sheen > 0 !== value > 0 ) {
this.version ++;
}
this._sheen = value;
}
get transmission() {
return this._transmission;
}
set transmission( value ) {
if ( this._transmission > 0 !== value > 0 ) {
this.version ++;
}
this._transmission = value;
}
copy( source ) {
super.copy( source );
this.defines = {
'STANDARD': '',
'PHYSICAL': ''
};
this.anisotropy = source.anisotropy;
this.anisotropyRotation = source.anisotropyRotation;
this.anisotropyMap = source.anisotropyMap;
this.clearcoat = source.clearcoat;
this.clearcoatMap = source.clearcoatMap;
this.clearcoatRoughness = source.clearcoatRoughness;
this.clearcoatRoughnessMap = source.clearcoatRoughnessMap;
this.clearcoatNormalMap = source.clearcoatNormalMap;
this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
this.dispersion = source.dispersion;
this.ior = source.ior;
this.iridescence = source.iridescence;
this.iridescenceMap = source.iridescenceMap;
this.iridescenceIOR = source.iridescenceIOR;
this.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ];
this.iridescenceThicknessMap = source.iridescenceThicknessMap;
this.sheen = source.sheen;
this.sheenColor.copy( source.sheenColor );
this.sheenColorMap = source.sheenColorMap;
this.sheenRoughness = source.sheenRoughness;
this.sheenRoughnessMap = source.sheenRoughnessMap;
this.transmission = source.transmission;
this.transmissionMap = source.transmissionMap;
this.thickness = source.thickness;
this.thicknessMap = source.thicknessMap;
this.attenuationDistance = source.attenuationDistance;
this.attenuationColor.copy( source.attenuationColor );
this.specularIntensity = source.specularIntensity;
this.specularIntensityMap = source.specularIntensityMap;
this.specularColor.copy( source.specularColor );
this.specularColorMap = source.specularColorMap;
return this;
}
}
export { MeshPhysicalMaterial };
+127
View File
@@ -0,0 +1,127 @@
import { TangentSpaceNormalMap } from '../constants.js';
import { Material } from './Material.js';
import { Vector2 } from '../math/Vector2.js';
import { Color } from '../math/Color.js';
import { Euler } from '../math/Euler.js';
class MeshStandardMaterial extends Material {
constructor( parameters ) {
super();
this.isMeshStandardMaterial = true;
this.type = 'MeshStandardMaterial';
this.defines = { 'STANDARD': '' };
this.color = new Color( 0xffffff ); // diffuse
this.roughness = 1.0;
this.metalness = 0.0;
this.map = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.emissive = new Color( 0x000000 );
this.emissiveIntensity = 1.0;
this.emissiveMap = null;
this.bumpMap = null;
this.bumpScale = 1;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.roughnessMap = null;
this.metalnessMap = null;
this.alphaMap = null;
this.envMap = null;
this.envMapRotation = new Euler();
this.envMapIntensity = 1.0;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.flatShading = false;
this.fog = true;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.defines = { 'STANDARD': '' };
this.color.copy( source.color );
this.roughness = source.roughness;
this.metalness = source.metalness;
this.map = source.map;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.emissive.copy( source.emissive );
this.emissiveMap = source.emissiveMap;
this.emissiveIntensity = source.emissiveIntensity;
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.roughnessMap = source.roughnessMap;
this.metalnessMap = source.metalnessMap;
this.alphaMap = source.alphaMap;
this.envMap = source.envMap;
this.envMapRotation.copy( source.envMapRotation );
this.envMapIntensity = source.envMapIntensity;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.flatShading = source.flatShading;
this.fog = source.fog;
return this;
}
}
export { MeshStandardMaterial };
+102
View File
@@ -0,0 +1,102 @@
import { TangentSpaceNormalMap } from '../constants.js';
import { Material } from './Material.js';
import { Vector2 } from '../math/Vector2.js';
import { Color } from '../math/Color.js';
class MeshToonMaterial extends Material {
constructor( parameters ) {
super();
this.isMeshToonMaterial = true;
this.defines = { 'TOON': '' };
this.type = 'MeshToonMaterial';
this.color = new Color( 0xffffff );
this.map = null;
this.gradientMap = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.emissive = new Color( 0x000000 );
this.emissiveIntensity = 1.0;
this.emissiveMap = null;
this.bumpMap = null;
this.bumpScale = 1;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.alphaMap = null;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.fog = true;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.gradientMap = source.gradientMap;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.emissive.copy( source.emissive );
this.emissiveMap = source.emissiveMap;
this.emissiveIntensity = source.emissiveIntensity;
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.alphaMap = source.alphaMap;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.fog = source.fog;
return this;
}
}
export { MeshToonMaterial };
+50
View File
@@ -0,0 +1,50 @@
import { Material } from './Material.js';
import { Color } from '../math/Color.js';
class PointsMaterial extends Material {
constructor( parameters ) {
super();
this.isPointsMaterial = true;
this.type = 'PointsMaterial';
this.color = new Color( 0xffffff );
this.map = null;
this.alphaMap = null;
this.size = 1;
this.sizeAttenuation = true;
this.fog = true;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.alphaMap = source.alphaMap;
this.size = source.size;
this.sizeAttenuation = source.sizeAttenuation;
this.fog = source.fog;
return this;
}
}
export { PointsMaterial };
+17
View File
@@ -0,0 +1,17 @@
import { ShaderMaterial } from './ShaderMaterial.js';
class RawShaderMaterial extends ShaderMaterial {
constructor( parameters ) {
super( parameters );
this.isRawShaderMaterial = true;
this.type = 'RawShaderMaterial';
}
}
export { RawShaderMaterial };
+185
View File
@@ -0,0 +1,185 @@
import { Material } from './Material.js';
import { cloneUniforms, cloneUniformsGroups } from '../renderers/shaders/UniformsUtils.js';
import default_vertex from '../renderers/shaders/ShaderChunk/default_vertex.glsl.js';
import default_fragment from '../renderers/shaders/ShaderChunk/default_fragment.glsl.js';
class ShaderMaterial extends Material {
constructor( parameters ) {
super();
this.isShaderMaterial = true;
this.type = 'ShaderMaterial';
this.defines = {};
this.uniforms = {};
this.uniformsGroups = [];
this.vertexShader = default_vertex;
this.fragmentShader = default_fragment;
this.linewidth = 1;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.fog = false; // set to use scene fog
this.lights = false; // set to use scene lights
this.clipping = false; // set to use user-defined clipping planes
this.forceSinglePass = true;
this.extensions = {
clipCullDistance: false, // set to use vertex shader clipping
multiDraw: false // set to use vertex shader multi_draw / enable gl_DrawID
};
// When rendered geometry doesn't include these attributes but the material does,
// use these default values in WebGL. This avoids errors when buffer data is missing.
this.defaultAttributeValues = {
'color': [ 1, 1, 1 ],
'uv': [ 0, 0 ],
'uv1': [ 0, 0 ]
};
this.index0AttributeName = undefined;
this.uniformsNeedUpdate = false;
this.glslVersion = null;
if ( parameters !== undefined ) {
this.setValues( parameters );
}
}
copy( source ) {
super.copy( source );
this.fragmentShader = source.fragmentShader;
this.vertexShader = source.vertexShader;
this.uniforms = cloneUniforms( source.uniforms );
this.uniformsGroups = cloneUniformsGroups( source.uniformsGroups );
this.defines = Object.assign( {}, source.defines );
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.fog = source.fog;
this.lights = source.lights;
this.clipping = source.clipping;
this.extensions = Object.assign( {}, source.extensions );
this.glslVersion = source.glslVersion;
return this;
}
toJSON( meta ) {
const data = super.toJSON( meta );
data.glslVersion = this.glslVersion;
data.uniforms = {};
for ( const name in this.uniforms ) {
const uniform = this.uniforms[ name ];
const value = uniform.value;
if ( value && value.isTexture ) {
data.uniforms[ name ] = {
type: 't',
value: value.toJSON( meta ).uuid
};
} else if ( value && value.isColor ) {
data.uniforms[ name ] = {
type: 'c',
value: value.getHex()
};
} else if ( value && value.isVector2 ) {
data.uniforms[ name ] = {
type: 'v2',
value: value.toArray()
};
} else if ( value && value.isVector3 ) {
data.uniforms[ name ] = {
type: 'v3',
value: value.toArray()
};
} else if ( value && value.isVector4 ) {
data.uniforms[ name ] = {
type: 'v4',
value: value.toArray()
};
} else if ( value && value.isMatrix3 ) {
data.uniforms[ name ] = {
type: 'm3',
value: value.toArray()
};
} else if ( value && value.isMatrix4 ) {
data.uniforms[ name ] = {
type: 'm4',
value: value.toArray()
};
} else {
data.uniforms[ name ] = {
value: value
};
// note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
}
}
if ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;
data.vertexShader = this.vertexShader;
data.fragmentShader = this.fragmentShader;
data.lights = this.lights;
data.clipping = this.clipping;
const extensions = {};
for ( const key in this.extensions ) {
if ( this.extensions[ key ] === true ) extensions[ key ] = true;
}
if ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;
return data;
}
}
export { ShaderMaterial };
+37
View File
@@ -0,0 +1,37 @@
import { Material } from './Material.js';
import { Color } from '../math/Color.js';
class ShadowMaterial extends Material {
constructor( parameters ) {
super();
this.isShadowMaterial = true;
this.type = 'ShadowMaterial';
this.color = new Color( 0x000000 );
this.transparent = true;
this.fog = true;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.fog = source.fog;
return this;
}
}
export { ShadowMaterial };
+54
View File
@@ -0,0 +1,54 @@
import { Material } from './Material.js';
import { Color } from '../math/Color.js';
class SpriteMaterial extends Material {
constructor( parameters ) {
super();
this.isSpriteMaterial = true;
this.type = 'SpriteMaterial';
this.color = new Color( 0xffffff );
this.map = null;
this.alphaMap = null;
this.rotation = 0;
this.sizeAttenuation = true;
this.transparent = true;
this.fog = true;
this.setValues( parameters );
}
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.alphaMap = source.alphaMap;
this.rotation = source.rotation;
this.sizeAttenuation = source.sizeAttenuation;
this.fog = source.fog;
return this;
}
}
export { SpriteMaterial };
+156
View File
@@ -0,0 +1,156 @@
import NodeMaterial from './NodeMaterial.js';
import { attribute } from '../../nodes/core/AttributeNode.js';
import { cameraProjectionMatrix } from '../../nodes/accessors/Camera.js';
import { materialColor, materialOpacity, materialPointWidth } from '../../nodes/accessors/MaterialNode.js'; // or should this be a property, instead?
import { modelViewMatrix } from '../../nodes/accessors/ModelNode.js';
import { positionGeometry } from '../../nodes/accessors/Position.js';
import { smoothstep, lengthSq } from '../../nodes/math/MathNode.js';
import { Fn, vec4, float } from '../../nodes/tsl/TSLBase.js';
import { uv } from '../../nodes/accessors/UV.js';
import { viewport } from '../../nodes/display/ScreenNode.js';
import { PointsMaterial } from '../PointsMaterial.js';
const _defaultValues = /*@__PURE__*/ new PointsMaterial();
class InstancedPointsNodeMaterial extends NodeMaterial {
static get type() {
return 'InstancedPointsNodeMaterial';
}
constructor( params = {} ) {
super();
this.lights = false;
this.useAlphaToCoverage = true;
this.useColor = params.vertexColors;
this.pointWidth = 1;
this.pointColorNode = null;
this.pointWidthNode = null;
this.setDefaultValues( _defaultValues );
this.setValues( params );
}
setup( builder ) {
this.setupShaders( builder );
super.setup( builder );
}
setupShaders( { renderer } ) {
const useAlphaToCoverage = this.alphaToCoverage;
const useColor = this.useColor;
this.vertexNode = Fn( () => {
const instancePosition = attribute( 'instancePosition' ).xyz;
// camera space
const mvPos = vec4( modelViewMatrix.mul( vec4( instancePosition, 1.0 ) ) );
const aspect = viewport.z.div( viewport.w );
// clip space
const clipPos = cameraProjectionMatrix.mul( mvPos );
// offset in ndc space
const offset = positionGeometry.xy.toVar();
offset.mulAssign( this.pointWidthNode ? this.pointWidthNode : materialPointWidth );
offset.assign( offset.div( viewport.z ) );
offset.y.assign( offset.y.mul( aspect ) );
// back to clip space
offset.assign( offset.mul( clipPos.w ) );
//clipPos.xy += offset;
clipPos.addAssign( vec4( offset, 0, 0 ) );
return clipPos;
} )();
this.fragmentNode = Fn( () => {
const alpha = float( 1 ).toVar();
const len2 = lengthSq( uv().mul( 2 ).sub( 1 ) );
if ( useAlphaToCoverage && renderer.samples > 1 ) {
const dlen = float( len2.fwidth() ).toVar();
alpha.assign( smoothstep( dlen.oneMinus(), dlen.add( 1 ), len2 ).oneMinus() );
} else {
len2.greaterThan( 1.0 ).discard();
}
let pointColorNode;
if ( this.pointColorNode ) {
pointColorNode = this.pointColorNode;
} else {
if ( useColor ) {
const instanceColor = attribute( 'instanceColor' );
pointColorNode = instanceColor.mul( materialColor );
} else {
pointColorNode = materialColor;
}
}
alpha.mulAssign( materialOpacity );
return vec4( pointColorNode, alpha );
} )();
}
get alphaToCoverage() {
return this.useAlphaToCoverage;
}
set alphaToCoverage( value ) {
if ( this.useAlphaToCoverage !== value ) {
this.useAlphaToCoverage = value;
this.needsUpdate = true;
}
}
}
export default InstancedPointsNodeMaterial;
+456
View File
@@ -0,0 +1,456 @@
import NodeMaterial from './NodeMaterial.js';
import { varyingProperty } from '../../nodes/core/PropertyNode.js';
import { attribute } from '../../nodes/core/AttributeNode.js';
import { cameraProjectionMatrix } from '../../nodes/accessors/Camera.js';
import { materialColor, materialLineScale, materialLineDashSize, materialLineGapSize, materialLineDashOffset, materialLineWidth, materialOpacity } from '../../nodes/accessors/MaterialNode.js';
import { modelViewMatrix } from '../../nodes/accessors/ModelNode.js';
import { positionGeometry } from '../../nodes/accessors/Position.js';
import { mix, smoothstep } from '../../nodes/math/MathNode.js';
import { Fn, float, vec2, vec3, vec4, If } from '../../nodes/tsl/TSLBase.js';
import { uv } from '../../nodes/accessors/UV.js';
import { viewport } from '../../nodes/display/ScreenNode.js';
import { dashSize, gapSize } from '../../nodes/core/PropertyNode.js';
import { viewportSharedTexture } from '../../nodes/display/ViewportSharedTextureNode.js';
import { LineDashedMaterial } from '../LineDashedMaterial.js';
import { NoBlending } from '../../constants.js';
const _defaultValues = /*@__PURE__*/ new LineDashedMaterial();
class Line2NodeMaterial extends NodeMaterial {
static get type() {
return 'Line2NodeMaterial';
}
constructor( params = {} ) {
super();
this.lights = false;
this.setDefaultValues( _defaultValues );
this.useAlphaToCoverage = true;
this.useColor = params.vertexColors;
this.useDash = params.dashed;
this.useWorldUnits = false;
this.dashOffset = 0;
this.lineWidth = 1;
this.lineColorNode = null;
this.offsetNode = null;
this.dashScaleNode = null;
this.dashSizeNode = null;
this.gapSizeNode = null;
this.blending = NoBlending;
this.setValues( params );
}
setup( builder ) {
this.setupShaders( builder );
super.setup( builder );
}
setupShaders( { renderer } ) {
const useAlphaToCoverage = this.alphaToCoverage;
const useColor = this.useColor;
const useDash = this.dashed;
const useWorldUnits = this.worldUnits;
const trimSegment = Fn( ( { start, end } ) => {
const a = cameraProjectionMatrix.element( 2 ).element( 2 ); // 3nd entry in 3th column
const b = cameraProjectionMatrix.element( 3 ).element( 2 ); // 3nd entry in 4th column
const nearEstimate = b.mul( - 0.5 ).div( a );
const alpha = nearEstimate.sub( start.z ).div( end.z.sub( start.z ) );
return vec4( mix( start.xyz, end.xyz, alpha ), end.w );
} ).setLayout( {
name: 'trimSegment',
type: 'vec4',
inputs: [
{ name: 'start', type: 'vec4' },
{ name: 'end', type: 'vec4' }
]
} );
this.vertexNode = Fn( () => {
const instanceStart = attribute( 'instanceStart' );
const instanceEnd = attribute( 'instanceEnd' );
// camera space
const start = vec4( modelViewMatrix.mul( vec4( instanceStart, 1.0 ) ) ).toVar( 'start' );
const end = vec4( modelViewMatrix.mul( vec4( instanceEnd, 1.0 ) ) ).toVar( 'end' );
if ( useDash ) {
const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale;
const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset;
const instanceDistanceStart = attribute( 'instanceDistanceStart' );
const instanceDistanceEnd = attribute( 'instanceDistanceEnd' );
let lineDistance = positionGeometry.y.lessThan( 0.5 ).select( dashScaleNode.mul( instanceDistanceStart ), dashScaleNode.mul( instanceDistanceEnd ) );
lineDistance = lineDistance.add( offsetNode );
varyingProperty( 'float', 'lineDistance' ).assign( lineDistance );
}
if ( useWorldUnits ) {
varyingProperty( 'vec3', 'worldStart' ).assign( start.xyz );
varyingProperty( 'vec3', 'worldEnd' ).assign( end.xyz );
}
const aspect = viewport.z.div( viewport.w );
// special case for perspective projection, and segments that terminate either in, or behind, the camera plane
// clearly the gpu firmware has a way of addressing this issue when projecting into ndc space
// but we need to perform ndc-space calculations in the shader, so we must address this issue directly
// perhaps there is a more elegant solution -- WestLangley
const perspective = cameraProjectionMatrix.element( 2 ).element( 3 ).equal( - 1.0 ); // 4th entry in the 3rd column
If( perspective, () => {
If( start.z.lessThan( 0.0 ).and( end.z.greaterThan( 0.0 ) ), () => {
end.assign( trimSegment( { start: start, end: end } ) );
} ).ElseIf( end.z.lessThan( 0.0 ).and( start.z.greaterThanEqual( 0.0 ) ), () => {
start.assign( trimSegment( { start: end, end: start } ) );
} );
} );
// clip space
const clipStart = cameraProjectionMatrix.mul( start );
const clipEnd = cameraProjectionMatrix.mul( end );
// ndc space
const ndcStart = clipStart.xyz.div( clipStart.w );
const ndcEnd = clipEnd.xyz.div( clipEnd.w );
// direction
const dir = ndcEnd.xy.sub( ndcStart.xy ).toVar();
// account for clip-space aspect ratio
dir.x.assign( dir.x.mul( aspect ) );
dir.assign( dir.normalize() );
const clip = vec4().toVar();
if ( useWorldUnits ) {
// get the offset direction as perpendicular to the view vector
const worldDir = end.xyz.sub( start.xyz ).normalize();
const tmpFwd = mix( start.xyz, end.xyz, 0.5 ).normalize();
const worldUp = worldDir.cross( tmpFwd ).normalize();
const worldFwd = worldDir.cross( worldUp );
const worldPos = varyingProperty( 'vec4', 'worldPos' );
worldPos.assign( positionGeometry.y.lessThan( 0.5 ).select( start, end ) );
// height offset
const hw = materialLineWidth.mul( 0.5 );
worldPos.addAssign( vec4( positionGeometry.x.lessThan( 0.0 ).select( worldUp.mul( hw ), worldUp.mul( hw ).negate() ), 0 ) );
// don't extend the line if we're rendering dashes because we
// won't be rendering the endcaps
if ( ! useDash ) {
// cap extension
worldPos.addAssign( vec4( positionGeometry.y.lessThan( 0.5 ).select( worldDir.mul( hw ).negate(), worldDir.mul( hw ) ), 0 ) );
// add width to the box
worldPos.addAssign( vec4( worldFwd.mul( hw ), 0 ) );
// endcaps
If( positionGeometry.y.greaterThan( 1.0 ).or( positionGeometry.y.lessThan( 0.0 ) ), () => {
worldPos.subAssign( vec4( worldFwd.mul( 2.0 ).mul( hw ), 0 ) );
} );
}
// project the worldpos
clip.assign( cameraProjectionMatrix.mul( worldPos ) );
// shift the depth of the projected points so the line
// segments overlap neatly
const clipPose = vec3().toVar();
clipPose.assign( positionGeometry.y.lessThan( 0.5 ).select( ndcStart, ndcEnd ) );
clip.z.assign( clipPose.z.mul( clip.w ) );
} else {
const offset = vec2( dir.y, dir.x.negate() ).toVar( 'offset' );
// undo aspect ratio adjustment
dir.x.assign( dir.x.div( aspect ) );
offset.x.assign( offset.x.div( aspect ) );
// sign flip
offset.assign( positionGeometry.x.lessThan( 0.0 ).select( offset.negate(), offset ) );
// endcaps
If( positionGeometry.y.lessThan( 0.0 ), () => {
offset.assign( offset.sub( dir ) );
} ).ElseIf( positionGeometry.y.greaterThan( 1.0 ), () => {
offset.assign( offset.add( dir ) );
} );
// adjust for linewidth
offset.assign( offset.mul( materialLineWidth ) );
// adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ...
offset.assign( offset.div( viewport.w ) );
// select end
clip.assign( positionGeometry.y.lessThan( 0.5 ).select( clipStart, clipEnd ) );
// back to clip space
offset.assign( offset.mul( clip.w ) );
clip.assign( clip.add( vec4( offset, 0, 0 ) ) );
}
return clip;
} )();
const closestLineToLine = Fn( ( { p1, p2, p3, p4 } ) => {
const p13 = p1.sub( p3 );
const p43 = p4.sub( p3 );
const p21 = p2.sub( p1 );
const d1343 = p13.dot( p43 );
const d4321 = p43.dot( p21 );
const d1321 = p13.dot( p21 );
const d4343 = p43.dot( p43 );
const d2121 = p21.dot( p21 );
const denom = d2121.mul( d4343 ).sub( d4321.mul( d4321 ) );
const numer = d1343.mul( d4321 ).sub( d1321.mul( d4343 ) );
const mua = numer.div( denom ).clamp();
const mub = d1343.add( d4321.mul( mua ) ).div( d4343 ).clamp();
return vec2( mua, mub );
} );
this.colorNode = Fn( () => {
const vUv = uv();
if ( useDash ) {
const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize;
const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize;
dashSize.assign( dashSizeNode );
gapSize.assign( gapSizeNode );
const vLineDistance = varyingProperty( 'float', 'lineDistance' );
vUv.y.lessThan( - 1.0 ).or( vUv.y.greaterThan( 1.0 ) ).discard(); // discard endcaps
vLineDistance.mod( dashSize.add( gapSize ) ).greaterThan( dashSize ).discard(); // todo - FIX
}
const alpha = float( 1 ).toVar( 'alpha' );
if ( useWorldUnits ) {
const worldStart = varyingProperty( 'vec3', 'worldStart' );
const worldEnd = varyingProperty( 'vec3', 'worldEnd' );
// Find the closest points on the view ray and the line segment
const rayEnd = varyingProperty( 'vec4', 'worldPos' ).xyz.normalize().mul( 1e5 );
const lineDir = worldEnd.sub( worldStart );
const params = closestLineToLine( { p1: worldStart, p2: worldEnd, p3: vec3( 0.0, 0.0, 0.0 ), p4: rayEnd } );
const p1 = worldStart.add( lineDir.mul( params.x ) );
const p2 = rayEnd.mul( params.y );
const delta = p1.sub( p2 );
const len = delta.length();
const norm = len.div( materialLineWidth );
if ( ! useDash ) {
if ( useAlphaToCoverage && renderer.samples > 1 ) {
const dnorm = norm.fwidth();
alpha.assign( smoothstep( dnorm.negate().add( 0.5 ), dnorm.add( 0.5 ), norm ).oneMinus() );
} else {
norm.greaterThan( 0.5 ).discard();
}
}
} else {
// round endcaps
if ( useAlphaToCoverage && renderer.samples > 1 ) {
const a = vUv.x;
const b = vUv.y.greaterThan( 0.0 ).select( vUv.y.sub( 1.0 ), vUv.y.add( 1.0 ) );
const len2 = a.mul( a ).add( b.mul( b ) );
const dlen = float( len2.fwidth() ).toVar( 'dlen' );
If( vUv.y.abs().greaterThan( 1.0 ), () => {
alpha.assign( smoothstep( dlen.oneMinus(), dlen.add( 1 ), len2 ).oneMinus() );
} );
} else {
If( vUv.y.abs().greaterThan( 1.0 ), () => {
const a = vUv.x;
const b = vUv.y.greaterThan( 0.0 ).select( vUv.y.sub( 1.0 ), vUv.y.add( 1.0 ) );
const len2 = a.mul( a ).add( b.mul( b ) );
len2.greaterThan( 1.0 ).discard();
} );
}
}
let lineColorNode;
if ( this.lineColorNode ) {
lineColorNode = this.lineColorNode;
} else {
if ( useColor ) {
const instanceColorStart = attribute( 'instanceColorStart' );
const instanceColorEnd = attribute( 'instanceColorEnd' );
const instanceColor = positionGeometry.y.lessThan( 0.5 ).select( instanceColorStart, instanceColorEnd );
lineColorNode = instanceColor.mul( materialColor );
} else {
lineColorNode = materialColor;
}
}
return vec4( lineColorNode, alpha );
} )();
if ( this.transparent ) {
const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity;
this.outputNode = vec4( this.colorNode.rgb.mul( opacityNode ).add( viewportSharedTexture().rgb.mul( opacityNode.oneMinus() ) ), this.colorNode.a );
}
}
get worldUnits() {
return this.useWorldUnits;
}
set worldUnits( value ) {
if ( this.useWorldUnits !== value ) {
this.useWorldUnits = value;
this.needsUpdate = true;
}
}
get dashed() {
return this.useDash;
}
set dashed( value ) {
if ( this.useDash !== value ) {
this.useDash = value;
this.needsUpdate = true;
}
}
get alphaToCoverage() {
return this.useAlphaToCoverage;
}
set alphaToCoverage( value ) {
if ( this.useAlphaToCoverage !== value ) {
this.useAlphaToCoverage = value;
this.needsUpdate = true;
}
}
}
export default Line2NodeMaterial;
+31
View File
@@ -0,0 +1,31 @@
import NodeMaterial from './NodeMaterial.js';
import { LineBasicMaterial } from '../LineBasicMaterial.js';
const _defaultValues = /*@__PURE__*/ new LineBasicMaterial();
class LineBasicNodeMaterial extends NodeMaterial {
static get type() {
return 'LineBasicNodeMaterial';
}
constructor( parameters ) {
super();
this.isLineBasicNodeMaterial = true;
this.lights = false;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
}
export default LineBasicNodeMaterial;
+59
View File
@@ -0,0 +1,59 @@
import NodeMaterial from './NodeMaterial.js';
import { attribute } from '../../nodes/core/AttributeNode.js';
import { materialLineDashOffset, materialLineDashSize, materialLineGapSize, materialLineScale } from '../../nodes/accessors/MaterialNode.js';
import { dashSize, gapSize } from '../../nodes/core/PropertyNode.js';
import { varying, float } from '../../nodes/tsl/TSLBase.js';
import { LineDashedMaterial } from '../LineDashedMaterial.js';
const _defaultValues = /*@__PURE__*/ new LineDashedMaterial();
class LineDashedNodeMaterial extends NodeMaterial {
static get type() {
return 'LineDashedNodeMaterial';
}
constructor( parameters ) {
super();
this.isLineDashedNodeMaterial = true;
this.lights = false;
this.setDefaultValues( _defaultValues );
this.dashOffset = 0;
this.offsetNode = null;
this.dashScaleNode = null;
this.dashSizeNode = null;
this.gapSizeNode = null;
this.setValues( parameters );
}
setupVariants() {
const offsetNode = this.offsetNode ? float( this.offsetNodeNode ) : materialLineDashOffset;
const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale;
const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize;
const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize;
dashSize.assign( dashSizeNode );
gapSize.assign( gapSizeNode );
const vLineDistance = varying( attribute( 'lineDistance' ).mul( dashScaleNode ) );
const vLineDistanceOffset = offsetNode ? vLineDistance.add( offsetNode ) : vLineDistance;
vLineDistanceOffset.mod( dashSize.add( gapSize ) ).greaterThan( dashSize ).discard();
}
}
export default LineDashedNodeMaterial;
+77
View File
@@ -0,0 +1,77 @@
import NodeMaterial from './NodeMaterial.js';
import { materialLightMap } from '../../nodes/accessors/MaterialNode.js';
import BasicEnvironmentNode from '../../nodes/lighting/BasicEnvironmentNode.js';
import BasicLightMapNode from '../../nodes/lighting/BasicLightMapNode.js';
import BasicLightingModel from '../../nodes/functions/BasicLightingModel.js';
import { normalView } from '../../nodes/accessors/Normal.js';
import { diffuseColor } from '../../nodes/core/PropertyNode.js';
import { MeshBasicMaterial } from '../MeshBasicMaterial.js';
const _defaultValues = /*@__PURE__*/ new MeshBasicMaterial();
class MeshBasicNodeMaterial extends NodeMaterial {
static get type() {
return 'MeshBasicNodeMaterial';
}
constructor( parameters ) {
super();
this.isMeshBasicNodeMaterial = true;
this.lights = true;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
setupNormal() {
return normalView; // see #28839
}
setupEnvironment( builder ) {
const envNode = super.setupEnvironment( builder );
return envNode ? new BasicEnvironmentNode( envNode ) : null;
}
setupLightMap( builder ) {
let node = null;
if ( builder.material.lightMap ) {
node = new BasicLightMapNode( materialLightMap );
}
return node;
}
setupOutgoingLight() {
return diffuseColor.rgb;
}
setupLightingModel() {
return new BasicLightingModel();
}
}
export default MeshBasicNodeMaterial;
+47
View File
@@ -0,0 +1,47 @@
import NodeMaterial from './NodeMaterial.js';
import BasicEnvironmentNode from '../../nodes/lighting/BasicEnvironmentNode.js';
import PhongLightingModel from '../../nodes/functions/PhongLightingModel.js';
import { MeshLambertMaterial } from '../MeshLambertMaterial.js';
const _defaultValues = /*@__PURE__*/ new MeshLambertMaterial();
class MeshLambertNodeMaterial extends NodeMaterial {
static get type() {
return 'MeshLambertNodeMaterial';
}
constructor( parameters ) {
super();
this.isMeshLambertNodeMaterial = true;
this.lights = true;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
setupEnvironment( builder ) {
const envNode = super.setupEnvironment( builder );
return envNode ? new BasicEnvironmentNode( envNode ) : null;
}
setupLightingModel( /*builder*/ ) {
return new PhongLightingModel( false ); // ( specular ) -> force lambert
}
}
export default MeshLambertNodeMaterial;
+57
View File
@@ -0,0 +1,57 @@
import NodeMaterial from './NodeMaterial.js';
import { materialReference } from '../../nodes/accessors/MaterialReferenceNode.js';
import { diffuseColor } from '../../nodes/core/PropertyNode.js';
import { vec3 } from '../../nodes/tsl/TSLBase.js';
import { mix } from '../../nodes/math/MathNode.js';
import { matcapUV } from '../../nodes/utils/MatcapUVNode.js';
import { MeshMatcapMaterial } from '../MeshMatcapMaterial.js';
const _defaultValues = /*@__PURE__*/ new MeshMatcapMaterial();
class MeshMatcapNodeMaterial extends NodeMaterial {
static get type() {
return 'MeshMatcapNodeMaterial';
}
constructor( parameters ) {
super();
this.lights = false;
this.isMeshMatcapNodeMaterial = true;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
setupVariants( builder ) {
const uv = matcapUV;
let matcapColor;
if ( builder.material.matcap ) {
matcapColor = materialReference( 'matcap', 'texture' ).context( { getUV: () => uv } );
} else {
matcapColor = vec3( mix( 0.2, 0.8, uv.y ) ); // default if matcap is missing
}
diffuseColor.rgb.mulAssign( matcapColor.rgb );
}
}
export default MeshMatcapNodeMaterial;
+44
View File
@@ -0,0 +1,44 @@
import NodeMaterial from './NodeMaterial.js';
import { diffuseColor } from '../../nodes/core/PropertyNode.js';
import { directionToColor } from '../../nodes/utils/Packing.js';
import { materialOpacity } from '../../nodes/accessors/MaterialNode.js';
import { transformedNormalView } from '../../nodes/accessors/Normal.js';
import { float, vec4 } from '../../nodes/tsl/TSLBase.js';
import { MeshNormalMaterial } from '../MeshNormalMaterial.js';
const _defaultValues = /*@__PURE__*/ new MeshNormalMaterial();
class MeshNormalNodeMaterial extends NodeMaterial {
static get type() {
return 'MeshNormalNodeMaterial';
}
constructor( parameters ) {
super();
this.lights = false;
this.isMeshNormalNodeMaterial = true;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
setupDiffuseColor() {
const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity;
diffuseColor.assign( vec4( directionToColor( transformedNormalView ), opacityNode ) );
}
}
export default MeshNormalNodeMaterial;
+78
View File
@@ -0,0 +1,78 @@
import NodeMaterial from './NodeMaterial.js';
import { shininess, specularColor } from '../../nodes/core/PropertyNode.js';
import { materialShininess, materialSpecular } from '../../nodes/accessors/MaterialNode.js';
import { float } from '../../nodes/tsl/TSLBase.js';
import BasicEnvironmentNode from '../../nodes/lighting/BasicEnvironmentNode.js';
import PhongLightingModel from '../../nodes/functions/PhongLightingModel.js';
import { MeshPhongMaterial } from '../MeshPhongMaterial.js';
const _defaultValues = /*@__PURE__*/ new MeshPhongMaterial();
class MeshPhongNodeMaterial extends NodeMaterial {
static get type() {
return 'MeshPhongNodeMaterial';
}
constructor( parameters ) {
super();
this.isMeshPhongNodeMaterial = true;
this.lights = true;
this.shininessNode = null;
this.specularNode = null;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
setupEnvironment( builder ) {
const envNode = super.setupEnvironment( builder );
return envNode ? new BasicEnvironmentNode( envNode ) : null;
}
setupLightingModel( /*builder*/ ) {
return new PhongLightingModel();
}
setupVariants() {
// SHININESS
const shininessNode = ( this.shininessNode ? float( this.shininessNode ) : materialShininess ).max( 1e-4 ); // to prevent pow( 0.0, 0.0 )
shininess.assign( shininessNode );
// SPECULAR COLOR
const specularNode = this.specularNode || materialSpecular;
specularColor.assign( specularNode );
}
copy( source ) {
this.shininessNode = source.shininessNode;
this.specularNode = source.specularNode;
return super.copy( source );
}
}
export default MeshPhongNodeMaterial;
+248
View File
@@ -0,0 +1,248 @@
import { clearcoat, clearcoatRoughness, sheen, sheenRoughness, iridescence, iridescenceIOR, iridescenceThickness, specularColor, specularF90, diffuseColor, metalness, roughness, anisotropy, alphaT, anisotropyT, anisotropyB, ior, transmission, thickness, attenuationDistance, attenuationColor, dispersion } from '../../nodes/core/PropertyNode.js';
import { materialClearcoat, materialClearcoatRoughness, materialClearcoatNormal, materialSheen, materialSheenRoughness, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialSpecularIntensity, materialSpecularColor, materialAnisotropy, materialIOR, materialTransmission, materialThickness, materialAttenuationDistance, materialAttenuationColor, materialDispersion } from '../../nodes/accessors/MaterialNode.js';
import { float, vec2, vec3, If } from '../../nodes/tsl/TSLBase.js';
import getRoughness from '../../nodes/functions/material/getRoughness.js';
import { TBNViewMatrix } from '../../nodes/accessors/AccessorsUtils.js';
import PhysicalLightingModel from '../../nodes/functions/PhysicalLightingModel.js';
import MeshStandardNodeMaterial from './MeshStandardNodeMaterial.js';
import { mix, pow2, min } from '../../nodes/math/MathNode.js';
import { MeshPhysicalMaterial } from '../MeshPhysicalMaterial.js';
const _defaultValues = /*@__PURE__*/ new MeshPhysicalMaterial();
class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial {
static get type() {
return 'MeshPhysicalNodeMaterial';
}
constructor( parameters ) {
super();
this.isMeshPhysicalNodeMaterial = true;
this.clearcoatNode = null;
this.clearcoatRoughnessNode = null;
this.clearcoatNormalNode = null;
this.sheenNode = null;
this.sheenRoughnessNode = null;
this.iridescenceNode = null;
this.iridescenceIORNode = null;
this.iridescenceThicknessNode = null;
this.specularIntensityNode = null;
this.specularColorNode = null;
this.iorNode = null;
this.transmissionNode = null;
this.thicknessNode = null;
this.attenuationDistanceNode = null;
this.attenuationColorNode = null;
this.dispersionNode = null;
this.anisotropyNode = null;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
get useClearcoat() {
return this.clearcoat > 0 || this.clearcoatNode !== null;
}
get useIridescence() {
return this.iridescence > 0 || this.iridescenceNode !== null;
}
get useSheen() {
return this.sheen > 0 || this.sheenNode !== null;
}
get useAnisotropy() {
return this.anisotropy > 0 || this.anisotropyNode !== null;
}
get useTransmission() {
return this.transmission > 0 || this.transmissionNode !== null;
}
get useDispersion() {
return this.dispersion > 0 || this.dispersionNode !== null;
}
setupSpecular() {
const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR;
ior.assign( iorNode );
specularColor.assign( mix( min( pow2( ior.sub( 1.0 ).div( ior.add( 1.0 ) ) ).mul( materialSpecularColor ), vec3( 1.0 ) ).mul( materialSpecularIntensity ), diffuseColor.rgb, metalness ) );
specularF90.assign( mix( materialSpecularIntensity, 1.0, metalness ) );
}
setupLightingModel( /*builder*/ ) {
return new PhysicalLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useAnisotropy, this.useTransmission, this.useDispersion );
}
setupVariants( builder ) {
super.setupVariants( builder );
// CLEARCOAT
if ( this.useClearcoat ) {
const clearcoatNode = this.clearcoatNode ? float( this.clearcoatNode ) : materialClearcoat;
const clearcoatRoughnessNode = this.clearcoatRoughnessNode ? float( this.clearcoatRoughnessNode ) : materialClearcoatRoughness;
clearcoat.assign( clearcoatNode );
clearcoatRoughness.assign( getRoughness( { roughness: clearcoatRoughnessNode } ) );
}
// SHEEN
if ( this.useSheen ) {
const sheenNode = this.sheenNode ? vec3( this.sheenNode ) : materialSheen;
const sheenRoughnessNode = this.sheenRoughnessNode ? float( this.sheenRoughnessNode ) : materialSheenRoughness;
sheen.assign( sheenNode );
sheenRoughness.assign( sheenRoughnessNode );
}
// IRIDESCENCE
if ( this.useIridescence ) {
const iridescenceNode = this.iridescenceNode ? float( this.iridescenceNode ) : materialIridescence;
const iridescenceIORNode = this.iridescenceIORNode ? float( this.iridescenceIORNode ) : materialIridescenceIOR;
const iridescenceThicknessNode = this.iridescenceThicknessNode ? float( this.iridescenceThicknessNode ) : materialIridescenceThickness;
iridescence.assign( iridescenceNode );
iridescenceIOR.assign( iridescenceIORNode );
iridescenceThickness.assign( iridescenceThicknessNode );
}
// ANISOTROPY
if ( this.useAnisotropy ) {
const anisotropyV = ( this.anisotropyNode ? vec2( this.anisotropyNode ) : materialAnisotropy ).toVar();
anisotropy.assign( anisotropyV.length() );
If( anisotropy.equal( 0.0 ), () => {
anisotropyV.assign( vec2( 1.0, 0.0 ) );
} ).Else( () => {
anisotropyV.divAssign( vec2( anisotropy ) );
anisotropy.assign( anisotropy.saturate() );
} );
// Roughness along the anisotropy bitangent is the material roughness, while the tangent roughness increases with anisotropy.
alphaT.assign( anisotropy.pow2().mix( roughness.pow2(), 1.0 ) );
anisotropyT.assign( TBNViewMatrix[ 0 ].mul( anisotropyV.x ).add( TBNViewMatrix[ 1 ].mul( anisotropyV.y ) ) );
anisotropyB.assign( TBNViewMatrix[ 1 ].mul( anisotropyV.x ).sub( TBNViewMatrix[ 0 ].mul( anisotropyV.y ) ) );
}
// TRANSMISSION
if ( this.useTransmission ) {
const transmissionNode = this.transmissionNode ? float( this.transmissionNode ) : materialTransmission;
const thicknessNode = this.thicknessNode ? float( this.thicknessNode ) : materialThickness;
const attenuationDistanceNode = this.attenuationDistanceNode ? float( this.attenuationDistanceNode ) : materialAttenuationDistance;
const attenuationColorNode = this.attenuationColorNode ? vec3( this.attenuationColorNode ) : materialAttenuationColor;
transmission.assign( transmissionNode );
thickness.assign( thicknessNode );
attenuationDistance.assign( attenuationDistanceNode );
attenuationColor.assign( attenuationColorNode );
if ( this.useDispersion ) {
const dispersionNode = this.dispersionNode ? float( this.dispersionNode ) : materialDispersion;
dispersion.assign( dispersionNode );
}
}
}
setupClearcoatNormal() {
return this.clearcoatNormalNode ? vec3( this.clearcoatNormalNode ) : materialClearcoatNormal;
}
setup( builder ) {
builder.context.setupClearcoatNormal = () => this.setupClearcoatNormal( builder );
super.setup( builder );
}
copy( source ) {
this.clearcoatNode = source.clearcoatNode;
this.clearcoatRoughnessNode = source.clearcoatRoughnessNode;
this.clearcoatNormalNode = source.clearcoatNormalNode;
this.sheenNode = source.sheenNode;
this.sheenRoughnessNode = source.sheenRoughnessNode;
this.iridescenceNode = source.iridescenceNode;
this.iridescenceIORNode = source.iridescenceIORNode;
this.iridescenceThicknessNode = source.iridescenceThicknessNode;
this.specularIntensityNode = source.specularIntensityNode;
this.specularColorNode = source.specularColorNode;
this.transmissionNode = source.transmissionNode;
this.thicknessNode = source.thicknessNode;
this.attenuationDistanceNode = source.attenuationDistanceNode;
this.attenuationColorNode = source.attenuationColorNode;
this.dispersionNode = source.dispersionNode;
this.anisotropyNode = source.anisotropyNode;
return super.copy( source );
}
}
export default MeshPhysicalNodeMaterial;
+87
View File
@@ -0,0 +1,87 @@
import MeshPhysicalNodeMaterial from './MeshPhysicalNodeMaterial.js';
import PhysicalLightingModel from '../../nodes/functions/PhysicalLightingModel.js';
import { transformedNormalView } from '../../nodes/accessors/Normal.js';
import { positionViewDirection } from '../../nodes/accessors/Position.js';
import { float, vec3 } from '../../nodes/tsl/TSLBase.js';
class SSSLightingModel extends PhysicalLightingModel {
constructor( useClearcoat, useSheen, useIridescence, useSSS ) {
super( useClearcoat, useSheen, useIridescence );
this.useSSS = useSSS;
}
direct( { lightDirection, lightColor, reflectedLight }, stack, builder ) {
if ( this.useSSS === true ) {
const material = builder.material;
const { thicknessColorNode, thicknessDistortionNode, thicknessAmbientNode, thicknessAttenuationNode, thicknessPowerNode, thicknessScaleNode } = material;
const scatteringHalf = lightDirection.add( transformedNormalView.mul( thicknessDistortionNode ) ).normalize();
const scatteringDot = float( positionViewDirection.dot( scatteringHalf.negate() ).saturate().pow( thicknessPowerNode ).mul( thicknessScaleNode ) );
const scatteringIllu = vec3( scatteringDot.add( thicknessAmbientNode ).mul( thicknessColorNode ) );
reflectedLight.directDiffuse.addAssign( scatteringIllu.mul( thicknessAttenuationNode.mul( lightColor ) ) );
}
super.direct( { lightDirection, lightColor, reflectedLight }, stack, builder );
}
}
class MeshSSSNodeMaterial extends MeshPhysicalNodeMaterial {
static get type() {
return 'MeshSSSNodeMaterial';
}
constructor( parameters ) {
super( parameters );
this.thicknessColorNode = null;
this.thicknessDistortionNode = float( 0.1 );
this.thicknessAmbientNode = float( 0.0 );
this.thicknessAttenuationNode = float( .1 );
this.thicknessPowerNode = float( 2.0 );
this.thicknessScaleNode = float( 10.0 );
}
get useSSS() {
return this.thicknessColorNode !== null;
}
setupLightingModel( /*builder*/ ) {
return new SSSLightingModel( this.useClearcoat, this.useSheen, this.useIridescence, this.useSSS );
}
copy( source ) {
this.thicknessColorNode = source.thicknessColorNode;
this.thicknessDistortionNode = source.thicknessDistortionNode;
this.thicknessAmbientNode = source.thicknessAmbientNode;
this.thicknessAttenuationNode = source.thicknessAttenuationNode;
this.thicknessPowerNode = source.thicknessPowerNode;
this.thicknessScaleNode = source.thicknessScaleNode;
return super.copy( source );
}
}
export default MeshSSSNodeMaterial;
+108
View File
@@ -0,0 +1,108 @@
import NodeMaterial from './NodeMaterial.js';
import { diffuseColor, metalness, roughness, specularColor, specularF90 } from '../../nodes/core/PropertyNode.js';
import { mix } from '../../nodes/math/MathNode.js';
import { materialRoughness, materialMetalness } from '../../nodes/accessors/MaterialNode.js';
import getRoughness from '../../nodes/functions/material/getRoughness.js';
import PhysicalLightingModel from '../../nodes/functions/PhysicalLightingModel.js';
import EnvironmentNode from '../../nodes/lighting/EnvironmentNode.js';
import { float, vec3, vec4 } from '../../nodes/tsl/TSLBase.js';
import { MeshStandardMaterial } from '../MeshStandardMaterial.js';
const _defaultValues = /*@__PURE__*/ new MeshStandardMaterial();
class MeshStandardNodeMaterial extends NodeMaterial {
static get type() {
return 'MeshStandardNodeMaterial';
}
constructor( parameters ) {
super();
this.isMeshStandardNodeMaterial = true;
this.lights = true;
this.emissiveNode = null;
this.metalnessNode = null;
this.roughnessNode = null;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
setupEnvironment( builder ) {
let envNode = super.setupEnvironment( builder );
if ( envNode === null && builder.environmentNode ) {
envNode = builder.environmentNode;
}
return envNode ? new EnvironmentNode( envNode ) : null;
}
setupLightingModel( /*builder*/ ) {
return new PhysicalLightingModel();
}
setupSpecular() {
const specularColorNode = mix( vec3( 0.04 ), diffuseColor.rgb, metalness );
specularColor.assign( specularColorNode );
specularF90.assign( 1.0 );
}
setupVariants() {
// METALNESS
const metalnessNode = this.metalnessNode ? float( this.metalnessNode ) : materialMetalness;
metalness.assign( metalnessNode );
// ROUGHNESS
let roughnessNode = this.roughnessNode ? float( this.roughnessNode ) : materialRoughness;
roughnessNode = getRoughness( { roughness: roughnessNode } );
roughness.assign( roughnessNode );
// SPECULAR COLOR
this.setupSpecular();
// DIFFUSE COLOR
diffuseColor.assign( vec4( diffuseColor.rgb.mul( metalnessNode.oneMinus() ), diffuseColor.a ) );
}
copy( source ) {
this.emissiveNode = source.emissiveNode;
this.metalnessNode = source.metalnessNode;
this.roughnessNode = source.roughnessNode;
return super.copy( source );
}
}
export default MeshStandardNodeMaterial;
+38
View File
@@ -0,0 +1,38 @@
import NodeMaterial from './NodeMaterial.js';
import ToonLightingModel from '../../nodes/functions/ToonLightingModel.js';
import { MeshToonMaterial } from '../MeshToonMaterial.js';
const _defaultValues = /*@__PURE__*/ new MeshToonMaterial();
class MeshToonNodeMaterial extends NodeMaterial {
static get type() {
return 'MeshToonNodeMaterial';
}
constructor( parameters ) {
super();
this.isMeshToonNodeMaterial = true;
this.lights = true;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
setupLightingModel( /*builder*/ ) {
return new ToonLightingModel();
}
}
export default MeshToonNodeMaterial;
+712
View File
@@ -0,0 +1,712 @@
import { Material } from '../Material.js';
import { NormalBlending } from '../../constants.js';
import { getNodeChildren, getCacheKey } from '../../nodes/core/NodeUtils.js';
import { attribute } from '../../nodes/core/AttributeNode.js';
import { output, diffuseColor, emissive, varyingProperty } from '../../nodes/core/PropertyNode.js';
import { materialAlphaTest, materialColor, materialOpacity, materialEmissive, materialNormal, materialLightMap, materialAOMap } from '../../nodes/accessors/MaterialNode.js';
import { modelViewProjection } from '../../nodes/accessors/ModelViewProjectionNode.js';
import { normalLocal } from '../../nodes/accessors/Normal.js';
import { instancedMesh } from '../../nodes/accessors/InstancedMeshNode.js';
import { batch } from '../../nodes/accessors/BatchNode.js';
import { materialReference } from '../../nodes/accessors/MaterialReferenceNode.js';
import { positionLocal, positionView } from '../../nodes/accessors/Position.js';
import { skinningReference } from '../../nodes/accessors/SkinningNode.js';
import { morphReference } from '../../nodes/accessors/MorphNode.js';
import { mix } from '../../nodes/math/MathNode.js';
import { float, vec3, vec4 } from '../../nodes/tsl/TSLBase.js';
import AONode from '../../nodes/lighting/AONode.js';
import { lightingContext } from '../../nodes/lighting/LightingContextNode.js';
import IrradianceNode from '../../nodes/lighting/IrradianceNode.js';
import { depth, viewZToLogarithmicDepth, viewZToOrthographicDepth } from '../../nodes/display/ViewportDepthNode.js';
import { cameraFar, cameraNear } from '../../nodes/accessors/Camera.js';
import { clipping, clippingAlpha, hardwareClipping } from '../../nodes/accessors/ClippingNode.js';
import NodeMaterialObserver from './manager/NodeMaterialObserver.js';
import getAlphaHashThreshold from '../../nodes/functions/material/getAlphaHashThreshold.js';
class NodeMaterial extends Material {
static get type() {
return 'NodeMaterial';
}
get type() {
return this.constructor.type;
}
set type( _value ) { /* */ }
constructor() {
super();
this.isNodeMaterial = true;
this.forceSinglePass = false;
this.fog = true;
this.lights = false;
this.hardwareClipping = false;
this.lightsNode = null;
this.envNode = null;
this.aoNode = null;
this.colorNode = null;
this.normalNode = null;
this.opacityNode = null;
this.backdropNode = null;
this.backdropAlphaNode = null;
this.alphaTestNode = null;
this.positionNode = null;
this.geometryNode = null;
this.depthNode = null;
this.shadowPositionNode = null;
this.receivedShadowNode = null;
this.castShadowNode = null;
this.outputNode = null;
this.mrtNode = null;
this.fragmentNode = null;
this.vertexNode = null;
}
customProgramCacheKey() {
return this.type + getCacheKey( this );
}
build( builder ) {
this.setup( builder );
}
setupObserver( builder ) {
return new NodeMaterialObserver( builder );
}
setup( builder ) {
builder.context.setupNormal = () => this.setupNormal( builder );
const renderer = builder.renderer;
const renderTarget = renderer.getRenderTarget();
// < VERTEX STAGE >
builder.addStack();
builder.stack.outputNode = this.vertexNode || this.setupPosition( builder );
if ( this.geometryNode !== null ) {
builder.stack.outputNode = builder.stack.outputNode.bypass( this.geometryNode );
}
builder.addFlow( 'vertex', builder.removeStack() );
// < FRAGMENT STAGE >
builder.addStack();
let resultNode;
const clippingNode = this.setupClipping( builder );
if ( this.depthWrite === true ) {
// only write depth if depth buffer is configured
if ( renderTarget !== null ) {
if ( renderTarget.depthBuffer === true ) this.setupDepth( builder );
} else {
if ( renderer.depth === true ) this.setupDepth( builder );
}
}
if ( this.fragmentNode === null ) {
this.setupDiffuseColor( builder );
this.setupVariants( builder );
const outgoingLightNode = this.setupLighting( builder );
if ( clippingNode !== null ) builder.stack.add( clippingNode );
// force unsigned floats - useful for RenderTargets
const basicOutput = vec4( outgoingLightNode, diffuseColor.a ).max( 0 );
resultNode = this.setupOutput( builder, basicOutput );
// OUTPUT NODE
output.assign( resultNode );
//
if ( this.outputNode !== null ) resultNode = this.outputNode;
// MRT
if ( renderTarget !== null ) {
const mrt = renderer.getMRT();
const materialMRT = this.mrtNode;
if ( mrt !== null ) {
resultNode = mrt;
if ( materialMRT !== null ) {
resultNode = mrt.merge( materialMRT );
}
} else if ( materialMRT !== null ) {
resultNode = materialMRT;
}
}
} else {
let fragmentNode = this.fragmentNode;
if ( fragmentNode.isOutputStructNode !== true ) {
fragmentNode = vec4( fragmentNode );
}
resultNode = this.setupOutput( builder, fragmentNode );
}
builder.stack.outputNode = resultNode;
builder.addFlow( 'fragment', builder.removeStack() );
// < MONITOR >
builder.monitor = this.setupObserver( builder );
}
setupClipping( builder ) {
if ( builder.clippingContext === null ) return null;
const { unionPlanes, intersectionPlanes } = builder.clippingContext;
let result = null;
if ( unionPlanes.length > 0 || intersectionPlanes.length > 0 ) {
const samples = builder.renderer.samples;
if ( this.alphaToCoverage && samples > 1 ) {
// to be added to flow when the color/alpha value has been determined
result = clippingAlpha();
} else {
builder.stack.add( clipping() );
}
}
return result;
}
setupHardwareClipping( builder ) {
this.hardwareClipping = false;
if ( builder.clippingContext === null ) return;
const candidateCount = builder.clippingContext.unionPlanes.length;
// 8 planes supported by WebGL ANGLE_clip_cull_distance and WebGPU clip-distances
if ( candidateCount > 0 && candidateCount <= 8 && builder.isAvailable( 'clipDistance' ) ) {
builder.stack.add( hardwareClipping() );
this.hardwareClipping = true;
}
return;
}
setupDepth( builder ) {
const { renderer, camera } = builder;
// Depth
let depthNode = this.depthNode;
if ( depthNode === null ) {
const mrt = renderer.getMRT();
if ( mrt && mrt.has( 'depth' ) ) {
depthNode = mrt.get( 'depth' );
} else if ( renderer.logarithmicDepthBuffer === true ) {
if ( camera.isPerspectiveCamera ) {
depthNode = viewZToLogarithmicDepth( positionView.z, cameraNear, cameraFar );
} else {
depthNode = viewZToOrthographicDepth( positionView.z, cameraNear, cameraFar );
}
}
}
if ( depthNode !== null ) {
depth.assign( depthNode ).append();
}
}
setupPosition( builder ) {
const { object } = builder;
const geometry = object.geometry;
builder.addStack();
// Vertex
if ( geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color ) {
morphReference( object ).append();
}
if ( object.isSkinnedMesh === true ) {
skinningReference( object ).append();
}
if ( this.displacementMap ) {
const displacementMap = materialReference( 'displacementMap', 'texture' );
const displacementScale = materialReference( 'displacementScale', 'float' );
const displacementBias = materialReference( 'displacementBias', 'float' );
positionLocal.addAssign( normalLocal.normalize().mul( ( displacementMap.x.mul( displacementScale ).add( displacementBias ) ) ) );
}
if ( object.isBatchedMesh ) {
batch( object ).append();
}
if ( ( object.isInstancedMesh && object.instanceMatrix && object.instanceMatrix.isInstancedBufferAttribute === true ) ) {
instancedMesh( object ).append();
}
if ( this.positionNode !== null ) {
positionLocal.assign( this.positionNode );
}
this.setupHardwareClipping( builder );
const mvp = modelViewProjection();
builder.context.vertex = builder.removeStack();
builder.context.mvp = mvp;
return mvp;
}
setupDiffuseColor( { object, geometry } ) {
let colorNode = this.colorNode ? vec4( this.colorNode ) : materialColor;
// VERTEX COLORS
if ( this.vertexColors === true && geometry.hasAttribute( 'color' ) ) {
colorNode = vec4( colorNode.xyz.mul( attribute( 'color', 'vec3' ) ), colorNode.a );
}
// Instanced colors
if ( object.instanceColor ) {
const instanceColor = varyingProperty( 'vec3', 'vInstanceColor' );
colorNode = instanceColor.mul( colorNode );
}
if ( object.isBatchedMesh && object._colorsTexture ) {
const batchColor = varyingProperty( 'vec3', 'vBatchColor' );
colorNode = batchColor.mul( colorNode );
}
// COLOR
diffuseColor.assign( colorNode );
// OPACITY
const opacityNode = this.opacityNode ? float( this.opacityNode ) : materialOpacity;
diffuseColor.a.assign( diffuseColor.a.mul( opacityNode ) );
// ALPHA TEST
if ( this.alphaTestNode !== null || this.alphaTest > 0 ) {
const alphaTestNode = this.alphaTestNode !== null ? float( this.alphaTestNode ) : materialAlphaTest;
diffuseColor.a.lessThanEqual( alphaTestNode ).discard();
}
// ALPHA HASH
if ( this.alphaHash === true ) {
diffuseColor.a.lessThan( getAlphaHashThreshold( positionLocal ) ).discard();
}
if ( this.transparent === false && this.blending === NormalBlending && this.alphaToCoverage === false ) {
diffuseColor.a.assign( 1.0 );
}
}
setupVariants( /*builder*/ ) {
// Interface function.
}
setupOutgoingLight() {
return ( this.lights === true ) ? vec3( 0 ) : diffuseColor.rgb;
}
setupNormal() {
return this.normalNode ? vec3( this.normalNode ) : materialNormal;
}
setupEnvironment( /*builder*/ ) {
let node = null;
if ( this.envNode ) {
node = this.envNode;
} else if ( this.envMap ) {
node = this.envMap.isCubeTexture ? materialReference( 'envMap', 'cubeTexture' ) : materialReference( 'envMap', 'texture' );
}
return node;
}
setupLightMap( builder ) {
let node = null;
if ( builder.material.lightMap ) {
node = new IrradianceNode( materialLightMap );
}
return node;
}
setupLights( builder ) {
const materialLightsNode = [];
//
const envNode = this.setupEnvironment( builder );
if ( envNode && envNode.isLightingNode ) {
materialLightsNode.push( envNode );
}
const lightMapNode = this.setupLightMap( builder );
if ( lightMapNode && lightMapNode.isLightingNode ) {
materialLightsNode.push( lightMapNode );
}
if ( this.aoNode !== null || builder.material.aoMap ) {
const aoNode = this.aoNode !== null ? this.aoNode : materialAOMap;
materialLightsNode.push( new AONode( aoNode ) );
}
let lightsN = this.lightsNode || builder.lightsNode;
if ( materialLightsNode.length > 0 ) {
lightsN = builder.renderer.lighting.createNode( [ ...lightsN.getLights(), ...materialLightsNode ] );
}
return lightsN;
}
setupLightingModel( /*builder*/ ) {
// Interface function.
}
setupLighting( builder ) {
const { material } = builder;
const { backdropNode, backdropAlphaNode, emissiveNode } = this;
// OUTGOING LIGHT
const lights = this.lights === true || this.lightsNode !== null;
const lightsNode = lights ? this.setupLights( builder ) : null;
let outgoingLightNode = this.setupOutgoingLight( builder );
if ( lightsNode && lightsNode.getScope().hasLights ) {
const lightingModel = this.setupLightingModel( builder );
outgoingLightNode = lightingContext( lightsNode, lightingModel, backdropNode, backdropAlphaNode );
} else if ( backdropNode !== null ) {
outgoingLightNode = vec3( backdropAlphaNode !== null ? mix( outgoingLightNode, backdropNode, backdropAlphaNode ) : backdropNode );
}
// EMISSIVE
if ( ( emissiveNode && emissiveNode.isNode === true ) || ( material.emissive && material.emissive.isColor === true ) ) {
emissive.assign( vec3( emissiveNode ? emissiveNode : materialEmissive ) );
outgoingLightNode = outgoingLightNode.add( emissive );
}
return outgoingLightNode;
}
setupOutput( builder, outputNode ) {
// FOG
if ( this.fog === true ) {
const fogNode = builder.fogNode;
if ( fogNode ) outputNode = vec4( fogNode.mix( outputNode.rgb, fogNode.colorNode ), outputNode.a );
}
return outputNode;
}
setDefaultValues( material ) {
// This approach is to reuse the native refreshUniforms*
// and turn available the use of features like transmission and environment in core
for ( const property in material ) {
const value = material[ property ];
if ( this[ property ] === undefined ) {
this[ property ] = value;
if ( value && value.clone ) this[ property ] = value.clone();
}
}
const descriptors = Object.getOwnPropertyDescriptors( material.constructor.prototype );
for ( const key in descriptors ) {
if ( Object.getOwnPropertyDescriptor( this.constructor.prototype, key ) === undefined &&
descriptors[ key ].get !== undefined ) {
Object.defineProperty( this.constructor.prototype, key, descriptors[ key ] );
}
}
}
toJSON( meta ) {
const isRoot = ( meta === undefined || typeof meta === 'string' );
if ( isRoot ) {
meta = {
textures: {},
images: {},
nodes: {}
};
}
const data = Material.prototype.toJSON.call( this, meta );
const nodeChildren = getNodeChildren( this );
data.inputNodes = {};
for ( const { property, childNode } of nodeChildren ) {
data.inputNodes[ property ] = childNode.toJSON( meta ).uuid;
}
// TODO: Copied from Object3D.toJSON
function extractFromCache( cache ) {
const values = [];
for ( const key in cache ) {
const data = cache[ key ];
delete data.metadata;
values.push( data );
}
return values;
}
if ( isRoot ) {
const textures = extractFromCache( meta.textures );
const images = extractFromCache( meta.images );
const nodes = extractFromCache( meta.nodes );
if ( textures.length > 0 ) data.textures = textures;
if ( images.length > 0 ) data.images = images;
if ( nodes.length > 0 ) data.nodes = nodes;
}
return data;
}
copy( source ) {
this.lightsNode = source.lightsNode;
this.envNode = source.envNode;
this.colorNode = source.colorNode;
this.normalNode = source.normalNode;
this.opacityNode = source.opacityNode;
this.backdropNode = source.backdropNode;
this.backdropAlphaNode = source.backdropAlphaNode;
this.alphaTestNode = source.alphaTestNode;
this.positionNode = source.positionNode;
this.geometryNode = source.geometryNode;
this.depthNode = source.depthNode;
this.shadowPositionNode = source.shadowPositionNode;
this.receivedShadowNode = source.receivedShadowNode;
this.castShadowNode = source.castShadowNode;
this.outputNode = source.outputNode;
this.mrtNode = source.mrtNode;
this.fragmentNode = source.fragmentNode;
this.vertexNode = source.vertexNode;
return super.copy( source );
}
}
export default NodeMaterial;
+22
View File
@@ -0,0 +1,22 @@
// @TODO: We can simplify "export { default as SomeNode, other, exports } from '...'" to just "export * from '...'" if we will use only named exports
export { default as NodeMaterialObserver } from './manager/NodeMaterialObserver.js';
export { default as NodeMaterial } from './NodeMaterial.js';
export { default as InstancedPointsNodeMaterial } from './InstancedPointsNodeMaterial.js';
export { default as LineBasicNodeMaterial } from './LineBasicNodeMaterial.js';
export { default as LineDashedNodeMaterial } from './LineDashedNodeMaterial.js';
export { default as Line2NodeMaterial } from './Line2NodeMaterial.js';
export { default as MeshNormalNodeMaterial } from './MeshNormalNodeMaterial.js';
export { default as MeshBasicNodeMaterial } from './MeshBasicNodeMaterial.js';
export { default as MeshLambertNodeMaterial } from './MeshLambertNodeMaterial.js';
export { default as MeshPhongNodeMaterial } from './MeshPhongNodeMaterial.js';
export { default as MeshStandardNodeMaterial } from './MeshStandardNodeMaterial.js';
export { default as MeshPhysicalNodeMaterial } from './MeshPhysicalNodeMaterial.js';
export { default as MeshSSSNodeMaterial } from './MeshSSSNodeMaterial.js';
export { default as MeshToonNodeMaterial } from './MeshToonNodeMaterial.js';
export { default as MeshMatcapNodeMaterial } from './MeshMatcapNodeMaterial.js';
export { default as PointsNodeMaterial } from './PointsNodeMaterial.js';
export { default as SpriteNodeMaterial } from './SpriteNodeMaterial.js';
export { default as ShadowNodeMaterial } from './ShadowNodeMaterial.js';
export { default as VolumeNodeMaterial } from './VolumeNodeMaterial.js';
+42
View File
@@ -0,0 +1,42 @@
import NodeMaterial from './NodeMaterial.js';
import { PointsMaterial } from '../PointsMaterial.js';
const _defaultValues = /*@__PURE__*/ new PointsMaterial();
class PointsNodeMaterial extends NodeMaterial {
static get type() {
return 'PointsNodeMaterial';
}
constructor( parameters ) {
super();
this.isPointsNodeMaterial = true;
this.lights = false;
this.transparent = true;
this.sizeNode = null;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
copy( source ) {
this.sizeNode = source.sizeNode;
return super.copy( source );
}
}
export default PointsNodeMaterial;
+38
View File
@@ -0,0 +1,38 @@
import NodeMaterial from './NodeMaterial.js';
import ShadowMaskModel from '../../nodes/functions/ShadowMaskModel.js';
import { ShadowMaterial } from '../ShadowMaterial.js';
const _defaultValues = /*@__PURE__*/ new ShadowMaterial();
class ShadowNodeMaterial extends NodeMaterial {
static get type() {
return 'ShadowNodeMaterial';
}
constructor( parameters ) {
super();
this.isShadowNodeMaterial = true;
this.lights = true;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
setupLightingModel( /*builder*/ ) {
return new ShadowMaskModel();
}
}
export default ShadowNodeMaterial;
+132
View File
@@ -0,0 +1,132 @@
import NodeMaterial from './NodeMaterial.js';
import { cameraProjectionMatrix } from '../../nodes/accessors/Camera.js';
import { materialRotation } from '../../nodes/accessors/MaterialNode.js';
import { modelViewMatrix, modelWorldMatrix } from '../../nodes/accessors/ModelNode.js';
import { positionLocal } from '../../nodes/accessors/Position.js';
import { rotate } from '../../nodes/utils/RotateNode.js';
import { float, vec2, vec3, vec4 } from '../../nodes/tsl/TSLBase.js';
import { SpriteMaterial } from '../SpriteMaterial.js';
import { reference } from '../../nodes/accessors/ReferenceBaseNode.js';
const _defaultValues = /*@__PURE__*/ new SpriteMaterial();
class SpriteNodeMaterial extends NodeMaterial {
static get type() {
return 'SpriteNodeMaterial';
}
constructor( parameters ) {
super();
this.isSpriteNodeMaterial = true;
this.lights = false;
this._useSizeAttenuation = true;
this.positionNode = null;
this.rotationNode = null;
this.scaleNode = null;
this.setDefaultValues( _defaultValues );
this.setValues( parameters );
}
setupPosition( { object, camera, context } ) {
const sizeAttenuation = this.sizeAttenuation;
// < VERTEX STAGE >
const { positionNode, rotationNode, scaleNode } = this;
const vertex = positionLocal;
let mvPosition = modelViewMatrix.mul( vec3( positionNode || 0 ) );
let scale = vec2( modelWorldMatrix[ 0 ].xyz.length(), modelWorldMatrix[ 1 ].xyz.length() );
if ( scaleNode !== null ) {
scale = scale.mul( scaleNode );
}
if ( ! sizeAttenuation ) {
if ( camera.isPerspectiveCamera ) {
scale = scale.mul( mvPosition.z.negate() );
} else {
const orthoScale = float( 2.0 ).div( cameraProjectionMatrix.element( 1 ).element( 1 ) );
scale = scale.mul( orthoScale.mul( 2 ) );
}
}
let alignedPosition = vertex.xy;
if ( object.center && object.center.isVector2 === true ) {
const center = reference( 'center', 'vec2' );
alignedPosition = alignedPosition.sub( center.sub( 0.5 ) );
}
alignedPosition = alignedPosition.mul( scale );
const rotation = float( rotationNode || materialRotation );
const rotatedPosition = rotate( alignedPosition, rotation );
mvPosition = vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw );
const modelViewProjection = cameraProjectionMatrix.mul( mvPosition );
context.vertex = vertex;
return modelViewProjection;
}
copy( source ) {
this.positionNode = source.positionNode;
this.rotationNode = source.rotationNode;
this.scaleNode = source.scaleNode;
return super.copy( source );
}
get sizeAttenuation() {
return this._useSizeAttenuation;
}
set sizeAttenuation( value ) {
if ( this._useSizeAttenuation !== value ) {
this._useSizeAttenuation = value;
this.needsUpdate = true;
}
}
}
export default SpriteNodeMaterial;
+108
View File
@@ -0,0 +1,108 @@
import NodeMaterial from './NodeMaterial.js';
import { property } from '../../nodes/core/PropertyNode.js';
import { materialReference } from '../../nodes/accessors/MaterialReferenceNode.js';
import { modelWorldMatrixInverse } from '../../nodes/accessors/ModelNode.js';
import { cameraPosition } from '../../nodes/accessors/Camera.js';
import { positionGeometry } from '../../nodes/accessors/Position.js';
import { Fn, varying, float, vec2, vec3, vec4 } from '../../nodes/tsl/TSLBase.js';
import { min, max } from '../../nodes/math/MathNode.js';
import { Loop, Break } from '../../nodes/utils/LoopNode.js';
import { texture3D } from '../../nodes/accessors/Texture3DNode.js';
class VolumeNodeMaterial extends NodeMaterial {
static get type() {
return 'VolumeNodeMaterial';
}
constructor( params = {} ) {
super();
this.lights = false;
this.isVolumeNodeMaterial = true;
this.testNode = null;
this.setValues( params );
}
setup( builder ) {
const map = texture3D( this.map, null, 0 );
const hitBox = Fn( ( { orig, dir } ) => {
const box_min = vec3( - 0.5 );
const box_max = vec3( 0.5 );
const inv_dir = dir.reciprocal();
const tmin_tmp = box_min.sub( orig ).mul( inv_dir );
const tmax_tmp = box_max.sub( orig ).mul( inv_dir );
const tmin = min( tmin_tmp, tmax_tmp );
const tmax = max( tmin_tmp, tmax_tmp );
const t0 = max( tmin.x, max( tmin.y, tmin.z ) );
const t1 = min( tmax.x, min( tmax.y, tmax.z ) );
return vec2( t0, t1 );
} );
this.fragmentNode = Fn( () => {
const vOrigin = varying( vec3( modelWorldMatrixInverse.mul( vec4( cameraPosition, 1.0 ) ) ) );
const vDirection = varying( positionGeometry.sub( vOrigin ) );
const rayDir = vDirection.normalize();
const bounds = vec2( hitBox( { orig: vOrigin, dir: rayDir } ) ).toVar();
bounds.x.greaterThan( bounds.y ).discard();
bounds.assign( vec2( max( bounds.x, 0.0 ), bounds.y ) );
const p = vec3( vOrigin.add( bounds.x.mul( rayDir ) ) ).toVar();
const inc = vec3( rayDir.abs().reciprocal() ).toVar();
const delta = float( min( inc.x, min( inc.y, inc.z ) ) ).toVar( 'delta' ); // used 'delta' name in loop
delta.divAssign( materialReference( 'steps', 'float' ) );
const ac = vec4( materialReference( 'base', 'color' ), 0.0 ).toVar();
Loop( { type: 'float', start: bounds.x, end: bounds.y, update: '+= delta' }, () => {
const d = property( 'float', 'd' ).assign( map.uv( p.add( 0.5 ) ).r );
if ( this.testNode !== null ) {
this.testNode( { map: map, mapValue: d, probe: p, finalColor: ac } ).append();
} else {
// default to show surface of mesh
ac.a.assign( 1 );
Break();
}
p.addAssign( rayDir.mul( delta ) );
} );
ac.a.equal( 0 ).discard();
return vec4( ac );
} )();
super.setup( builder );
}
}
export default VolumeNodeMaterial;
+414
View File
@@ -0,0 +1,414 @@
const refreshUniforms = [
'alphaMap',
'alphaTest',
'anisotropy',
'anisotropyMap',
'anisotropyRotation',
'aoMap',
'attenuationColor',
'attenuationDistance',
'bumpMap',
'clearcoat',
'clearcoatMap',
'clearcoatNormalMap',
'clearcoatNormalScale',
'clearcoatRoughness',
'color',
'dispersion',
'displacementMap',
'emissive',
'emissiveMap',
'envMap',
'gradientMap',
'ior',
'iridescence',
'iridescenceIOR',
'iridescenceMap',
'iridescenceThicknessMap',
'lightMap',
'map',
'matcap',
'metalness',
'metalnessMap',
'normalMap',
'normalScale',
'opacity',
'roughness',
'roughnessMap',
'sheen',
'sheenColor',
'sheenColorMap',
'sheenRoughnessMap',
'shininess',
'specular',
'specularColor',
'specularColorMap',
'specularIntensity',
'specularIntensityMap',
'specularMap',
'thickness',
'transmission',
'transmissionMap'
];
class NodeMaterialObserver {
constructor( builder ) {
this.renderObjects = new WeakMap();
this.hasNode = this.containsNode( builder );
this.hasAnimation = builder.object.isSkinnedMesh === true;
this.refreshUniforms = refreshUniforms;
this.renderId = 0;
}
firstInitialization( renderObject ) {
const hasInitialized = this.renderObjects.has( renderObject );
if ( hasInitialized === false ) {
this.getRenderObjectData( renderObject );
return true;
}
return false;
}
getRenderObjectData( renderObject ) {
let data = this.renderObjects.get( renderObject );
if ( data === undefined ) {
const { geometry, material, object } = renderObject;
data = {
material: this.getMaterialData( material ),
geometry: {
attributes: this.getAttributesData( geometry.attributes ),
indexVersion: geometry.index ? geometry.index.version : null,
drawRange: { start: geometry.drawRange.start, count: geometry.drawRange.count }
},
worldMatrix: object.matrixWorld.clone()
};
if ( object.center ) {
data.center = object.center.clone();
}
if ( object.morphTargetInfluences ) {
data.morphTargetInfluences = object.morphTargetInfluences.slice();
}
if ( renderObject.bundle !== null ) {
data.version = renderObject.bundle.version;
}
if ( data.material.transmission > 0 ) {
const { width, height } = renderObject.context;
data.bufferWidth = width;
data.bufferHeight = height;
}
this.renderObjects.set( renderObject, data );
}
return data;
}
getAttributesData( attributes ) {
const attributesData = {};
for ( const name in attributes ) {
const attribute = attributes[ name ];
attributesData[ name ] = {
version: attribute.version
};
}
return attributesData;
}
containsNode( builder ) {
const material = builder.material;
for ( const property in material ) {
if ( material[ property ] && material[ property ].isNode )
return true;
}
if ( builder.renderer.nodes.modelViewMatrix !== null || builder.renderer.nodes.modelNormalViewMatrix !== null )
return true;
return false;
}
getMaterialData( material ) {
const data = {};
for ( const property of this.refreshUniforms ) {
const value = material[ property ];
if ( value === null || value === undefined ) continue;
if ( typeof value === 'object' && value.clone !== undefined ) {
if ( value.isTexture === true ) {
data[ property ] = { id: value.id, version: value.version };
} else {
data[ property ] = value.clone();
}
} else {
data[ property ] = value;
}
}
return data;
}
equals( renderObject ) {
const { object, material, geometry } = renderObject;
const renderObjectData = this.getRenderObjectData( renderObject );
// world matrix
if ( renderObjectData.worldMatrix.equals( object.matrixWorld ) !== true ) {
renderObjectData.worldMatrix.copy( object.matrixWorld );
return false;
}
// material
const materialData = renderObjectData.material;
for ( const property in materialData ) {
const value = materialData[ property ];
const mtlValue = material[ property ];
if ( value.equals !== undefined ) {
if ( value.equals( mtlValue ) === false ) {
value.copy( mtlValue );
return false;
}
} else if ( mtlValue.isTexture === true ) {
if ( value.id !== mtlValue.id || value.version !== mtlValue.version ) {
value.id = mtlValue.id;
value.version = mtlValue.version;
return false;
}
} else if ( value !== mtlValue ) {
materialData[ property ] = mtlValue;
return false;
}
}
if ( materialData.transmission > 0 ) {
const { width, height } = renderObject.context;
if ( renderObjectData.bufferWidth !== width || renderObjectData.bufferHeight !== height ) {
renderObjectData.bufferWidth = width;
renderObjectData.bufferHeight = height;
return false;
}
}
// geometry
const storedGeometryData = renderObjectData.geometry;
const attributes = geometry.attributes;
const storedAttributes = storedGeometryData.attributes;
const storedAttributeNames = Object.keys( storedAttributes );
const currentAttributeNames = Object.keys( attributes );
if ( storedAttributeNames.length !== currentAttributeNames.length ) {
renderObjectData.geometry.attributes = this.getAttributesData( attributes );
return false;
}
// compare each attribute
for ( const name of storedAttributeNames ) {
const storedAttributeData = storedAttributes[ name ];
const attribute = attributes[ name ];
if ( attribute === undefined ) {
// attribute was removed
delete storedAttributes[ name ];
return false;
}
if ( storedAttributeData.version !== attribute.version ) {
storedAttributeData.version = attribute.version;
return false;
}
}
// check index
const index = geometry.index;
const storedIndexVersion = storedGeometryData.indexVersion;
const currentIndexVersion = index ? index.version : null;
if ( storedIndexVersion !== currentIndexVersion ) {
storedGeometryData.indexVersion = currentIndexVersion;
return false;
}
// check drawRange
if ( storedGeometryData.drawRange.start !== geometry.drawRange.start || storedGeometryData.drawRange.count !== geometry.drawRange.count ) {
storedGeometryData.drawRange.start = geometry.drawRange.start;
storedGeometryData.drawRange.count = geometry.drawRange.count;
return false;
}
// morph targets
if ( renderObjectData.morphTargetInfluences ) {
let morphChanged = false;
for ( let i = 0; i < renderObjectData.morphTargetInfluences.length; i ++ ) {
if ( renderObjectData.morphTargetInfluences[ i ] !== object.morphTargetInfluences[ i ] ) {
morphChanged = true;
}
}
if ( morphChanged ) return true;
}
// center
if ( renderObjectData.center ) {
if ( renderObjectData.center.equals( object.center ) === false ) {
renderObjectData.center.copy( object.center );
return true;
}
}
// bundle
if ( renderObject.bundle !== null ) {
renderObjectData.version = renderObject.bundle.version;
}
return true;
}
needsRefresh( renderObject, nodeFrame ) {
if ( this.hasNode || this.hasAnimation || this.firstInitialization( renderObject ) )
return true;
const { renderId } = nodeFrame;
if ( this.renderId !== renderId ) {
this.renderId = renderId;
return true;
}
const isStatic = renderObject.object.static === true;
const isBundle = renderObject.bundle !== null && renderObject.bundle.static === true && this.getRenderObjectData( renderObject ).version === renderObject.bundle.version;
if ( isStatic || isBundle )
return false;
const notEqual = this.equals( renderObject ) !== true;
return notEqual;
}
}
export default NodeMaterialObserver;