pucek89
pucek89

Reputation: 21

Create animation of transparency, revealing the Mesh in threejs

I need to create linear animation (something like slideUp in 2d jquery object) with revealing a really complex mesh (building 3d model) - form the bottom to the top.

I was looking for opacity channel / opacity map or something like that and now I know that is not possible.

Using sprites of textures and changing offset is not the best idea because my UVs map is too complicated.

Is there any way to create that effect in THREE.JS?

Upvotes: 1

Views: 662

Answers (3)

pucek89
pucek89

Reputation: 21

I figured another solution.

I use one texture for the whole building (no repeated pattern). I put UVS progressively vertically (faces from bottom on the bottom of texture, etc) and I animate texture by filling with transparent rectangle (canvas texture).

// x - current step
// steps - number of steps

var canvas = document.getElementById('canvas-texture'),
    ctx    = canvas.getContext('2d');

ctx.beginPath();
ctx.drawImage(image, 0, 0);
ctx.globalCompositeOperation = 'destination-out';
ctx.fillRect(0, 0, width, height/steps * x);
ctx.closePath();

I needed it ASAP so at weekend if I find some time I'll try yours ideas and if you want I could create some fiddle with my solution.

Anyway, thanks for your help guys.

Upvotes: 1

Griffork
Griffork

Reputation: 682

Alternatively you can draw the building to the screen using gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA), and give your building an alpha gradient (from top to bottom).

The way drawing to any output works, is that WebGL evaluates the source information, and the destination information (the stuff that has already been drawn to that output) and combines the two, but you can dictate how it does that.

The equation for drawing to an output can be loosely described as:

SOURCE_VALUE * [SOURCE_FACTOR] [BLEND EQUATION] DESTINATION_VALUE * [DESTINATION_FACTOR];

By default this is:

SOURCE_VALUE * 1 + DESTINATION_VALUE * 0;

This equation discards all existing information in the buffer, and draws over it with the new information. What we want to do is to tell WebGL to keep the existing information where we're not drawing onto the buffer, and take the new information where we are going to draw, so the equation becomes:

SOURCE_VALUE * SRC_ALPHA + DESTINATION_VALUE * ONE_MINUS_SRC_ALPHA;

If your building is 20% transparent in one fragment, then the fragment will be 20% the colour of the building, and 80% of the colour of whatever's behind the building.

This method of drawing semitransparent objects honours the depth buffer.

Upvotes: 1

Dragan Okanovic
Dragan Okanovic

Reputation: 7761

Render entire scene into first framebuffer (texture).
Rendre only mesh into second framebuffer (texture).

Render a fullscreen rectangle that would use two previously mentioned textures, and use some some version of the code below:

uniform sampler2D texScene;
uniform sampler2D texMesh;

uniform vec2 uResolution;
uniform float time;

void main() {
    vec2 uv = gl_FragCoord.xy / uResolution;

    vec3 s = texture2D( texScene, uv ).xyz;
    vec4 m = texture2D( texMesh, uv );

    // slide up effect
    float percent = clamp( time, 0, endAnim ) / endAnim;  // endAnim is the time animation ends (assuming animation starts at time=0)

    vec3 color = s;
    if( uv.y > (1.0 - percent) ) {
        color = s * (1.0 - m.a) + m.xyz * m.a;
    }
    gl_FragColor = vec4( color, 1.0 );
}

It should be intuitively understood how code works. Depending on the passed time, it checks at which percent the animation is at, and depending on that, it calculates if it should include the mesh's color, or just output background color.

Hope it helps.

Upvotes: 1

Related Questions