Particles keep disappearing when rotating the camera even though frustumCulled is set to false on the model that it is attached to?
import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js';
import {GLTFLoader} from 'https://cdn.jsdelivr.net/npm/three@0.118.1/examples/jsm/loaders/GLTFLoader.js';
import {OrbitControls} from 'https://cdn.jsdelivr.net/npm/three@0.118/examples/jsm/controls/OrbitControls.js';
var scene, model;
const _VS = `
uniform float pointMultiplier;
attribute float size;
attribute float angle;
attribute vec4 colour;
varying vec4 vColour;
varying vec2 vAngle;
void main() {
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * mvPosition;
gl_PointSize = size * pointMultiplier / gl_Position.w;
vAngle = vec2(cos(angle), sin(angle));
vColour = colour;
}`;
const _FS = `
uniform sampler2D diffuseTexture;
varying vec4 vColour;
varying vec2 vAngle;
void main() {
vec2 coords = (gl_PointCoord - 0.5) * mat2(vAngle.x, vAngle.y, -vAngle.y, vAngle.x) + 0.5;
gl_FragColor = texture2D(diffuseTexture, coords) * vColour;
}`;
class LinearSpline {
constructor(lerp) {
this._points = [];
this._lerp = lerp;
}
AddPoint(t, d) {
this._points.push([t, d]);
}
Get(t) {
let p1 = 0;
for (let i = 0; i < this._points.length; i++) {
if (this._points[i][0] >= t) {
break;
}
p1 = i;
}
const p2 = Math.min(this._points.length - 1, p1 + 1);
if (p1 == p2) {
return this._points[p1][1];
}
return this._lerp(
(t - this._points[p1][0]) / (
this._points[p2][0] - this._points[p1][0]),
this._points[p1][1], this._points[p2][1]);
}
}
class ParticleSystem {
constructor(params) {
const uniforms = {
diffuseTexture: {
value: new THREE.TextureLoader().load('https://i.imgur.com/gaGmL1c.png')
},
pointMultiplier: {
value: window.innerHeight / (2.0 * Math.tan(0.5 * 60.0 * Math.PI / 180.0))
}
};
this._material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: _VS,
fragmentShader: _FS,
blending: THREE.AdditiveBlending,
depthTest: true,
depthWrite: false,
transparent: true,
vertexColors: true
});
this._material.frustumCulled = false;
this._camera = params.camera;
this._particles = [];
this._geometry = new THREE.BufferGeometry();
this._geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3));
this._geometry.setAttribute('size', new THREE.Float32BufferAttribute([], 1));
this._geometry.setAttribute('colour', new THREE.Float32BufferAttribute([], 4));
this._geometry.setAttribute('angle', new THREE.Float32BufferAttribute([], 1));
this._points = new THREE.Points(this._geometry, this._material);
params.parent.add(this._points);
this._alphaSpline = new LinearSpline((t, a, b) => {
return a + t * (b - a);
});
this._alphaSpline.AddPoint(0.0, 0.0);
this._alphaSpline.AddPoint(0.1, 1.0);
this._alphaSpline.AddPoint(0.6, 1.0);
this._alphaSpline.AddPoint(1.0, 0.0);
this._colourSpline = new LinearSpline((t, a, b) => {
const c = a.clone();
return c.lerp(b, t);
});
this._colourSpline.AddPoint(0.0, new THREE.Color(0x785912));
this._colourSpline.AddPoint(1.0, new THREE.Color(0xba8b1e));
this._sizeSpline = new LinearSpline((t, a, b) => {
return a + t * (b - a);
});
this._sizeSpline.AddPoint(0.0, 1.0);
this._sizeSpline.AddPoint(0.5, 5.0);
this._sizeSpline.AddPoint(1.0, 1.0);
document.addEventListener('keydown', (e) => this._onKeyDown(e), false);
document.addEventListener('keyup', (e) => this._onKeyUp(e), false);
this._UpdateGeometry();
}
_onKeyUp(event) {
switch(event.keyCode) {
case 32: // SPACE
var points = this._particles;
for (var i = 0; i < points.length; i++) {
// console.log(points[i].alpha);
points[i].position.y = 100000;
this._UpdateGeometry();
}
// console.log(this._particles[1])
break;
}
}
_onKeyDown(event) {
switch(event.keyCode) {
case 32: // SPACE
this._AddParticles();
this._UpdateGeometry();
break;
}
}
_AddParticles(timeElapsed) {
if (!this.gdfsghk) {
this.gdfsghk = 0.0;
}
this.gdfsghk += timeElapsed;
const n = Math.floor(this.gdfsghk * 75.0);
this.gdfsghk -= n / 75.0;
for (let i = 0; i < n; i++) {
const life = (Math.random() * 0.75 + 0.25) * 10.0;
this._particles.push({
position: new THREE.Vector3(
(Math.random() * 2 - 1) * 1.0,
(Math.random() * 2 - 1) * 1.0,
(Math.random() * 2 - 1) * 1.0),
size: (Math.random() * 0.5 + 0.5) * 4.0,
colour: new THREE.Color(),
alpha: 1.0,
life: life,
maxLife: life,
rotation: Math.random() * 2.0 * Math.PI,
velocity: new THREE.Vector3(-10, 0, 0),
});
}
}
_UpdateGeometry() {
const positions = [];
const sizes = [];
const colours = [];
const angles = [];
for (let p of this._particles) {
positions.push(p.position.x, p.position.y, p.position.z);
colours.push(p.colour.r, p.colour.g, p.colour.b, p.alpha);
sizes.push(p.currentSize);
angles.push(p.rotation);
}
this._geometry.setAttribute(
'position', new THREE.Float32BufferAttribute(positions, 3));
this._geometry.setAttribute(
'size', new THREE.Float32BufferAttribute(sizes, 1));
this._geometry.setAttribute(
'colour', new THREE.Float32BufferAttribute(colours, 4));
this._geometry.setAttribute(
'angle', new THREE.Float32BufferAttribute(angles, 1));
this._geometry.attributes.position.needsUpdate = true;
this._geometry.attributes.size.needsUpdate = true;
this._geometry.attributes.colour.needsUpdate = true;
this._geometry.attributes.angle.needsUpdate = true;
}
_UpdateParticles(timeElapsed) {
var points = this._particles;
for (var i = 0; i < points.length; i++) {
// Maybe i duno?
// points[i].frustumCulled = false;
}
for (let p of this._particles) {
p.life -= timeElapsed;
}
this._particles = this._particles.filter(p => {
return p.life > 0.0;
});
for (let p of this._particles) {
const t = 1.0 - p.life / p.maxLife;
p.rotation += timeElapsed * 0.5;
p.alpha = this._alphaSpline.Get(t);
p.currentSize = p.size * this._sizeSpline.Get(t);
p.colour.copy(this._colourSpline.Get(t));
p.position.add(p.velocity.clone().multiplyScalar(timeElapsed));
const drag = p.velocity.clone();
drag.multiplyScalar(timeElapsed * 0.1);
drag.x = Math.sign(p.velocity.x) * Math.min(Math.abs(drag.x), Math.abs(p.velocity.x));
drag.y = Math.sign(p.velocity.y) * Math.min(Math.abs(drag.y), Math.abs(p.velocity.y));
drag.z = Math.sign(p.velocity.z) * Math.min(Math.abs(drag.z), Math.abs(p.velocity.z));
p.velocity.sub(drag);
}
this._particles.sort((a, b) => {
const d1 = this._camera.position.distanceTo(a.position);
const d2 = this._camera.position.distanceTo(b.position);
if (d1 > d2) {
return -1;
}
if (d1 < d2) {
return 1;
}
return 0;
});
}
Step(timeElapsed) {
this._AddParticles(timeElapsed);
this._UpdateParticles(timeElapsed);
}
}
class ParticleSystemDemo {
constructor() {
this._Initialize();
}
_Initialize() {
this._threejs = new THREE.WebGLRenderer({
antialias: true,
});
this._threejs.shadowMap.enabled = true;
this._threejs.shadowMap.type = THREE.PCFSoftShadowMap;
this._threejs.setPixelRatio(window.devicePixelRatio);
this._threejs.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(this._threejs.domElement);
window.addEventListener('resize', () => {
this._OnWindowResize();
}, false);
const fov = 60;
const aspect = 1920 / 1080;
const near = 1.0;
const far = 1000.0;
this._camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
this._camera.position.set(25, 10, 0);
this._scene = new THREE.Scene();
scene = this._scene;
let light = new THREE.DirectionalLight(0xFFFFFF, 1.0);
light.position.set(20, 100, 10);
light.target.position.set(0, 0, 0);
light.castShadow = true;
light.shadow.bias = -0.001;
light.shadow.mapSize.width = 2048;
light.shadow.mapSize.height = 2048;
light.shadow.camera.near = 0.1;
light.shadow.camera.far = 500.0;
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 500.0;
light.shadow.camera.left = 100;
light.shadow.camera.right = -100;
light.shadow.camera.top = 100;
light.shadow.camera.bottom = -100;
this._scene.add(light);
light = new THREE.AmbientLight(0x101010);
this._scene.add(light);
const controls = new OrbitControls(
this._camera, this._threejs.domElement);
controls.target.set(0, 0, 0);
controls.update();
const loader = new THREE.CubeTextureLoader();
const texture = loader.load([
'./resources/posx.jpg',
'./resources/negx.jpg',
'./resources/posy.jpg',
'./resources/negy.jpg',
'./resources/posz.jpg',
'./resources/negz.jpg',
]);
this._scene.background = texture;
const loaderr = new GLTFLoader();
loaderr.load('./resources/rocket/Rocket_Ship_01.gltf', (gltf) => {
model = gltf.scene;
gltf.scene.traverse(c => {
c.castShadow = true;
c.frustumCulled = false;
this._particles = new ParticleSystem({
parent: model,
camera: this._camera,
});
})
model.position.x = 20;
// model.scene.scale.set(0, 0, 0);
this._scene.add(model);
});
this._previousRAF = null;
this._RAF();
}
_LoadModel() {
const loader = new GLTFLoader();
loader.load('./resources/rocket/Rocket_Ship_01.gltf', (gltf) => {
model = gltf.scene;
gltf.scene.traverse(c => {
c.castShadow = true;
});
this._scene.add(gltf.scene);
});
}
_OnWindowResize() {
this._camera.aspect = window.innerWidth / window.innerHeight;
this._camera.updateProjectionMatrix();
this._threejs.setSize(window.innerWidth, window.innerHeight);
}
_RAF() {
requestAnimationFrame((t) => {
if (this._previousRAF === null) {
this._previousRAF = t;
}
this._RAF();
this._threejs.render(this._scene, this._camera);
this._Step(t - this._previousRAF);
this._previousRAF = t;
});
}
_Step(timeElapsed) {
const timeElapsedS = timeElapsed * 0.001;
this._particles.Step(timeElapsedS);
}
}
let _APP = null;
window.addEventListener('DOMContentLoaded', () => {
_APP = new ParticleSystemDemo();
});
i also tried:
var points = this._particles;
for (var i = 0; i < points.length; i++) {
// Maybe i duno?
points[i].frustumCulled = false;
}
that failed also