Try this:
var vs=[];
var fs=[];
var mesh=[];
var tex=[];
var mat=[];
var texture_loader=new THREE.TextureLoader();
const canvas = document.querySelector('#app');
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const context = canvas.getContext('webgl');
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
transparent:true,
canvas: canvas,
context: context,
});
renderer.setClearColor(0x000000, 0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height, false);
const camera = new THREE.PerspectiveCamera(
45,
width / height,
1,
100000
);
camera.position.z = 500;
const scene = new THREE.Scene();
const pl1 = new THREE.PointLight(0xffffff, 0.8);
pl1.position.set(
-200,
200,
200,
);
scene.add(pl1);
const clock = new THREE.Clock();
let elapsedTime;
const group = new THREE.Object3D();
group.add(
new THREE.Mesh(
new THREE.SphereGeometry(100, 32, 32),
new THREE.MeshPhongMaterial({
color: 0xfffaaa,
transparent: true,
opacity: 1,
})
)
);
scene.add(group);
group.add(
new THREE.Line(
new THREE.BufferGeometry().setFromPoints([
new THREE.Vector3(-100, 0, 0),
new THREE.Vector3(0, 100, 0),
new THREE.Vector3(100, 0, 0)
]),
new THREE.LineBasicMaterial({
color: 0x0000ff
})
)
);
const vert = `
uniform float uPointSize;
uniform float uTime;
uniform float uEnableAnimation;
attribute float type;
attribute float startTime;
attribute vec3 pointColor;
varying float vAlpha;
varying vec3 vColor;
void main() {
float p = fract(uTime - startTime);
vAlpha = 1.0 - p;
gl_PointSize = p * uPointSize;
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * mvPosition;
vColor = vec3(pointColor);
}`;
const frag = `
uniform sampler2D uPointTexture;
varying float vAlpha;
varying vec3 vColor;
void main() {
if (vAlpha <= 0.0) {
discard;
}
vec4 texColor = texture2D(uPointTexture, gl_PointCoord);
gl_FragColor = vec4(vColor, texColor.a * vAlpha);
}`;
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: {
value: 0,
},
uPointSize: {
value: 50,
},
uPointTexture: {
value: new THREE.TextureLoader().load(image),
},
},
vertexShader: vert,
fragmentShader: frag,
vertexColors: true,
transparent: true,
depthWrite: false,
side: THREE.DoubleSide,
});
var geometry = new THREE.BufferGeometry();
const positionSize = 20;
geometry.setAttribute(
"position",
new THREE.BufferAttribute(new Float32Array(positionSize * 3), 3)
);
geometry.setAttribute(
"startTime",
new THREE.BufferAttribute(new Float32Array(positionSize), 1)
);
geometry.setAttribute(
"pointColor",
new THREE.BufferAttribute(new Float32Array(positionSize * 3), 3)
);
mesh["points"] = new THREE.Points(geometry, material);
group.add(mesh["points"]);
const position = geometry.attributes.position;
Array.from(Array(positionSize)).forEach((_, i) => {
position.setXYZ(
i,
Math.random() * 210 - 105,
Math.random() * 210 - 105,
Math.random() * 210 - 105,
);
});
position.needsUpdate = true;
tex["one"]=texture_loader.load(image);
tex["two"]=texture_loader.load("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABPUlEQVR42mNgoDpovvF/2v//qVtf8wpLEVatYuu75fv/////P/3/v+7RfwYGBib8Gt49uf/hLwMDA4MUA4MlP4NReCYhDfevnLr048lfBgYGBnc+Bgkzf8Ku4uAVKb3+/8v//////8898JuJoIYfn98sCVaa8IiBgYHh969vTGzc/AT1PL92/+VThh8MDK/vX2b68/MbMYF7cnblPQaGL08eMP3785sYDe4F7U++Mby7c5KBgYEhrGs2ftU6niEr3v6f+wMWDyzskj33/uNSLSAlm7Zg9X8WhtX1UxGiXXf+TnrxX8XaGU21VWz+1Df/57//X7D9IUSEES5XtPmmrofa+xcM+6dN+/LusbCcrkN6FBMTAzcvw45pe5bnu2KxXVrXPmrCqr6H/5f+/7/o///GM/+DWxeycQtRlHgBrNiEw8eNQ4gAAAAASUVORK5CYII=");
vs["sprite"]=`
attribute vec3 offset;
attribute vec2 scale;
attribute vec4 quaternion;
attribute float rotation;
attribute vec4 color;
attribute float blend;
attribute float texture;
uniform float time;
varying vec2 vUv;
varying vec4 vColor;
varying float vBlend;
varying float num;
void main(){
float angle=time*rotation;
float p=fract(time-sin(length(offset)));
vec3 vRotated=vec3(position.x*scale.x*p*cos(angle)-position.y*scale.y*p*sin(angle),position.y*scale.y*p*cos(angle)+position.x*scale.x*p*sin(angle),position.z);
vUv=uv;
vColor=color;
vBlend=blend;
num=texture;
vColor.w=1.0-p;
vec3 eye=offset;
vec3 target=quaternion.xyz;
vec3 up=vec3(0.0,1.0,0.0);
vec3 zaxis=normalize(eye-target);
if(length(zaxis)==0.0){
// eye and target are in the same position
zaxis.z=1.0;
}
zaxis=normalize(zaxis);
vec3 xaxis=cross(up,zaxis);
if(length(xaxis)==0.0) {
// up and z are parallel
if (abs(up.z)==1.0){ zaxis.x +=0.0001; }
else{ zaxis.z +=0.0001; }
zaxis=normalize(zaxis);
xaxis=cross(up, zaxis);
}
xaxis=normalize(xaxis);
vec3 yaxis=cross(zaxis,xaxis);
float m11=xaxis.x,m12=yaxis.x,m13=zaxis.x,m21=xaxis.y,m22=yaxis.y,m23=zaxis.y,m31=xaxis.z,m32=yaxis.z,m33=zaxis.z;
float s,qx,qy,qz,qw;
float trace=m11+m22+m33;
if(trace>0.0){ s=0.5/sqrt(trace+1.0); qw=0.25/s; qx=(m32-m23)*s; qy=(m13-m31)*s; qz=(m21-m12)*s; }
else if(m11>m22 && m11>m33){ s=2.0*sqrt(1.0+m11-m22-m33); qw=(m32-m23)/s; qx=0.25*s; qy=(m12+m21)/s; qz=(m13+m31)/s; }
else if(m22>m33){ s=2.0*sqrt(1.0+m22-m11-m33); qw=(m13-m31)/s; qx=(m12+m21)/s; qy=0.25*s; qz=(m23+m32)/s; }
else{ s=2.0*sqrt(1.0+m33-m11-m22); qw=(m21-m12)/s; qx=(m13+m31)/s; qy=(m23+m32)/s; qz=0.25*s; }
vec4 vQuaternion=vec4(qx,qy,qz,qw);
vec3 vcV=cross(vQuaternion.xyz,vRotated);
vec3 vPosition=vcV*(2.0*vQuaternion.w)+(cross(vQuaternion.xyz,vcV)*2.0+vRotated);
gl_Position=projectionMatrix*modelViewMatrix*vec4(vPosition+offset,1.0);
}
`;
fs["sprite"]=`
const int count=2;
uniform sampler2D map[count];
varying vec2 vUv;
varying vec4 vColor;
varying float vBlend;
varying float num;
void main(){
if(num==0.0){ gl_FragColor=texture2D(map[0],vUv)*vColor; }
else if(num==1.0){ gl_FragColor=texture2D(map[1],vUv)*vColor; }
gl_FragColor.rgb*=gl_FragColor.a;
gl_FragColor.a*=vBlend;
}
`;
var particles=[];
function particles_update(){
particles=[];
var max_1=particles_flare_a.length;
particles.length=max_1;
for(var n=0;n<max_1;n++){
particles[n]=particles_flare_a[n];
}
var count=particles.length;
var item=camera.position;
var x=item.x;
var y=item.y;
var z=item.z;
for(var n=0;n<count;n++){
var item=particles[n].offset;
particles[n].d=Math.sqrt(Math.pow((x-item[0]),2)+Math.pow((y-item[1]),2)+Math.pow((z-item[2]),2));
}
particles.sort((a,b)=>b.d-a.d);
var offset=new Float32Array(count*3);
var scale=new Float32Array(count*2);
var quaternion=new Float32Array(count*4);
var rotation=new Float32Array(count);
var color=new Float32Array(count*4);
var blend=new Float32Array(count);
var texture=new Float32Array(count);
for(var n=0;n<count;n++){
// 1 VALUE
var item=particles[n];
rotation[n]=item.rotation;
texture[n]=item.texture;
blend[n]=item.blend;
// 2 VALUE
var p=n*2;
var one=p+1;
var i_scale=item.scale;
scale[p]=i_scale[0];
scale[one]=i_scale[1];
// 3 VALUE
var p=n*3;
var one=p+1;
var two=p+2;
var i_offset=item.offset;
offset[p]=i_offset[0];
offset[one]=i_offset[1];
offset[two]=i_offset[2];
// 4 VALUE
var p=n*4;
var one=p+1;
var two=p+2;
var three=p+3;
var i_color=item.color;
color[p]=i_color[0];
color[one]=i_color[1];
color[two]=i_color[2];
color[three]=i_color[3];
var i_quaternion=item.quaternion;
quaternion[p]=i_quaternion[0];
quaternion[one]=i_quaternion[1];
quaternion[two]=i_quaternion[2];
quaternion[three]=i_quaternion[3];
}
var item=mesh["sprite"].geometry.attributes;
item.offset=new THREE.InstancedBufferAttribute(offset,3).setUsage(THREE.DynamicDrawUsage);
item.scale=new THREE.InstancedBufferAttribute(scale,2).setUsage(THREE.DynamicDrawUsage);
item.quaternion=new THREE.InstancedBufferAttribute(quaternion,4).setUsage(THREE.DynamicDrawUsage);
item.rotation=new THREE.InstancedBufferAttribute(rotation,1).setUsage(THREE.DynamicDrawUsage);
item.color=new THREE.InstancedBufferAttribute(color,4).setUsage(THREE.DynamicDrawUsage);
item.blend=new THREE.InstancedBufferAttribute(blend,1).setUsage(THREE.DynamicDrawUsage);
item.texture=new THREE.InstancedBufferAttribute(texture,1).setUsage(THREE.DynamicDrawUsage);
mesh["sprite"].geometry._maxInstanceCount=count;
}
var geometry=new THREE.InstancedBufferGeometry();
geometry.setAttribute('position',new THREE.Float32BufferAttribute(new Float32Array([-0.5,0.5,0,-0.5,-0.5,0,0.5,0.5,0,0.5,-0.5,0,0.5,0.5,0,-0.5,-0.5,0]),3));
geometry.setAttribute('uv',new THREE.Float32BufferAttribute(new Float32Array([0,1,0,0,1,1,1,0,1,1,0,0]),2));
geometry.setAttribute('offset',new THREE.InstancedBufferAttribute(new Float32Array(),3));
geometry.setAttribute('scale',new THREE.InstancedBufferAttribute(new Float32Array(),2));
geometry.setAttribute('quaternion',new THREE.InstancedBufferAttribute(new Float32Array(),4));
geometry.setAttribute('rotation',new THREE.InstancedBufferAttribute(new Float32Array(),1));
geometry.setAttribute('color',new THREE.InstancedBufferAttribute(new Float32Array(),4));
geometry.setAttribute('blend',new THREE.InstancedBufferAttribute(new Float32Array(),1));
geometry.setAttribute('texture',new THREE.InstancedBufferAttribute(new Float32Array(),1));
mat["sprite"]=new THREE.ShaderMaterial({
uniforms:{
map:{value:[tex["one"],tex["two"]]},
time:{value:0}
},
vertexShader:vs["sprite"],
fragmentShader:fs["sprite"],
side:THREE.DoubleSide,
transparent:true,
depthWrite:false,
blending:THREE.CustomBlending,
blendEquation:THREE.AddEquation,
blendSrc:THREE.OneFactor,
blendDst:THREE.OneMinusSrcAlphaFactor
});
mesh["sprite"]=new THREE.Mesh(geometry,mat["sprite"]);
mesh["sprite"].frustumCulled=false;
//mesh["sprite"].matrixAutoUpdate=false;
//mesh["sprite"].updateMatrixWorld=function(){};
scene.add(mesh["sprite"]);
var particles_flare_a=[];
particles_flare_a.push({offset:[100,0,0],scale:[100,100],quaternion:[0,0,0,1],rotation:0.01,color:[1,1,1,1],blend:1,texture:1});
particles_flare_a.push({offset:[-100,0,0],scale:[20,30],quaternion:[0,0,0,1],rotation:0,color:[1,1,1,1],blend:1,texture:0});
particles_flare_a.push({offset:[100,100,0],scale:[60,40],quaternion:[0,0,0,1],rotation:0,color:[1,1,1,1],blend:1,texture:1});
for(var n=0;n<10;n++){
particles_flare_a.push({offset:[Math.random()*210-105,Math.random()*210-105,Math.random()*210-105],scale:[100,100],quaternion:[0,0,0,1],rotation:10,color:[Math.random(),Math.random(),Math.random(),1],blend:1,texture:1});
}
for(var n=0;n<100;n++){
particles_flare_a.push({offset:[Math.random()*210-105,Math.random()*210-105,Math.random()*210-105],scale:[30,30],quaternion:[0,0,0,1],rotation:0.01,color:[1,1,1,1],blend:1,texture:0});
}
const update = () => {
const delta = clock.getDelta();
elapsedTime = clock.elapsedTime;
material.uniforms.uTime.value = elapsedTime;
group.rotation.y += 0.01;
particles_update();
mat["sprite"].uniforms.time.value = elapsedTime;
mesh["sprite"].rotation.y += 0.01;
renderer.render(scene, camera);
requestAnimationFrame(update);
}
update();