Create mesh billboard like default sprite geometry - plane with UV, offsets and custom material
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"]);
Changed code of placing one particle and one grass into mesh:
var count=2;
var item=mesh["sprite"].geometry.attributes;
item.offset=new THREE.InstancedBufferAttribute(new Float32Array([1,2,4,4,2,9]),3).setUsage(THREE.DynamicDrawUsage);
item.scale=new THREE.InstancedBufferAttribute(new Float32Array([1,1,2,2]),2).setUsage(THREE.DynamicDrawUsage);
item.quaternion=new THREE.InstancedBufferAttribute(new Float32Array([0,0,0,1,0,0,0,1]),4).setUsage(THREE.DynamicDrawUsage);
item.rotation=new THREE.InstancedBufferAttribute(new Float32Array([0,0]),1).setUsage(THREE.DynamicDrawUsage);
item.color=new THREE.InstancedBufferAttribute(new Float32Array([1,1,1,1,1,1,1,1]),4).setUsage(THREE.DynamicDrawUsage);
item.blend=new THREE.InstancedBufferAttribute(new Float32Array([0,1]),1).setUsage(THREE.DynamicDrawUsage);
item.texture=new THREE.InstancedBufferAttribute(new Float32Array([0,1]),1).setUsage(THREE.DynamicDrawUsage);
mesh["sprite"].geometry._maxInstanceCount=count;
Shader:
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;
vec3 vRotated=vec3(position.x*scale.x*cos(angle)-position.y*scale.y*sin(angle),position.y*scale.y*cos(angle)+position.x*scale.x*sin(angle),position.z);
vUv=uv;
vColor=color;
vBlend=blend;
num=texture;
vec3 localUpVector=vec3(0.0,1.0,0.0);
vec3 vLook=offset-cameraPosition;
vec3 vRight=normalize(cross(vLook,localUpVector));
vec3 vPosition=vRotated.x*vRight+vRotated.y*localUpVector+vRotated.z;
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;
}
`;