@openhps/core
Version:
Open Hybrid Positioning System - Core component
277 lines (262 loc) • 13.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WebGLShadowMap = WebGLShadowMap;
var _constants = require("../../constants.js");
var _WebGLRenderTarget = require("../WebGLRenderTarget.js");
var _MeshDepthMaterial = require("../../materials/MeshDepthMaterial.js");
var _MeshDistanceMaterial = require("../../materials/MeshDistanceMaterial.js");
var _ShaderMaterial = require("../../materials/ShaderMaterial.js");
var _BufferAttribute = require("../../core/BufferAttribute.js");
var _BufferGeometry = require("../../core/BufferGeometry.js");
var _Mesh = require("../../objects/Mesh.js");
var _Vector = require("../../math/Vector4.js");
var _Vector2 = require("../../math/Vector2.js");
var _Frustum = require("../../math/Frustum.js");
var vsm = _interopRequireWildcard(require("../shaders/ShaderLib/vsm.glsl.js"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function WebGLShadowMap(renderer, objects, capabilities) {
let _frustum = new _Frustum.Frustum();
const _shadowMapSize = new _Vector2.Vector2(),
_viewportSize = new _Vector2.Vector2(),
_viewport = new _Vector.Vector4(),
_depthMaterial = new _MeshDepthMaterial.MeshDepthMaterial({
depthPacking: _constants.RGBADepthPacking
}),
_distanceMaterial = new _MeshDistanceMaterial.MeshDistanceMaterial(),
_materialCache = {},
_maxTextureSize = capabilities.maxTextureSize;
const shadowSide = {
[_constants.FrontSide]: _constants.BackSide,
[_constants.BackSide]: _constants.FrontSide,
[_constants.DoubleSide]: _constants.DoubleSide
};
const shadowMaterialVertical = new _ShaderMaterial.ShaderMaterial({
defines: {
VSM_SAMPLES: 8
},
uniforms: {
shadow_pass: {
value: null
},
resolution: {
value: new _Vector2.Vector2()
},
radius: {
value: 4.0
}
},
vertexShader: vsm.vertex,
fragmentShader: vsm.fragment
});
const shadowMaterialHorizontal = shadowMaterialVertical.clone();
shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;
const fullScreenTri = new _BufferGeometry.BufferGeometry();
fullScreenTri.setAttribute('position', new _BufferAttribute.BufferAttribute(new Float32Array([-1, -1, 0.5, 3, -1, 0.5, -1, 3, 0.5]), 3));
const fullScreenMesh = new _Mesh.Mesh(fullScreenTri, shadowMaterialVertical);
const scope = this;
this.enabled = false;
this.autoUpdate = true;
this.needsUpdate = false;
this.type = _constants.PCFShadowMap;
let _previousType = this.type;
this.render = function (lights, scene, camera) {
if (scope.enabled === false) return;
if (scope.autoUpdate === false && scope.needsUpdate === false) return;
if (lights.length === 0) return;
const currentRenderTarget = renderer.getRenderTarget();
const activeCubeFace = renderer.getActiveCubeFace();
const activeMipmapLevel = renderer.getActiveMipmapLevel();
const _state = renderer.state;
// Set GL state for depth map.
_state.setBlending(_constants.NoBlending);
_state.buffers.color.setClear(1, 1, 1, 1);
_state.buffers.depth.setTest(true);
_state.setScissorTest(false);
// check for shadow map type changes
const toVSM = _previousType !== _constants.VSMShadowMap && this.type === _constants.VSMShadowMap;
const fromVSM = _previousType === _constants.VSMShadowMap && this.type !== _constants.VSMShadowMap;
// render depth map
for (let i = 0, il = lights.length; i < il; i++) {
const light = lights[i];
const shadow = light.shadow;
if (shadow === undefined) {
console.warn('THREE.WebGLShadowMap:', light, 'has no shadow.');
continue;
}
if (shadow.autoUpdate === false && shadow.needsUpdate === false) continue;
_shadowMapSize.copy(shadow.mapSize);
const shadowFrameExtents = shadow.getFrameExtents();
_shadowMapSize.multiply(shadowFrameExtents);
_viewportSize.copy(shadow.mapSize);
if (_shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize) {
if (_shadowMapSize.x > _maxTextureSize) {
_viewportSize.x = Math.floor(_maxTextureSize / shadowFrameExtents.x);
_shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;
shadow.mapSize.x = _viewportSize.x;
}
if (_shadowMapSize.y > _maxTextureSize) {
_viewportSize.y = Math.floor(_maxTextureSize / shadowFrameExtents.y);
_shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;
shadow.mapSize.y = _viewportSize.y;
}
}
if (shadow.map === null || toVSM === true || fromVSM === true) {
const pars = this.type !== _constants.VSMShadowMap ? {
minFilter: _constants.NearestFilter,
magFilter: _constants.NearestFilter
} : {};
if (shadow.map !== null) {
shadow.map.dispose();
}
shadow.map = new _WebGLRenderTarget.WebGLRenderTarget(_shadowMapSize.x, _shadowMapSize.y, pars);
shadow.map.texture.name = light.name + '.shadowMap';
shadow.camera.updateProjectionMatrix();
}
renderer.setRenderTarget(shadow.map);
renderer.clear();
const viewportCount = shadow.getViewportCount();
for (let vp = 0; vp < viewportCount; vp++) {
const viewport = shadow.getViewport(vp);
_viewport.set(_viewportSize.x * viewport.x, _viewportSize.y * viewport.y, _viewportSize.x * viewport.z, _viewportSize.y * viewport.w);
_state.viewport(_viewport);
shadow.updateMatrices(light, vp);
_frustum = shadow.getFrustum();
renderObject(scene, camera, shadow.camera, light, this.type);
}
// do blur pass for VSM
if (shadow.isPointLightShadow !== true && this.type === _constants.VSMShadowMap) {
VSMPass(shadow, camera);
}
shadow.needsUpdate = false;
}
_previousType = this.type;
scope.needsUpdate = false;
renderer.setRenderTarget(currentRenderTarget, activeCubeFace, activeMipmapLevel);
};
function VSMPass(shadow, camera) {
const geometry = objects.update(fullScreenMesh);
if (shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples) {
shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples;
shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples;
shadowMaterialVertical.needsUpdate = true;
shadowMaterialHorizontal.needsUpdate = true;
}
if (shadow.mapPass === null) {
shadow.mapPass = new _WebGLRenderTarget.WebGLRenderTarget(_shadowMapSize.x, _shadowMapSize.y);
}
// vertical pass
shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
shadowMaterialVertical.uniforms.radius.value = shadow.radius;
renderer.setRenderTarget(shadow.mapPass);
renderer.clear();
renderer.renderBufferDirect(camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null);
// horizontal pass
shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;
shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
renderer.setRenderTarget(shadow.map);
renderer.clear();
renderer.renderBufferDirect(camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null);
}
function getDepthMaterial(object, material, light, type) {
let result = null;
const customMaterial = light.isPointLight === true ? object.customDistanceMaterial : object.customDepthMaterial;
if (customMaterial !== undefined) {
result = customMaterial;
} else {
result = light.isPointLight === true ? _distanceMaterial : _depthMaterial;
if (renderer.localClippingEnabled && material.clipShadows === true && Array.isArray(material.clippingPlanes) && material.clippingPlanes.length !== 0 || material.displacementMap && material.displacementScale !== 0 || material.alphaMap && material.alphaTest > 0 || material.map && material.alphaTest > 0) {
// in this case we need a unique material instance reflecting the
// appropriate state
const keyA = result.uuid,
keyB = material.uuid;
let materialsForVariant = _materialCache[keyA];
if (materialsForVariant === undefined) {
materialsForVariant = {};
_materialCache[keyA] = materialsForVariant;
}
let cachedMaterial = materialsForVariant[keyB];
if (cachedMaterial === undefined) {
cachedMaterial = result.clone();
materialsForVariant[keyB] = cachedMaterial;
material.addEventListener('dispose', onMaterialDispose);
}
result = cachedMaterial;
}
}
result.visible = material.visible;
result.wireframe = material.wireframe;
if (type === _constants.VSMShadowMap) {
result.side = material.shadowSide !== null ? material.shadowSide : material.side;
} else {
result.side = material.shadowSide !== null ? material.shadowSide : shadowSide[material.side];
}
result.alphaMap = material.alphaMap;
result.alphaTest = material.alphaTest;
result.map = material.map;
result.clipShadows = material.clipShadows;
result.clippingPlanes = material.clippingPlanes;
result.clipIntersection = material.clipIntersection;
result.displacementMap = material.displacementMap;
result.displacementScale = material.displacementScale;
result.displacementBias = material.displacementBias;
result.wireframeLinewidth = material.wireframeLinewidth;
result.linewidth = material.linewidth;
if (light.isPointLight === true && result.isMeshDistanceMaterial === true) {
const materialProperties = renderer.properties.get(result);
materialProperties.light = light;
}
return result;
}
function renderObject(object, camera, shadowCamera, light, type) {
if (object.visible === false) return;
const visible = object.layers.test(camera.layers);
if (visible && (object.isMesh || object.isLine || object.isPoints)) {
if ((object.castShadow || object.receiveShadow && type === _constants.VSMShadowMap) && (!object.frustumCulled || _frustum.intersectsObject(object))) {
object.modelViewMatrix.multiplyMatrices(shadowCamera.matrixWorldInverse, object.matrixWorld);
const geometry = objects.update(object);
const material = object.material;
if (Array.isArray(material)) {
const groups = geometry.groups;
for (let k = 0, kl = groups.length; k < kl; k++) {
const group = groups[k];
const groupMaterial = material[group.materialIndex];
if (groupMaterial && groupMaterial.visible) {
const depthMaterial = getDepthMaterial(object, groupMaterial, light, type);
object.onBeforeShadow(renderer, object, camera, shadowCamera, geometry, depthMaterial, group);
renderer.renderBufferDirect(shadowCamera, null, geometry, depthMaterial, object, group);
object.onAfterShadow(renderer, object, camera, shadowCamera, geometry, depthMaterial, group);
}
}
} else if (material.visible) {
const depthMaterial = getDepthMaterial(object, material, light, type);
object.onBeforeShadow(renderer, object, camera, shadowCamera, geometry, depthMaterial, null);
renderer.renderBufferDirect(shadowCamera, null, geometry, depthMaterial, object, null);
object.onAfterShadow(renderer, object, camera, shadowCamera, geometry, depthMaterial, null);
}
}
}
const children = object.children;
for (let i = 0, l = children.length; i < l; i++) {
renderObject(children[i], camera, shadowCamera, light, type);
}
}
function onMaterialDispose(event) {
const material = event.target;
material.removeEventListener('dispose', onMaterialDispose);
// make sure to remove the unique distance/depth materials used for shadow map rendering
for (const id in _materialCache) {
const cache = _materialCache[id];
const uuid = event.target.uuid;
if (uuid in cache) {
const shadowMaterial = cache[uuid];
shadowMaterial.dispose();
delete cache[uuid];
}
}
}
}