admin管理员组文章数量:1395906
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 /.
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: /
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/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/6qrubbk6/5/
Share Improve this question edited Oct 28, 2014 at 18:34 mystaticself asked Oct 26, 2014 at 23:19 mystaticselfmystaticself 911 silver badge7 bronze badges3 Answers
Reset to default 2Also you can cast vTexIndex to int.
int textureIndex = int(vTexIndex + 0.5);
if (textureIndex == 0) {
finalColor = texture2D(textures[0], gl_PointCoord);
} else if (textureIndex == 1) {
finalColor = texture2D(textures[1], gl_PointCoord);
} else if (textureIndex == 2) {
finalColor = texture2D(textures[2], gl_PointCoord);
}
Thanks for replying to your own question. You helped me get started on a similar feature I was working.
I thought this might be helpful to someone else so I'm replying here.
I've created a fiddle that does what you're doing, but dynamically. You can add as many textures to the textures array and they will be dynamically added to the nodes. This was tricky to do in glsl, and required some hacky javascript templating.
To do this, I just created 2 methods that return the vertex and fragment shader to the shader material:
Fragment Shader Method:
World.prototype.getFragmentShader = function(numTextures){
var fragShader = `uniform sampler2D textures[${numTextures}];
varying vec3 vColor;
varying float vTexIndex;
void main() {
vec4 startColor = vec4(vColor, 1.0);
vec4 finalColor;
`;
for(var i = 0; i < numTextures; i++){
if(i == 0){
fragShader += `if (vTexIndex < ${i}.5) {
finalColor = texture2D(textures[${i}], gl_PointCoord);
}
`
}
else{
fragShader += `else if (vTexIndex < ${i}.5) {
finalColor = texture2D(textures[${i}], gl_PointCoord);
}
`
}
}
fragShader += `gl_FragColor = startColor * finalColor;
}`;
console.log('frag shader: ', fragShader)
return fragShader;
}
Vertex Shader:
World.prototype.getVertexShader = function(){
let vertexShader = `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;
}`;
return vertexShader;
}
You can see a live demo here: http://jsfiddle/jigglebilly/drmvz5co/
The new version of Three.js doesn't support attributes in ShaderMaterial. We'll have to delete attributes: attributes
in new THREE.ShaderMaterial
and use geometry.addAttribute
instead. Here's the code to define texIndex:
var vIndex = new Float32Array( vertices.length );
for ( var i = 0, l = vertices.length; i < l; i ++ ) {
vIndex[i] = Math.random()*getTextures().length;
}
geometry.addAttribute( 'texIndex', new THREE.BufferAttribute( vIndex, 1 ) );
本文标签: javascriptThreejsUsing multiple textures in a single PointCloudStack Overflow
版权声明:本文标题:javascript - Three.js - Using multiple textures in a single PointCloud - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744610140a2615605.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论