Несколько прозрачных текстур на одной и той же поверхности сетки в Three.js

Возможно ли разместить несколько текстур друг над другом на одной грани в Three.js, чтобы альфа-смешение выполнялось с помощью GPU, ускоренного в webGL?

Текстуры применяются (или должны быть) к одной и той же стороне, чтобы нижняя текстура (текстура 1) не имела альфа-канала, а приведенные выше текстуры альфа-канала были подобны текстуре 2 в примере ниже.

Это смешение может быть достигнуто с использованием HTML5 Canvas в качестве предварительного шага, но поскольку текстурные растровые изображения могут быть огромными, я предпочитаю пропускать операции смешивания холста.

Я протестировал, создав копию сетки и применив одну текстуру в ячейку, и сделал другую сетку прозрачной и немного переместил ее, что получилось почти хорошо, но есть некоторые мерцания и потому, что объекты не могут быть точно в том же положении, есть некоторая комната между текстурами, которая не является правильным эффектом. Они должны казаться, что они были смешаны, например. Photoshop (как показано ниже).

enter image description here

Ответ 1

Используйте ShaderMaterial и установите обе текстуры как униформы, а затем смешайте их в шейдере.

Я сделал этот пример: http://abstract-algorithm.com/three_sh/, и этого действительно должно быть достаточно.

Итак, вы создаете ShaderMaterial:

var vertShader = document.getElementById('vertex_shh').innerHTML;
var fragShader = document.getElementById('fragment_shh').innerHTML;

var attributes = {}; // custom attributes

var uniforms = {    // custom uniforms (your textures)

  tOne: { type: "t", value: THREE.ImageUtils.loadTexture( "cover.png" ) },
  tSec: { type: "t", value: THREE.ImageUtils.loadTexture( "grass.jpg" ) }

};

var material_shh = new THREE.ShaderMaterial({

  uniforms: uniforms,
  attributes: attributes,
  vertexShader: vertShader,
  fragmentShader: fragShader

});

И создайте сетку с этим материалом:

var me = new THREE.Mesh( new THREE.CubeGeometry(80,80,80), material_shh );

Вы можете задать простейший вершинный шейдер:

varying vec2 vUv;

void main()
{
    vUv = uv;
    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
    gl_Position = projectionMatrix * mvPosition;
}

И фрагментарный шейдер, который на самом деле будет выполнять смешение:

#ifdef GL_ES
precision highp float;
#endif

uniform sampler2D tOne;
uniform sampler2D tSec;

varying vec2 vUv;

void main(void)
{
    vec3 c;
    vec4 Ca = texture2D(tOne, vUv);
    vec4 Cb = texture2D(tSec, vUv);
    c = Ca.rgb * Ca.a + Cb.rgb * Cb.a * (1.0 - Ca.a);  // blending equation
    gl_FragColor= vec4(c, 1.0);
}

Если вам нужно смешать еще больше текстур, вы используете одно и то же уравнение для смешивания всего несколько раз.

Итак, вот результат:

enter image description here