MCP 3D Printer Server

by DMontgomery40
Verified
import ShadowNode from './ShadowNode.js'; import { uniform } from '../core/UniformNode.js'; import { float, vec2, If, Fn, nodeObject } from '../tsl/TSLBase.js'; import { reference } from '../accessors/ReferenceNode.js'; import { texture } from '../accessors/TextureNode.js'; import { max, abs, sign } from '../math/MathNode.js'; import { sub, div } from '../math/OperatorNode.js'; import { renderGroup } from '../core/UniformGroupNode.js'; import { Vector2 } from '../../math/Vector2.js'; import { Vector4 } from '../../math/Vector4.js'; import { Color } from '../../math/Color.js'; import { BasicShadowMap } from '../../constants.js'; /** @module PointShadowNode **/ const _clearColor = /*@__PURE__*/ new Color(); // cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D // vector suitable for 2D texture mapping. This code uses the following layout for the // 2D texture: // // xzXZ // y Y // // Y - Positive y direction // y - Negative y direction // X - Positive x direction // x - Negative x direction // Z - Positive z direction // z - Negative z direction // // Source and test bed: // https://gist.github.com/tschw/da10c43c467ce8afd0c4 export const cubeToUV = /*@__PURE__*/ Fn( ( [ pos, texelSizeY ] ) => { const v = pos.toVar(); // Number of texels to avoid at the edge of each square const absV = abs( v ); // Intersect unit cube const scaleToCube = div( 1.0, max( absV.x, max( absV.y, absV.z ) ) ); absV.mulAssign( scaleToCube ); // Apply scale to avoid seams // two texels less per square (one texel will do for NEAREST) v.mulAssign( scaleToCube.mul( texelSizeY.mul( 2 ).oneMinus() ) ); // Unwrap // space: -1 ... 1 range for each square // // #X## dim := ( 4 , 2 ) // # # center := ( 1 , 1 ) const planar = vec2( v.xy ).toVar(); const almostATexel = texelSizeY.mul( 1.5 ); const almostOne = almostATexel.oneMinus(); If( absV.z.greaterThanEqual( almostOne ), () => { If( v.z.greaterThan( 0.0 ), () => { planar.x.assign( sub( 4.0, v.x ) ); } ); } ).ElseIf( absV.x.greaterThanEqual( almostOne ), () => { const signX = sign( v.x ); planar.x.assign( v.z.mul( signX ).add( signX.mul( 2.0 ) ) ); } ).ElseIf( absV.y.greaterThanEqual( almostOne ), () => { const signY = sign( v.y ); planar.x.assign( v.x.add( signY.mul( 2.0 ) ).add( 2.0 ) ); planar.y.assign( v.z.mul( signY ).sub( 2.0 ) ); } ); // Transform to UV space // scale := 0.5 / dim // translate := ( center + 0.5 ) / dim return vec2( 0.125, 0.25 ).mul( planar ).add( vec2( 0.375, 0.75 ) ).flipY(); } ).setLayout( { name: 'cubeToUV', type: 'vec2', inputs: [ { name: 'pos', type: 'vec3' }, { name: 'texelSizeY', type: 'float' } ] } ); export const BasicPointShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, bd3D, dp, texelSize } ) => { return texture( depthTexture, cubeToUV( bd3D, texelSize.y ) ).compare( dp ); } ); export const PointShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, bd3D, dp, texelSize, shadow } ) => { const radius = reference( 'radius', 'float', shadow ).setGroup( renderGroup ); const offset = vec2( - 1.0, 1.0 ).mul( radius ).mul( texelSize.y ); return texture( depthTexture, cubeToUV( bd3D.add( offset.xyy ), texelSize.y ) ).compare( dp ) .add( texture( depthTexture, cubeToUV( bd3D.add( offset.yyy ), texelSize.y ) ).compare( dp ) ) .add( texture( depthTexture, cubeToUV( bd3D.add( offset.xyx ), texelSize.y ) ).compare( dp ) ) .add( texture( depthTexture, cubeToUV( bd3D.add( offset.yyx ), texelSize.y ) ).compare( dp ) ) .add( texture( depthTexture, cubeToUV( bd3D, texelSize.y ) ).compare( dp ) ) .add( texture( depthTexture, cubeToUV( bd3D.add( offset.xxy ), texelSize.y ) ).compare( dp ) ) .add( texture( depthTexture, cubeToUV( bd3D.add( offset.yxy ), texelSize.y ) ).compare( dp ) ) .add( texture( depthTexture, cubeToUV( bd3D.add( offset.xxx ), texelSize.y ) ).compare( dp ) ) .add( texture( depthTexture, cubeToUV( bd3D.add( offset.yxx ), texelSize.y ) ).compare( dp ) ) .mul( 1.0 / 9.0 ); } ); const pointShadowFilter = /*@__PURE__*/ Fn( ( { filterFn, depthTexture, shadowCoord, shadow } ) => { // for point lights, the uniform @vShadowCoord is re-purposed to hold // the vector from the light to the world-space position of the fragment. const lightToPosition = shadowCoord.xyz.toVar(); const lightToPositionLength = lightToPosition.length(); const cameraNearLocal = uniform( 'float' ).setGroup( renderGroup ).onRenderUpdate( () => shadow.camera.near ); const cameraFarLocal = uniform( 'float' ).setGroup( renderGroup ).onRenderUpdate( () => shadow.camera.far ); const bias = reference( 'bias', 'float', shadow ).setGroup( renderGroup ); const mapSize = uniform( shadow.mapSize ).setGroup( renderGroup ); const result = float( 1.0 ).toVar(); If( lightToPositionLength.sub( cameraFarLocal ).lessThanEqual( 0.0 ).and( lightToPositionLength.sub( cameraNearLocal ).greaterThanEqual( 0.0 ) ), () => { // dp = normalized distance from light to fragment position const dp = lightToPositionLength.sub( cameraNearLocal ).div( cameraFarLocal.sub( cameraNearLocal ) ).toVar(); // need to clamp? dp.addAssign( bias ); // bd3D = base direction 3D const bd3D = lightToPosition.normalize(); const texelSize = vec2( 1.0 ).div( mapSize.mul( vec2( 4.0, 2.0 ) ) ); // percentage-closer filtering result.assign( filterFn( { depthTexture, bd3D, dp, texelSize, shadow } ) ); } ); return result; } ); const _viewport = /*@__PURE__*/ new Vector4(); const _viewportSize = /*@__PURE__*/ new Vector2(); const _shadowMapSize = /*@__PURE__*/ new Vector2(); /** * Represents the shadow implementation for point light nodes. * * @augments module:ShadowNode~ShadowNode */ class PointShadowNode extends ShadowNode { static get type() { return 'PointShadowNode'; } /** * Constructs a new point shadow node. * * @param {PointLight} light - The shadow casting point light. * @param {PointLightShadow?} [shadow=null] - An optional point light shadow. */ constructor( light, shadow = null ) { super( light, shadow ); } /** * Overwrites the default implementation to return point light shadow specific * filtering functions. * * @param {Number} type - The shadow type. * @return {Function} The filtering function. */ getShadowFilterFn( type ) { return type === BasicShadowMap ? BasicPointShadowFilter : PointShadowFilter; } /** * Overwrites the default implementation so the unaltered shadow position is used. * * @param {NodeBuilder} builder - A reference to the current node builder. * @param {Node<vec3>} shadowPosition - A node representing the shadow position. * @return {Node<vec3>} The shadow coordinates. */ setupShadowCoord( builder, shadowPosition ) { return shadowPosition; } /** * Overwrites the default implementation to only use point light specific * shadow filter functions. * * @param {NodeBuilder} builder - A reference to the current node builder. * @param {Object} inputs - A configuration object that defines the shadow filtering. * @param {Function} inputs.filterFn - This function defines the filtering type of the shadow map e.g. PCF. * @param {Texture} inputs.shadowTexture - A reference to the shadow map's texture. * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data. * @param {Node<vec3>} inputs.shadowCoord - Shadow coordinates which are used to sample from the shadow map. * @param {LightShadow} inputs.shadow - The light shadow. * @return {Node<float>} The result node of the shadow filtering. */ setupShadowFilter( builder, { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } ) { return pointShadowFilter( { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } ); } /** * Overwrites the default implementation with point light specific * rendering code. * * @param {NodeFrame} frame - A reference to the current node frame. */ renderShadow( frame ) { const { shadow, shadowMap, light } = this; const { renderer, scene } = frame; const shadowFrameExtents = shadow.getFrameExtents(); _shadowMapSize.copy( shadow.mapSize ); _shadowMapSize.multiply( shadowFrameExtents ); shadowMap.setSize( _shadowMapSize.width, _shadowMapSize.height ); _viewportSize.copy( shadow.mapSize ); // const previousAutoClear = renderer.autoClear; const previousClearColor = renderer.getClearColor( _clearColor ); const previousClearAlpha = renderer.getClearAlpha(); renderer.autoClear = false; renderer.setClearColor( shadow.clearColor, shadow.clearAlpha ); renderer.clear(); const viewportCount = shadow.getViewportCount(); for ( let vp = 0; vp < viewportCount; vp ++ ) { const viewport = shadow.getViewport( vp ); const x = _viewportSize.x * viewport.x; const y = _shadowMapSize.y - _viewportSize.y - ( _viewportSize.y * viewport.y ); _viewport.set( x, y, _viewportSize.x * viewport.z, _viewportSize.y * viewport.w ); shadowMap.viewport.copy( _viewport ); shadow.updateMatrices( light, vp ); renderer.render( scene, shadow.camera ); } // renderer.autoClear = previousAutoClear; renderer.setClearColor( previousClearColor, previousClearAlpha ); } } export default PointShadowNode; /** * TSL function for creating an instance of `PointShadowNode`. * * @function * @param {PointLight} light - The shadow casting point light. * @param {PointLightShadow?} [shadow=null] - An optional point light shadow. * @return {PointShadowNode} The created point shadow node. */ export const pointShadow = ( light, shadow ) => nodeObject( new PointShadowNode( light, shadow ) );