feat: pseudo 3d layer
Some checks failed
Build Demo / build (push) Failing after 6m39s

This commit is contained in:
Cdm2883 2024-08-09 22:24:14 +08:00
parent c966b1c617
commit c40aeb1dfb
5 changed files with 95 additions and 6 deletions

View File

@ -9,3 +9,10 @@
width: 100%;
height: 100%;
}
#pseudo-3d-layer {
position: fixed;
width: 100%;
height: 100%;
pointer-events: none;
}

View File

@ -14,6 +14,8 @@
<canvas id="three-viewport"></canvas>
<div id="pseudo-3d-layer"></div>
<script src="assets/javascripts/main.js"></script>
</body>
</html>

View File

@ -1,8 +1,31 @@
import ThreeViewport from "./three.js";
import WorldViewport from "./world-viewport.js";
import WebGL from "three/examples/jsm/capabilities/WebGL.js";
import Pseudo3DLayer from "./pseudo-3d-layer.js";
if (WebGL.isWebGL2Available()) {
new ThreeViewport(document.getElementById('three-viewport')).setup();
const canvas = document.getElementById('three-viewport');
const world = new WorldViewport(canvas);
world.setup();
console.log(world);
const container = document.getElementById('pseudo-3d-layer');
const layer = new Pseudo3DLayer(container);
layer.bind(world);
console.log(layer);
const test1 = document.createElement('div');
test1.style.width = '10%';
test1.style.height = '10%';
test1.style.background = 'red';
test1.style.pointerEvents = 'fill';
layer.add(test1, { x: 0, y: 0, z: 0 });
const test2 = document.createElement('div');
test2.style.width = '5%';
test2.style.height = '5%';
test2.style.background = 'green';
test2.style.pointerEvents = 'fill';
layer.add(test2, { x: 0, y: 0, z: 1 });
} else {
document.body.appendChild(WebGL.getWebGL2ErrorMessage());
}

56
src/pseudo-3d-layer.js Normal file
View File

@ -0,0 +1,56 @@
export default class Pseudo3DLayer {
/** @param {HTMLDivElement} container */
constructor(container) {
this.container = container;
}
/** @param {WorldViewport} world */
bind(world) {
this.world = world;
this.originX = world.camera.position.z;
world.renderPseudo = this.render.bind(this);
}
/** @type {[ { wrapper: HTMLDivElement, element: HTMLElement, x: (layer: Pseudo3DLayer) => number, y: (layer: Pseudo3DLayer) => number, z: (layer: Pseudo3DLayer) => number } ]} */
items = [];
/**
* @param {HTMLElement} element
* @param {{ x: number | (() => number), y?: number | (() => number), z?: number | (() => number) }} options
*/
add(element, options) {
const wrapper = document.createElement('div');
wrapper.style.position = 'absolute';
wrapper.style.width = '100%';
wrapper.style.height = '100%';
wrapper.appendChild(element);
this.container.appendChild(wrapper);
// const
const value = x => typeof x === 'function' ? x : () => (x || 0);
this.items.push({
wrapper,
element,
x: value(options.x),
y: value(options.y),
z: value(options.z),
});
}
static PixelToBlockMultiple = 40;
render(item) {
if (!item) return this.items.forEach(item => this.render(item));
const { innerWidth: windowWidth, innerHeight: windowHeight } = window;
const { clientWidth: width, clientHeight: height } = item.element;
const [ x, y, z ] = [ item.x(this), item.y(this), item.z(this) ];
const cameraZ = this.world.camera.position.z;
const top = windowHeight / 2 - height / 2 + y;
const left = windowWidth / 2 - width / 2
+ x
+ (this.originX - cameraZ) * Pseudo3DLayer.PixelToBlockMultiple
* (1 + z);
item.wrapper.style.top = `${top}px`;
item.wrapper.style.left = `${left}px`;
}
}

View File

@ -34,7 +34,7 @@ const motionBlurShader = {
`,
};
export default class ThreeViewport {
export default class WorldViewport {
/** @param {HTMLCanvasElement} canvas */
constructor(canvas) {
this.canvas = canvas;
@ -229,8 +229,6 @@ export default class ThreeViewport {
this.camera.position.set(-34, -12, -0.1);
this.camera.rotation.set(0, THREE.MathUtils.degToRad(270), 0);
// this.camera.position.z += -3;
this.controller();
this.animate();
}
@ -249,12 +247,13 @@ export default class ThreeViewport {
this.canvas.addEventListener('touchstart', event => this.previousX = event.touches[0].clientX);
this.canvas.addEventListener('touchmove', event => {
const currentX = event.touches[0].clientX;
if (this.previousX) this.targetZ += (this.previousX - currentX) * 0.02;
if (this.previousX) this.targetZ += (this.previousX - currentX) * 0.025;
this.previousX = currentX;
});
window.addEventListener('touchend', () => this.previousX = null);
}
renderPseudo;
animate() {
requestAnimationFrame(this.animate.bind(this));
@ -275,6 +274,8 @@ export default class ThreeViewport {
this.animatePetals();
if (this.renderPseudo) this.renderPseudo();
this.composer.render();
}
}