2014-10-26 3 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); 

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

Фрагмент 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; 
} 

-ц oblem - некоторые точки (те, которые используют индекс текстуры выше 0) мерцают по причинам и не могут понять. Другие попытки также, казалось, мерцали между текстурами, а не прозрачностью.

Примером этого можно ознакомиться на странице http://jsfiddle.net/6qrubbk6/4/.

Я отказался от этого по нескольким проектам, но мне бы хотелось найти решение раз и навсегда. Любая помощь приветствуется.

Edit: Проверка 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/

ответ

0

Также вы можете бросить vTexIndex в целое.

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, и потребовалось несколько хакерских шаблонов JavaScript.

Чтобы сделать это, я просто создал 2 методы, которые возвращают вершину и фрагмент шейдера в шейдерный материал:

Фрагмент 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; 
} 

Вы можете посмотреть демо-версию здесь: http://jsfiddle.net/jigglebilly/drmvz5co/