mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-03-07 14:39:30 -07:00
FIX: Update LaserFlow component with dynamic pixel ratio handling
This commit is contained in:
@@ -83,7 +83,7 @@ uniform float uFade;
|
|||||||
// Wisps (animated micro-streaks) that travel along the beam
|
// Wisps (animated micro-streaks) that travel along the beam
|
||||||
#define W_BASE_X 1.5
|
#define W_BASE_X 1.5
|
||||||
#define W_LAYER_GAP 0.25
|
#define W_LAYER_GAP 0.25
|
||||||
#define W_LANES 55
|
#define W_LANES 10
|
||||||
#define W_SIDE_DECAY 0.5
|
#define W_SIDE_DECAY 0.5
|
||||||
#define W_HALF 0.01
|
#define W_HALF 0.01
|
||||||
#define W_AA 0.15
|
#define W_AA 0.15
|
||||||
@@ -96,7 +96,7 @@ uniform float uFade;
|
|||||||
|
|
||||||
// Volumetric fog controls
|
// Volumetric fog controls
|
||||||
#define FOG_ON 1
|
#define FOG_ON 1
|
||||||
#define FOG_CONTRAST 1.5
|
#define FOG_CONTRAST 1.2
|
||||||
#define FOG_SPEED_U 0.1
|
#define FOG_SPEED_U 0.1
|
||||||
#define FOG_SPEED_V -0.1
|
#define FOG_SPEED_V -0.1
|
||||||
#define FOG_OCTAVES 5
|
#define FOG_OCTAVES 5
|
||||||
@@ -107,7 +107,7 @@ uniform float uFade;
|
|||||||
#define FOG_TILT_SHAPE 1.5
|
#define FOG_TILT_SHAPE 1.5
|
||||||
#define FOG_BEAM_MIN 0.0
|
#define FOG_BEAM_MIN 0.0
|
||||||
#define FOG_BEAM_MAX 0.75
|
#define FOG_BEAM_MAX 0.75
|
||||||
#define FOG_MASK_GAMMA 0.20
|
#define FOG_MASK_GAMMA 0.5
|
||||||
#define FOG_EXPAND_SHAPE 12.2
|
#define FOG_EXPAND_SHAPE 12.2
|
||||||
#define FOG_EDGE_MIX 0.5
|
#define FOG_EDGE_MIX 0.5
|
||||||
|
|
||||||
@@ -235,7 +235,12 @@ void mainImage(out vec4 fc,in vec2 frag){
|
|||||||
float nxF=abs((frag.x-C.x)*invW),hE=1.0-smoothstep(HFOG_EDGE_START,HFOG_EDGE_END,nxF); hE=pow(clamp(hE,0.0,1.0),HFOG_EDGE_GAMMA);
|
float nxF=abs((frag.x-C.x)*invW),hE=1.0-smoothstep(HFOG_EDGE_START,HFOG_EDGE_END,nxF); hE=pow(clamp(hE,0.0,1.0),HFOG_EDGE_GAMMA);
|
||||||
float hW=mix(1.0,hE,clamp(yP,0.0,1.0));
|
float hW=mix(1.0,hE,clamp(yP,0.0,1.0));
|
||||||
float bBias=mix(1.0,1.0-sPix,FOG_BOTTOM_BIAS);
|
float bBias=mix(1.0,1.0-sPix,FOG_BOTTOM_BIAS);
|
||||||
fog=n*uFogIntensity*bBias*bm*hW;
|
float browserFogIntensity = uFogIntensity;
|
||||||
|
browserFogIntensity *= 1.8;
|
||||||
|
|
||||||
|
float radialFade = 1.0 - smoothstep(0.0, 0.7, length(uvc) / 120.0);
|
||||||
|
float safariFog = n * browserFogIntensity * bBias * bm * hW * radialFade;
|
||||||
|
fog = safariFog;
|
||||||
#endif
|
#endif
|
||||||
float LF=L+fog;
|
float LF=L+fog;
|
||||||
float dith=(h21(frag)-0.5)*(DITHER_STRENGTH/255.0);
|
float dith=(h21(frag)-0.5)*(DITHER_STRENGTH/255.0);
|
||||||
@@ -278,23 +283,60 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const mountRef = useTemplateRef('mountRef');
|
const mountRef = useTemplateRef('mountRef');
|
||||||
|
const rendererRef = ref<THREE.WebGLRenderer | null>(null);
|
||||||
|
const uniformsRef = ref<any>(null);
|
||||||
const hasFadedRef = ref(false);
|
const hasFadedRef = ref(false);
|
||||||
|
const rectRef = ref<DOMRect | null>(null);
|
||||||
|
const baseDprRef = ref<number>(1);
|
||||||
|
const currentDprRef = ref<number>(1);
|
||||||
|
const fpsSamplesRef = ref<number[]>([]);
|
||||||
|
const lastFpsCheckRef = ref<number>(performance.now());
|
||||||
|
const emaDtRef = ref<number>(16.7); // ms
|
||||||
|
const pausedRef = ref<boolean>(false);
|
||||||
|
const inViewRef = ref<boolean>(true);
|
||||||
|
|
||||||
|
const hexToRGB = (hex: string) => {
|
||||||
|
let c = hex.trim();
|
||||||
|
if (c[0] === '#') c = c.slice(1);
|
||||||
|
if (c.length === 3)
|
||||||
|
c = c
|
||||||
|
.split('')
|
||||||
|
.map(x => x + x)
|
||||||
|
.join('');
|
||||||
|
const n = parseInt(c, 16) || 0xffffff;
|
||||||
|
return { r: ((n >> 16) & 255) / 255, g: ((n >> 8) & 255) / 255, b: (n & 255) / 255 };
|
||||||
|
};
|
||||||
|
|
||||||
let cleanup: (() => void) | null = null;
|
let cleanup: (() => void) | null = null;
|
||||||
|
|
||||||
const setup = () => {
|
const setup = () => {
|
||||||
const mount = mountRef.value!;
|
const mount = mountRef.value!;
|
||||||
const renderer = new THREE.WebGLRenderer({
|
const renderer = new THREE.WebGLRenderer({
|
||||||
antialias: true,
|
antialias: false,
|
||||||
alpha: false,
|
alpha: false,
|
||||||
|
depth: false,
|
||||||
|
stencil: false,
|
||||||
powerPreference: 'high-performance',
|
powerPreference: 'high-performance',
|
||||||
premultipliedAlpha: false
|
premultipliedAlpha: false,
|
||||||
|
preserveDrawingBuffer: false,
|
||||||
|
failIfMajorPerformanceCaveat: false,
|
||||||
|
logarithmicDepthBuffer: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
rendererRef.value = renderer;
|
||||||
|
|
||||||
|
baseDprRef.value = Math.min(props.dpr ?? (window.devicePixelRatio || 1), 2);
|
||||||
|
currentDprRef.value = baseDprRef.value;
|
||||||
|
|
||||||
|
renderer.setPixelRatio(currentDprRef.value);
|
||||||
|
renderer.shadowMap.enabled = false;
|
||||||
|
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
||||||
renderer.setClearColor(0x000000, 1);
|
renderer.setClearColor(0x000000, 1);
|
||||||
renderer.domElement.style.width = '100%';
|
const canvas = renderer.domElement;
|
||||||
renderer.domElement.style.height = '100%';
|
canvas.style.width = '100%';
|
||||||
renderer.domElement.style.display = 'block';
|
canvas.style.height = '100%';
|
||||||
mount.appendChild(renderer.domElement);
|
canvas.style.display = 'block';
|
||||||
|
mount.appendChild(canvas);
|
||||||
|
|
||||||
const scene = new THREE.Scene();
|
const scene = new THREE.Scene();
|
||||||
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
||||||
@@ -302,6 +344,8 @@ const setup = () => {
|
|||||||
const geometry = new THREE.BufferGeometry();
|
const geometry = new THREE.BufferGeometry();
|
||||||
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array([-1, -1, 0, 3, -1, 0, -1, 3, 0]), 3));
|
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array([-1, -1, 0, 3, -1, 0, -1, 3, 0]), 3));
|
||||||
|
|
||||||
|
const { r, g, b } = hexToRGB(props.color || '#FFFFFF');
|
||||||
|
|
||||||
const uniforms = {
|
const uniforms = {
|
||||||
iTime: { value: 0 },
|
iTime: { value: 0 },
|
||||||
iResolution: { value: new THREE.Vector3(1, 1, 1) },
|
iResolution: { value: new THREE.Vector3(1, 1, 1) },
|
||||||
@@ -323,9 +367,10 @@ const setup = () => {
|
|||||||
uDecay: { value: props.decay },
|
uDecay: { value: props.decay },
|
||||||
uFalloffStart: { value: props.falloffStart },
|
uFalloffStart: { value: props.falloffStart },
|
||||||
uFogFallSpeed: { value: props.fogFallSpeed },
|
uFogFallSpeed: { value: props.fogFallSpeed },
|
||||||
uColor: { value: new THREE.Vector3(1, 1, 1) },
|
uColor: { value: new THREE.Vector3(r, g, b) },
|
||||||
uFade: { value: hasFadedRef.value ? 1 : 0 }
|
uFade: { value: hasFadedRef.value ? 1 : 0 }
|
||||||
};
|
};
|
||||||
|
uniformsRef.value = uniforms;
|
||||||
|
|
||||||
const material = new THREE.RawShaderMaterial({
|
const material = new THREE.RawShaderMaterial({
|
||||||
vertexShader: VERT,
|
vertexShader: VERT,
|
||||||
@@ -338,33 +383,55 @@ const setup = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const mesh = new THREE.Mesh(geometry, material);
|
const mesh = new THREE.Mesh(geometry, material);
|
||||||
|
mesh.frustumCulled = false;
|
||||||
scene.add(mesh);
|
scene.add(mesh);
|
||||||
|
|
||||||
const clock = new THREE.Clock();
|
const clock = new THREE.Clock();
|
||||||
let prevTime = 0;
|
let prevTime = 0;
|
||||||
let flowTime = 0;
|
|
||||||
let fogTime = 0;
|
|
||||||
let fade = hasFadedRef.value ? 1 : 0;
|
let fade = hasFadedRef.value ? 1 : 0;
|
||||||
const mouseTarget = new THREE.Vector2(0, 0);
|
const mouseTarget = new THREE.Vector2(0, 0);
|
||||||
const mouseSmooth = new THREE.Vector2(0, 0);
|
const mouseSmooth = new THREE.Vector2(0, 0);
|
||||||
|
|
||||||
const setSize = () => {
|
const setSizeNow = () => {
|
||||||
const { clientWidth: w, clientHeight: h } = mount;
|
const w = mount.clientWidth || 1;
|
||||||
const pixelRatio = Math.min(props.dpr ?? window.devicePixelRatio ?? 1, 2);
|
const h = mount.clientHeight || 1;
|
||||||
renderer.setPixelRatio(pixelRatio);
|
const pr = currentDprRef.value;
|
||||||
|
renderer.setPixelRatio(pr);
|
||||||
renderer.setSize(w, h, false);
|
renderer.setSize(w, h, false);
|
||||||
uniforms.iResolution.value.set(w * pixelRatio, h * pixelRatio, pixelRatio);
|
uniforms.iResolution.value.set(w * pr, h * pr, pr);
|
||||||
|
rectRef.value = canvas.getBoundingClientRect();
|
||||||
};
|
};
|
||||||
|
|
||||||
setSize();
|
let resizeRaf = 0;
|
||||||
const ro = new ResizeObserver(setSize);
|
const scheduleResize = () => {
|
||||||
|
if (resizeRaf) cancelAnimationFrame(resizeRaf);
|
||||||
|
resizeRaf = requestAnimationFrame(setSizeNow);
|
||||||
|
};
|
||||||
|
|
||||||
|
setSizeNow();
|
||||||
|
const ro = new ResizeObserver(scheduleResize);
|
||||||
ro.observe(mount);
|
ro.observe(mount);
|
||||||
|
|
||||||
|
const io = new IntersectionObserver(
|
||||||
|
entries => {
|
||||||
|
inViewRef.value = entries[0]?.isIntersecting ?? true;
|
||||||
|
},
|
||||||
|
{ root: null, threshold: 0 }
|
||||||
|
);
|
||||||
|
io.observe(mount);
|
||||||
|
|
||||||
|
const onVis = () => {
|
||||||
|
pausedRef.value = document.hidden;
|
||||||
|
};
|
||||||
|
document.addEventListener('visibilitychange', onVis, { passive: true });
|
||||||
|
|
||||||
const updateMouse = (clientX: number, clientY: number) => {
|
const updateMouse = (clientX: number, clientY: number) => {
|
||||||
const rect = renderer.domElement.getBoundingClientRect();
|
const rect = rectRef.value;
|
||||||
|
if (!rect) return;
|
||||||
const x = clientX - rect.left;
|
const x = clientX - rect.left;
|
||||||
const y = clientY - rect.top;
|
const y = clientY - rect.top;
|
||||||
const ratio = renderer.getPixelRatio();
|
const ratio = currentDprRef.value;
|
||||||
const hb = rect.height * ratio;
|
const hb = rect.height * ratio;
|
||||||
mouseTarget.set(x * ratio, hb - y * ratio);
|
mouseTarget.set(x * ratio, hb - y * ratio);
|
||||||
};
|
};
|
||||||
@@ -372,20 +439,155 @@ const setup = () => {
|
|||||||
const onMove = (ev: PointerEvent | MouseEvent) => updateMouse(ev.clientX, ev.clientY);
|
const onMove = (ev: PointerEvent | MouseEvent) => updateMouse(ev.clientX, ev.clientY);
|
||||||
const onLeave = () => mouseTarget.set(0, 0);
|
const onLeave = () => mouseTarget.set(0, 0);
|
||||||
|
|
||||||
renderer.domElement.addEventListener('pointermove', onMove as any);
|
canvas.addEventListener('pointermove', onMove as any, { passive: true });
|
||||||
renderer.domElement.addEventListener('pointerdown', onMove as any);
|
canvas.addEventListener('pointerdown', onMove as any, { passive: true });
|
||||||
renderer.domElement.addEventListener('pointerenter', onMove as any);
|
canvas.addEventListener('pointerenter', onMove as any, { passive: true });
|
||||||
renderer.domElement.addEventListener('pointerleave', onLeave as any);
|
canvas.addEventListener('pointerleave', onLeave as any, { passive: true });
|
||||||
window.addEventListener('mousemove', onMove);
|
|
||||||
|
const onCtxLost = (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
pausedRef.value = true;
|
||||||
|
};
|
||||||
|
const onCtxRestored = () => {
|
||||||
|
pausedRef.value = false;
|
||||||
|
scheduleResize();
|
||||||
|
};
|
||||||
|
canvas.addEventListener('webglcontextlost', onCtxLost, false);
|
||||||
|
canvas.addEventListener('webglcontextrestored', onCtxRestored, false);
|
||||||
|
|
||||||
let raf = 0;
|
let raf = 0;
|
||||||
|
const clamp = (v: number, lo: number, hi: number) => Math.max(lo, Math.min(hi, v));
|
||||||
|
const dprFloor = 0.6;
|
||||||
|
const lowerThresh = 50;
|
||||||
|
const upperThresh = 58;
|
||||||
|
|
||||||
|
const adjustDprIfNeeded = (now: number) => {
|
||||||
|
const elapsed = now - lastFpsCheckRef.value;
|
||||||
|
if (elapsed < 750) return;
|
||||||
|
|
||||||
|
const samples = fpsSamplesRef.value;
|
||||||
|
if (samples.length === 0) {
|
||||||
|
lastFpsCheckRef.value = now;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const avgFps = samples.reduce((a, b) => a + b, 0) / samples.length;
|
||||||
|
|
||||||
|
let next = currentDprRef.value;
|
||||||
|
const base = baseDprRef.value;
|
||||||
|
|
||||||
|
if (avgFps < lowerThresh) {
|
||||||
|
next = clamp(currentDprRef.value * 0.9, dprFloor, base);
|
||||||
|
} else if (avgFps > upperThresh && currentDprRef.value < base) {
|
||||||
|
next = clamp(currentDprRef.value * 1.05, dprFloor, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(next - currentDprRef.value) > 0.01) {
|
||||||
|
currentDprRef.value = next;
|
||||||
|
setSizeNow();
|
||||||
|
}
|
||||||
|
|
||||||
|
fpsSamplesRef.value = [];
|
||||||
|
lastFpsCheckRef.value = now;
|
||||||
|
};
|
||||||
|
|
||||||
const animate = () => {
|
const animate = () => {
|
||||||
|
raf = requestAnimationFrame(animate);
|
||||||
|
if (pausedRef.value || !inViewRef.value) return;
|
||||||
|
|
||||||
const t = clock.getElapsedTime();
|
const t = clock.getElapsedTime();
|
||||||
const dt = Math.max(0, t - prevTime);
|
const dt = Math.max(0, t - prevTime);
|
||||||
prevTime = t;
|
prevTime = t;
|
||||||
|
|
||||||
|
const dtMs = dt * 1000;
|
||||||
|
emaDtRef.value = emaDtRef.value * 0.9 + dtMs * 0.1;
|
||||||
|
const instFps = 1000 / Math.max(1, emaDtRef.value);
|
||||||
|
fpsSamplesRef.value.push(instFps);
|
||||||
|
|
||||||
uniforms.iTime.value = t;
|
uniforms.iTime.value = t;
|
||||||
uniforms.uTiltScale.value = props.mouseTiltStrength;
|
|
||||||
|
const cdt = Math.min(0.033, Math.max(0.001, dt));
|
||||||
|
(uniforms.uFlowTime.value as number) += cdt;
|
||||||
|
(uniforms.uFogTime.value as number) += cdt;
|
||||||
|
|
||||||
|
if (!hasFadedRef.value) {
|
||||||
|
const fadeDur = 1.0;
|
||||||
|
fade = Math.min(1, fade + cdt / fadeDur);
|
||||||
|
uniforms.uFade.value = fade;
|
||||||
|
if (fade >= 1) hasFadedRef.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tau = Math.max(1e-3, props.mouseSmoothTime);
|
||||||
|
const alpha = 1 - Math.exp(-cdt / tau);
|
||||||
|
mouseSmooth.lerp(mouseTarget, alpha);
|
||||||
|
uniforms.iMouse.value.set(mouseSmooth.x, mouseSmooth.y, 0, 0);
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
|
||||||
|
adjustDprIfNeeded(performance.now());
|
||||||
|
};
|
||||||
|
|
||||||
|
animate();
|
||||||
|
|
||||||
|
cleanup = () => {
|
||||||
|
cancelAnimationFrame(raf);
|
||||||
|
ro.disconnect();
|
||||||
|
io.disconnect();
|
||||||
|
document.removeEventListener('visibilitychange', onVis);
|
||||||
|
canvas.removeEventListener('pointermove', onMove as any);
|
||||||
|
canvas.removeEventListener('pointerdown', onMove as any);
|
||||||
|
canvas.removeEventListener('pointerenter', onMove as any);
|
||||||
|
canvas.removeEventListener('pointerleave', onLeave as any);
|
||||||
|
canvas.removeEventListener('webglcontextlost', onCtxLost);
|
||||||
|
canvas.removeEventListener('webglcontextrestored', onCtxRestored);
|
||||||
|
geometry.dispose();
|
||||||
|
material.dispose();
|
||||||
|
renderer.dispose();
|
||||||
|
if (mount.contains(canvas)) mount.removeChild(canvas);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setup();
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
cleanup?.();
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [props.dpr],
|
||||||
|
() => {
|
||||||
|
cleanup?.();
|
||||||
|
setup();
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [
|
||||||
|
props.wispDensity,
|
||||||
|
props.mouseTiltStrength,
|
||||||
|
props.horizontalBeamOffset,
|
||||||
|
props.verticalBeamOffset,
|
||||||
|
props.flowSpeed,
|
||||||
|
props.verticalSizing,
|
||||||
|
props.horizontalSizing,
|
||||||
|
props.fogIntensity,
|
||||||
|
props.fogScale,
|
||||||
|
props.wispSpeed,
|
||||||
|
props.wispIntensity,
|
||||||
|
props.flowStrength,
|
||||||
|
props.decay,
|
||||||
|
props.falloffStart,
|
||||||
|
props.fogFallSpeed,
|
||||||
|
props.color
|
||||||
|
],
|
||||||
|
() => {
|
||||||
|
const uniforms = uniformsRef.value;
|
||||||
|
if (!uniforms) return;
|
||||||
|
|
||||||
uniforms.uWispDensity.value = props.wispDensity;
|
uniforms.uWispDensity.value = props.wispDensity;
|
||||||
|
uniforms.uTiltScale.value = props.mouseTiltStrength;
|
||||||
uniforms.uBeamXFrac.value = props.horizontalBeamOffset;
|
uniforms.uBeamXFrac.value = props.horizontalBeamOffset;
|
||||||
uniforms.uBeamYFrac.value = props.verticalBeamOffset;
|
uniforms.uBeamYFrac.value = props.verticalBeamOffset;
|
||||||
uniforms.uFlowSpeed.value = props.flowSpeed;
|
uniforms.uFlowSpeed.value = props.flowSpeed;
|
||||||
@@ -399,74 +601,10 @@ const setup = () => {
|
|||||||
uniforms.uDecay.value = props.decay;
|
uniforms.uDecay.value = props.decay;
|
||||||
uniforms.uFalloffStart.value = props.falloffStart;
|
uniforms.uFalloffStart.value = props.falloffStart;
|
||||||
uniforms.uFogFallSpeed.value = props.fogFallSpeed;
|
uniforms.uFogFallSpeed.value = props.fogFallSpeed;
|
||||||
(function () {
|
|
||||||
let c = props.color || '#ffffff';
|
|
||||||
c = c.trim();
|
|
||||||
if (c[0] === '#') c = c.slice(1);
|
|
||||||
if (c.length === 3)
|
|
||||||
c = c
|
|
||||||
.split('')
|
|
||||||
.map(x => x + x)
|
|
||||||
.join('');
|
|
||||||
let n = parseInt(c, 16);
|
|
||||||
if (isNaN(n)) n = 0xffffff;
|
|
||||||
const r = ((n >> 16) & 255) / 255;
|
|
||||||
const g = ((n >> 8) & 255) / 255;
|
|
||||||
const b = (n & 255) / 255;
|
|
||||||
uniforms.uColor.value.set(r, g, b);
|
|
||||||
})();
|
|
||||||
const cdt = Math.min(0.033, Math.max(0.001, dt));
|
|
||||||
flowTime += cdt;
|
|
||||||
fogTime += cdt;
|
|
||||||
uniforms.uFlowTime.value = flowTime;
|
|
||||||
uniforms.uFogTime.value = fogTime;
|
|
||||||
if (!hasFadedRef.value) {
|
|
||||||
const fadeDur = 1.0;
|
|
||||||
fade = Math.min(1, fade + cdt / fadeDur);
|
|
||||||
uniforms.uFade.value = fade;
|
|
||||||
if (fade >= 1) hasFadedRef.value = true;
|
|
||||||
} else if (uniforms.uFade.value !== 1) {
|
|
||||||
uniforms.uFade.value = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tau = Math.max(1e-3, props.mouseSmoothTime);
|
const { r, g, b } = hexToRGB(props.color || '#FFFFFF');
|
||||||
const alpha = 1 - Math.exp(-cdt / tau);
|
console.log(props.color);
|
||||||
mouseSmooth.lerp(mouseTarget, alpha);
|
uniforms.uColor.value.set(r, g, b);
|
||||||
uniforms.iMouse.value.set(mouseSmooth.x, mouseSmooth.y, 0, 0);
|
|
||||||
|
|
||||||
renderer.render(scene, camera);
|
|
||||||
raf = requestAnimationFrame(animate);
|
|
||||||
};
|
|
||||||
animate();
|
|
||||||
|
|
||||||
cleanup = () => {
|
|
||||||
cancelAnimationFrame(raf);
|
|
||||||
ro.disconnect();
|
|
||||||
renderer.domElement.removeEventListener('pointermove', onMove as any);
|
|
||||||
renderer.domElement.removeEventListener('pointerdown', onMove as any);
|
|
||||||
renderer.domElement.removeEventListener('pointerenter', onMove as any);
|
|
||||||
renderer.domElement.removeEventListener('pointerleave', onLeave as any);
|
|
||||||
window.removeEventListener('mousemove', onMove);
|
|
||||||
geometry.dispose();
|
|
||||||
material.dispose();
|
|
||||||
renderer.dispose();
|
|
||||||
mount.removeChild(renderer.domElement);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
setup();
|
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
cleanup?.();
|
|
||||||
});
|
|
||||||
|
|
||||||
watch(
|
|
||||||
props,
|
|
||||||
() => {
|
|
||||||
cleanup?.();
|
|
||||||
setup();
|
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
:fog-scale="fogScale"
|
:fog-scale="fogScale"
|
||||||
:fog-fall-speed="fogFallSpeed"
|
:fog-fall-speed="fogFallSpeed"
|
||||||
:decay="decay"
|
:decay="decay"
|
||||||
|
:dpr="1"
|
||||||
:falloff-start="falloffStart"
|
:falloff-start="falloffStart"
|
||||||
:color="laserColor"
|
:color="laserColor"
|
||||||
:key="key"
|
:key="key"
|
||||||
|
|||||||
Reference in New Issue
Block a user