31

Is it possible to lay multiple textures on top of each other on the same face in Three.js so that the alpha blending is done GPU accelerated in webGL?

The textures are (or should be) applied to the same face so that the bottom texture (texture 1) is without alpha channel and the above textures are alpha channeled in a way like texture 2 in the below image example.

This blending can be achieved using HTML5 Canvas as pre-step, but because texture bitmaps can be huge, I prefer to skip Canvas blending operations.

I tested by creating a copy of the mesh and applying one texture per mesh and made other mesh transparent and moved it a little, which succeeded nearly well, but there is some flickering and because objects cannot be exactly in the same position, there is some room between textures which is not the right effect. They should seem like they were blended in eg. Photoshop (as is the below image).

enter image description here

Timo Kähkönen
  • 10,897
  • 8
  • 64
  • 105
  • 2
    You could try the approach in the answer [here](http://stackoverflow.com/questions/13309289/three-js-geometry-in-top-of-another/13309722#13309722) – WestLangley Apr 30 '13 at 20:21
  • Thanks. Seems to be a good way. And possibly can handle also rendering multiple textures on top of each other. But not yet tested so far. – Timo Kähkönen May 01 '13 at 08:53

1 Answers1

66

Use ShaderMaterial and set both textures as uniforms, and then blend them within shader.

I made this example: http://abstract-algorithm.com/three_sh/ and that really should be enough.

So, you make 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

});

And create mesh with that material:

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

You can put simplest vertex shader:

varying vec2 vUv;

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

And fragment shader that will actually do the blending:

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

If you need to blend even more textures, you use same equation for blending just multiple times.

So here's the result:

enter image description here

Abstract Algorithm
  • 6,601
  • 3
  • 28
  • 42
  • 1
    Thanks for the answer. I need to wait for 17 hours to award the bounty. – Harsha Venkatram Jun 03 '13 at 13:26
  • This approach doesn't suits for the case where we have to place multiple textures at specific position. – Tarun Jun 11 '15 at 11:29
  • @Tarun Yeah, UV mapping takes care of that. Well, any kind of UV-coordiante-wise manipulation. – Abstract Algorithm Jun 11 '15 at 14:32
  • Nice! But what if I wanted to make any of the materials metallic/shiny/emissive/etc? How would I control other material properties beyond RGBA color? – ALx Nov 29 '16 at 15:49
  • 1
    You always interpolate/mix properties in some way. But it's important how and when do you mix them. For example, you cannot just add two shiny coefficients together, you probably want to calc lighting then somehow combine the results of the shading and not the properties themselves. Think also about normal maps, then cannot be just interpolated, but you need to combine them one on top of another. Depends on the property type and what is physically logical thing to do. – Abstract Algorithm Nov 29 '16 at 16:08
  • Thanks! My use case: http://stackoverflow.com/questions/12494781/how-to-use-and-blend-multiple-textures-with-custom-values-in-three-js – I'd be happy to fine tune the algorithm if I had one :) – ALx Nov 29 '16 at 16:34
  • Anyone knows if is possible to apply blending modes for this cases? @Abstract Algorithm – Toni Gallardo Jul 17 '20 at 10:59