added particles on beat slicing (fixes #54)
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
var SIGN_MATERIAL = {shader: 'flat', color: '#88f'};
|
||||
|
||||
var auxObj3D = new THREE.Object3D();
|
||||
|
||||
/**
|
||||
* Create beat from pool, collision detection, clipping planes.
|
||||
*/
|
||||
@@ -52,6 +54,7 @@ AFRAME.registerComponent('beat', {
|
||||
this.missElRight = document.getElementById('missRight');
|
||||
|
||||
this.beams = document.getElementById('beams').components['beams'];
|
||||
this.particles = document.getElementById('saberParticles');
|
||||
|
||||
this.initBlock();
|
||||
this.initColliders();
|
||||
@@ -308,7 +311,12 @@ AFRAME.registerComponent('beat', {
|
||||
|
||||
this.returnToPoolTimer = 800;
|
||||
|
||||
// this.el.sceneEl.components['json-particles__hit'].explode(this.el.object3D.position, rightCutPlane.normal, direction, this.data.color);
|
||||
auxObj3D.up.copy(rightCutPlane.normal);
|
||||
auxObj3D.lookAt(direction);
|
||||
this.particles.emit('explode', {
|
||||
position: this.el.object3D.position,
|
||||
rotation: auxObj3D.rotation
|
||||
});
|
||||
}
|
||||
})(),
|
||||
|
||||
|
||||
621
src/components/particleplayer.js
Normal file
621
src/components/particleplayer.js
Normal file
@@ -0,0 +1,621 @@
|
||||
const NUM_PLANE_POSITIONS = 12;
|
||||
|
||||
const BLENDINGS = {
|
||||
normal: THREE.NormalBlending,
|
||||
additive: THREE.AdditiveBlending,
|
||||
substractive: THREE.SubstractiveBlending,
|
||||
multiply: THREE.MultiplyBlending
|
||||
};
|
||||
|
||||
const SHADERS = {
|
||||
flat: THREE.MeshBasicMaterial,
|
||||
lambert: THREE.MeshLambertMaterial,
|
||||
phong: THREE.MeshPhongMaterial,
|
||||
standard: THREE.MeshStandardMaterial
|
||||
};
|
||||
|
||||
const OFFSCREEN_VEC3 = new THREE.Vector3(-99999, -99999, -99999);
|
||||
|
||||
/**
|
||||
* Particle Player component for A-Frame.
|
||||
*/
|
||||
AFRAME.registerComponent('particleplayer', {
|
||||
schema: {
|
||||
blending: {
|
||||
default: 'additive',
|
||||
oneOf: ['normal', 'additive', 'multiply', 'substractive']
|
||||
},
|
||||
color: {default: '#fff', type: 'color'},
|
||||
count: {default: '100%'},
|
||||
delay: {default: 0, type: 'int'},
|
||||
dur: {default: 1000, type: 'int'},
|
||||
img: {type: 'selector'},
|
||||
interpolate: {default: false},
|
||||
loop: {default: 'false'},
|
||||
on: {default: 'init'},
|
||||
poolSize: {default: 5, type: 'int'}, // number of simultaneous particle systems
|
||||
protation: {type: 'vec3'},
|
||||
pscale: {default: 1.0, type: 'float'},
|
||||
scale: {default: 1.0, type: 'float'},
|
||||
initialScale: {type: 'vec3'},
|
||||
finalScale: {type: 'vec3'},
|
||||
animateScale: {default: false},
|
||||
shader: {
|
||||
default: 'flat',
|
||||
oneOf: ['flat', 'lambert', 'phong', 'standard']
|
||||
},
|
||||
src: {type: 'selector'}
|
||||
},
|
||||
|
||||
multiple: true,
|
||||
|
||||
init: function() {
|
||||
this.frame = 0;
|
||||
this.framedata = null;
|
||||
this.indexPool = null;
|
||||
this.lastFrame = 0;
|
||||
this.material = null;
|
||||
this.msPerFrame = 0;
|
||||
this.numFrames = 0;
|
||||
this.numParticles = 0; // total number of particles per system
|
||||
this.originalVertexPositions = [];
|
||||
this.particleCount = 0; // actual number of particles to spawn per event (data.count)
|
||||
this.particleSystems = [];
|
||||
this.protation = false;
|
||||
this.restPositions = []; // position at first frame each particle is alive
|
||||
this.restRotations = [];
|
||||
this.sprite_rotation = false;
|
||||
this.systems = null;
|
||||
this.useRotation = false;
|
||||
this.scaleAnim = new THREE.Vector3();
|
||||
},
|
||||
|
||||
update: function(oldData) {
|
||||
const data = this.data;
|
||||
|
||||
if (!data.src) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldData.on !== data.on) {
|
||||
if (oldData.on) {
|
||||
this.el.removeEventListener(oldData.on, this.start);
|
||||
}
|
||||
if (data.on !== 'play') {
|
||||
this.el.addEventListener(data.on, this.start.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
this.loadParticlesJSON(data.src, data.scale);
|
||||
|
||||
this.numFrames = this.framedata.length;
|
||||
this.numParticles = this.numFrames > 0 ? this.framedata[0].length : 0;
|
||||
|
||||
if (data.count[data.count.length - 1] === '%') {
|
||||
this.particleCount = Math.floor(
|
||||
(parseInt(data.count) * this.numParticles) / 100.0
|
||||
);
|
||||
} else {
|
||||
this.particleCount = parseInt(data.count);
|
||||
}
|
||||
this.particleCount = Math.min(
|
||||
this.numParticles,
|
||||
Math.max(0, this.particleCount)
|
||||
);
|
||||
|
||||
this.msPerFrame = data.dur / this.numFrames;
|
||||
|
||||
this.indexPool = new Array(this.numParticles);
|
||||
|
||||
const materialParams = {
|
||||
color: new THREE.Color(data.color),
|
||||
side: THREE.DoubleSide,
|
||||
blending: BLENDINGS[data.blending],
|
||||
map: data.img ? new THREE.TextureLoader().load(data.img.src) : null,
|
||||
depthWrite: false,
|
||||
opacity: data.opacity,
|
||||
transparent: !!data.img || data.blending !== 'normal' || data.opacity < 1
|
||||
};
|
||||
if (SHADERS[data.shader] !== undefined) {
|
||||
this.material = new SHADERS[data.shader](materialParams);
|
||||
} else {
|
||||
this.material = new SHADERS['flat'](materialParams);
|
||||
}
|
||||
|
||||
this.createParticles(data.poolSize);
|
||||
|
||||
if (data.on === 'init') {
|
||||
this.start();
|
||||
}
|
||||
},
|
||||
|
||||
loadParticlesJSON: function(json, scale) {
|
||||
var alive;
|
||||
|
||||
this.restPositions.length = 0;
|
||||
this.restRotations.length = 0;
|
||||
|
||||
const jsonData = JSON.parse(json.data);
|
||||
const frames = jsonData.frames;
|
||||
const precision = jsonData.precision;
|
||||
|
||||
this.useRotation = jsonData.rotation;
|
||||
|
||||
if (jsonData.sprite_rotation !== false) {
|
||||
this.sprite_rotation = {
|
||||
x: jsonData.sprite_rotation[0] / precision,
|
||||
y: jsonData.sprite_rotation[1] / precision,
|
||||
z: jsonData.sprite_rotation[2] / precision
|
||||
};
|
||||
} else {
|
||||
this.sprite_rotation = false;
|
||||
}
|
||||
|
||||
this.framedata = new Array(frames.length);
|
||||
for (let frameIndex = 0; frameIndex < frames.length; frameIndex++) {
|
||||
this.framedata[frameIndex] = new Array(frames[frameIndex].length);
|
||||
for (
|
||||
let particleIndex = 0;
|
||||
particleIndex < frames[frameIndex].length;
|
||||
particleIndex++
|
||||
) {
|
||||
let rawP = frames[frameIndex][particleIndex]; // data of particle i in frame f
|
||||
alive = rawP !== 0; // 0 means not alive yet this frame.
|
||||
|
||||
let p = (this.framedata[frameIndex][particleIndex] = {
|
||||
position: alive
|
||||
? {
|
||||
x: (rawP[0] / precision) * scale,
|
||||
y: (rawP[1] / precision) * scale,
|
||||
z: (rawP[2] / precision) * scale
|
||||
}
|
||||
: null,
|
||||
alive: alive
|
||||
});
|
||||
|
||||
if (jsonData.rotation) {
|
||||
p.rotation = alive
|
||||
? {
|
||||
x: rawP[3] / precision,
|
||||
y: rawP[4] / precision,
|
||||
z: rawP[5] / precision
|
||||
}
|
||||
: null;
|
||||
}
|
||||
|
||||
if (alive && frameIndex === 0) {
|
||||
this.restPositions[particleIndex] = p.position
|
||||
? {x: p.position.y, y: p.position.y, z: p.position.z}
|
||||
: null;
|
||||
this.restRotations[particleIndex] = p.rotation
|
||||
? {x: p.rotation.y, y: p.rotation.y, z: p.rotation.z}
|
||||
: null;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
createParticles: (function() {
|
||||
const tempGeometries = [];
|
||||
|
||||
return function(numParticleSystems) {
|
||||
const data = this.data;
|
||||
var loop = parseInt(this.data.loop);
|
||||
|
||||
this.particleSystems.length = 0;
|
||||
|
||||
if (isNaN(loop)) {
|
||||
loop = this.data.loop === 'true' ? Number.MAX_VALUE : 0;
|
||||
}
|
||||
|
||||
for (let i = 0; i < numParticleSystems; i++) {
|
||||
let particleSystem = {
|
||||
active: false,
|
||||
activeParticleIndices: new Array(this.particleCount),
|
||||
loopCount: 0,
|
||||
loopTotal: loop,
|
||||
mesh: null,
|
||||
time: 0,
|
||||
pscale: data.animateScale ? new THREE.Vector3() : null
|
||||
};
|
||||
|
||||
// Fill array of geometries to merge.
|
||||
const ratio = data.img ? data.img.width / data.img.height : 1;
|
||||
tempGeometries.length = 0;
|
||||
for (let p = 0; p < this.numParticles; p++) {
|
||||
let geometry = new THREE.PlaneBufferGeometry(
|
||||
0.1 * ratio * data.pscale,
|
||||
0.1 * data.pscale
|
||||
);
|
||||
if (this.sprite_rotation !== false) {
|
||||
geometry.rotateX(this.sprite_rotation.x);
|
||||
geometry.rotateY(this.sprite_rotation.y);
|
||||
geometry.rotateZ(this.sprite_rotation.z);
|
||||
} else {
|
||||
geometry.rotateX((this.data.protation.x * Math.PI) / 180);
|
||||
geometry.rotateY((this.data.protation.y * Math.PI) / 180);
|
||||
geometry.rotateZ((this.data.protation.z * Math.PI) / 180);
|
||||
}
|
||||
tempGeometries.push(geometry);
|
||||
}
|
||||
|
||||
// Create merged geometry for whole particle system.
|
||||
let mergedBufferGeometry = THREE.BufferGeometryUtils.mergeBufferGeometries(
|
||||
tempGeometries
|
||||
);
|
||||
|
||||
particleSystem.mesh = new THREE.Mesh(
|
||||
mergedBufferGeometry,
|
||||
this.material
|
||||
);
|
||||
particleSystem.mesh.visible = false;
|
||||
this.el.setObject3D(`particleplayer${i}`, particleSystem.mesh);
|
||||
copyArray(
|
||||
this.originalVertexPositions,
|
||||
mergedBufferGeometry.attributes.position.array
|
||||
);
|
||||
|
||||
// Hide all particles by default.
|
||||
for (
|
||||
let i = 0;
|
||||
i < mergedBufferGeometry.attributes.position.array.length;
|
||||
i++
|
||||
) {
|
||||
mergedBufferGeometry.attributes.position.array[i] = -99999;
|
||||
}
|
||||
|
||||
for (let i = 0; i < particleSystem.activeParticleIndices.length; i++) {
|
||||
particleSystem.activeParticleIndices[i] = i;
|
||||
};
|
||||
|
||||
this.particleSystems.push(particleSystem);
|
||||
}
|
||||
};
|
||||
})(),
|
||||
|
||||
start: function(evt) {
|
||||
if (this.data.delay > 0) {
|
||||
setTimeout(() => this.startAfterDelay(evt), this.data.delay);
|
||||
} else {
|
||||
this.startAfterDelay(evt);
|
||||
}
|
||||
},
|
||||
|
||||
startAfterDelay: function(evt) {
|
||||
// position, rotation
|
||||
var found = -1;
|
||||
var particleSystem;
|
||||
var oldestTime = 0;
|
||||
var position = evt ? evt.detail.position : null;
|
||||
var rotation = evt ? evt.detail.rotation : null;
|
||||
|
||||
if (!(position instanceof THREE.Vector3)) {
|
||||
position = new THREE.Vector3();
|
||||
}
|
||||
if (!(rotation instanceof THREE.Euler)) {
|
||||
rotation = new THREE.Euler();
|
||||
}
|
||||
|
||||
// find available (or oldest) particle system
|
||||
for (var i = 0; i < this.particleSystems.length; i++) {
|
||||
if (this.particleSystems[i].active === false) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
if (this.particleSystems[i].time > oldestTime) {
|
||||
found = i;
|
||||
oldestTime = this.particleSystems[i].time;
|
||||
}
|
||||
}
|
||||
|
||||
particleSystem = this.particleSystems[found];
|
||||
particleSystem.active = true;
|
||||
particleSystem.loopCount = 1;
|
||||
particleSystem.mesh.visible = true;
|
||||
particleSystem.mesh.position.copy(position);
|
||||
particleSystem.mesh.rotation.copy(rotation);
|
||||
particleSystem.time = 0;
|
||||
if (this.data.animateScale) {
|
||||
particleSystem.pscale.copy(this.data.initialScale);
|
||||
}
|
||||
|
||||
this.resetParticles(particleSystem);
|
||||
},
|
||||
|
||||
doLoop: function(particleSystem) {
|
||||
particleSystem.loopCount++;
|
||||
particleSystem.frame = -1;
|
||||
particleSystem.time = 0;
|
||||
if (this.data.animateScale) {
|
||||
particleSystem.pscale.copy(data.initialScale);
|
||||
}
|
||||
this.resetParticles(particleSystem);
|
||||
},
|
||||
|
||||
resetParticle: function(particleSystem, particleIndex) {
|
||||
const geometry = particleSystem.mesh.geometry;
|
||||
|
||||
if (this.restPositions[particleIndex]) {
|
||||
transformPlane(
|
||||
particleIndex,
|
||||
geometry,
|
||||
this.originalVertexPositions,
|
||||
this.restPositions[particleIndex],
|
||||
this.useRotation && this.restRotations[particleIndex],
|
||||
particleSystem.pscale
|
||||
);
|
||||
} else {
|
||||
// Hide.
|
||||
transformPlane(
|
||||
particleIndex,
|
||||
geometry,
|
||||
this.originalVertexPositions,
|
||||
OFFSCREEN_VEC3,
|
||||
undefined,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Can update transformPlane for lookAt.
|
||||
// lookAt does not support rotated or translated parents! :_(
|
||||
// part.lookAt(this.camera.position);
|
||||
},
|
||||
|
||||
/**
|
||||
* When starting or finishing (looping) animation, this resets particles
|
||||
* to their initial position and, if user asked for replaying less than 100%
|
||||
* of particles, randomly choose them.
|
||||
*/
|
||||
resetParticles: function(particleSystem) {
|
||||
var i;
|
||||
var rand;
|
||||
|
||||
// no picking, just hide and reset
|
||||
if (this.particleCount === this.numParticles) {
|
||||
for (i = 0; i < this.numParticles; i++) {
|
||||
this.resetParticle(particleSystem, i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// hide particles from last animation and initialize indexPool
|
||||
const geometry = particleSystem.mesh.geometry;
|
||||
for (i = 0; i < this.numParticles; i++) {
|
||||
if (i < this.particleCount) {
|
||||
transformPlane(
|
||||
particleSystem.activeParticleIndices[i],
|
||||
geometry,
|
||||
this.originalVertexPositions,
|
||||
OFFSCREEN_VEC3,
|
||||
undefined,
|
||||
null
|
||||
);
|
||||
}
|
||||
this.indexPool[i] = i;
|
||||
}
|
||||
|
||||
// scramble indexPool
|
||||
for (i = 0; i < this.particleCount; i++) {
|
||||
rand = i + Math.floor(Math.random() * (this.numParticles - i));
|
||||
particleSystem.activeParticleIndices[i] = this.indexPool[rand];
|
||||
this.indexPool[rand] = this.indexPool[i];
|
||||
this.resetParticle(
|
||||
particleSystem,
|
||||
particleSystem.activeParticleIndices[i]
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
tick: (function() {
|
||||
const helperPositionVec3 = new THREE.Vector3();
|
||||
|
||||
return function(time, delta) {
|
||||
var frame; // current particle system frame
|
||||
var fdata; // all particles data in current frame
|
||||
var fdataNext; // next frame (for interpolation)
|
||||
var useRotation = this.useRotation;
|
||||
var frameTime; // time in current frame (for interpolation)
|
||||
var relTime; // current particle system relative time (0-1)
|
||||
var interpolate; // whether interpolate between frames or not
|
||||
|
||||
for (
|
||||
let particleSystemIndex = 0;
|
||||
particleSystemIndex < this.particleSystems.length;
|
||||
particleSystemIndex++
|
||||
) {
|
||||
let particleSystem = this.particleSystems[particleSystemIndex];
|
||||
if (!particleSystem.active) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if the duration is so short that there's no need to interpolate, don't do it
|
||||
// even if user asked for it.
|
||||
interpolate =
|
||||
this.data.interpolate && this.data.dur / this.numFrames > delta;
|
||||
relTime = particleSystem.time / this.data.dur;
|
||||
frame = relTime * this.numFrames;
|
||||
fdata = this.framedata[Math.floor(frame)];
|
||||
if (interpolate) {
|
||||
frameTime = frame - Math.floor(frame);
|
||||
fdataNext =
|
||||
frame < this.numFrames - 1
|
||||
? this.framedata[Math.floor(frame) + 1]
|
||||
: null;
|
||||
}
|
||||
|
||||
if (this.data.animateScale){
|
||||
particleSystem.pscale.lerp(this.data.finalScale, relTime);
|
||||
}
|
||||
|
||||
for (
|
||||
let activeParticleIndex = 0;
|
||||
activeParticleIndex < particleSystem.activeParticleIndices.length;
|
||||
activeParticleIndex++
|
||||
) {
|
||||
|
||||
let particleIndex =
|
||||
particleSystem.activeParticleIndices[activeParticleIndex];
|
||||
let rotation = useRotation && fdata[particleIndex].rotation;
|
||||
|
||||
// TODO: Add vertex position to original position to all vertices of plane...
|
||||
if (!fdata[particleIndex].alive) {
|
||||
// Hide plane off-screen when not alive.
|
||||
transformPlane(
|
||||
particleIndex,
|
||||
particleSystem.mesh.geometry,
|
||||
this.originalVertexPositions,
|
||||
OFFSCREEN_VEC3,
|
||||
undefined,
|
||||
null
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (interpolate && fdataNext && fdataNext[particleIndex].alive) {
|
||||
helperPositionVec3.lerpVectors(
|
||||
fdata[particleIndex].position,
|
||||
fdataNext[particleIndex].position,
|
||||
frameTime
|
||||
);
|
||||
transformPlane(
|
||||
particleIndex,
|
||||
particleSystem.mesh.geometry,
|
||||
this.originalVertexPositions,
|
||||
helperPositionVec3,
|
||||
rotation,
|
||||
particleSystem.pscale
|
||||
);
|
||||
} else {
|
||||
transformPlane(
|
||||
particleIndex,
|
||||
particleSystem.mesh.geometry,
|
||||
this.originalVertexPositions,
|
||||
fdata[particleIndex].position,
|
||||
rotation,
|
||||
particleSystem.pscale
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
particleSystem.time += delta;
|
||||
if (particleSystem.time >= this.data.dur) {
|
||||
if (particleSystem.loopCount < particleSystem.loopTotal) {
|
||||
this.el.emit('particleplayerloop', null, false);
|
||||
this.doLoop(particleSystem);
|
||||
} else {
|
||||
this.el.emit('particleplayerfinished', null, false);
|
||||
particleSystem.active = false;
|
||||
particleSystem.mesh.visible = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
})(),
|
||||
|
||||
_transformPlane: transformPlane
|
||||
});
|
||||
|
||||
// Use triangle geometry as a helper for rotating.
|
||||
const tri = (function() {
|
||||
const tri = new THREE.Geometry();
|
||||
tri.vertices.push(new THREE.Vector3());
|
||||
tri.vertices.push(new THREE.Vector3());
|
||||
tri.vertices.push(new THREE.Vector3());
|
||||
tri.faces.push(new THREE.Face3(0, 1, 2));
|
||||
return tri;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Faces of a plane are v0, v2, v1 and v2, v3, v1.
|
||||
* Positions are 12 numbers: [v0, v1, v2, v3].
|
||||
*/
|
||||
function transformPlane(
|
||||
particleIndex,
|
||||
geometry,
|
||||
originalArray,
|
||||
position,
|
||||
rotation,
|
||||
scale
|
||||
) {
|
||||
const array = geometry.attributes.position.array;
|
||||
const index = particleIndex * NUM_PLANE_POSITIONS;
|
||||
|
||||
// Calculate first face (0, 2, 1).
|
||||
tri.vertices[0].set(
|
||||
originalArray[index + 0],
|
||||
originalArray[index + 1],
|
||||
originalArray[index + 2]
|
||||
);
|
||||
tri.vertices[1].set(
|
||||
originalArray[index + 3],
|
||||
originalArray[index + 4],
|
||||
originalArray[index + 5]
|
||||
);
|
||||
tri.vertices[2].set(
|
||||
originalArray[index + 6],
|
||||
originalArray[index + 7],
|
||||
originalArray[index + 8]
|
||||
);
|
||||
if (scale !== null) {
|
||||
tri.scale(scale.x, scale.y, scale.z);
|
||||
}
|
||||
if (rotation) {
|
||||
tri.rotateX(rotation.x);
|
||||
tri.rotateY(rotation.y);
|
||||
tri.rotateZ(rotation.z);
|
||||
}
|
||||
tri.vertices[0].add(position);
|
||||
tri.vertices[1].add(position);
|
||||
tri.vertices[2].add(position);
|
||||
array[index + 0] = tri.vertices[0].x;
|
||||
array[index + 1] = tri.vertices[0].y;
|
||||
array[index + 2] = tri.vertices[0].z;
|
||||
array[index + 3] = tri.vertices[1].x;
|
||||
array[index + 4] = tri.vertices[1].y;
|
||||
array[index + 5] = tri.vertices[1].z;
|
||||
array[index + 6] = tri.vertices[2].x;
|
||||
array[index + 7] = tri.vertices[2].y;
|
||||
array[index + 8] = tri.vertices[2].z;
|
||||
|
||||
// Calculate second face (2, 3, 1) just for the last vertex.
|
||||
tri.vertices[0].set(
|
||||
originalArray[index + 3],
|
||||
originalArray[index + 4],
|
||||
originalArray[index + 5]
|
||||
);
|
||||
tri.vertices[1].set(
|
||||
originalArray[index + 6],
|
||||
originalArray[index + 7],
|
||||
originalArray[index + 8]
|
||||
);
|
||||
tri.vertices[2].set(
|
||||
originalArray[index + 9],
|
||||
originalArray[index + 10],
|
||||
originalArray[index + 11]
|
||||
);
|
||||
if (scale !== null) {
|
||||
tri.scale(scale.x, scale.y, scale.z);
|
||||
}
|
||||
if (rotation) {
|
||||
tri.rotateX(rotation.x);
|
||||
tri.rotateY(rotation.y);
|
||||
tri.rotateZ(rotation.z);
|
||||
}
|
||||
tri.vertices[0].add(position);
|
||||
tri.vertices[1].add(position);
|
||||
tri.vertices[2].add(position);
|
||||
array[index + 9] = tri.vertices[2].x;
|
||||
array[index + 10] = tri.vertices[2].y;
|
||||
array[index + 11] = tri.vertices[2].z;
|
||||
|
||||
geometry.attributes.position.needsUpdate = true;
|
||||
}
|
||||
module.exports.transformPlane = transformPlane;
|
||||
|
||||
function copyArray(dest, src) {
|
||||
dest.length = 0;
|
||||
for (let i = 0; i < src.length; i++) {
|
||||
dest[i] = src[i];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user