I'm trying to use multiple textures in a single PointCloud using a ShaderMaterial. I'm passing a texture array to the shader along with texture index attributes and selecting the appropriate texture to use in the fragment shader.
Relevant Setup Code:
var particleCount = 100;
var uniforms = {
textures: {
type: 'tv',
value: this.getTextures()
}
};
var attributes = {
texIndex: {
type: 'f',
value: []
},
color: {
type: 'c',
value: []
},
};
var material = new THREE.ShaderMaterial({
uniforms: uniforms,
attributes: attributes,
vertexShader: document.getElementById('vertexShader').textContent,
fragmentShader: document.getElementById('fragmentShader').textContent,
transparent: true
});
var geometry = new THREE.Geometry();
for (var i = 0; i < particleCount; i++) {
geometry.vertices.push(new THREE.Vector3(
(Math.random() - 0.5) * 50, (Math.random() - 0.5) * 50, (Math.random() - 0.5) * 50));
attributes.texIndex.value.push(Math.random() * 3 | 0);
attributes.color.value.push(new THREE.Color(0xffffff));
}
var particles = new THREE.PointCloud(geometry, material);
particles.sortParticles = true;
this.container.add(particles);
Vertex Shader:
attribute vec3 color;
attribute float texIndex;
varying vec3 vColor;
varying float vTexIndex;
void main() {
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
vColor = color;
vTexIndex = texIndex;
gl_PointSize = 50.0;
gl_Position = projectionMatrix * mvPosition;
}
Fragment Shader:
uniform sampler2D textures[3];
varying vec3 vColor;
varying float vTexIndex;
void main() {
vec4 startColor = vec4(vColor, 1.0);
vec4 finalColor;
if (vTexIndex == 0.0) {
finalColor = texture2D(textures[0], gl_PointCoord);
} else if (vTexIndex == 1.0) {
finalColor = texture2D(textures[1], gl_PointCoord);
} else if (vTexIndex == 2.0) {
finalColor = texture2D(textures[2], gl_PointCoord);
}
gl_FragColor = startColor * finalColor;
}
The problem is some points (ones using a texture index higher than 0) are flickering for reasons and can't figure out. Other attempts have also seemed to flicker between textures rather than opacity.
An example of this can be seen at http://jsfiddle.net/6qrubbk6/4/.
I've given up on this over multiple projects but I'd love to find a solution once and for all. Any help is greatly appreciated.
Edit: Checking if vTexIndex is < n, instead of == n solves the issue.
if (vTexIndex < 0.5) {
finalColor = texture2D(textures[0], gl_PointCoord);
} else if (vTexIndex < 1.5) {
finalColor = texture2D(textures[1], gl_PointCoord);
} else if (vTexIndex < 2.5) {
finalColor = texture2D(textures[2], gl_PointCoord);
}
As seen here: http://jsfiddle.net/6qrubbk6/5/