mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 04:12:02 +08:00
add AnimatedPlane
This commit is contained in:
parent
742e404ee3
commit
144afd98a5
201
src/components/sliders/AnimatedPlane.js
Normal file
201
src/components/sliders/AnimatedPlane.js
Normal file
@ -0,0 +1,201 @@
|
||||
|
||||
import {
|
||||
BufferGeometry,
|
||||
DoubleSide,
|
||||
Face3,
|
||||
Geometry,
|
||||
InstancedBufferAttribute,
|
||||
InstancedMesh,
|
||||
MathUtils,
|
||||
MeshBasicMaterial,
|
||||
Object3D,
|
||||
Vector2,
|
||||
Vector3,
|
||||
} from 'three';
|
||||
|
||||
export default class AnimatedPlane {
|
||||
constructor(params) {
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
this[key] = value;
|
||||
});
|
||||
|
||||
this.o3d = new Object3D();
|
||||
this.uProgress = { value: 0 };
|
||||
this.uvScale = new Vector2();
|
||||
|
||||
this.initMaterial();
|
||||
this.initPlane();
|
||||
}
|
||||
|
||||
initMaterial() {
|
||||
this.material = new MeshBasicMaterial({
|
||||
side: DoubleSide,
|
||||
transparent: true,
|
||||
map: this.texture,
|
||||
onBeforeCompile: shader => {
|
||||
shader.uniforms.progress = this.uProgress;
|
||||
shader.uniforms.uvScale = { value: this.uvScale };
|
||||
shader.vertexShader = `
|
||||
uniform float progress;
|
||||
uniform vec2 uvScale;
|
||||
|
||||
attribute vec3 offset;
|
||||
attribute vec3 rotation;
|
||||
attribute vec2 uvOffset;
|
||||
|
||||
mat3 rotationMatrixXYZ(vec3 r)
|
||||
{
|
||||
float cx = cos(r.x);
|
||||
float sx = sin(r.x);
|
||||
float cy = cos(r.y);
|
||||
float sy = sin(r.y);
|
||||
float cz = cos(r.z);
|
||||
float sz = sin(r.z);
|
||||
|
||||
return mat3(
|
||||
cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz,
|
||||
-cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz,
|
||||
sy, -sx * cy, cx * cy
|
||||
);
|
||||
}
|
||||
` + shader.vertexShader;
|
||||
|
||||
shader.vertexShader = shader.vertexShader.replace('#include <uv_vertex>', `
|
||||
#include <uv_vertex>
|
||||
vUv = vUv * uvScale + uvOffset;
|
||||
`);
|
||||
|
||||
shader.vertexShader = shader.vertexShader.replace('#include <project_vertex>', `
|
||||
mat3 rotMat = rotationMatrixXYZ(progress * rotation);
|
||||
transformed = rotMat * transformed;
|
||||
|
||||
vec4 mvPosition = vec4(transformed, 1.0);
|
||||
#ifdef USE_INSTANCING
|
||||
mvPosition = instanceMatrix * mvPosition;
|
||||
#endif
|
||||
|
||||
mvPosition.xyz += progress * offset;
|
||||
|
||||
mvPosition = modelViewMatrix * mvPosition;
|
||||
gl_Position = projectionMatrix * mvPosition;
|
||||
`);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
initPlane() {
|
||||
const { width, wWidth, wHeight } = this.screen;
|
||||
this.wSize = this.size * wWidth / width;
|
||||
this.nx = Math.ceil(wWidth / this.wSize) + 1;
|
||||
this.ny = Math.ceil(wHeight / this.wSize) + 1;
|
||||
this.icount = this.nx * this.ny;
|
||||
|
||||
this.initGeometry();
|
||||
this.initUV();
|
||||
this.initAnimAttributes();
|
||||
|
||||
if (this.imesh) {
|
||||
this.o3d.remove(this.imesh);
|
||||
}
|
||||
this.imesh = new InstancedMesh(this.bGeometry, this.material, this.icount);
|
||||
this.o3d.add(this.imesh);
|
||||
|
||||
const dummy = new Object3D();
|
||||
let index = 0;
|
||||
let x = -(wWidth - (wWidth - this.nx * this.wSize)) / 2 + this.dx;
|
||||
for (let i = 0; i < this.nx; i++) {
|
||||
let y = -(wHeight - (wHeight - this.ny * this.wSize)) / 2 + this.dy;
|
||||
for (let j = 0; j < this.ny; j++) {
|
||||
dummy.position.set(x, y, 0);
|
||||
dummy.updateMatrix();
|
||||
this.imesh.setMatrixAt(index++, dummy.matrix);
|
||||
y += this.wSize;
|
||||
}
|
||||
x += this.wSize;
|
||||
}
|
||||
}
|
||||
|
||||
initGeometry() {
|
||||
// square
|
||||
const geometry = new Geometry();
|
||||
geometry.vertices.push(new Vector3(0, 0, 0));
|
||||
geometry.vertices.push(new Vector3(this.wSize, 0, 0));
|
||||
geometry.vertices.push(new Vector3(0, this.wSize, 0));
|
||||
geometry.vertices.push(new Vector3(this.wSize, this.wSize, 0));
|
||||
geometry.faces.push(new Face3(0, 2, 1));
|
||||
geometry.faces.push(new Face3(2, 3, 1));
|
||||
|
||||
geometry.faceVertexUvs[0].push([
|
||||
new Vector2(0, 0),
|
||||
new Vector2(0, 1),
|
||||
new Vector2(1, 0),
|
||||
]);
|
||||
geometry.faceVertexUvs[0].push([
|
||||
new Vector2(0, 1),
|
||||
new Vector2(1, 1),
|
||||
new Vector2(1, 0),
|
||||
]);
|
||||
|
||||
// geometry.computeFaceNormals();
|
||||
// geometry.computeVertexNormals();
|
||||
|
||||
// center
|
||||
this.dx = this.wSize / 2;
|
||||
this.dy = this.wSize / 2;
|
||||
geometry.translate(-this.dx, -this.dy, 0);
|
||||
|
||||
this.bGeometry = new BufferGeometry().fromGeometry(geometry);
|
||||
}
|
||||
|
||||
initAnimAttributes() {
|
||||
const { randFloat: rnd, randFloatSpread: rndFS } = MathUtils;
|
||||
const v3 = new Vector3();
|
||||
|
||||
const offsets = new Float32Array(this.icount * 3);
|
||||
for (let i = 0; i < offsets.length; i += 3) {
|
||||
if (this.anim === 1) v3.set(rndFS(10), rnd(50, 100), rnd(20, 50)).toArray(offsets, i);
|
||||
else v3.set(rndFS(20), rndFS(20), rnd(20, 200)).toArray(offsets, i);
|
||||
}
|
||||
this.bGeometry.setAttribute('offset', new InstancedBufferAttribute(offsets, 3));
|
||||
|
||||
const rotations = new Float32Array(this.icount * 3);
|
||||
const angle = Math.PI * 4;
|
||||
for (let i = 0; i < rotations.length; i += 3) {
|
||||
rotations[i] = rndFS(angle);
|
||||
rotations[i + 1] = rndFS(angle);
|
||||
rotations[i + 2] = rndFS(angle);
|
||||
}
|
||||
this.bGeometry.setAttribute('rotation', new InstancedBufferAttribute(rotations, 3));
|
||||
}
|
||||
|
||||
initUV() {
|
||||
const ratio = this.nx / this.ny;
|
||||
const tRatio = this.texture.image.width / this.texture.image.height;
|
||||
if (ratio > tRatio) this.uvScale.set(1 / this.nx, (tRatio / ratio) / this.ny);
|
||||
else this.uvScale.set((ratio / tRatio) / this.nx, 1 / this.ny);
|
||||
const nW = this.uvScale.x * this.nx;
|
||||
const nH = this.uvScale.y * this.ny;
|
||||
|
||||
const v2 = new Vector2();
|
||||
const uvOffsets = new Float32Array(this.icount * 2);
|
||||
for (let i = 0; i < this.nx; i++) {
|
||||
for (let j = 0; j < this.ny; j++) {
|
||||
v2.set(
|
||||
this.uvScale.x * i + (1 - nW) / 2,
|
||||
this.uvScale.y * j + (1 - nH) / 2
|
||||
).toArray(uvOffsets, (i * this.ny + j) * 2);
|
||||
}
|
||||
}
|
||||
this.bGeometry.setAttribute('uvOffset', new InstancedBufferAttribute(uvOffsets, 2));
|
||||
}
|
||||
|
||||
setTexture(texture) {
|
||||
this.texture = texture;
|
||||
this.material.map = texture;
|
||||
this.initUV();
|
||||
}
|
||||
|
||||
resize() {
|
||||
this.initPlane();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user