最新代码
This commit is contained in:
25
public/sdk/three/jsm/nodes/accessors/AccessorsUtils.js
Normal file
25
public/sdk/three/jsm/nodes/accessors/AccessorsUtils.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { bitangentView } from './BitangentNode.js';
|
||||
import { normalView, transformedNormalView } from './NormalNode.js';
|
||||
import { tangentView } from './TangentNode.js';
|
||||
import { mat3 } from '../shadernode/ShaderNode.js';
|
||||
import { mix } from '../math/MathNode.js';
|
||||
import { anisotropy, anisotropyB, roughness } from '../core/PropertyNode.js';
|
||||
import { positionViewDirection } from './PositionNode.js';
|
||||
|
||||
export const TBNViewMatrix = mat3( tangentView, bitangentView, normalView );
|
||||
|
||||
export const parallaxDirection = positionViewDirection.mul( TBNViewMatrix )/*.normalize()*/;
|
||||
export const parallaxUV = ( uv, scale ) => uv.sub( parallaxDirection.mul( scale ) );
|
||||
|
||||
export const transformedBentNormalView = ( () => {
|
||||
|
||||
// https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights/anisotropy
|
||||
|
||||
let bentNormal = anisotropyB.cross( positionViewDirection );
|
||||
bentNormal = bentNormal.cross( anisotropyB ).normalize();
|
||||
bentNormal = mix( bentNormal, transformedNormalView, anisotropy.mul( roughness.oneMinus() ).oneMinus().pow2().pow2() ).normalize();
|
||||
|
||||
return bentNormal;
|
||||
|
||||
|
||||
} )();
|
78
public/sdk/three/jsm/nodes/accessors/BatchNode.js
Normal file
78
public/sdk/three/jsm/nodes/accessors/BatchNode.js
Normal file
@ -0,0 +1,78 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { normalLocal } from './NormalNode.js';
|
||||
import { positionLocal } from './PositionNode.js';
|
||||
import { nodeProxy, vec3, mat3, mat4, int, ivec2, float } from '../shadernode/ShaderNode.js';
|
||||
import { textureLoad } from './TextureNode.js';
|
||||
import { textureSize } from './TextureSizeNode.js';
|
||||
import { attribute } from '../core/AttributeNode.js';
|
||||
import { tangentLocal } from './TangentNode.js';
|
||||
|
||||
class BatchNode extends Node {
|
||||
|
||||
constructor( batchMesh ) {
|
||||
|
||||
super( 'void' );
|
||||
|
||||
this.batchMesh = batchMesh;
|
||||
|
||||
|
||||
this.instanceColorNode = null;
|
||||
|
||||
this.batchingIdNode = null;
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
// POSITION
|
||||
|
||||
if ( this.batchingIdNode === null ) {
|
||||
|
||||
this.batchingIdNode = attribute( 'batchId' );
|
||||
|
||||
}
|
||||
|
||||
const matriceTexture = this.batchMesh._matricesTexture;
|
||||
|
||||
const size = textureSize( textureLoad( matriceTexture ), 0 );
|
||||
const j = float( int( this.batchingIdNode ) ).mul( 4 ).toVar();
|
||||
|
||||
const x = int( j.mod( size ) );
|
||||
const y = int( j ).div( int( size ) );
|
||||
const batchingMatrix = mat4(
|
||||
textureLoad( matriceTexture, ivec2( x, y ) ),
|
||||
textureLoad( matriceTexture, ivec2( x.add( 1 ), y ) ),
|
||||
textureLoad( matriceTexture, ivec2( x.add( 2 ), y ) ),
|
||||
textureLoad( matriceTexture, ivec2( x.add( 3 ), y ) )
|
||||
);
|
||||
|
||||
|
||||
const bm = mat3(
|
||||
batchingMatrix[ 0 ].xyz,
|
||||
batchingMatrix[ 1 ].xyz,
|
||||
batchingMatrix[ 2 ].xyz
|
||||
);
|
||||
|
||||
positionLocal.assign( batchingMatrix.mul( positionLocal ) );
|
||||
|
||||
const transformedNormal = normalLocal.div( vec3( bm[ 0 ].dot( bm[ 0 ] ), bm[ 1 ].dot( bm[ 1 ] ), bm[ 2 ].dot( bm[ 2 ] ) ) );
|
||||
|
||||
const batchingNormal = bm.mul( transformedNormal ).xyz;
|
||||
|
||||
normalLocal.assign( batchingNormal );
|
||||
|
||||
if ( builder.hasGeometryAttribute( 'tangent' ) ) {
|
||||
|
||||
tangentLocal.mulAssign( bm );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BatchNode;
|
||||
|
||||
export const batch = nodeProxy( BatchNode );
|
||||
|
||||
addNodeClass( 'batch', BatchNode );
|
89
public/sdk/three/jsm/nodes/accessors/BitangentNode.js
Normal file
89
public/sdk/three/jsm/nodes/accessors/BitangentNode.js
Normal file
@ -0,0 +1,89 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { varying } from '../core/VaryingNode.js';
|
||||
import { normalize } from '../math/MathNode.js';
|
||||
import { cameraViewMatrix } from './CameraNode.js';
|
||||
import { normalGeometry, normalLocal, normalView, normalWorld, transformedNormalView } from './NormalNode.js';
|
||||
import { tangentGeometry, tangentLocal, tangentView, tangentWorld, transformedTangentView } from './TangentNode.js';
|
||||
import { nodeImmutable } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class BitangentNode extends Node {
|
||||
|
||||
constructor( scope = BitangentNode.LOCAL ) {
|
||||
|
||||
super( 'vec3' );
|
||||
|
||||
this.scope = scope;
|
||||
|
||||
}
|
||||
|
||||
getHash( /*builder*/ ) {
|
||||
|
||||
return `bitangent-${this.scope}`;
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
const scope = this.scope;
|
||||
|
||||
let crossNormalTangent;
|
||||
|
||||
if ( scope === BitangentNode.GEOMETRY ) {
|
||||
|
||||
crossNormalTangent = normalGeometry.cross( tangentGeometry );
|
||||
|
||||
} else if ( scope === BitangentNode.LOCAL ) {
|
||||
|
||||
crossNormalTangent = normalLocal.cross( tangentLocal );
|
||||
|
||||
} else if ( scope === BitangentNode.VIEW ) {
|
||||
|
||||
crossNormalTangent = normalView.cross( tangentView );
|
||||
|
||||
} else if ( scope === BitangentNode.WORLD ) {
|
||||
|
||||
crossNormalTangent = normalWorld.cross( tangentWorld );
|
||||
|
||||
}
|
||||
|
||||
const vertexNode = crossNormalTangent.mul( tangentGeometry.w ).xyz;
|
||||
|
||||
const outputNode = normalize( varying( vertexNode ) );
|
||||
|
||||
return outputNode.build( builder, this.getNodeType( builder ) );
|
||||
|
||||
}
|
||||
|
||||
serialize( data ) {
|
||||
|
||||
super.serialize( data );
|
||||
|
||||
data.scope = this.scope;
|
||||
|
||||
}
|
||||
|
||||
deserialize( data ) {
|
||||
|
||||
super.deserialize( data );
|
||||
|
||||
this.scope = data.scope;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BitangentNode.GEOMETRY = 'geometry';
|
||||
BitangentNode.LOCAL = 'local';
|
||||
BitangentNode.VIEW = 'view';
|
||||
BitangentNode.WORLD = 'world';
|
||||
|
||||
export default BitangentNode;
|
||||
|
||||
export const bitangentGeometry = nodeImmutable( BitangentNode, BitangentNode.GEOMETRY );
|
||||
export const bitangentLocal = nodeImmutable( BitangentNode, BitangentNode.LOCAL );
|
||||
export const bitangentView = nodeImmutable( BitangentNode, BitangentNode.VIEW );
|
||||
export const bitangentWorld = nodeImmutable( BitangentNode, BitangentNode.WORLD );
|
||||
export const transformedBitangentView = normalize( transformedNormalView.cross( transformedTangentView ).mul( tangentGeometry.w ) );
|
||||
export const transformedBitangentWorld = normalize( transformedBitangentView.transformDirection( cameraViewMatrix ) );
|
||||
|
||||
addNodeClass( 'BitangentNode', BitangentNode );
|
127
public/sdk/three/jsm/nodes/accessors/BufferAttributeNode.js
Normal file
127
public/sdk/three/jsm/nodes/accessors/BufferAttributeNode.js
Normal file
@ -0,0 +1,127 @@
|
||||
import InputNode from '../core/InputNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { varying } from '../core/VaryingNode.js';
|
||||
import { nodeObject, addNodeElement } from '../shadernode/ShaderNode.js';
|
||||
import { InterleavedBufferAttribute, InterleavedBuffer, StaticDrawUsage, DynamicDrawUsage } from 'three';
|
||||
|
||||
class BufferAttributeNode extends InputNode {
|
||||
|
||||
constructor( value, bufferType = null, bufferStride = 0, bufferOffset = 0 ) {
|
||||
|
||||
super( value, bufferType );
|
||||
|
||||
this.isBufferNode = true;
|
||||
|
||||
this.bufferType = bufferType;
|
||||
this.bufferStride = bufferStride;
|
||||
this.bufferOffset = bufferOffset;
|
||||
|
||||
this.usage = StaticDrawUsage;
|
||||
this.instanced = false;
|
||||
|
||||
this.attribute = null;
|
||||
|
||||
if ( value && value.isBufferAttribute === true ) {
|
||||
|
||||
this.attribute = value;
|
||||
this.usage = value.usage;
|
||||
this.instanced = value.isInstancedBufferAttribute;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getNodeType( builder ) {
|
||||
|
||||
if ( this.bufferType === null ) {
|
||||
|
||||
this.bufferType = builder.getTypeFromAttribute( this.attribute );
|
||||
|
||||
}
|
||||
|
||||
return this.bufferType;
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
if ( this.attribute !== null ) return;
|
||||
|
||||
const type = this.getNodeType( builder );
|
||||
const array = this.value;
|
||||
const itemSize = builder.getTypeLength( type );
|
||||
const stride = this.bufferStride || itemSize;
|
||||
const offset = this.bufferOffset;
|
||||
|
||||
const buffer = array.isInterleavedBuffer === true ? array : new InterleavedBuffer( array, stride );
|
||||
const bufferAttribute = new InterleavedBufferAttribute( buffer, itemSize, offset );
|
||||
|
||||
buffer.setUsage( this.usage );
|
||||
|
||||
this.attribute = bufferAttribute;
|
||||
this.attribute.isInstancedBufferAttribute = this.instanced; // @TODO: Add a possible: InstancedInterleavedBufferAttribute
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
const nodeType = this.getNodeType( builder );
|
||||
|
||||
const nodeAttribute = builder.getBufferAttributeFromNode( this, nodeType );
|
||||
const propertyName = builder.getPropertyName( nodeAttribute );
|
||||
|
||||
let output = null;
|
||||
|
||||
if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) {
|
||||
|
||||
this.name = propertyName;
|
||||
|
||||
output = propertyName;
|
||||
|
||||
} else {
|
||||
|
||||
const nodeVarying = varying( this );
|
||||
|
||||
output = nodeVarying.build( builder, nodeType );
|
||||
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
}
|
||||
|
||||
getInputType( /*builder*/ ) {
|
||||
|
||||
return 'bufferAttribute';
|
||||
|
||||
}
|
||||
|
||||
setUsage( value ) {
|
||||
|
||||
this.usage = value;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
setInstanced( value ) {
|
||||
|
||||
this.instanced = value;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BufferAttributeNode;
|
||||
|
||||
export const bufferAttribute = ( array, type, stride, offset ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) );
|
||||
export const dynamicBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setUsage( DynamicDrawUsage );
|
||||
|
||||
export const instancedBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setInstanced( true );
|
||||
export const instancedDynamicBufferAttribute = ( array, type, stride, offset ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true );
|
||||
|
||||
addNodeElement( 'toAttribute', ( bufferNode ) => bufferAttribute( bufferNode.value ) );
|
||||
|
||||
addNodeClass( 'BufferAttributeNode', BufferAttributeNode );
|
30
public/sdk/three/jsm/nodes/accessors/BufferNode.js
Normal file
30
public/sdk/three/jsm/nodes/accessors/BufferNode.js
Normal file
@ -0,0 +1,30 @@
|
||||
import UniformNode from '../core/UniformNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class BufferNode extends UniformNode {
|
||||
|
||||
constructor( value, bufferType, bufferCount = 0 ) {
|
||||
|
||||
super( value, bufferType );
|
||||
|
||||
this.isBufferNode = true;
|
||||
|
||||
this.bufferType = bufferType;
|
||||
this.bufferCount = bufferCount;
|
||||
|
||||
}
|
||||
|
||||
getInputType( /*builder*/ ) {
|
||||
|
||||
return 'buffer';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BufferNode;
|
||||
|
||||
export const buffer = ( value, type, count ) => nodeObject( new BufferNode( value, type, count ) );
|
||||
|
||||
addNodeClass( 'BufferNode', BufferNode );
|
119
public/sdk/three/jsm/nodes/accessors/CameraNode.js
Normal file
119
public/sdk/three/jsm/nodes/accessors/CameraNode.js
Normal file
@ -0,0 +1,119 @@
|
||||
import Object3DNode from './Object3DNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { NodeUpdateType } from '../core/constants.js';
|
||||
//import { sharedUniformGroup } from '../core/UniformGroupNode.js';
|
||||
import { nodeImmutable } from '../shadernode/ShaderNode.js';
|
||||
|
||||
//const cameraGroup = sharedUniformGroup( 'camera' );
|
||||
|
||||
class CameraNode extends Object3DNode {
|
||||
|
||||
constructor( scope = CameraNode.POSITION ) {
|
||||
|
||||
super( scope );
|
||||
|
||||
this.updateType = NodeUpdateType.RENDER;
|
||||
|
||||
//this._uniformNode.groupNode = cameraGroup;
|
||||
|
||||
}
|
||||
|
||||
getNodeType( builder ) {
|
||||
|
||||
const scope = this.scope;
|
||||
|
||||
if ( scope === CameraNode.PROJECTION_MATRIX || scope === CameraNode.PROJECTION_MATRIX_INVERSE ) {
|
||||
|
||||
return 'mat4';
|
||||
|
||||
} else if ( scope === CameraNode.NEAR || scope === CameraNode.FAR || scope === CameraNode.LOG_DEPTH ) {
|
||||
|
||||
return 'float';
|
||||
|
||||
}
|
||||
|
||||
return super.getNodeType( builder );
|
||||
|
||||
}
|
||||
|
||||
update( frame ) {
|
||||
|
||||
const camera = frame.camera;
|
||||
const uniformNode = this._uniformNode;
|
||||
const scope = this.scope;
|
||||
|
||||
//cameraGroup.needsUpdate = true;
|
||||
|
||||
if ( scope === CameraNode.VIEW_MATRIX ) {
|
||||
|
||||
uniformNode.value = camera.matrixWorldInverse;
|
||||
|
||||
} else if ( scope === CameraNode.PROJECTION_MATRIX ) {
|
||||
|
||||
uniformNode.value = camera.projectionMatrix;
|
||||
|
||||
} else if ( scope === CameraNode.PROJECTION_MATRIX_INVERSE ) {
|
||||
|
||||
uniformNode.value = camera.projectionMatrixInverse;
|
||||
|
||||
} else if ( scope === CameraNode.NEAR ) {
|
||||
|
||||
uniformNode.value = camera.near;
|
||||
|
||||
} else if ( scope === CameraNode.FAR ) {
|
||||
|
||||
uniformNode.value = camera.far;
|
||||
|
||||
} else if ( scope === CameraNode.LOG_DEPTH ) {
|
||||
|
||||
uniformNode.value = 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 );
|
||||
|
||||
} else {
|
||||
|
||||
this.object3d = camera;
|
||||
|
||||
super.update( frame );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
const scope = this.scope;
|
||||
|
||||
if ( scope === CameraNode.PROJECTION_MATRIX || scope === CameraNode.PROJECTION_MATRIX_INVERSE ) {
|
||||
|
||||
this._uniformNode.nodeType = 'mat4';
|
||||
|
||||
} else if ( scope === CameraNode.NEAR || scope === CameraNode.FAR || scope === CameraNode.LOG_DEPTH ) {
|
||||
|
||||
this._uniformNode.nodeType = 'float';
|
||||
|
||||
}
|
||||
|
||||
return super.generate( builder );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CameraNode.PROJECTION_MATRIX = 'projectionMatrix';
|
||||
CameraNode.PROJECTION_MATRIX_INVERSE = 'projectionMatrixInverse';
|
||||
CameraNode.NEAR = 'near';
|
||||
CameraNode.FAR = 'far';
|
||||
CameraNode.LOG_DEPTH = 'logDepth';
|
||||
|
||||
export default CameraNode;
|
||||
|
||||
export const cameraProjectionMatrix = nodeImmutable( CameraNode, CameraNode.PROJECTION_MATRIX );
|
||||
export const cameraProjectionMatrixInverse = nodeImmutable( CameraNode, CameraNode.PROJECTION_MATRIX_INVERSE );
|
||||
export const cameraNear = nodeImmutable( CameraNode, CameraNode.NEAR );
|
||||
export const cameraFar = nodeImmutable( CameraNode, CameraNode.FAR );
|
||||
export const cameraLogDepth = nodeImmutable( CameraNode, CameraNode.LOG_DEPTH );
|
||||
export const cameraViewMatrix = nodeImmutable( CameraNode, CameraNode.VIEW_MATRIX );
|
||||
export const cameraNormalMatrix = nodeImmutable( CameraNode, CameraNode.NORMAL_MATRIX );
|
||||
export const cameraWorldMatrix = nodeImmutable( CameraNode, CameraNode.WORLD_MATRIX );
|
||||
export const cameraPosition = nodeImmutable( CameraNode, CameraNode.POSITION );
|
||||
|
||||
addNodeClass( 'CameraNode', CameraNode );
|
145
public/sdk/three/jsm/nodes/accessors/ClippingNode.js
Normal file
145
public/sdk/three/jsm/nodes/accessors/ClippingNode.js
Normal file
@ -0,0 +1,145 @@
|
||||
|
||||
import Node from '../core/Node.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
import { positionView } from './PositionNode.js';
|
||||
import { diffuseColor, property } from '../core/PropertyNode.js';
|
||||
import { tslFn } from '../shadernode/ShaderNode.js';
|
||||
import { loop } from '../utils/LoopNode.js';
|
||||
import { smoothstep } from '../math/MathNode.js';
|
||||
import { uniforms } from './UniformsNode.js';
|
||||
|
||||
class ClippingNode extends Node {
|
||||
|
||||
constructor( scope = ClippingNode.DEFAULT ) {
|
||||
|
||||
super();
|
||||
|
||||
this.scope = scope;
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
super.setup( builder );
|
||||
|
||||
const clippingContext = builder.clippingContext;
|
||||
const { localClipIntersection, localClippingCount, globalClippingCount } = clippingContext;
|
||||
|
||||
const numClippingPlanes = globalClippingCount + localClippingCount;
|
||||
const numUnionClippingPlanes = localClipIntersection ? numClippingPlanes - localClippingCount : numClippingPlanes;
|
||||
|
||||
if ( this.scope === ClippingNode.ALPHA_TO_COVERAGE ) {
|
||||
|
||||
return this.setupAlphaToCoverage( clippingContext.planes, numClippingPlanes, numUnionClippingPlanes );
|
||||
|
||||
} else {
|
||||
|
||||
return this.setupDefault( clippingContext.planes, numClippingPlanes, numUnionClippingPlanes );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setupAlphaToCoverage( planes, numClippingPlanes, numUnionClippingPlanes ) {
|
||||
|
||||
return tslFn( () => {
|
||||
|
||||
const clippingPlanes = uniforms( planes );
|
||||
|
||||
const distanceToPlane = property( 'float', 'distanceToPlane' );
|
||||
const distanceGradient = property( 'float', 'distanceToGradient' );
|
||||
|
||||
const clipOpacity = property( 'float', 'clipOpacity' );
|
||||
|
||||
clipOpacity.assign( 1 );
|
||||
|
||||
let plane;
|
||||
|
||||
loop( numUnionClippingPlanes, ( { i } ) => {
|
||||
|
||||
plane = clippingPlanes.element( i );
|
||||
|
||||
distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) );
|
||||
distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) );
|
||||
|
||||
clipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ) );
|
||||
|
||||
clipOpacity.equal( 0.0 ).discard();
|
||||
|
||||
} );
|
||||
|
||||
if ( numUnionClippingPlanes < numClippingPlanes ) {
|
||||
|
||||
const unionClipOpacity = property( 'float', 'unionclipOpacity' );
|
||||
|
||||
unionClipOpacity.assign( 1 );
|
||||
|
||||
loop( { start: numUnionClippingPlanes, end: numClippingPlanes }, ( { i } ) => {
|
||||
|
||||
plane = clippingPlanes.element( i );
|
||||
|
||||
distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) );
|
||||
distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) );
|
||||
|
||||
unionClipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ).oneMinus() );
|
||||
|
||||
} );
|
||||
|
||||
clipOpacity.mulAssign( unionClipOpacity.oneMinus() );
|
||||
|
||||
}
|
||||
|
||||
diffuseColor.a.mulAssign( clipOpacity );
|
||||
|
||||
diffuseColor.a.equal( 0.0 ).discard();
|
||||
|
||||
} )();
|
||||
|
||||
}
|
||||
|
||||
setupDefault( planes, numClippingPlanes, numUnionClippingPlanes ) {
|
||||
|
||||
return tslFn( () => {
|
||||
|
||||
const clippingPlanes = uniforms( planes );
|
||||
|
||||
let plane;
|
||||
|
||||
loop( numUnionClippingPlanes, ( { i } ) => {
|
||||
|
||||
plane = clippingPlanes.element( i );
|
||||
positionView.dot( plane.xyz ).greaterThan( plane.w ).discard();
|
||||
|
||||
} );
|
||||
|
||||
if ( numUnionClippingPlanes < numClippingPlanes ) {
|
||||
|
||||
const clipped = property( 'bool', 'clipped' );
|
||||
|
||||
clipped.assign( true );
|
||||
|
||||
loop( { start: numUnionClippingPlanes, end: numClippingPlanes }, ( { i } ) => {
|
||||
|
||||
plane = clippingPlanes.element( i );
|
||||
clipped.assign( positionView.dot( plane.xyz ).greaterThan( plane.w ).and( clipped ) );
|
||||
|
||||
} );
|
||||
|
||||
clipped.discard();
|
||||
|
||||
}
|
||||
|
||||
} )();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ClippingNode.ALPHA_TO_COVERAGE = 'alphaToCoverage';
|
||||
ClippingNode.DEFAULT = 'default';
|
||||
|
||||
export default ClippingNode;
|
||||
|
||||
export const clipping = () => nodeObject( new ClippingNode() );
|
||||
|
||||
export const clippingAlpha = () => nodeObject( new ClippingNode( ClippingNode.ALPHA_TO_COVERAGE ) );
|
61
public/sdk/three/jsm/nodes/accessors/CubeTextureNode.js
Normal file
61
public/sdk/three/jsm/nodes/accessors/CubeTextureNode.js
Normal file
@ -0,0 +1,61 @@
|
||||
import TextureNode from './TextureNode.js';
|
||||
import { reflectVector } from './ReflectVectorNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { addNodeElement, nodeProxy, vec3 } from '../shadernode/ShaderNode.js';
|
||||
import { WebGPUCoordinateSystem } from 'three';
|
||||
|
||||
class CubeTextureNode extends TextureNode {
|
||||
|
||||
constructor( value, uvNode = null, levelNode = null ) {
|
||||
|
||||
super( value, uvNode, levelNode );
|
||||
|
||||
this.isCubeTextureNode = true;
|
||||
|
||||
}
|
||||
|
||||
getInputType( /*builder*/ ) {
|
||||
|
||||
return 'cubeTexture';
|
||||
|
||||
}
|
||||
|
||||
getDefaultUV() {
|
||||
|
||||
return reflectVector;
|
||||
|
||||
}
|
||||
|
||||
setUpdateMatrix( /*updateMatrix*/ ) { } // Ignore .updateMatrix for CubeTextureNode
|
||||
|
||||
setupUV( builder, uvNode ) {
|
||||
|
||||
const texture = this.value;
|
||||
|
||||
if ( builder.renderer.coordinateSystem === WebGPUCoordinateSystem || ! texture.isRenderTargetTexture ) {
|
||||
|
||||
return vec3( uvNode.x.negate(), uvNode.yz );
|
||||
|
||||
} else {
|
||||
|
||||
return uvNode;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
generateUV( builder, cubeUV ) {
|
||||
|
||||
return cubeUV.build( builder, 'vec3' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CubeTextureNode;
|
||||
|
||||
export const cubeTexture = nodeProxy( CubeTextureNode );
|
||||
|
||||
addNodeElement( 'cubeTexture', cubeTexture );
|
||||
|
||||
addNodeClass( 'CubeTextureNode', CubeTextureNode );
|
94
public/sdk/three/jsm/nodes/accessors/InstanceNode.js
Normal file
94
public/sdk/three/jsm/nodes/accessors/InstanceNode.js
Normal file
@ -0,0 +1,94 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { varyingProperty } from '../core/PropertyNode.js';
|
||||
import { instancedBufferAttribute, instancedDynamicBufferAttribute } from './BufferAttributeNode.js';
|
||||
import { normalLocal } from './NormalNode.js';
|
||||
import { positionLocal } from './PositionNode.js';
|
||||
import { nodeProxy, vec3, mat3, mat4 } from '../shadernode/ShaderNode.js';
|
||||
import { DynamicDrawUsage, InstancedInterleavedBuffer, InstancedBufferAttribute } from 'three';
|
||||
|
||||
class InstanceNode extends Node {
|
||||
|
||||
constructor( instanceMesh ) {
|
||||
|
||||
super( 'void' );
|
||||
|
||||
this.instanceMesh = instanceMesh;
|
||||
|
||||
this.instanceMatrixNode = null;
|
||||
|
||||
this.instanceColorNode = null;
|
||||
|
||||
}
|
||||
|
||||
setup( /*builder*/ ) {
|
||||
|
||||
let instanceMatrixNode = this.instanceMatrixNode;
|
||||
|
||||
const instanceMesh = this.instanceMesh;
|
||||
|
||||
if ( instanceMatrixNode === null ) {
|
||||
|
||||
const instanceAttribute = instanceMesh.instanceMatrix;
|
||||
const buffer = new InstancedInterleavedBuffer( instanceAttribute.array, 16, 1 );
|
||||
|
||||
const bufferFn = instanceAttribute.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
|
||||
|
||||
const instanceBuffers = [
|
||||
// F.Signature -> bufferAttribute( array, type, stride, offset )
|
||||
bufferFn( buffer, 'vec4', 16, 0 ),
|
||||
bufferFn( buffer, 'vec4', 16, 4 ),
|
||||
bufferFn( buffer, 'vec4', 16, 8 ),
|
||||
bufferFn( buffer, 'vec4', 16, 12 )
|
||||
];
|
||||
|
||||
instanceMatrixNode = mat4( ...instanceBuffers );
|
||||
|
||||
this.instanceMatrixNode = instanceMatrixNode;
|
||||
|
||||
}
|
||||
|
||||
const instanceColorAttribute = instanceMesh.instanceColor;
|
||||
|
||||
if ( instanceColorAttribute && this.instanceColorNode === null ) {
|
||||
|
||||
const buffer = new InstancedBufferAttribute( instanceColorAttribute.array, 3 );
|
||||
const bufferFn = instanceColorAttribute.usage === DynamicDrawUsage ? instancedDynamicBufferAttribute : instancedBufferAttribute;
|
||||
|
||||
this.instanceColorNode = vec3( bufferFn( buffer, 'vec3', 3, 0 ) );
|
||||
|
||||
}
|
||||
|
||||
// POSITION
|
||||
|
||||
const instancePosition = instanceMatrixNode.mul( positionLocal ).xyz;
|
||||
|
||||
// NORMAL
|
||||
|
||||
const m = mat3( instanceMatrixNode[ 0 ].xyz, instanceMatrixNode[ 1 ].xyz, instanceMatrixNode[ 2 ].xyz );
|
||||
|
||||
const transformedNormal = normalLocal.div( vec3( m[ 0 ].dot( m[ 0 ] ), m[ 1 ].dot( m[ 1 ] ), m[ 2 ].dot( m[ 2 ] ) ) );
|
||||
|
||||
const instanceNormal = m.mul( transformedNormal ).xyz;
|
||||
|
||||
// ASSIGNS
|
||||
|
||||
positionLocal.assign( instancePosition );
|
||||
normalLocal.assign( instanceNormal );
|
||||
|
||||
// COLOR
|
||||
|
||||
if ( this.instanceColorNode !== null ) {
|
||||
|
||||
varyingProperty( 'vec3', 'vInstanceColor' ).assign( this.instanceColorNode );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default InstanceNode;
|
||||
|
||||
export const instance = nodeProxy( InstanceNode );
|
||||
|
||||
addNodeClass( 'InstanceNode', InstanceNode );
|
@ -0,0 +1,21 @@
|
||||
import MaterialNode from './MaterialNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { nodeImmutable } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class InstancedPointsMaterialNode extends MaterialNode {
|
||||
|
||||
setup( /*builder*/ ) {
|
||||
|
||||
return this.getFloat( this.scope );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
InstancedPointsMaterialNode.POINT_WIDTH = 'pointWidth';
|
||||
|
||||
export default InstancedPointsMaterialNode;
|
||||
|
||||
export const materialPointWidth = nodeImmutable( InstancedPointsMaterialNode, InstancedPointsMaterialNode.POINT_WIDTH );
|
||||
|
||||
addNodeClass( 'InstancedPointsMaterialNode', InstancedPointsMaterialNode );
|
418
public/sdk/three/jsm/nodes/accessors/MaterialNode.js
Normal file
418
public/sdk/three/jsm/nodes/accessors/MaterialNode.js
Normal file
@ -0,0 +1,418 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { reference } from './ReferenceNode.js';
|
||||
import { materialReference } from './MaterialReferenceNode.js';
|
||||
import { normalView } from './NormalNode.js';
|
||||
import { nodeImmutable, float, vec2, mat2 } from '../shadernode/ShaderNode.js';
|
||||
import { uniform } from '../core/UniformNode.js';
|
||||
import { Vector2 } from 'three';
|
||||
|
||||
const _propertyCache = new Map();
|
||||
|
||||
class MaterialNode extends Node {
|
||||
|
||||
constructor( scope ) {
|
||||
|
||||
super();
|
||||
|
||||
this.scope = scope;
|
||||
|
||||
}
|
||||
|
||||
getCache( property, type ) {
|
||||
|
||||
let node = _propertyCache.get( property );
|
||||
|
||||
if ( node === undefined ) {
|
||||
|
||||
node = materialReference( property, type );
|
||||
|
||||
_propertyCache.set( property, node );
|
||||
|
||||
}
|
||||
|
||||
return node;
|
||||
|
||||
}
|
||||
|
||||
getFloat( property ) {
|
||||
|
||||
return this.getCache( property, 'float' );
|
||||
|
||||
}
|
||||
|
||||
getColor( property ) {
|
||||
|
||||
return this.getCache( property, 'color' );
|
||||
|
||||
}
|
||||
|
||||
getTexture( property ) {
|
||||
|
||||
return this.getCache( property === 'map' ? 'map' : property + 'Map', 'texture' );
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
const material = builder.context.material;
|
||||
const scope = this.scope;
|
||||
|
||||
let node = null;
|
||||
|
||||
if ( scope === MaterialNode.COLOR ) {
|
||||
|
||||
const colorNode = this.getColor( scope );
|
||||
|
||||
if ( material.map && material.map.isTexture === true ) {
|
||||
|
||||
node = colorNode.mul( this.getTexture( 'map' ) );
|
||||
|
||||
} else {
|
||||
|
||||
node = colorNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.OPACITY ) {
|
||||
|
||||
const opacityNode = this.getFloat( scope );
|
||||
|
||||
if ( material.alphaMap && material.alphaMap.isTexture === true ) {
|
||||
|
||||
node = opacityNode.mul( this.getTexture( 'alpha' ) );
|
||||
|
||||
} else {
|
||||
|
||||
node = opacityNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.SPECULAR_STRENGTH ) {
|
||||
|
||||
if ( material.specularMap && material.specularMap.isTexture === true ) {
|
||||
|
||||
node = this.getTexture( 'specular' ).r;
|
||||
|
||||
} else {
|
||||
|
||||
node = float( 1 );
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.SPECULAR_INTENSITY ) {
|
||||
|
||||
const specularIntensity = this.getFloat( scope );
|
||||
|
||||
if ( material.specularMap ) {
|
||||
|
||||
node = specularIntensity.mul( this.getTexture( scope ).a );
|
||||
|
||||
} else {
|
||||
|
||||
node = specularIntensity;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.SPECULAR_COLOR ) {
|
||||
|
||||
const specularColorNode = this.getColor( scope );
|
||||
|
||||
if ( material.specularColorMap && material.specularColorMap.isTexture === true ) {
|
||||
|
||||
node = specularColorNode.mul( this.getTexture( scope ).rgb );
|
||||
|
||||
} else {
|
||||
|
||||
node = specularColorNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.ROUGHNESS ) { // TODO: cleanup similar branches
|
||||
|
||||
const roughnessNode = this.getFloat( scope );
|
||||
|
||||
if ( material.roughnessMap && material.roughnessMap.isTexture === true ) {
|
||||
|
||||
node = roughnessNode.mul( this.getTexture( scope ).g );
|
||||
|
||||
} else {
|
||||
|
||||
node = roughnessNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.METALNESS ) {
|
||||
|
||||
const metalnessNode = this.getFloat( scope );
|
||||
|
||||
if ( material.metalnessMap && material.metalnessMap.isTexture === true ) {
|
||||
|
||||
node = metalnessNode.mul( this.getTexture( scope ).b );
|
||||
|
||||
} else {
|
||||
|
||||
node = metalnessNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.EMISSIVE ) {
|
||||
|
||||
const emissiveNode = this.getColor( scope );
|
||||
|
||||
if ( material.emissiveMap && material.emissiveMap.isTexture === true ) {
|
||||
|
||||
node = emissiveNode.mul( this.getTexture( scope ) );
|
||||
|
||||
} else {
|
||||
|
||||
node = emissiveNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.NORMAL ) {
|
||||
|
||||
if ( material.normalMap ) {
|
||||
|
||||
node = this.getTexture( 'normal' ).normalMap( this.getCache( 'normalScale', 'vec2' ) );
|
||||
|
||||
} else if ( material.bumpMap ) {
|
||||
|
||||
node = this.getTexture( 'bump' ).r.bumpMap( this.getFloat( 'bumpScale' ) );
|
||||
|
||||
} else {
|
||||
|
||||
node = normalView;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.CLEARCOAT ) {
|
||||
|
||||
const clearcoatNode = this.getFloat( scope );
|
||||
|
||||
if ( material.clearcoatMap && material.clearcoatMap.isTexture === true ) {
|
||||
|
||||
node = clearcoatNode.mul( this.getTexture( scope ).r );
|
||||
|
||||
} else {
|
||||
|
||||
node = clearcoatNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.CLEARCOAT_ROUGHNESS ) {
|
||||
|
||||
const clearcoatRoughnessNode = this.getFloat( scope );
|
||||
|
||||
if ( material.clearcoatRoughnessMap && material.clearcoatRoughnessMap.isTexture === true ) {
|
||||
|
||||
node = clearcoatRoughnessNode.mul( this.getTexture( scope ).r );
|
||||
|
||||
} else {
|
||||
|
||||
node = clearcoatRoughnessNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.CLEARCOAT_NORMAL ) {
|
||||
|
||||
if ( material.clearcoatNormalMap ) {
|
||||
|
||||
node = this.getTexture( scope ).normalMap( this.getCache( scope + 'Scale', 'vec2' ) );
|
||||
|
||||
} else {
|
||||
|
||||
node = normalView;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.SHEEN ) {
|
||||
|
||||
const sheenNode = this.getColor( 'sheenColor' ).mul( this.getFloat( 'sheen' ) ); // Move this mul() to CPU
|
||||
|
||||
if ( material.sheenColorMap && material.sheenColorMap.isTexture === true ) {
|
||||
|
||||
node = sheenNode.mul( this.getTexture( 'sheenColor' ).rgb );
|
||||
|
||||
} else {
|
||||
|
||||
node = sheenNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.SHEEN_ROUGHNESS ) {
|
||||
|
||||
const sheenRoughnessNode = this.getFloat( scope );
|
||||
|
||||
if ( material.sheenRoughnessMap && material.sheenRoughnessMap.isTexture === true ) {
|
||||
|
||||
node = sheenRoughnessNode.mul( this.getTexture( scope ).a );
|
||||
|
||||
} else {
|
||||
|
||||
node = sheenRoughnessNode;
|
||||
|
||||
}
|
||||
|
||||
node = node.clamp( 0.07, 1.0 );
|
||||
|
||||
} else if ( scope === MaterialNode.ANISOTROPY ) {
|
||||
|
||||
if ( material.anisotropyMap && material.anisotropyMap.isTexture === true ) {
|
||||
|
||||
const anisotropyPolar = this.getTexture( scope );
|
||||
const anisotropyMat = mat2( materialAnisotropyVector.x, materialAnisotropyVector.y, materialAnisotropyVector.y.negate(), materialAnisotropyVector.x );
|
||||
|
||||
node = anisotropyMat.mul( anisotropyPolar.rg.mul( 2.0 ).sub( vec2( 1.0 ) ).normalize().mul( anisotropyPolar.b ) );
|
||||
|
||||
} else {
|
||||
|
||||
node = materialAnisotropyVector;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.IRIDESCENCE_THICKNESS ) {
|
||||
|
||||
const iridescenceThicknessMaximum = reference( '1', 'float', material.iridescenceThicknessRange );
|
||||
|
||||
if ( material.iridescenceThicknessMap ) {
|
||||
|
||||
const iridescenceThicknessMinimum = reference( '0', 'float', material.iridescenceThicknessRange );
|
||||
|
||||
node = iridescenceThicknessMaximum.sub( iridescenceThicknessMinimum ).mul( this.getTexture( scope ).g ).add( iridescenceThicknessMinimum );
|
||||
|
||||
} else {
|
||||
|
||||
node = iridescenceThicknessMaximum;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.TRANSMISSION ) {
|
||||
|
||||
const transmissionNode = this.getFloat( scope );
|
||||
|
||||
if ( material.transmissionMap ) {
|
||||
|
||||
node = transmissionNode.mul( this.getTexture( scope ).r );
|
||||
|
||||
} else {
|
||||
|
||||
node = transmissionNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.THICKNESS ) {
|
||||
|
||||
const thicknessNode = this.getFloat( scope );
|
||||
|
||||
if ( material.thicknessMap ) {
|
||||
|
||||
node = thicknessNode.mul( this.getTexture( scope ).g );
|
||||
|
||||
} else {
|
||||
|
||||
node = thicknessNode;
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === MaterialNode.IOR ) {
|
||||
|
||||
node = this.getFloat( scope );
|
||||
|
||||
} else {
|
||||
|
||||
const outputType = this.getNodeType( builder );
|
||||
|
||||
node = this.getCache( scope, outputType );
|
||||
|
||||
}
|
||||
|
||||
return node;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MaterialNode.ALPHA_TEST = 'alphaTest';
|
||||
MaterialNode.COLOR = 'color';
|
||||
MaterialNode.OPACITY = 'opacity';
|
||||
MaterialNode.SHININESS = 'shininess';
|
||||
MaterialNode.SPECULAR = 'specular';
|
||||
MaterialNode.SPECULAR_STRENGTH = 'specularStrength';
|
||||
MaterialNode.SPECULAR_INTENSITY = 'specularIntensity';
|
||||
MaterialNode.SPECULAR_COLOR = 'specularColor';
|
||||
MaterialNode.REFLECTIVITY = 'reflectivity';
|
||||
MaterialNode.ROUGHNESS = 'roughness';
|
||||
MaterialNode.METALNESS = 'metalness';
|
||||
MaterialNode.NORMAL = 'normal';
|
||||
MaterialNode.CLEARCOAT = 'clearcoat';
|
||||
MaterialNode.CLEARCOAT_ROUGHNESS = 'clearcoatRoughness';
|
||||
MaterialNode.CLEARCOAT_NORMAL = 'clearcoatNormal';
|
||||
MaterialNode.EMISSIVE = 'emissive';
|
||||
MaterialNode.ROTATION = 'rotation';
|
||||
MaterialNode.SHEEN = 'sheen';
|
||||
MaterialNode.SHEEN_ROUGHNESS = 'sheenRoughness';
|
||||
MaterialNode.ANISOTROPY = 'anisotropy';
|
||||
MaterialNode.IRIDESCENCE = 'iridescence';
|
||||
MaterialNode.IRIDESCENCE_IOR = 'iridescenceIOR';
|
||||
MaterialNode.IRIDESCENCE_THICKNESS = 'iridescenceThickness';
|
||||
MaterialNode.IOR = 'ior';
|
||||
MaterialNode.TRANSMISSION = 'transmission';
|
||||
MaterialNode.THICKNESS = 'thickness';
|
||||
MaterialNode.ATTENUATION_DISTANCE = 'attenuationDistance';
|
||||
MaterialNode.ATTENUATION_COLOR = 'attenuationColor';
|
||||
MaterialNode.LINE_SCALE = 'scale';
|
||||
MaterialNode.LINE_DASH_SIZE = 'dashSize';
|
||||
MaterialNode.LINE_GAP_SIZE = 'gapSize';
|
||||
MaterialNode.LINE_WIDTH = 'linewidth';
|
||||
MaterialNode.LINE_DASH_OFFSET = 'dashOffset';
|
||||
MaterialNode.POINT_WIDTH = 'pointWidth';
|
||||
|
||||
export default MaterialNode;
|
||||
|
||||
export const materialAlphaTest = nodeImmutable( MaterialNode, MaterialNode.ALPHA_TEST );
|
||||
export const materialColor = nodeImmutable( MaterialNode, MaterialNode.COLOR );
|
||||
export const materialShininess = nodeImmutable( MaterialNode, MaterialNode.SHININESS );
|
||||
export const materialEmissive = nodeImmutable( MaterialNode, MaterialNode.EMISSIVE );
|
||||
export const materialOpacity = nodeImmutable( MaterialNode, MaterialNode.OPACITY );
|
||||
export const materialSpecular = nodeImmutable( MaterialNode, MaterialNode.SPECULAR );
|
||||
|
||||
export const materialSpecularIntensity = nodeImmutable( MaterialNode, MaterialNode.SPECULAR_INTENSITY );
|
||||
export const materialSpecularColor = nodeImmutable( MaterialNode, MaterialNode.SPECULAR_COLOR );
|
||||
|
||||
export const materialSpecularStrength = nodeImmutable( MaterialNode, MaterialNode.SPECULAR_STRENGTH );
|
||||
export const materialReflectivity = nodeImmutable( MaterialNode, MaterialNode.REFLECTIVITY );
|
||||
export const materialRoughness = nodeImmutable( MaterialNode, MaterialNode.ROUGHNESS );
|
||||
export const materialMetalness = nodeImmutable( MaterialNode, MaterialNode.METALNESS );
|
||||
export const materialNormal = nodeImmutable( MaterialNode, MaterialNode.NORMAL );
|
||||
export const materialClearcoat = nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT );
|
||||
export const materialClearcoatRoughness = nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_ROUGHNESS );
|
||||
export const materialClearcoatNormal = nodeImmutable( MaterialNode, MaterialNode.CLEARCOAT_NORMAL );
|
||||
export const materialRotation = nodeImmutable( MaterialNode, MaterialNode.ROTATION );
|
||||
export const materialSheen = nodeImmutable( MaterialNode, MaterialNode.SHEEN );
|
||||
export const materialSheenRoughness = nodeImmutable( MaterialNode, MaterialNode.SHEEN_ROUGHNESS );
|
||||
export const materialAnisotropy = nodeImmutable( MaterialNode, MaterialNode.ANISOTROPY );
|
||||
export const materialIridescence = nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE );
|
||||
export const materialIridescenceIOR = nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_IOR );
|
||||
export const materialIridescenceThickness = nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_THICKNESS );
|
||||
export const materialTransmission = nodeImmutable( MaterialNode, MaterialNode.TRANSMISSION );
|
||||
export const materialThickness = nodeImmutable( MaterialNode, MaterialNode.THICKNESS );
|
||||
export const materialIOR = nodeImmutable( MaterialNode, MaterialNode.IOR );
|
||||
export const materialAttenuationDistance = nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_DISTANCE );
|
||||
export const materialAttenuationColor = nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_COLOR );
|
||||
export const materialLineScale = nodeImmutable( MaterialNode, MaterialNode.LINE_SCALE );
|
||||
export const materialLineDashSize = nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_SIZE );
|
||||
export const materialLineGapSize = nodeImmutable( MaterialNode, MaterialNode.LINE_GAP_SIZE );
|
||||
export const materialLineWidth = nodeImmutable( MaterialNode, MaterialNode.LINE_WIDTH );
|
||||
export const materialLineDashOffset = nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_OFFSET );
|
||||
export const materialPointWidth = nodeImmutable( MaterialNode, MaterialNode.POINT_WIDTH );
|
||||
export const materialAnisotropyVector = uniform( new Vector2() ).onReference( function ( frame ) {
|
||||
|
||||
return frame.material;
|
||||
|
||||
} ).onRenderUpdate( function ( { material } ) {
|
||||
|
||||
this.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) );
|
||||
|
||||
} );
|
||||
|
||||
addNodeClass( 'MaterialNode', MaterialNode );
|
@ -0,0 +1,41 @@
|
||||
import ReferenceNode from './ReferenceNode.js';
|
||||
//import { renderGroup } from '../core/UniformGroupNode.js';
|
||||
//import { NodeUpdateType } from '../core/constants.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class MaterialReferenceNode extends ReferenceNode {
|
||||
|
||||
constructor( property, inputType, material = null ) {
|
||||
|
||||
super( property, inputType, material );
|
||||
|
||||
this.material = material;
|
||||
|
||||
//this.updateType = NodeUpdateType.RENDER;
|
||||
|
||||
}
|
||||
|
||||
/*setNodeType( node ) {
|
||||
|
||||
super.setNodeType( node );
|
||||
|
||||
this.node.groupNode = renderGroup;
|
||||
|
||||
}*/
|
||||
|
||||
updateReference( state ) {
|
||||
|
||||
this.reference = this.material !== null ? this.material : state.material;
|
||||
|
||||
return this.reference;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default MaterialReferenceNode;
|
||||
|
||||
export const materialReference = ( name, type, material ) => nodeObject( new MaterialReferenceNode( name, type, material ) );
|
||||
|
||||
addNodeClass( 'MaterialReferenceNode', MaterialReferenceNode );
|
33
public/sdk/three/jsm/nodes/accessors/ModelNode.js
Normal file
33
public/sdk/three/jsm/nodes/accessors/ModelNode.js
Normal file
@ -0,0 +1,33 @@
|
||||
import Object3DNode from './Object3DNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { nodeImmutable } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class ModelNode extends Object3DNode {
|
||||
|
||||
constructor( scope = ModelNode.VIEW_MATRIX ) {
|
||||
|
||||
super( scope );
|
||||
|
||||
}
|
||||
|
||||
update( frame ) {
|
||||
|
||||
this.object3d = frame.object;
|
||||
|
||||
super.update( frame );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ModelNode;
|
||||
|
||||
export const modelDirection = nodeImmutable( ModelNode, ModelNode.DIRECTION );
|
||||
export const modelViewMatrix = nodeImmutable( ModelNode, ModelNode.VIEW_MATRIX ).label( 'modelViewMatrix' ).temp( 'ModelViewMatrix' );
|
||||
export const modelNormalMatrix = nodeImmutable( ModelNode, ModelNode.NORMAL_MATRIX );
|
||||
export const modelWorldMatrix = nodeImmutable( ModelNode, ModelNode.WORLD_MATRIX );
|
||||
export const modelPosition = nodeImmutable( ModelNode, ModelNode.POSITION );
|
||||
export const modelScale = nodeImmutable( ModelNode, ModelNode.SCALE );
|
||||
export const modelViewPosition = nodeImmutable( ModelNode, ModelNode.VIEW_POSITION );
|
||||
|
||||
addNodeClass( 'ModelNode', ModelNode );
|
@ -0,0 +1,39 @@
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import TempNode from '../core/TempNode.js';
|
||||
import { cameraProjectionMatrix } from './CameraNode.js';
|
||||
import { modelViewMatrix } from './ModelNode.js';
|
||||
import { positionLocal } from './PositionNode.js';
|
||||
import { nodeProxy } from '../shadernode/ShaderNode.js';
|
||||
import { varying } from '../core/VaryingNode.js';
|
||||
|
||||
class ModelViewProjectionNode extends TempNode {
|
||||
|
||||
constructor( positionNode = null ) {
|
||||
|
||||
super( 'vec4' );
|
||||
|
||||
this.positionNode = positionNode;
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
if ( builder.shaderStage === 'fragment' ) {
|
||||
|
||||
return varying( builder.context.mvp );
|
||||
|
||||
}
|
||||
|
||||
const position = this.positionNode || positionLocal;
|
||||
|
||||
return cameraProjectionMatrix.mul( modelViewMatrix ).mul( position );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ModelViewProjectionNode;
|
||||
|
||||
export const modelViewProjection = nodeProxy( ModelViewProjectionNode );
|
||||
|
||||
addNodeClass( 'ModelViewProjectionNode', ModelViewProjectionNode );
|
255
public/sdk/three/jsm/nodes/accessors/MorphNode.js
Normal file
255
public/sdk/three/jsm/nodes/accessors/MorphNode.js
Normal file
@ -0,0 +1,255 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { NodeUpdateType } from '../core/constants.js';
|
||||
import { float, nodeProxy, tslFn } from '../shadernode/ShaderNode.js';
|
||||
import { uniform } from '../core/UniformNode.js';
|
||||
import { reference } from './ReferenceNode.js';
|
||||
import { positionLocal } from './PositionNode.js';
|
||||
import { normalLocal } from './NormalNode.js';
|
||||
import { textureLoad } from './TextureNode.js';
|
||||
import { instanceIndex, vertexIndex } from '../core/IndexNode.js';
|
||||
import { ivec2, int } from '../shadernode/ShaderNode.js';
|
||||
import { DataArrayTexture, Vector2, Vector4, FloatType } from 'three';
|
||||
import { loop } from '../utils/LoopNode.js';
|
||||
|
||||
const morphTextures = new WeakMap();
|
||||
const morphVec4 = new Vector4();
|
||||
|
||||
const getMorph = tslFn( ( { bufferMap, influence, stride, width, depth, offset } ) => {
|
||||
|
||||
const texelIndex = int( vertexIndex ).mul( stride ).add( offset );
|
||||
|
||||
const y = texelIndex.div( width );
|
||||
const x = texelIndex.sub( y.mul( width ) );
|
||||
|
||||
const bufferAttrib = textureLoad( bufferMap, ivec2( x, y ) ).depth( depth );
|
||||
|
||||
return bufferAttrib.mul( influence );
|
||||
|
||||
} );
|
||||
|
||||
function getEntry( geometry ) {
|
||||
|
||||
const hasMorphPosition = geometry.morphAttributes.position !== undefined;
|
||||
const hasMorphNormals = geometry.morphAttributes.normal !== undefined;
|
||||
const hasMorphColors = geometry.morphAttributes.color !== undefined;
|
||||
|
||||
// instead of using attributes, the WebGL 2 code path encodes morph targets
|
||||
// into an array of data textures. Each layer represents a single morph target.
|
||||
|
||||
const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
|
||||
const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
|
||||
|
||||
let entry = morphTextures.get( geometry );
|
||||
|
||||
if ( entry === undefined || entry.count !== morphTargetsCount ) {
|
||||
|
||||
if ( entry !== undefined ) entry.texture.dispose();
|
||||
|
||||
const morphTargets = geometry.morphAttributes.position || [];
|
||||
const morphNormals = geometry.morphAttributes.normal || [];
|
||||
const morphColors = geometry.morphAttributes.color || [];
|
||||
|
||||
let vertexDataCount = 0;
|
||||
|
||||
if ( hasMorphPosition === true ) vertexDataCount = 1;
|
||||
if ( hasMorphNormals === true ) vertexDataCount = 2;
|
||||
if ( hasMorphColors === true ) vertexDataCount = 3;
|
||||
|
||||
let width = geometry.attributes.position.count * vertexDataCount;
|
||||
let height = 1;
|
||||
|
||||
const maxTextureSize = 4096; // @TODO: Use 'capabilities.maxTextureSize'
|
||||
|
||||
if ( width > maxTextureSize ) {
|
||||
|
||||
height = Math.ceil( width / maxTextureSize );
|
||||
width = maxTextureSize;
|
||||
|
||||
}
|
||||
|
||||
const buffer = new Float32Array( width * height * 4 * morphTargetsCount );
|
||||
|
||||
const bufferTexture = new DataArrayTexture( buffer, width, height, morphTargetsCount );
|
||||
bufferTexture.type = FloatType;
|
||||
bufferTexture.needsUpdate = true;
|
||||
|
||||
// fill buffer
|
||||
|
||||
const vertexDataStride = vertexDataCount * 4;
|
||||
|
||||
for ( let i = 0; i < morphTargetsCount; i ++ ) {
|
||||
|
||||
const morphTarget = morphTargets[ i ];
|
||||
const morphNormal = morphNormals[ i ];
|
||||
const morphColor = morphColors[ i ];
|
||||
|
||||
const offset = width * height * 4 * i;
|
||||
|
||||
for ( let j = 0; j < morphTarget.count; j ++ ) {
|
||||
|
||||
const stride = j * vertexDataStride;
|
||||
|
||||
if ( hasMorphPosition === true ) {
|
||||
|
||||
morphVec4.fromBufferAttribute( morphTarget, j );
|
||||
|
||||
buffer[ offset + stride + 0 ] = morphVec4.x;
|
||||
buffer[ offset + stride + 1 ] = morphVec4.y;
|
||||
buffer[ offset + stride + 2 ] = morphVec4.z;
|
||||
buffer[ offset + stride + 3 ] = 0;
|
||||
|
||||
}
|
||||
|
||||
if ( hasMorphNormals === true ) {
|
||||
|
||||
morphVec4.fromBufferAttribute( morphNormal, j );
|
||||
|
||||
buffer[ offset + stride + 4 ] = morphVec4.x;
|
||||
buffer[ offset + stride + 5 ] = morphVec4.y;
|
||||
buffer[ offset + stride + 6 ] = morphVec4.z;
|
||||
buffer[ offset + stride + 7 ] = 0;
|
||||
|
||||
}
|
||||
|
||||
if ( hasMorphColors === true ) {
|
||||
|
||||
morphVec4.fromBufferAttribute( morphColor, j );
|
||||
|
||||
buffer[ offset + stride + 8 ] = morphVec4.x;
|
||||
buffer[ offset + stride + 9 ] = morphVec4.y;
|
||||
buffer[ offset + stride + 10 ] = morphVec4.z;
|
||||
buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morphVec4.w : 1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
entry = {
|
||||
count: morphTargetsCount,
|
||||
texture: bufferTexture,
|
||||
stride: vertexDataCount,
|
||||
size: new Vector2( width, height )
|
||||
};
|
||||
|
||||
morphTextures.set( geometry, entry );
|
||||
|
||||
function disposeTexture() {
|
||||
|
||||
bufferTexture.dispose();
|
||||
|
||||
morphTextures.delete( geometry );
|
||||
|
||||
geometry.removeEventListener( 'dispose', disposeTexture );
|
||||
|
||||
}
|
||||
|
||||
geometry.addEventListener( 'dispose', disposeTexture );
|
||||
|
||||
}
|
||||
|
||||
return entry;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class MorphNode extends Node {
|
||||
|
||||
constructor( mesh ) {
|
||||
|
||||
super( 'void' );
|
||||
|
||||
this.mesh = mesh;
|
||||
this.morphBaseInfluence = uniform( 1 );
|
||||
|
||||
this.updateType = NodeUpdateType.OBJECT;
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
const { geometry } = builder;
|
||||
|
||||
const hasMorphPosition = geometry.morphAttributes.position !== undefined;
|
||||
const hasMorphNormals = geometry.morphAttributes.normal !== undefined;
|
||||
|
||||
const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
|
||||
const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;
|
||||
|
||||
// nodes
|
||||
|
||||
const { texture: bufferMap, stride, size } = getEntry( geometry );
|
||||
|
||||
if ( hasMorphPosition === true ) positionLocal.mulAssign( this.morphBaseInfluence );
|
||||
if ( hasMorphNormals === true ) normalLocal.mulAssign( this.morphBaseInfluence );
|
||||
|
||||
const width = int( size.width );
|
||||
|
||||
loop( morphTargetsCount, ( { i } ) => {
|
||||
|
||||
const influence = float( 0 ).toVar();
|
||||
|
||||
if ( this.mesh.isInstancedMesh === true && ( this.mesh.morphTexture !== null && this.mesh.morphTexture !== undefined ) ) {
|
||||
|
||||
influence.assign( textureLoad( this.mesh.morphTexture, ivec2( int( i ).add( 1 ), int( instanceIndex ) ) ).r );
|
||||
|
||||
} else {
|
||||
|
||||
influence.assign( reference( 'morphTargetInfluences', 'float' ).element( i ).toVar() );
|
||||
|
||||
}
|
||||
|
||||
if ( hasMorphPosition === true ) {
|
||||
|
||||
positionLocal.addAssign( getMorph( {
|
||||
bufferMap,
|
||||
influence,
|
||||
stride,
|
||||
width,
|
||||
depth: i,
|
||||
offset: int( 0 )
|
||||
} ) );
|
||||
|
||||
}
|
||||
|
||||
if ( hasMorphNormals === true ) {
|
||||
|
||||
normalLocal.addAssign( getMorph( {
|
||||
bufferMap,
|
||||
influence,
|
||||
stride,
|
||||
width,
|
||||
depth: i,
|
||||
offset: int( 1 )
|
||||
} ) );
|
||||
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
}
|
||||
|
||||
update() {
|
||||
|
||||
const morphBaseInfluence = this.morphBaseInfluence;
|
||||
|
||||
if ( this.mesh.geometry.morphTargetsRelative ) {
|
||||
|
||||
morphBaseInfluence.value = 1;
|
||||
|
||||
} else {
|
||||
|
||||
morphBaseInfluence.value = 1 - this.mesh.morphTargetInfluences.reduce( ( a, b ) => a + b, 0 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default MorphNode;
|
||||
|
||||
export const morphReference = nodeProxy( MorphNode );
|
||||
|
||||
addNodeClass( 'MorphNode', MorphNode );
|
106
public/sdk/three/jsm/nodes/accessors/NormalNode.js
Normal file
106
public/sdk/three/jsm/nodes/accessors/NormalNode.js
Normal file
@ -0,0 +1,106 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { attribute } from '../core/AttributeNode.js';
|
||||
import { varying } from '../core/VaryingNode.js';
|
||||
import { property } from '../core/PropertyNode.js';
|
||||
import { normalize } from '../math/MathNode.js';
|
||||
import { cameraViewMatrix } from './CameraNode.js';
|
||||
import { modelNormalMatrix } from './ModelNode.js';
|
||||
import { nodeImmutable, vec3 } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class NormalNode extends Node {
|
||||
|
||||
constructor( scope = NormalNode.LOCAL ) {
|
||||
|
||||
super( 'vec3' );
|
||||
|
||||
this.scope = scope;
|
||||
|
||||
}
|
||||
|
||||
isGlobal() {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
getHash( /*builder*/ ) {
|
||||
|
||||
return `normal-${this.scope}`;
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
const scope = this.scope;
|
||||
|
||||
let outputNode = null;
|
||||
|
||||
if ( scope === NormalNode.GEOMETRY ) {
|
||||
|
||||
const geometryAttribute = builder.hasGeometryAttribute( 'normal' );
|
||||
|
||||
if ( geometryAttribute === false ) {
|
||||
|
||||
outputNode = vec3( 0, 1, 0 );
|
||||
|
||||
} else {
|
||||
|
||||
outputNode = attribute( 'normal', 'vec3' );
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === NormalNode.LOCAL ) {
|
||||
|
||||
outputNode = varying( normalGeometry );
|
||||
|
||||
} else if ( scope === NormalNode.VIEW ) {
|
||||
|
||||
const vertexNode = modelNormalMatrix.mul( normalLocal );
|
||||
outputNode = normalize( varying( vertexNode ) );
|
||||
|
||||
} else if ( scope === NormalNode.WORLD ) {
|
||||
|
||||
// To use inverseTransformDirection only inverse the param order like this: cameraViewMatrix.transformDirection( normalView )
|
||||
const vertexNode = normalView.transformDirection( cameraViewMatrix );
|
||||
outputNode = normalize( varying( vertexNode ) );
|
||||
|
||||
}
|
||||
|
||||
return outputNode.build( builder, this.getNodeType( builder ) );
|
||||
|
||||
}
|
||||
|
||||
serialize( data ) {
|
||||
|
||||
super.serialize( data );
|
||||
|
||||
data.scope = this.scope;
|
||||
|
||||
}
|
||||
|
||||
deserialize( data ) {
|
||||
|
||||
super.deserialize( data );
|
||||
|
||||
this.scope = data.scope;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NormalNode.GEOMETRY = 'geometry';
|
||||
NormalNode.LOCAL = 'local';
|
||||
NormalNode.VIEW = 'view';
|
||||
NormalNode.WORLD = 'world';
|
||||
|
||||
export default NormalNode;
|
||||
|
||||
export const normalGeometry = nodeImmutable( NormalNode, NormalNode.GEOMETRY );
|
||||
export const normalLocal = nodeImmutable( NormalNode, NormalNode.LOCAL ).temp( 'Normal' );
|
||||
export const normalView = nodeImmutable( NormalNode, NormalNode.VIEW );
|
||||
export const normalWorld = nodeImmutable( NormalNode, NormalNode.WORLD );
|
||||
export const transformedNormalView = property( 'vec3', 'TransformedNormalView' );
|
||||
export const transformedNormalWorld = transformedNormalView.transformDirection( cameraViewMatrix ).normalize();
|
||||
export const transformedClearcoatNormalView = property( 'vec3', 'TransformedClearcoatNormalView' );
|
||||
|
||||
addNodeClass( 'NormalNode', NormalNode );
|
150
public/sdk/three/jsm/nodes/accessors/Object3DNode.js
Normal file
150
public/sdk/three/jsm/nodes/accessors/Object3DNode.js
Normal file
@ -0,0 +1,150 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { NodeUpdateType } from '../core/constants.js';
|
||||
import UniformNode from '../core/UniformNode.js';
|
||||
import { nodeProxy } from '../shadernode/ShaderNode.js';
|
||||
|
||||
import { Vector3 } from 'three';
|
||||
|
||||
class Object3DNode extends Node {
|
||||
|
||||
constructor( scope = Object3DNode.VIEW_MATRIX, object3d = null ) {
|
||||
|
||||
super();
|
||||
|
||||
this.scope = scope;
|
||||
this.object3d = object3d;
|
||||
|
||||
this.updateType = NodeUpdateType.OBJECT;
|
||||
|
||||
this._uniformNode = new UniformNode( null );
|
||||
|
||||
}
|
||||
|
||||
getNodeType() {
|
||||
|
||||
const scope = this.scope;
|
||||
|
||||
if ( scope === Object3DNode.WORLD_MATRIX || scope === Object3DNode.VIEW_MATRIX ) {
|
||||
|
||||
return 'mat4';
|
||||
|
||||
} else if ( scope === Object3DNode.NORMAL_MATRIX ) {
|
||||
|
||||
return 'mat3';
|
||||
|
||||
} else if ( scope === Object3DNode.POSITION || scope === Object3DNode.VIEW_POSITION || scope === Object3DNode.DIRECTION || scope === Object3DNode.SCALE ) {
|
||||
|
||||
return 'vec3';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
update( frame ) {
|
||||
|
||||
const object = this.object3d;
|
||||
const uniformNode = this._uniformNode;
|
||||
const scope = this.scope;
|
||||
|
||||
if ( scope === Object3DNode.VIEW_MATRIX ) {
|
||||
|
||||
uniformNode.value = object.modelViewMatrix;
|
||||
|
||||
} else if ( scope === Object3DNode.NORMAL_MATRIX ) {
|
||||
|
||||
uniformNode.value = object.normalMatrix;
|
||||
|
||||
} else if ( scope === Object3DNode.WORLD_MATRIX ) {
|
||||
|
||||
uniformNode.value = object.matrixWorld;
|
||||
|
||||
} else if ( scope === Object3DNode.POSITION ) {
|
||||
|
||||
uniformNode.value = uniformNode.value || new Vector3();
|
||||
|
||||
uniformNode.value.setFromMatrixPosition( object.matrixWorld );
|
||||
|
||||
} else if ( scope === Object3DNode.SCALE ) {
|
||||
|
||||
uniformNode.value = uniformNode.value || new Vector3();
|
||||
|
||||
uniformNode.value.setFromMatrixScale( object.matrixWorld );
|
||||
|
||||
} else if ( scope === Object3DNode.DIRECTION ) {
|
||||
|
||||
uniformNode.value = uniformNode.value || new Vector3();
|
||||
|
||||
object.getWorldDirection( uniformNode.value );
|
||||
|
||||
} else if ( scope === Object3DNode.VIEW_POSITION ) {
|
||||
|
||||
const camera = frame.camera;
|
||||
|
||||
uniformNode.value = uniformNode.value || new Vector3();
|
||||
uniformNode.value.setFromMatrixPosition( object.matrixWorld );
|
||||
|
||||
uniformNode.value.applyMatrix4( camera.matrixWorldInverse );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
const scope = this.scope;
|
||||
|
||||
if ( scope === Object3DNode.WORLD_MATRIX || scope === Object3DNode.VIEW_MATRIX ) {
|
||||
|
||||
this._uniformNode.nodeType = 'mat4';
|
||||
|
||||
} else if ( scope === Object3DNode.NORMAL_MATRIX ) {
|
||||
|
||||
this._uniformNode.nodeType = 'mat3';
|
||||
|
||||
} else if ( scope === Object3DNode.POSITION || scope === Object3DNode.VIEW_POSITION || scope === Object3DNode.DIRECTION || scope === Object3DNode.SCALE ) {
|
||||
|
||||
this._uniformNode.nodeType = 'vec3';
|
||||
|
||||
}
|
||||
|
||||
return this._uniformNode.build( builder );
|
||||
|
||||
}
|
||||
|
||||
serialize( data ) {
|
||||
|
||||
super.serialize( data );
|
||||
|
||||
data.scope = this.scope;
|
||||
|
||||
}
|
||||
|
||||
deserialize( data ) {
|
||||
|
||||
super.deserialize( data );
|
||||
|
||||
this.scope = data.scope;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Object3DNode.VIEW_MATRIX = 'viewMatrix';
|
||||
Object3DNode.NORMAL_MATRIX = 'normalMatrix';
|
||||
Object3DNode.WORLD_MATRIX = 'worldMatrix';
|
||||
Object3DNode.POSITION = 'position';
|
||||
Object3DNode.SCALE = 'scale';
|
||||
Object3DNode.VIEW_POSITION = 'viewPosition';
|
||||
Object3DNode.DIRECTION = 'direction';
|
||||
|
||||
export default Object3DNode;
|
||||
|
||||
export const objectDirection = nodeProxy( Object3DNode, Object3DNode.DIRECTION );
|
||||
export const objectViewMatrix = nodeProxy( Object3DNode, Object3DNode.VIEW_MATRIX );
|
||||
export const objectNormalMatrix = nodeProxy( Object3DNode, Object3DNode.NORMAL_MATRIX );
|
||||
export const objectWorldMatrix = nodeProxy( Object3DNode, Object3DNode.WORLD_MATRIX );
|
||||
export const objectPosition = nodeProxy( Object3DNode, Object3DNode.POSITION );
|
||||
export const objectScale = nodeProxy( Object3DNode, Object3DNode.SCALE );
|
||||
export const objectViewPosition = nodeProxy( Object3DNode, Object3DNode.VIEW_POSITION );
|
||||
|
||||
addNodeClass( 'Object3DNode', Object3DNode );
|
26
public/sdk/three/jsm/nodes/accessors/PointUVNode.js
Normal file
26
public/sdk/three/jsm/nodes/accessors/PointUVNode.js
Normal file
@ -0,0 +1,26 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { nodeImmutable } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class PointUVNode extends Node {
|
||||
|
||||
constructor() {
|
||||
|
||||
super( 'vec2' );
|
||||
|
||||
this.isPointUVNode = true;
|
||||
|
||||
}
|
||||
|
||||
generate( /*builder*/ ) {
|
||||
|
||||
return 'vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PointUVNode;
|
||||
|
||||
export const pointUV = nodeImmutable( PointUVNode );
|
||||
|
||||
addNodeClass( 'PointUVNode', PointUVNode );
|
104
public/sdk/three/jsm/nodes/accessors/PositionNode.js
Normal file
104
public/sdk/three/jsm/nodes/accessors/PositionNode.js
Normal file
@ -0,0 +1,104 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { attribute } from '../core/AttributeNode.js';
|
||||
import { varying } from '../core/VaryingNode.js';
|
||||
import { normalize } from '../math/MathNode.js';
|
||||
import { modelWorldMatrix, modelViewMatrix } from './ModelNode.js';
|
||||
import { nodeImmutable } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class PositionNode extends Node {
|
||||
|
||||
constructor( scope = PositionNode.LOCAL ) {
|
||||
|
||||
super( 'vec3' );
|
||||
|
||||
this.scope = scope;
|
||||
|
||||
}
|
||||
|
||||
isGlobal() {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
getHash( /*builder*/ ) {
|
||||
|
||||
return `position-${this.scope}`;
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
const scope = this.scope;
|
||||
|
||||
let outputNode = null;
|
||||
|
||||
if ( scope === PositionNode.GEOMETRY ) {
|
||||
|
||||
outputNode = attribute( 'position', 'vec3' );
|
||||
|
||||
} else if ( scope === PositionNode.LOCAL ) {
|
||||
|
||||
outputNode = varying( positionGeometry );
|
||||
|
||||
} else if ( scope === PositionNode.WORLD ) {
|
||||
|
||||
const vertexPositionNode = modelWorldMatrix.mul( positionLocal );
|
||||
outputNode = varying( vertexPositionNode );
|
||||
|
||||
} else if ( scope === PositionNode.VIEW ) {
|
||||
|
||||
const vertexPositionNode = modelViewMatrix.mul( positionLocal );
|
||||
outputNode = varying( vertexPositionNode );
|
||||
|
||||
} else if ( scope === PositionNode.VIEW_DIRECTION ) {
|
||||
|
||||
const vertexPositionNode = positionView.negate();
|
||||
outputNode = normalize( varying( vertexPositionNode ) );
|
||||
|
||||
} else if ( scope === PositionNode.WORLD_DIRECTION ) {
|
||||
|
||||
const vertexPositionNode = positionLocal.transformDirection( modelWorldMatrix );
|
||||
outputNode = normalize( varying( vertexPositionNode ) );
|
||||
|
||||
}
|
||||
|
||||
return outputNode.build( builder, this.getNodeType( builder ) );
|
||||
|
||||
}
|
||||
|
||||
serialize( data ) {
|
||||
|
||||
super.serialize( data );
|
||||
|
||||
data.scope = this.scope;
|
||||
|
||||
}
|
||||
|
||||
deserialize( data ) {
|
||||
|
||||
super.deserialize( data );
|
||||
|
||||
this.scope = data.scope;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PositionNode.GEOMETRY = 'geometry';
|
||||
PositionNode.LOCAL = 'local';
|
||||
PositionNode.WORLD = 'world';
|
||||
PositionNode.WORLD_DIRECTION = 'worldDirection';
|
||||
PositionNode.VIEW = 'view';
|
||||
PositionNode.VIEW_DIRECTION = 'viewDirection';
|
||||
|
||||
export default PositionNode;
|
||||
|
||||
export const positionGeometry = nodeImmutable( PositionNode, PositionNode.GEOMETRY );
|
||||
export const positionLocal = nodeImmutable( PositionNode, PositionNode.LOCAL ).temp( 'Position' );
|
||||
export const positionWorld = nodeImmutable( PositionNode, PositionNode.WORLD );
|
||||
export const positionWorldDirection = nodeImmutable( PositionNode, PositionNode.WORLD_DIRECTION );
|
||||
export const positionView = nodeImmutable( PositionNode, PositionNode.VIEW );
|
||||
export const positionViewDirection = nodeImmutable( PositionNode, PositionNode.VIEW_DIRECTION );
|
||||
|
||||
addNodeClass( 'PositionNode', PositionNode );
|
160
public/sdk/three/jsm/nodes/accessors/ReferenceNode.js
Normal file
160
public/sdk/three/jsm/nodes/accessors/ReferenceNode.js
Normal file
@ -0,0 +1,160 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { NodeUpdateType } from '../core/constants.js';
|
||||
import { uniform } from '../core/UniformNode.js';
|
||||
import { texture } from './TextureNode.js';
|
||||
import { buffer } from './BufferNode.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
import { uniforms } from './UniformsNode.js';
|
||||
import ArrayElementNode from '../utils/ArrayElementNode.js';
|
||||
|
||||
class ReferenceElementNode extends ArrayElementNode {
|
||||
|
||||
constructor( referenceNode, indexNode ) {
|
||||
|
||||
super( referenceNode, indexNode );
|
||||
|
||||
this.referenceNode = referenceNode;
|
||||
|
||||
this.isReferenceElementNode = true;
|
||||
|
||||
}
|
||||
|
||||
getNodeType() {
|
||||
|
||||
return this.referenceNode.uniformType;
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
const snippet = super.generate( builder );
|
||||
const arrayType = this.referenceNode.getNodeType();
|
||||
const elementType = this.getNodeType();
|
||||
|
||||
return builder.format( snippet, arrayType, elementType );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ReferenceNode extends Node {
|
||||
|
||||
constructor( property, uniformType, object = null, count = null ) {
|
||||
|
||||
super();
|
||||
|
||||
this.property = property;
|
||||
this.uniformType = uniformType;
|
||||
this.object = object;
|
||||
this.count = count;
|
||||
|
||||
this.properties = property.split( '.' );
|
||||
this.reference = null;
|
||||
this.node = null;
|
||||
|
||||
this.updateType = NodeUpdateType.OBJECT;
|
||||
|
||||
}
|
||||
|
||||
element( indexNode ) {
|
||||
|
||||
return nodeObject( new ReferenceElementNode( this, nodeObject( indexNode ) ) );
|
||||
|
||||
}
|
||||
|
||||
setNodeType( uniformType ) {
|
||||
|
||||
let node = null;
|
||||
|
||||
if ( this.count !== null ) {
|
||||
|
||||
node = buffer( null, uniformType, this.count );
|
||||
|
||||
} else if ( Array.isArray( this.getValueFromReference() ) ) {
|
||||
|
||||
node = uniforms( null, uniformType );
|
||||
|
||||
} else if ( uniformType === 'texture' ) {
|
||||
|
||||
node = texture( null );
|
||||
|
||||
} else {
|
||||
|
||||
node = uniform( null, uniformType );
|
||||
|
||||
}
|
||||
|
||||
this.node = node;
|
||||
|
||||
}
|
||||
|
||||
getNodeType( builder ) {
|
||||
|
||||
return this.node.getNodeType( builder );
|
||||
|
||||
}
|
||||
|
||||
getValueFromReference( object = this.reference ) {
|
||||
|
||||
const { properties } = this;
|
||||
|
||||
let value = object[ properties[ 0 ] ];
|
||||
|
||||
for ( let i = 1; i < properties.length; i ++ ) {
|
||||
|
||||
value = value[ properties[ i ] ];
|
||||
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
updateReference( state ) {
|
||||
|
||||
this.reference = this.object !== null ? this.object : state.object;
|
||||
|
||||
return this.reference;
|
||||
|
||||
}
|
||||
|
||||
setup() {
|
||||
|
||||
this.updateValue();
|
||||
|
||||
return this.node;
|
||||
|
||||
}
|
||||
|
||||
update( /*frame*/ ) {
|
||||
|
||||
this.updateValue();
|
||||
|
||||
}
|
||||
|
||||
updateValue() {
|
||||
|
||||
if ( this.node === null ) this.setNodeType( this.uniformType );
|
||||
|
||||
const value = this.getValueFromReference();
|
||||
|
||||
if ( Array.isArray( value ) ) {
|
||||
|
||||
this.node.array = value;
|
||||
|
||||
} else {
|
||||
|
||||
this.node.value = value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ReferenceNode;
|
||||
|
||||
export const reference = ( name, type, object ) => nodeObject( new ReferenceNode( name, type, object ) );
|
||||
export const referenceBuffer = ( name, type, count, object ) => nodeObject( new ReferenceNode( name, type, object, count ) );
|
||||
|
||||
addNodeClass( 'ReferenceNode', ReferenceNode );
|
35
public/sdk/three/jsm/nodes/accessors/ReflectVectorNode.js
Normal file
35
public/sdk/three/jsm/nodes/accessors/ReflectVectorNode.js
Normal file
@ -0,0 +1,35 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { cameraViewMatrix } from './CameraNode.js';
|
||||
import { transformedNormalView } from './NormalNode.js';
|
||||
import { positionViewDirection } from './PositionNode.js';
|
||||
import { nodeImmutable } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class ReflectVectorNode extends Node {
|
||||
|
||||
constructor() {
|
||||
|
||||
super( 'vec3' );
|
||||
|
||||
}
|
||||
|
||||
getHash( /*builder*/ ) {
|
||||
|
||||
return 'reflectVector';
|
||||
|
||||
}
|
||||
|
||||
setup() {
|
||||
|
||||
const reflectView = positionViewDirection.negate().reflect( transformedNormalView );
|
||||
|
||||
return reflectView.transformDirection( cameraViewMatrix );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ReflectVectorNode;
|
||||
|
||||
export const reflectVector = nodeImmutable( ReflectVectorNode );
|
||||
|
||||
addNodeClass( 'ReflectVectorNode', ReflectVectorNode );
|
@ -0,0 +1,29 @@
|
||||
import ReferenceNode from './ReferenceNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class RendererReferenceNode extends ReferenceNode {
|
||||
|
||||
constructor( property, inputType, renderer = null ) {
|
||||
|
||||
super( property, inputType, renderer );
|
||||
|
||||
this.renderer = renderer;
|
||||
|
||||
}
|
||||
|
||||
updateReference( state ) {
|
||||
|
||||
this.reference = this.renderer !== null ? this.renderer : state.renderer;
|
||||
|
||||
return this.reference;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default RendererReferenceNode;
|
||||
|
||||
export const rendererReference = ( name, type, renderer ) => nodeObject( new RendererReferenceNode( name, type, renderer ) );
|
||||
|
||||
addNodeClass( 'RendererReferenceNode', RendererReferenceNode );
|
52
public/sdk/three/jsm/nodes/accessors/SceneNode.js
Normal file
52
public/sdk/three/jsm/nodes/accessors/SceneNode.js
Normal file
@ -0,0 +1,52 @@
|
||||
import Node from '../core/Node.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { nodeImmutable } from '../shadernode/ShaderNode.js';
|
||||
import { reference } from './ReferenceNode.js';
|
||||
|
||||
class SceneNode extends Node {
|
||||
|
||||
constructor( scope = SceneNode.BACKGROUND_BLURRINESS, scene = null ) {
|
||||
|
||||
super();
|
||||
|
||||
this.scope = scope;
|
||||
this.scene = scene;
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
const scope = this.scope;
|
||||
const scene = this.scene !== null ? this.scene : builder.scene;
|
||||
|
||||
let output;
|
||||
|
||||
if ( scope === SceneNode.BACKGROUND_BLURRINESS ) {
|
||||
|
||||
output = reference( 'backgroundBlurriness', 'float', scene );
|
||||
|
||||
} else if ( scope === SceneNode.BACKGROUND_INTENSITY ) {
|
||||
|
||||
output = reference( 'backgroundIntensity', 'float', scene );
|
||||
|
||||
} else {
|
||||
|
||||
console.error( 'THREE.SceneNode: Unknown scope:', scope );
|
||||
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SceneNode.BACKGROUND_BLURRINESS = 'backgroundBlurriness';
|
||||
SceneNode.BACKGROUND_INTENSITY = 'backgroundIntensity';
|
||||
|
||||
export default SceneNode;
|
||||
|
||||
export const backgroundBlurriness = nodeImmutable( SceneNode, SceneNode.BACKGROUND_BLURRINESS );
|
||||
export const backgroundIntensity = nodeImmutable( SceneNode, SceneNode.BACKGROUND_INTENSITY );
|
||||
|
||||
addNodeClass( 'SceneNode', SceneNode );
|
124
public/sdk/three/jsm/nodes/accessors/SkinningNode.js
Normal file
124
public/sdk/three/jsm/nodes/accessors/SkinningNode.js
Normal file
@ -0,0 +1,124 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { NodeUpdateType } from '../core/constants.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
import { attribute } from '../core/AttributeNode.js';
|
||||
import { reference, referenceBuffer } from './ReferenceNode.js';
|
||||
import { add } from '../math/OperatorNode.js';
|
||||
import { normalLocal } from './NormalNode.js';
|
||||
import { positionLocal } from './PositionNode.js';
|
||||
import { tangentLocal } from './TangentNode.js';
|
||||
import { uniform } from '../core/UniformNode.js';
|
||||
import { buffer } from './BufferNode.js';
|
||||
|
||||
class SkinningNode extends Node {
|
||||
|
||||
constructor( skinnedMesh, useReference = false ) {
|
||||
|
||||
super( 'void' );
|
||||
|
||||
this.skinnedMesh = skinnedMesh;
|
||||
this.useReference = useReference;
|
||||
|
||||
this.updateType = NodeUpdateType.OBJECT;
|
||||
|
||||
//
|
||||
|
||||
this.skinIndexNode = attribute( 'skinIndex', 'uvec4' );
|
||||
this.skinWeightNode = attribute( 'skinWeight', 'vec4' );
|
||||
|
||||
let bindMatrixNode, bindMatrixInverseNode, boneMatricesNode;
|
||||
|
||||
if ( useReference ) {
|
||||
|
||||
bindMatrixNode = reference( 'bindMatrix', 'mat4' );
|
||||
bindMatrixInverseNode = reference( 'bindMatrixInverse', 'mat4' );
|
||||
boneMatricesNode = referenceBuffer( 'skeleton.boneMatrices', 'mat4', skinnedMesh.skeleton.bones.length );
|
||||
|
||||
} else {
|
||||
|
||||
bindMatrixNode = uniform( skinnedMesh.bindMatrix, 'mat4' );
|
||||
bindMatrixInverseNode = uniform( skinnedMesh.bindMatrixInverse, 'mat4' );
|
||||
boneMatricesNode = buffer( skinnedMesh.skeleton.boneMatrices, 'mat4', skinnedMesh.skeleton.bones.length );
|
||||
|
||||
}
|
||||
|
||||
this.bindMatrixNode = bindMatrixNode;
|
||||
this.bindMatrixInverseNode = bindMatrixInverseNode;
|
||||
this.boneMatricesNode = boneMatricesNode;
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
const { skinIndexNode, skinWeightNode, bindMatrixNode, bindMatrixInverseNode, boneMatricesNode } = this;
|
||||
|
||||
const boneMatX = boneMatricesNode.element( skinIndexNode.x );
|
||||
const boneMatY = boneMatricesNode.element( skinIndexNode.y );
|
||||
const boneMatZ = boneMatricesNode.element( skinIndexNode.z );
|
||||
const boneMatW = boneMatricesNode.element( skinIndexNode.w );
|
||||
|
||||
// POSITION
|
||||
|
||||
const skinVertex = bindMatrixNode.mul( positionLocal );
|
||||
|
||||
const skinned = add(
|
||||
boneMatX.mul( skinWeightNode.x ).mul( skinVertex ),
|
||||
boneMatY.mul( skinWeightNode.y ).mul( skinVertex ),
|
||||
boneMatZ.mul( skinWeightNode.z ).mul( skinVertex ),
|
||||
boneMatW.mul( skinWeightNode.w ).mul( skinVertex )
|
||||
);
|
||||
|
||||
const skinPosition = bindMatrixInverseNode.mul( skinned ).xyz;
|
||||
|
||||
// NORMAL
|
||||
|
||||
let skinMatrix = add(
|
||||
skinWeightNode.x.mul( boneMatX ),
|
||||
skinWeightNode.y.mul( boneMatY ),
|
||||
skinWeightNode.z.mul( boneMatZ ),
|
||||
skinWeightNode.w.mul( boneMatW )
|
||||
);
|
||||
|
||||
skinMatrix = bindMatrixInverseNode.mul( skinMatrix ).mul( bindMatrixNode );
|
||||
|
||||
const skinNormal = skinMatrix.transformDirection( normalLocal ).xyz;
|
||||
|
||||
// ASSIGNS
|
||||
|
||||
positionLocal.assign( skinPosition );
|
||||
normalLocal.assign( skinNormal );
|
||||
|
||||
if ( builder.hasGeometryAttribute( 'tangent' ) ) {
|
||||
|
||||
tangentLocal.assign( skinNormal );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
generate( builder, output ) {
|
||||
|
||||
if ( output !== 'void' ) {
|
||||
|
||||
return positionLocal.build( builder, output );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
update( frame ) {
|
||||
|
||||
const object = this.useReference ? frame.object : this.skinnedMesh;
|
||||
|
||||
object.skeleton.update();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default SkinningNode;
|
||||
|
||||
export const skinning = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh ) );
|
||||
export const skinningReference = ( skinnedMesh ) => nodeObject( new SkinningNode( skinnedMesh, true ) );
|
||||
|
||||
addNodeClass( 'SkinningNode', SkinningNode );
|
81
public/sdk/three/jsm/nodes/accessors/StorageBufferNode.js
Normal file
81
public/sdk/three/jsm/nodes/accessors/StorageBufferNode.js
Normal file
@ -0,0 +1,81 @@
|
||||
import BufferNode from './BufferNode.js';
|
||||
import { bufferAttribute } from './BufferAttributeNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
import { varying } from '../core/VaryingNode.js';
|
||||
import { storageElement } from '../utils/StorageArrayElementNode.js';
|
||||
|
||||
class StorageBufferNode extends BufferNode {
|
||||
|
||||
constructor( value, bufferType, bufferCount = 0 ) {
|
||||
|
||||
super( value, bufferType, bufferCount );
|
||||
|
||||
this.isStorageBufferNode = true;
|
||||
|
||||
this.bufferObject = false;
|
||||
|
||||
this._attribute = null;
|
||||
this._varying = null;
|
||||
|
||||
if ( value.isStorageBufferAttribute !== true && value.isStorageInstancedBufferAttribute !== true ) {
|
||||
|
||||
// TOOD: Improve it, possibly adding a new property to the BufferAttribute to identify it as a storage buffer read-only attribute in Renderer
|
||||
|
||||
if ( value.isInstancedBufferAttribute ) value.isStorageInstancedBufferAttribute = true;
|
||||
else value.isStorageBufferAttribute = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getInputType( /*builder*/ ) {
|
||||
|
||||
return 'storageBuffer';
|
||||
|
||||
}
|
||||
|
||||
element( indexNode ) {
|
||||
|
||||
return storageElement( this, indexNode );
|
||||
|
||||
}
|
||||
|
||||
setBufferObject( value ) {
|
||||
|
||||
this.bufferObject = value;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
if ( builder.isAvailable( 'storageBuffer' ) ) return super.generate( builder );
|
||||
|
||||
const nodeType = this.getNodeType( builder );
|
||||
|
||||
if ( this._attribute === null ) {
|
||||
|
||||
this._attribute = bufferAttribute( this.value );
|
||||
this._varying = varying( this._attribute );
|
||||
|
||||
}
|
||||
|
||||
|
||||
const output = this._varying.build( builder, nodeType );
|
||||
|
||||
builder.registerTransform( output, this._attribute );
|
||||
|
||||
return output;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default StorageBufferNode;
|
||||
|
||||
export const storage = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ) );
|
||||
export const storageObject = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ).setBufferObject( true ) );
|
||||
|
||||
addNodeClass( 'StorageBufferNode', StorageBufferNode );
|
109
public/sdk/three/jsm/nodes/accessors/TangentNode.js
Normal file
109
public/sdk/three/jsm/nodes/accessors/TangentNode.js
Normal file
@ -0,0 +1,109 @@
|
||||
import Node, { addNodeClass } from '../core/Node.js';
|
||||
import { attribute } from '../core/AttributeNode.js';
|
||||
import { temp } from '../core/VarNode.js';
|
||||
import { varying } from '../core/VaryingNode.js';
|
||||
import { normalize } from '../math/MathNode.js';
|
||||
import { cameraViewMatrix } from './CameraNode.js';
|
||||
import { modelViewMatrix } from './ModelNode.js';
|
||||
import { nodeImmutable, vec4 } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class TangentNode extends Node {
|
||||
|
||||
constructor( scope = TangentNode.LOCAL ) {
|
||||
|
||||
super();
|
||||
|
||||
this.scope = scope;
|
||||
|
||||
}
|
||||
|
||||
getHash( /*builder*/ ) {
|
||||
|
||||
return `tangent-${this.scope}`;
|
||||
|
||||
}
|
||||
|
||||
getNodeType() {
|
||||
|
||||
const scope = this.scope;
|
||||
|
||||
if ( scope === TangentNode.GEOMETRY ) {
|
||||
|
||||
return 'vec4';
|
||||
|
||||
}
|
||||
|
||||
return 'vec3';
|
||||
|
||||
}
|
||||
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
const scope = this.scope;
|
||||
|
||||
let outputNode = null;
|
||||
|
||||
if ( scope === TangentNode.GEOMETRY ) {
|
||||
|
||||
outputNode = attribute( 'tangent', 'vec4' );
|
||||
|
||||
if ( builder.geometry.hasAttribute( 'tangent' ) === false ) {
|
||||
|
||||
builder.geometry.computeTangents();
|
||||
|
||||
}
|
||||
|
||||
} else if ( scope === TangentNode.LOCAL ) {
|
||||
|
||||
outputNode = varying( tangentGeometry.xyz );
|
||||
|
||||
} else if ( scope === TangentNode.VIEW ) {
|
||||
|
||||
const vertexNode = modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz;
|
||||
outputNode = normalize( varying( vertexNode ) );
|
||||
|
||||
} else if ( scope === TangentNode.WORLD ) {
|
||||
|
||||
const vertexNode = tangentView.transformDirection( cameraViewMatrix );
|
||||
outputNode = normalize( varying( vertexNode ) );
|
||||
|
||||
}
|
||||
|
||||
return outputNode.build( builder, this.getNodeType( builder ) );
|
||||
|
||||
}
|
||||
|
||||
serialize( data ) {
|
||||
|
||||
super.serialize( data );
|
||||
|
||||
data.scope = this.scope;
|
||||
|
||||
}
|
||||
|
||||
deserialize( data ) {
|
||||
|
||||
super.deserialize( data );
|
||||
|
||||
this.scope = data.scope;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TangentNode.GEOMETRY = 'geometry';
|
||||
TangentNode.LOCAL = 'local';
|
||||
TangentNode.VIEW = 'view';
|
||||
TangentNode.WORLD = 'world';
|
||||
|
||||
export default TangentNode;
|
||||
|
||||
export const tangentGeometry = nodeImmutable( TangentNode, TangentNode.GEOMETRY );
|
||||
export const tangentLocal = nodeImmutable( TangentNode, TangentNode.LOCAL );
|
||||
export const tangentView = nodeImmutable( TangentNode, TangentNode.VIEW );
|
||||
export const tangentWorld = nodeImmutable( TangentNode, TangentNode.WORLD );
|
||||
export const transformedTangentView = temp( tangentView, 'TransformedTangentView' );
|
||||
export const transformedTangentWorld = normalize( transformedTangentView.transformDirection( cameraViewMatrix ) );
|
||||
|
||||
addNodeClass( 'TangentNode', TangentNode );
|
94
public/sdk/three/jsm/nodes/accessors/TextureBicubicNode.js
Normal file
94
public/sdk/three/jsm/nodes/accessors/TextureBicubicNode.js
Normal file
@ -0,0 +1,94 @@
|
||||
import TempNode from '../core/TempNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { add, mul, div } from '../math/OperatorNode.js';
|
||||
import { floor, ceil, fract, pow } from '../math/MathNode.js';
|
||||
import { nodeProxy, addNodeElement, float, vec2, vec4, int } from '../shadernode/ShaderNode.js';
|
||||
|
||||
// Mipped Bicubic Texture Filtering by N8
|
||||
// https://www.shadertoy.com/view/Dl2SDW
|
||||
|
||||
const bC = 1.0 / 6.0;
|
||||
|
||||
const w0 = ( a ) => mul( bC, mul( a, mul( a, a.negate().add( 3.0 ) ).sub( 3.0 ) ).add( 1.0 ) );
|
||||
|
||||
const w1 = ( a ) => mul( bC, mul( a, mul( a, mul( 3.0, a ).sub( 6.0 ) ) ).add( 4.0 ) );
|
||||
|
||||
const w2 = ( a ) => mul( bC, mul( a, mul( a, mul( - 3.0, a ).add( 3.0 ) ).add( 3.0 ) ).add( 1.0 ) );
|
||||
|
||||
const w3 = ( a ) => mul( bC, pow( a, 3 ) );
|
||||
|
||||
const g0 = ( a ) => w0( a ).add( w1( a ) );
|
||||
|
||||
const g1 = ( a ) => w2( a ).add( w3( a ) );
|
||||
|
||||
// h0 and h1 are the two offset functions
|
||||
const h0 = ( a ) => add( - 1.0, w1( a ).div( w0( a ).add( w1( a ) ) ) );
|
||||
|
||||
const h1 = ( a ) => add( 1.0, w3( a ).div( w2( a ).add( w3( a ) ) ) );
|
||||
|
||||
const bicubic = ( textureNode, texelSize, lod ) => {
|
||||
|
||||
const uv = textureNode.uvNode;
|
||||
const uvScaled = mul( uv, texelSize.zw ).add( 0.5 );
|
||||
|
||||
const iuv = floor( uvScaled );
|
||||
const fuv = fract( uvScaled );
|
||||
|
||||
const g0x = g0( fuv.x );
|
||||
const g1x = g1( fuv.x );
|
||||
const h0x = h0( fuv.x );
|
||||
const h1x = h1( fuv.x );
|
||||
const h0y = h0( fuv.y );
|
||||
const h1y = h1( fuv.y );
|
||||
|
||||
const p0 = vec2( iuv.x.add( h0x ), iuv.y.add( h0y ) ).sub( 0.5 ).mul( texelSize.xy );
|
||||
const p1 = vec2( iuv.x.add( h1x ), iuv.y.add( h0y ) ).sub( 0.5 ).mul( texelSize.xy );
|
||||
const p2 = vec2( iuv.x.add( h0x ), iuv.y.add( h1y ) ).sub( 0.5 ).mul( texelSize.xy );
|
||||
const p3 = vec2( iuv.x.add( h1x ), iuv.y.add( h1y ) ).sub( 0.5 ).mul( texelSize.xy );
|
||||
|
||||
const a = g0( fuv.y ).mul( add( g0x.mul( textureNode.uv( p0 ).level( lod ) ), g1x.mul( textureNode.uv( p1 ).level( lod ) ) ) );
|
||||
const b = g1( fuv.y ).mul( add( g0x.mul( textureNode.uv( p2 ).level( lod ) ), g1x.mul( textureNode.uv( p3 ).level( lod ) ) ) );
|
||||
|
||||
return a.add( b );
|
||||
|
||||
};
|
||||
|
||||
const textureBicubicMethod = ( textureNode, lodNode ) => {
|
||||
|
||||
const fLodSize = vec2( textureNode.size( int( lodNode ) ) );
|
||||
const cLodSize = vec2( textureNode.size( int( lodNode.add( 1.0 ) ) ) );
|
||||
const fLodSizeInv = div( 1.0, fLodSize );
|
||||
const cLodSizeInv = div( 1.0, cLodSize );
|
||||
const fSample = bicubic( textureNode, vec4( fLodSizeInv, fLodSize ), floor( lodNode ) );
|
||||
const cSample = bicubic( textureNode, vec4( cLodSizeInv, cLodSize ), ceil( lodNode ) );
|
||||
|
||||
return fract( lodNode ).mix( fSample, cSample );
|
||||
|
||||
};
|
||||
|
||||
class TextureBicubicNode extends TempNode {
|
||||
|
||||
constructor( textureNode, blurNode = float( 3 ) ) {
|
||||
|
||||
super( 'vec4' );
|
||||
|
||||
this.textureNode = textureNode;
|
||||
this.blurNode = blurNode;
|
||||
|
||||
}
|
||||
|
||||
setup() {
|
||||
|
||||
return textureBicubicMethod( this.textureNode, this.blurNode );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TextureBicubicNode;
|
||||
|
||||
export const textureBicubic = nodeProxy( TextureBicubicNode );
|
||||
|
||||
addNodeElement( 'bicubic', textureBicubic );
|
||||
|
||||
addNodeClass( 'TextureBicubicNode', TextureBicubicNode );
|
408
public/sdk/three/jsm/nodes/accessors/TextureNode.js
Normal file
408
public/sdk/three/jsm/nodes/accessors/TextureNode.js
Normal file
@ -0,0 +1,408 @@
|
||||
import UniformNode, { uniform } from '../core/UniformNode.js';
|
||||
import { uv } from './UVNode.js';
|
||||
import { textureSize } from './TextureSizeNode.js';
|
||||
import { colorSpaceToLinear } from '../display/ColorSpaceNode.js';
|
||||
import { expression } from '../code/ExpressionNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { maxMipLevel } from '../utils/MaxMipLevelNode.js';
|
||||
import { addNodeElement, nodeProxy, vec3, nodeObject } from '../shadernode/ShaderNode.js';
|
||||
import { NodeUpdateType } from '../core/constants.js';
|
||||
|
||||
class TextureNode extends UniformNode {
|
||||
|
||||
constructor( value, uvNode = null, levelNode = null ) {
|
||||
|
||||
super( value );
|
||||
|
||||
this.isTextureNode = true;
|
||||
|
||||
this.uvNode = uvNode;
|
||||
this.levelNode = levelNode;
|
||||
this.compareNode = null;
|
||||
this.depthNode = null;
|
||||
this.gradNode = null;
|
||||
|
||||
this.sampler = true;
|
||||
this.updateMatrix = false;
|
||||
this.updateType = NodeUpdateType.NONE;
|
||||
|
||||
this.referenceNode = null;
|
||||
|
||||
this._value = value;
|
||||
|
||||
this.setUpdateMatrix( uvNode === null );
|
||||
|
||||
}
|
||||
|
||||
set value( value ) {
|
||||
|
||||
if ( this.referenceNode ) {
|
||||
|
||||
this.referenceNode.value = value;
|
||||
|
||||
} else {
|
||||
|
||||
this._value = value;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
get value() {
|
||||
|
||||
return this.referenceNode ? this.referenceNode.value : this._value;
|
||||
|
||||
}
|
||||
|
||||
getUniformHash( /*builder*/ ) {
|
||||
|
||||
return this.value.uuid;
|
||||
|
||||
}
|
||||
|
||||
getNodeType( /*builder*/ ) {
|
||||
|
||||
if ( this.value.isDepthTexture === true ) return 'float';
|
||||
|
||||
return 'vec4';
|
||||
|
||||
}
|
||||
|
||||
getInputType( /*builder*/ ) {
|
||||
|
||||
return 'texture';
|
||||
|
||||
}
|
||||
|
||||
getDefaultUV() {
|
||||
|
||||
return uv( this.value.channel );
|
||||
|
||||
}
|
||||
|
||||
updateReference( /*state*/ ) {
|
||||
|
||||
return this.value;
|
||||
|
||||
}
|
||||
|
||||
getTransformedUV( uvNode ) {
|
||||
|
||||
const texture = this.value;
|
||||
|
||||
return uniform( texture.matrix ).mul( vec3( uvNode, 1 ) ).xy;
|
||||
|
||||
}
|
||||
|
||||
setUpdateMatrix( value ) {
|
||||
|
||||
this.updateMatrix = value;
|
||||
this.updateType = value ? NodeUpdateType.FRAME : NodeUpdateType.NONE;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
setupUV( builder, uvNode ) {
|
||||
|
||||
const texture = this.value;
|
||||
|
||||
if ( builder.isFlipY() && ( texture.isRenderTargetTexture === true || texture.isFramebufferTexture === true || texture.isDepthTexture === true ) ) {
|
||||
|
||||
uvNode = uvNode.setY( uvNode.y.oneMinus() );
|
||||
|
||||
}
|
||||
|
||||
return uvNode;
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
const properties = builder.getNodeProperties( this );
|
||||
|
||||
//
|
||||
|
||||
let uvNode = this.uvNode;
|
||||
|
||||
if ( ( uvNode === null || builder.context.forceUVContext === true ) && builder.context.getUV ) {
|
||||
|
||||
uvNode = builder.context.getUV( this );
|
||||
|
||||
}
|
||||
|
||||
if ( ! uvNode ) uvNode = this.getDefaultUV();
|
||||
|
||||
if ( this.updateMatrix === true ) {
|
||||
|
||||
uvNode = this.getTransformedUV( uvNode );
|
||||
|
||||
}
|
||||
|
||||
uvNode = this.setupUV( builder, uvNode );
|
||||
|
||||
//
|
||||
|
||||
let levelNode = this.levelNode;
|
||||
|
||||
if ( levelNode === null && builder.context.getTextureLevel ) {
|
||||
|
||||
levelNode = builder.context.getTextureLevel( this );
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
properties.uvNode = uvNode;
|
||||
properties.levelNode = levelNode;
|
||||
properties.compareNode = this.compareNode;
|
||||
properties.gradNode = this.gradNode;
|
||||
properties.depthNode = this.depthNode;
|
||||
|
||||
}
|
||||
|
||||
generateUV( builder, uvNode ) {
|
||||
|
||||
return uvNode.build( builder, this.sampler === true ? 'vec2' : 'ivec2' );
|
||||
|
||||
}
|
||||
|
||||
generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, depthSnippet, compareSnippet, gradSnippet ) {
|
||||
|
||||
const texture = this.value;
|
||||
|
||||
let snippet;
|
||||
|
||||
if ( levelSnippet ) {
|
||||
|
||||
snippet = builder.generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet );
|
||||
|
||||
} else if ( gradSnippet ) {
|
||||
|
||||
snippet = builder.generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet );
|
||||
|
||||
} else if ( compareSnippet ) {
|
||||
|
||||
snippet = builder.generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet );
|
||||
|
||||
} else if ( this.sampler === false ) {
|
||||
|
||||
snippet = builder.generateTextureLoad( texture, textureProperty, uvSnippet, depthSnippet );
|
||||
|
||||
} else {
|
||||
|
||||
snippet = builder.generateTexture( texture, textureProperty, uvSnippet, depthSnippet );
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
generate( builder, output ) {
|
||||
|
||||
const properties = builder.getNodeProperties( this );
|
||||
|
||||
const texture = this.value;
|
||||
|
||||
if ( ! texture || texture.isTexture !== true ) {
|
||||
|
||||
throw new Error( 'TextureNode: Need a three.js texture.' );
|
||||
|
||||
}
|
||||
|
||||
const textureProperty = super.generate( builder, 'property' );
|
||||
|
||||
if ( output === 'sampler' ) {
|
||||
|
||||
return textureProperty + '_sampler';
|
||||
|
||||
} else if ( builder.isReference( output ) ) {
|
||||
|
||||
return textureProperty;
|
||||
|
||||
} else {
|
||||
|
||||
const nodeData = builder.getDataFromNode( this );
|
||||
|
||||
let propertyName = nodeData.propertyName;
|
||||
|
||||
if ( propertyName === undefined ) {
|
||||
|
||||
const { uvNode, levelNode, compareNode, depthNode, gradNode } = properties;
|
||||
|
||||
const uvSnippet = this.generateUV( builder, uvNode );
|
||||
const levelSnippet = levelNode ? levelNode.build( builder, 'float' ) : null;
|
||||
const depthSnippet = depthNode ? depthNode.build( builder, 'int' ) : null;
|
||||
const compareSnippet = compareNode ? compareNode.build( builder, 'float' ) : null;
|
||||
const gradSnippet = gradNode ? [ gradNode[ 0 ].build( builder, 'vec2' ), gradNode[ 1 ].build( builder, 'vec2' ) ] : null;
|
||||
|
||||
const nodeVar = builder.getVarFromNode( this );
|
||||
|
||||
propertyName = builder.getPropertyName( nodeVar );
|
||||
|
||||
const snippet = this.generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, depthSnippet, compareSnippet, gradSnippet );
|
||||
|
||||
builder.addLineFlowCode( `${propertyName} = ${snippet}` );
|
||||
|
||||
if ( builder.context.tempWrite !== false ) {
|
||||
|
||||
nodeData.snippet = snippet;
|
||||
nodeData.propertyName = propertyName;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let snippet = propertyName;
|
||||
const nodeType = this.getNodeType( builder );
|
||||
|
||||
if ( builder.needsColorSpaceToLinear( texture ) ) {
|
||||
|
||||
snippet = colorSpaceToLinear( expression( snippet, nodeType ), texture.colorSpace ).setup( builder ).build( builder, nodeType );
|
||||
|
||||
}
|
||||
|
||||
return builder.format( snippet, nodeType, output );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setSampler( value ) {
|
||||
|
||||
this.sampler = value;
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
getSampler() {
|
||||
|
||||
return this.sampler;
|
||||
|
||||
}
|
||||
|
||||
// @TODO: Move to TSL
|
||||
|
||||
uv( uvNode ) {
|
||||
|
||||
const textureNode = this.clone();
|
||||
textureNode.uvNode = uvNode;
|
||||
textureNode.referenceNode = this;
|
||||
|
||||
return nodeObject( textureNode );
|
||||
|
||||
}
|
||||
|
||||
blur( levelNode ) {
|
||||
|
||||
const textureNode = this.clone();
|
||||
textureNode.levelNode = levelNode.mul( maxMipLevel( textureNode ) );
|
||||
textureNode.referenceNode = this;
|
||||
|
||||
return nodeObject( textureNode );
|
||||
|
||||
}
|
||||
|
||||
level( levelNode ) {
|
||||
|
||||
const textureNode = this.clone();
|
||||
textureNode.levelNode = levelNode;
|
||||
textureNode.referenceNode = this;
|
||||
|
||||
return textureNode;
|
||||
|
||||
}
|
||||
|
||||
size( levelNode ) {
|
||||
|
||||
return textureSize( this, levelNode );
|
||||
|
||||
}
|
||||
|
||||
compare( compareNode ) {
|
||||
|
||||
const textureNode = this.clone();
|
||||
textureNode.compareNode = nodeObject( compareNode );
|
||||
textureNode.referenceNode = this;
|
||||
|
||||
return nodeObject( textureNode );
|
||||
|
||||
}
|
||||
|
||||
grad( gradNodeX, gradNodeY ) {
|
||||
|
||||
const textureNode = this.clone();
|
||||
textureNode.gradNode = [ nodeObject( gradNodeX ), nodeObject( gradNodeY ) ];
|
||||
|
||||
textureNode.referenceNode = this;
|
||||
|
||||
return nodeObject( textureNode );
|
||||
|
||||
}
|
||||
|
||||
depth( depthNode ) {
|
||||
|
||||
const textureNode = this.clone();
|
||||
textureNode.depthNode = nodeObject( depthNode );
|
||||
textureNode.referenceNode = this;
|
||||
|
||||
return nodeObject( textureNode );
|
||||
|
||||
}
|
||||
|
||||
// --
|
||||
|
||||
serialize( data ) {
|
||||
|
||||
super.serialize( data );
|
||||
|
||||
data.value = this.value.toJSON( data.meta ).uuid;
|
||||
|
||||
}
|
||||
|
||||
deserialize( data ) {
|
||||
|
||||
super.deserialize( data );
|
||||
|
||||
this.value = data.meta.textures[ data.value ];
|
||||
|
||||
}
|
||||
|
||||
update() {
|
||||
|
||||
const texture = this.value;
|
||||
|
||||
if ( texture.matrixAutoUpdate === true ) {
|
||||
|
||||
texture.updateMatrix();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
clone() {
|
||||
|
||||
const newNode = new this.constructor( this.value, this.uvNode, this.levelNode );
|
||||
newNode.sampler = this.sampler;
|
||||
|
||||
return newNode;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TextureNode;
|
||||
|
||||
export const texture = nodeProxy( TextureNode );
|
||||
export const textureLoad = ( ...params ) => texture( ...params ).setSampler( false );
|
||||
|
||||
//export const textureLevel = ( value, uv, level ) => texture( value, uv ).level( level );
|
||||
|
||||
export const sampler = ( aTexture ) => ( aTexture.isNode === true ? aTexture : texture( aTexture ) ).convert( 'sampler' );
|
||||
|
||||
addNodeElement( 'texture', texture );
|
||||
//addNodeElement( 'textureLevel', textureLevel );
|
||||
|
||||
addNodeClass( 'TextureNode', TextureNode );
|
35
public/sdk/three/jsm/nodes/accessors/TextureSizeNode.js
Normal file
35
public/sdk/three/jsm/nodes/accessors/TextureSizeNode.js
Normal file
@ -0,0 +1,35 @@
|
||||
import Node from '../core/Node.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { addNodeElement, nodeProxy } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class TextureSizeNode extends Node {
|
||||
|
||||
constructor( textureNode, levelNode = null ) {
|
||||
|
||||
super( 'uvec2' );
|
||||
|
||||
this.isTextureSizeNode = true;
|
||||
|
||||
this.textureNode = textureNode;
|
||||
this.levelNode = levelNode;
|
||||
|
||||
}
|
||||
|
||||
generate( builder, output ) {
|
||||
|
||||
const textureProperty = this.textureNode.build( builder, 'property' );
|
||||
const levelNode = this.levelNode.build( builder, 'int' );
|
||||
|
||||
return builder.format( `${ builder.getMethod( 'textureDimensions' ) }( ${ textureProperty }, ${ levelNode } )`, this.getNodeType( builder ), output );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TextureSizeNode;
|
||||
|
||||
export const textureSize = nodeProxy( TextureSizeNode );
|
||||
|
||||
addNodeElement( 'textureSize', textureSize );
|
||||
|
||||
addNodeClass( 'TextureSizeNode', TextureSizeNode );
|
82
public/sdk/three/jsm/nodes/accessors/TextureStoreNode.js
Normal file
82
public/sdk/three/jsm/nodes/accessors/TextureStoreNode.js
Normal file
@ -0,0 +1,82 @@
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import TextureNode from './TextureNode.js';
|
||||
import { nodeProxy } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class TextureStoreNode extends TextureNode {
|
||||
|
||||
constructor( value, uvNode, storeNode = null ) {
|
||||
|
||||
super( value, uvNode );
|
||||
|
||||
this.storeNode = storeNode;
|
||||
|
||||
this.isStoreTextureNode = true;
|
||||
|
||||
}
|
||||
|
||||
getInputType( /*builder*/ ) {
|
||||
|
||||
return 'storageTexture';
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
super.setup( builder );
|
||||
|
||||
const properties = builder.getNodeProperties( this );
|
||||
properties.storeNode = this.storeNode;
|
||||
|
||||
}
|
||||
|
||||
generate( builder, output ) {
|
||||
|
||||
let snippet;
|
||||
|
||||
if ( this.storeNode !== null ) {
|
||||
|
||||
snippet = this.generateStore( builder );
|
||||
|
||||
} else {
|
||||
|
||||
snippet = super.generate( builder, output );
|
||||
|
||||
}
|
||||
|
||||
return snippet;
|
||||
|
||||
}
|
||||
|
||||
generateStore( builder ) {
|
||||
|
||||
const properties = builder.getNodeProperties( this );
|
||||
|
||||
const { uvNode, storeNode } = properties;
|
||||
|
||||
const textureProperty = super.generate( builder, 'property' );
|
||||
const uvSnippet = uvNode.build( builder, 'uvec2' );
|
||||
const storeSnippet = storeNode.build( builder, 'vec4' );
|
||||
|
||||
const snippet = builder.generateTextureStore( builder, textureProperty, uvSnippet, storeSnippet );
|
||||
|
||||
builder.addLineFlowCode( snippet );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TextureStoreNode;
|
||||
|
||||
const textureStoreBase = nodeProxy( TextureStoreNode );
|
||||
|
||||
export const textureStore = ( value, uvNode, storeNode ) => {
|
||||
|
||||
const node = textureStoreBase( value, uvNode, storeNode );
|
||||
|
||||
if ( storeNode !== null ) node.append();
|
||||
|
||||
return node;
|
||||
|
||||
};
|
||||
|
||||
addNodeClass( 'TextureStoreNode', TextureStoreNode );
|
47
public/sdk/three/jsm/nodes/accessors/UVNode.js
Normal file
47
public/sdk/three/jsm/nodes/accessors/UVNode.js
Normal file
@ -0,0 +1,47 @@
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import AttributeNode from '../core/AttributeNode.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class UVNode extends AttributeNode {
|
||||
|
||||
constructor( index = 0 ) {
|
||||
|
||||
super( null, 'vec2' );
|
||||
|
||||
this.isUVNode = true;
|
||||
|
||||
this.index = index;
|
||||
|
||||
}
|
||||
|
||||
getAttributeName( /*builder*/ ) {
|
||||
|
||||
const index = this.index;
|
||||
|
||||
return 'uv' + ( index > 0 ? index : '' );
|
||||
|
||||
}
|
||||
|
||||
serialize( data ) {
|
||||
|
||||
super.serialize( data );
|
||||
|
||||
data.index = this.index;
|
||||
|
||||
}
|
||||
|
||||
deserialize( data ) {
|
||||
|
||||
super.deserialize( data );
|
||||
|
||||
this.index = data.index;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default UVNode;
|
||||
|
||||
export const uv = ( ...params ) => nodeObject( new UVNode( ...params ) );
|
||||
|
||||
addNodeClass( 'UVNode', UVNode );
|
140
public/sdk/three/jsm/nodes/accessors/UniformsNode.js
Normal file
140
public/sdk/three/jsm/nodes/accessors/UniformsNode.js
Normal file
@ -0,0 +1,140 @@
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
import { NodeUpdateType } from '../core/constants.js';
|
||||
import { getValueType } from '../core/NodeUtils.js';
|
||||
import ArrayElementNode from '../utils/ArrayElementNode.js';
|
||||
import BufferNode from './BufferNode.js';
|
||||
|
||||
class UniformsElementNode extends ArrayElementNode {
|
||||
|
||||
constructor( arrayBuffer, indexNode ) {
|
||||
|
||||
super( arrayBuffer, indexNode );
|
||||
|
||||
this.isArrayBufferElementNode = true;
|
||||
|
||||
}
|
||||
|
||||
getNodeType( builder ) {
|
||||
|
||||
return this.node.getElementType( builder );
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
const snippet = super.generate( builder );
|
||||
const type = this.getNodeType();
|
||||
|
||||
return builder.format( snippet, 'vec4', type );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UniformsNode extends BufferNode {
|
||||
|
||||
constructor( value, elementType = null ) {
|
||||
|
||||
super( null, 'vec4' );
|
||||
|
||||
this.array = value;
|
||||
this.elementType = elementType;
|
||||
|
||||
this._elementType = null;
|
||||
this._elementLength = 0;
|
||||
|
||||
this.updateType = NodeUpdateType.RENDER;
|
||||
|
||||
this.isArrayBufferNode = true;
|
||||
|
||||
}
|
||||
|
||||
getElementType() {
|
||||
|
||||
return this.elementType || this._elementType;
|
||||
|
||||
}
|
||||
|
||||
getElementLength() {
|
||||
|
||||
return this._elementLength;
|
||||
|
||||
}
|
||||
|
||||
update( /*frame*/ ) {
|
||||
|
||||
const { array, value } = this;
|
||||
|
||||
const elementLength = this.getElementLength();
|
||||
const elementType = this.getElementType();
|
||||
|
||||
if ( elementLength === 1 ) {
|
||||
|
||||
for ( let i = 0; i < array.length; i ++ ) {
|
||||
|
||||
const index = i * 4;
|
||||
|
||||
value[ index ] = array[ i ];
|
||||
|
||||
}
|
||||
|
||||
} else if ( elementType === 'color' ) {
|
||||
|
||||
for ( let i = 0; i < array.length; i ++ ) {
|
||||
|
||||
const index = i * 4;
|
||||
const vector = array[ i ];
|
||||
|
||||
value[ index ] = vector.r;
|
||||
value[ index + 1 ] = vector.g;
|
||||
value[ index + 2 ] = vector.b || 0;
|
||||
//value[ index + 3 ] = vector.a || 0;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
for ( let i = 0; i < array.length; i ++ ) {
|
||||
|
||||
const index = i * 4;
|
||||
const vector = array[ i ];
|
||||
|
||||
value[ index ] = vector.x;
|
||||
value[ index + 1 ] = vector.y;
|
||||
value[ index + 2 ] = vector.z || 0;
|
||||
value[ index + 3 ] = vector.w || 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setup( builder ) {
|
||||
|
||||
const length = this.array.length;
|
||||
|
||||
this._elementType = this.elementType === null ? getValueType( this.array[ 0 ] ) : this.elementType;
|
||||
this._elementLength = builder.getTypeLength( this._elementType );
|
||||
|
||||
this.value = new Float32Array( length * 4 );
|
||||
this.bufferCount = length;
|
||||
|
||||
return super.setup( builder );
|
||||
|
||||
}
|
||||
|
||||
element( indexNode ) {
|
||||
|
||||
return nodeObject( new UniformsElementNode( this, nodeObject( indexNode ) ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default UniformsNode;
|
||||
|
||||
export const uniforms = ( values, nodeType ) => nodeObject( new UniformsNode( values, nodeType ) );
|
||||
|
||||
addNodeClass( 'UniformsNode', UniformsNode );
|
29
public/sdk/three/jsm/nodes/accessors/UserDataNode.js
Normal file
29
public/sdk/three/jsm/nodes/accessors/UserDataNode.js
Normal file
@ -0,0 +1,29 @@
|
||||
import ReferenceNode from './ReferenceNode.js';
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
|
||||
class UserDataNode extends ReferenceNode {
|
||||
|
||||
constructor( property, inputType, userData = null ) {
|
||||
|
||||
super( property, inputType, userData );
|
||||
|
||||
this.userData = userData;
|
||||
|
||||
}
|
||||
|
||||
update( frame ) {
|
||||
|
||||
this.reference = this.userData !== null ? this.userData : frame.object.userData;
|
||||
|
||||
super.update( frame );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default UserDataNode;
|
||||
|
||||
export const userData = ( name, inputType, userData ) => nodeObject( new UserDataNode( name, inputType, userData ) );
|
||||
|
||||
addNodeClass( 'UserDataNode', UserDataNode );
|
70
public/sdk/three/jsm/nodes/accessors/VertexColorNode.js
Normal file
70
public/sdk/three/jsm/nodes/accessors/VertexColorNode.js
Normal file
@ -0,0 +1,70 @@
|
||||
import { addNodeClass } from '../core/Node.js';
|
||||
import AttributeNode from '../core/AttributeNode.js';
|
||||
import { nodeObject } from '../shadernode/ShaderNode.js';
|
||||
import { Vector4 } from 'three';
|
||||
|
||||
class VertexColorNode extends AttributeNode {
|
||||
|
||||
constructor( index = 0 ) {
|
||||
|
||||
super( null, 'vec4' );
|
||||
|
||||
this.isVertexColorNode = true;
|
||||
|
||||
this.index = index;
|
||||
|
||||
}
|
||||
|
||||
getAttributeName( /*builder*/ ) {
|
||||
|
||||
const index = this.index;
|
||||
|
||||
return 'color' + ( index > 0 ? index : '' );
|
||||
|
||||
}
|
||||
|
||||
generate( builder ) {
|
||||
|
||||
const attributeName = this.getAttributeName( builder );
|
||||
const geometryAttribute = builder.hasGeometryAttribute( attributeName );
|
||||
|
||||
let result;
|
||||
|
||||
if ( geometryAttribute === true ) {
|
||||
|
||||
result = super.generate( builder );
|
||||
|
||||
} else {
|
||||
|
||||
// Vertex color fallback should be white
|
||||
result = builder.generateConst( this.nodeType, new Vector4( 1, 1, 1, 1 ) );
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
serialize( data ) {
|
||||
|
||||
super.serialize( data );
|
||||
|
||||
data.index = this.index;
|
||||
|
||||
}
|
||||
|
||||
deserialize( data ) {
|
||||
|
||||
super.deserialize( data );
|
||||
|
||||
this.index = data.index;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default VertexColorNode;
|
||||
|
||||
export const vertexColor = ( ...params ) => nodeObject( new VertexColorNode( ...params ) );
|
||||
|
||||
addNodeClass( 'VertexColorNode', VertexColorNode );
|
Reference in New Issue
Block a user