UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

282 lines (256 loc) 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.pointShadow = exports.default = exports.cubeToUV = exports.PointShadowFilter = exports.BasicPointShadowFilter = void 0; var _ShadowNode = _interopRequireDefault(require("./ShadowNode.js")); var _UniformNode = require("../core/UniformNode.js"); var _TSLBase = require("../tsl/TSLBase.js"); var _ReferenceNode = require("../accessors/ReferenceNode.js"); var _TextureNode = require("../accessors/TextureNode.js"); var _MathNode = require("../math/MathNode.js"); var _OperatorNode = require("../math/OperatorNode.js"); var _UniformGroupNode = require("../core/UniformGroupNode.js"); var _Vector = require("../../math/Vector2.js"); var _Vector2 = require("../../math/Vector4.js"); var _Color = require("../../math/Color.js"); var _constants = require("../../constants.js"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const _clearColor = /*@__PURE__*/new _Color.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 const cubeToUV = exports.cubeToUV = /*@__PURE__*/(0, _TSLBase.Fn)(([pos, texelSizeY]) => { const v = pos.toVar(); // Number of texels to avoid at the edge of each square const absV = (0, _MathNode.abs)(v); // Intersect unit cube const scaleToCube = (0, _OperatorNode.div)(1.0, (0, _MathNode.max)(absV.x, (0, _MathNode.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 = (0, _TSLBase.vec2)(v.xy).toVar(); const almostATexel = texelSizeY.mul(1.5); const almostOne = almostATexel.oneMinus(); (0, _TSLBase.If)(absV.z.greaterThanEqual(almostOne), () => { (0, _TSLBase.If)(v.z.greaterThan(0.0), () => { planar.x.assign((0, _OperatorNode.sub)(4.0, v.x)); }); }).ElseIf(absV.x.greaterThanEqual(almostOne), () => { const signX = (0, _MathNode.sign)(v.x); planar.x.assign(v.z.mul(signX).add(signX.mul(2.0))); }).ElseIf(absV.y.greaterThanEqual(almostOne), () => { const signY = (0, _MathNode.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 (0, _TSLBase.vec2)(0.125, 0.25).mul(planar).add((0, _TSLBase.vec2)(0.375, 0.75)).flipY(); }).setLayout({ name: 'cubeToUV', type: 'vec2', inputs: [{ name: 'pos', type: 'vec3' }, { name: 'texelSizeY', type: 'float' }] }); const BasicPointShadowFilter = exports.BasicPointShadowFilter = /*@__PURE__*/(0, _TSLBase.Fn)(({ depthTexture, bd3D, dp, texelSize }) => { return (0, _TextureNode.texture)(depthTexture, cubeToUV(bd3D, texelSize.y)).compare(dp); }); const PointShadowFilter = exports.PointShadowFilter = /*@__PURE__*/(0, _TSLBase.Fn)(({ depthTexture, bd3D, dp, texelSize, shadow }) => { const radius = (0, _ReferenceNode.reference)('radius', 'float', shadow).setGroup(_UniformGroupNode.renderGroup); const offset = (0, _TSLBase.vec2)(-1.0, 1.0).mul(radius).mul(texelSize.y); return (0, _TextureNode.texture)(depthTexture, cubeToUV(bd3D.add(offset.xyy), texelSize.y)).compare(dp).add((0, _TextureNode.texture)(depthTexture, cubeToUV(bd3D.add(offset.yyy), texelSize.y)).compare(dp)).add((0, _TextureNode.texture)(depthTexture, cubeToUV(bd3D.add(offset.xyx), texelSize.y)).compare(dp)).add((0, _TextureNode.texture)(depthTexture, cubeToUV(bd3D.add(offset.yyx), texelSize.y)).compare(dp)).add((0, _TextureNode.texture)(depthTexture, cubeToUV(bd3D, texelSize.y)).compare(dp)).add((0, _TextureNode.texture)(depthTexture, cubeToUV(bd3D.add(offset.xxy), texelSize.y)).compare(dp)).add((0, _TextureNode.texture)(depthTexture, cubeToUV(bd3D.add(offset.yxy), texelSize.y)).compare(dp)).add((0, _TextureNode.texture)(depthTexture, cubeToUV(bd3D.add(offset.xxx), texelSize.y)).compare(dp)).add((0, _TextureNode.texture)(depthTexture, cubeToUV(bd3D.add(offset.yxx), texelSize.y)).compare(dp)).mul(1.0 / 9.0); }); const pointShadowFilter = /*@__PURE__*/(0, _TSLBase.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 = (0, _UniformNode.uniform)('float').setGroup(_UniformGroupNode.renderGroup).onRenderUpdate(() => shadow.camera.near); const cameraFarLocal = (0, _UniformNode.uniform)('float').setGroup(_UniformGroupNode.renderGroup).onRenderUpdate(() => shadow.camera.far); const bias = (0, _ReferenceNode.reference)('bias', 'float', shadow).setGroup(_UniformGroupNode.renderGroup); const mapSize = (0, _UniformNode.uniform)(shadow.mapSize).setGroup(_UniformGroupNode.renderGroup); const result = (0, _TSLBase.float)(1.0).toVar(); (0, _TSLBase.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 = (0, _TSLBase.vec2)(1.0).div(mapSize.mul((0, _TSLBase.vec2)(4.0, 2.0))); // percentage-closer filtering result.assign(filterFn({ depthTexture, bd3D, dp, texelSize, shadow })); }); return result; }); const _viewport = /*@__PURE__*/new _Vector2.Vector4(); const _viewportSize = /*@__PURE__*/new _Vector.Vector2(); const _shadowMapSize = /*@__PURE__*/new _Vector.Vector2(); /** * Represents the shadow implementation for point light nodes. * * @augments ShadowNode */ class PointShadowNode extends _ShadowNode.default { 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 === _constants.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); } } var _default = exports.default = PointShadowNode; /** * TSL function for creating an instance of `PointShadowNode`. * * @tsl * @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. */ const pointShadow = (light, shadow) => (0, _TSLBase.nodeObject)(new PointShadowNode(light, shadow)); exports.pointShadow = pointShadow;