Three.js - 在单个 PointCloud 中使用多个纹理

mys*_*elf 5 javascript webgl three.js glsles

我正在尝试使用 ShaderMaterial 在单个 PointCloud 中使用多个纹理。我将纹理数组与纹理索引属性一起传递给着色器,并选择适当的纹理以在片段着色器中使用。

相关设置代码:

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);
Run Code Online (Sandbox Code Playgroud)

顶点着色器:

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;
}
Run Code Online (Sandbox Code Playgroud)

片段着色器:

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;
}
Run Code Online (Sandbox Code Playgroud)

问题是某些点(使用高于 0 的纹理索引的点)由于原因而闪烁并且无法弄清楚。其他尝试似乎也在纹理之间闪烁而不是不透明度。

这方面的一个例子可以在http://jsfiddle.net/6qrubbk6/4/看到。

我已经在多个项目中放弃了这个,但我很想一劳永逸地找到解决方案。任何帮助是极大的赞赏。

编辑: 检查 vTexIndex 是否 < n,而不是 == n 可以解决问题。

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);
}
Run Code Online (Sandbox Code Playgroud)

如下所示:http : //jsfiddle.net/6qrubbk6/5/

小智 2

您还可以将 vTexIndex 转换为 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);
}
Run Code Online (Sandbox Code Playgroud)