【问题标题】:Three.js - Using multiple textures in a single PointCloudThree.js - 在单个 PointCloud 中使用多个纹理
【发布时间】:2014-12-22 03:11:04
【问题描述】:

我正在尝试使用 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);

顶点着色器:

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 的纹理索引的点)由于某些原因而闪烁并且无法弄清楚。其他尝试似乎也在纹理而不是不透明度之间闪烁。

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

我已经在多个项目中放弃了这个,但我很想一劳永逸地找到一个解决方案。非常感谢任何帮助。

编辑: 检查 vTexIndex 是否为

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/

【问题讨论】:

    标签: javascript three.js webgl glsles


    【解决方案1】:

    您也可以将 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);
    }
    

    【讨论】:

      【解决方案2】:

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

      我认为这可能对其他人有帮助,所以我在这里回复。

      我已经创建了一个小提琴,它可以做你正在做的事情,但是是动态的。您可以将尽可能多的纹理添加到纹理数组中,它们将被动态添加到节点中。这在 glsl 中很棘手,并且需要一些 hacky javascript 模板。

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

      片段着色器方法:

      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/

      【讨论】:

        【解决方案3】:

        Three.js 新版本不支持 ShaderMaterial 中的属性。我们必须删除new THREE.ShaderMaterial 中的attributes: attributes 并改用geometry.addAttribute。这是定义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 ) );
        

        【讨论】:

          猜你喜欢
          • 2019-11-23
          • 2018-10-24
          • 2013-12-19
          • 2015-01-26
          • 2016-06-10
          • 1970-01-01
          • 2017-02-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多