Initial project import
This commit is contained in:
310
node_modules/@react-three/drei/core/AccumulativeShadows.js
generated
vendored
Normal file
310
node_modules/@react-three/drei/core/AccumulativeShadows.js
generated
vendored
Normal file
@@ -0,0 +1,310 @@
|
||||
import _extends from '@babel/runtime/helpers/esm/extends';
|
||||
import * as THREE from 'three';
|
||||
import * as React from 'react';
|
||||
import { extend, useThree, useFrame } from '@react-three/fiber';
|
||||
import { shaderMaterial } from './shaderMaterial.js';
|
||||
import { DiscardMaterial } from '../materials/DiscardMaterial.js';
|
||||
import { version } from '../helpers/constants.js';
|
||||
|
||||
function isLight(object) {
|
||||
return object.isLight;
|
||||
}
|
||||
function isGeometry(object) {
|
||||
return !!object.geometry;
|
||||
}
|
||||
const accumulativeContext = /* @__PURE__ */React.createContext(null);
|
||||
const SoftShadowMaterial = /* @__PURE__ */shaderMaterial({
|
||||
color: /* @__PURE__ */new THREE.Color(),
|
||||
blend: 2.0,
|
||||
alphaTest: 0.75,
|
||||
opacity: 0,
|
||||
map: null
|
||||
}, `varying vec2 vUv;
|
||||
void main() {
|
||||
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.);
|
||||
vUv = uv;
|
||||
}`, `varying vec2 vUv;
|
||||
uniform sampler2D map;
|
||||
uniform vec3 color;
|
||||
uniform float opacity;
|
||||
uniform float alphaTest;
|
||||
uniform float blend;
|
||||
void main() {
|
||||
vec4 sampledDiffuseColor = texture2D(map, vUv);
|
||||
gl_FragColor = vec4(color * sampledDiffuseColor.r * blend, max(0.0, (1.0 - (sampledDiffuseColor.r + sampledDiffuseColor.g + sampledDiffuseColor.b) / alphaTest)) * opacity);
|
||||
#include <tonemapping_fragment>
|
||||
#include <${version >= 154 ? 'colorspace_fragment' : 'encodings_fragment'}>
|
||||
}`);
|
||||
const AccumulativeShadows = /* @__PURE__ */React.forwardRef(({
|
||||
children,
|
||||
temporal,
|
||||
frames = 40,
|
||||
limit = Infinity,
|
||||
blend = 20,
|
||||
scale = 10,
|
||||
opacity = 1,
|
||||
alphaTest = 0.75,
|
||||
color = 'black',
|
||||
colorBlend = 2,
|
||||
resolution = 1024,
|
||||
toneMapped = true,
|
||||
...props
|
||||
}, forwardRef) => {
|
||||
extend({
|
||||
SoftShadowMaterial
|
||||
});
|
||||
const gl = useThree(state => state.gl);
|
||||
const scene = useThree(state => state.scene);
|
||||
const camera = useThree(state => state.camera);
|
||||
const invalidate = useThree(state => state.invalidate);
|
||||
const gPlane = React.useRef(null);
|
||||
const gLights = React.useRef(null);
|
||||
const [plm] = React.useState(() => new ProgressiveLightMap(gl, scene, resolution));
|
||||
React.useLayoutEffect(() => {
|
||||
plm.configure(gPlane.current);
|
||||
}, []);
|
||||
const api = React.useMemo(() => ({
|
||||
lights: new Map(),
|
||||
temporal: !!temporal,
|
||||
frames: Math.max(2, frames),
|
||||
blend: Math.max(2, frames === Infinity ? blend : frames),
|
||||
count: 0,
|
||||
getMesh: () => gPlane.current,
|
||||
reset: () => {
|
||||
// Clear buffers, reset opacities, set frame count to 0
|
||||
plm.clear();
|
||||
const material = gPlane.current.material;
|
||||
material.opacity = 0;
|
||||
material.alphaTest = 0;
|
||||
api.count = 0;
|
||||
},
|
||||
update: (frames = 1) => {
|
||||
// Adapt the opacity-blend ratio to the number of frames
|
||||
const material = gPlane.current.material;
|
||||
if (!api.temporal) {
|
||||
material.opacity = opacity;
|
||||
material.alphaTest = alphaTest;
|
||||
} else {
|
||||
material.opacity = Math.min(opacity, material.opacity + opacity / api.blend);
|
||||
material.alphaTest = Math.min(alphaTest, material.alphaTest + alphaTest / api.blend);
|
||||
}
|
||||
|
||||
// Switch accumulative lights on
|
||||
gLights.current.visible = true;
|
||||
// Collect scene lights and meshes
|
||||
plm.prepare();
|
||||
|
||||
// Update the lightmap and the accumulative lights
|
||||
for (let i = 0; i < frames; i++) {
|
||||
api.lights.forEach(light => light.update());
|
||||
plm.update(camera, api.blend);
|
||||
}
|
||||
// Switch lights off
|
||||
gLights.current.visible = false;
|
||||
// Restore lights and meshes
|
||||
plm.finish();
|
||||
}
|
||||
}), [plm, camera, scene, temporal, frames, blend, opacity, alphaTest]);
|
||||
React.useLayoutEffect(() => {
|
||||
// Reset internals, buffers, ...
|
||||
api.reset();
|
||||
// Update lightmap
|
||||
if (!api.temporal && api.frames !== Infinity) api.update(api.blend);
|
||||
});
|
||||
|
||||
// Expose api, allow children to set itself as the main light source
|
||||
React.useImperativeHandle(forwardRef, () => api, [api]);
|
||||
useFrame(() => {
|
||||
if ((api.temporal || api.frames === Infinity) && api.count < api.frames && api.count < limit) {
|
||||
invalidate();
|
||||
api.update();
|
||||
api.count++;
|
||||
}
|
||||
});
|
||||
return /*#__PURE__*/React.createElement("group", props, /*#__PURE__*/React.createElement("group", {
|
||||
traverse: () => null,
|
||||
ref: gLights
|
||||
}, /*#__PURE__*/React.createElement(accumulativeContext.Provider, {
|
||||
value: api
|
||||
}, children)), /*#__PURE__*/React.createElement("mesh", {
|
||||
receiveShadow: true,
|
||||
ref: gPlane,
|
||||
scale: scale,
|
||||
rotation: [-Math.PI / 2, 0, 0]
|
||||
}, /*#__PURE__*/React.createElement("planeGeometry", null), /*#__PURE__*/React.createElement("softShadowMaterial", {
|
||||
transparent: true,
|
||||
depthWrite: false,
|
||||
toneMapped: toneMapped,
|
||||
color: color,
|
||||
blend: colorBlend,
|
||||
map: plm.progressiveLightMap2.texture
|
||||
})));
|
||||
});
|
||||
const RandomizedLight = /* @__PURE__ */React.forwardRef(({
|
||||
castShadow = true,
|
||||
bias = 0.001,
|
||||
mapSize = 512,
|
||||
size = 5,
|
||||
near = 0.5,
|
||||
far = 500,
|
||||
frames = 1,
|
||||
position = [0, 0, 0],
|
||||
radius = 1,
|
||||
amount = 8,
|
||||
intensity = version >= 155 ? Math.PI : 1,
|
||||
ambient = 0.5,
|
||||
...props
|
||||
}, forwardRef) => {
|
||||
const gLights = React.useRef(null);
|
||||
const length = new THREE.Vector3(...position).length();
|
||||
const parent = React.useContext(accumulativeContext);
|
||||
const update = React.useCallback(() => {
|
||||
let light;
|
||||
if (gLights.current) {
|
||||
for (let l = 0; l < gLights.current.children.length; l++) {
|
||||
light = gLights.current.children[l];
|
||||
if (Math.random() > ambient) {
|
||||
light.position.set(position[0] + THREE.MathUtils.randFloatSpread(radius), position[1] + THREE.MathUtils.randFloatSpread(radius), position[2] + THREE.MathUtils.randFloatSpread(radius));
|
||||
} else {
|
||||
let lambda = Math.acos(2 * Math.random() - 1) - Math.PI / 2.0;
|
||||
let phi = 2 * Math.PI * Math.random();
|
||||
light.position.set(Math.cos(lambda) * Math.cos(phi) * length, Math.abs(Math.cos(lambda) * Math.sin(phi) * length), Math.sin(lambda) * length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [radius, ambient, length, ...position]);
|
||||
const api = React.useMemo(() => ({
|
||||
update
|
||||
}), [update]);
|
||||
React.useImperativeHandle(forwardRef, () => api, [api]);
|
||||
React.useLayoutEffect(() => {
|
||||
var _parent$lights;
|
||||
const group = gLights.current;
|
||||
if (parent) (_parent$lights = parent.lights) == null || _parent$lights.set(group.uuid, api);
|
||||
return () => {
|
||||
var _parent$lights2;
|
||||
return void (parent == null || (_parent$lights2 = parent.lights) == null ? void 0 : _parent$lights2.delete(group.uuid));
|
||||
};
|
||||
}, [parent, api]);
|
||||
return /*#__PURE__*/React.createElement("group", _extends({
|
||||
ref: gLights
|
||||
}, props), Array.from({
|
||||
length: amount
|
||||
}, (_, index) => /*#__PURE__*/React.createElement("directionalLight", {
|
||||
key: index,
|
||||
castShadow: castShadow,
|
||||
"shadow-bias": bias,
|
||||
"shadow-mapSize": [mapSize, mapSize],
|
||||
intensity: intensity / amount
|
||||
}, /*#__PURE__*/React.createElement("orthographicCamera", {
|
||||
attach: "shadow-camera",
|
||||
args: [-size, size, size, -size, near, far]
|
||||
}))));
|
||||
});
|
||||
|
||||
// Based on "Progressive Light Map Accumulator", by [zalo](https://github.com/zalo/)
|
||||
class ProgressiveLightMap {
|
||||
constructor(renderer, scene, res = 1024) {
|
||||
this.renderer = renderer;
|
||||
this.res = res;
|
||||
this.scene = scene;
|
||||
this.buffer1Active = false;
|
||||
this.lights = [];
|
||||
this.meshes = [];
|
||||
this.object = null;
|
||||
this.clearColor = new THREE.Color();
|
||||
this.clearAlpha = 0;
|
||||
|
||||
// Create the Progressive LightMap Texture
|
||||
const textureParams = {
|
||||
type: THREE.HalfFloatType,
|
||||
magFilter: THREE.NearestFilter,
|
||||
minFilter: THREE.NearestFilter
|
||||
};
|
||||
this.progressiveLightMap1 = new THREE.WebGLRenderTarget(this.res, this.res, textureParams);
|
||||
this.progressiveLightMap2 = new THREE.WebGLRenderTarget(this.res, this.res, textureParams);
|
||||
|
||||
// Inject some spicy new logic into a standard phong material
|
||||
this.discardMat = new DiscardMaterial();
|
||||
this.targetMat = new THREE.MeshLambertMaterial({
|
||||
fog: false
|
||||
});
|
||||
this.previousShadowMap = {
|
||||
value: this.progressiveLightMap1.texture
|
||||
};
|
||||
this.averagingWindow = {
|
||||
value: 100
|
||||
};
|
||||
this.targetMat.onBeforeCompile = shader => {
|
||||
// Vertex Shader: Set Vertex Positions to the Unwrapped UV Positions
|
||||
shader.vertexShader = 'varying vec2 vUv;\n' + shader.vertexShader.slice(0, -1) + 'vUv = uv; gl_Position = vec4((uv - 0.5) * 2.0, 1.0, 1.0); }';
|
||||
|
||||
// Fragment Shader: Set Pixels to average in the Previous frame's Shadows
|
||||
const bodyStart = shader.fragmentShader.indexOf('void main() {');
|
||||
shader.fragmentShader = 'varying vec2 vUv;\n' + shader.fragmentShader.slice(0, bodyStart) + 'uniform sampler2D previousShadowMap;\n uniform float averagingWindow;\n' + shader.fragmentShader.slice(bodyStart - 1, -1) + `\nvec3 texelOld = texture2D(previousShadowMap, vUv).rgb;
|
||||
gl_FragColor.rgb = mix(texelOld, gl_FragColor.rgb, 1.0/ averagingWindow);
|
||||
}`;
|
||||
|
||||
// Set the Previous Frame's Texture Buffer and Averaging Window
|
||||
shader.uniforms.previousShadowMap = this.previousShadowMap;
|
||||
shader.uniforms.averagingWindow = this.averagingWindow;
|
||||
};
|
||||
}
|
||||
clear() {
|
||||
this.renderer.getClearColor(this.clearColor);
|
||||
this.clearAlpha = this.renderer.getClearAlpha();
|
||||
this.renderer.setClearColor('black', 1);
|
||||
this.renderer.setRenderTarget(this.progressiveLightMap1);
|
||||
this.renderer.clear();
|
||||
this.renderer.setRenderTarget(this.progressiveLightMap2);
|
||||
this.renderer.clear();
|
||||
this.renderer.setRenderTarget(null);
|
||||
this.renderer.setClearColor(this.clearColor, this.clearAlpha);
|
||||
this.lights = [];
|
||||
this.meshes = [];
|
||||
this.scene.traverse(object => {
|
||||
if (isGeometry(object)) {
|
||||
this.meshes.push({
|
||||
object,
|
||||
material: object.material
|
||||
});
|
||||
} else if (isLight(object)) {
|
||||
this.lights.push({
|
||||
object,
|
||||
intensity: object.intensity
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
prepare() {
|
||||
this.lights.forEach(light => light.object.intensity = 0);
|
||||
this.meshes.forEach(mesh => mesh.object.material = this.discardMat);
|
||||
}
|
||||
finish() {
|
||||
this.lights.forEach(light => light.object.intensity = light.intensity);
|
||||
this.meshes.forEach(mesh => mesh.object.material = mesh.material);
|
||||
}
|
||||
configure(object) {
|
||||
this.object = object;
|
||||
}
|
||||
update(camera, blendWindow = 100) {
|
||||
if (!this.object) return;
|
||||
// Set each object's material to the UV Unwrapped Surface Mapping Version
|
||||
this.averagingWindow.value = blendWindow;
|
||||
this.object.material = this.targetMat;
|
||||
// Ping-pong two surface buffers for reading/writing
|
||||
const activeMap = this.buffer1Active ? this.progressiveLightMap1 : this.progressiveLightMap2;
|
||||
const inactiveMap = this.buffer1Active ? this.progressiveLightMap2 : this.progressiveLightMap1;
|
||||
// Render the object's surface maps
|
||||
const oldBg = this.scene.background;
|
||||
this.scene.background = null;
|
||||
this.renderer.setRenderTarget(activeMap);
|
||||
this.previousShadowMap.value = inactiveMap.texture;
|
||||
this.buffer1Active = !this.buffer1Active;
|
||||
this.renderer.render(this.scene, camera);
|
||||
this.renderer.setRenderTarget(null);
|
||||
this.scene.background = oldBg;
|
||||
}
|
||||
}
|
||||
|
||||
export { AccumulativeShadows, RandomizedLight, accumulativeContext };
|
||||
Reference in New Issue
Block a user