@openhps/core
Version:
Open Hybrid Positioning System - Core component
282 lines (256 loc) • 10.8 kB
JavaScript
;
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;