2014-10-26 101 views
3

我試圖在一個PointCloud中使用ShaderMaterial使用多個紋理。我將紋理數組與紋理索引屬性一起傳遞給着色器,並選擇適當的紋理用於片段着色器。Three.js - 在單個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; 
} 

在PR有些點(使用高於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); 
} 

正如在這裏看到:http://jsfiddle.net/6qrubbk6/5/

回答

0

您也可以施放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); 
} 
1

感謝您回覆您自己的問題。您幫助我開始了我正在工作的類似功能。

我認爲這可能對別人有幫助,所以我在這裏回覆。

我創建了一個小提琴,它可以動態地做你正在做的事。您可以將紋理添加到紋理數組中,並將它們動態添加到節點中。這在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/