Three.js - 在单个 PointCloud 中使用多个纹理 [英] Three.js - Using multiple textures in a single PointCloud

查看:11
本文介绍了Three.js - 在单个 PointCloud 中使用多个纹理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

相关设置代码:

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);

顶点着色器:

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;
}

片段着色器:

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;
}

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

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.

一个例子可以在 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.

检查 vTexIndex 是否小于等于n, 而不是 == n 解决了这个问题.

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);
}

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

推荐答案

感谢您回答自己的问题.您帮助我开始使用我正在使用的类似功能.

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.

我已经创建了一个小提琴,它可以动态地完成您正在做的事情.您可以向纹理数组添加任意数量的纹理,它们将被动态添加到节点中.这在 glsl 中很难做到,并且需要一些 hacky javascript 模板.

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.

为此,我刚刚创建了 2 个将顶点和片段着色器返回给着色器材质的方法:

To do this, I just created 2 methods that return the vertex and fragment shader to the shader material:

片段着色器方法:

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;
}

顶点着色器:

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;
}

您可以在这里看到现场演示:http://jsfiddle.net/jigglebilly/drmvz5co/

You can see a live demo here: http://jsfiddle.net/jigglebilly/drmvz5co/

这篇关于Three.js - 在单个 PointCloud 中使用多个纹理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆