47

Interactive Animated Landscape

 6 years ago
source link: https://www.tuicool.com/articles/hit/Qfqaqqn
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

An exploration of an animated interactive landscape built with three.js.

yaqIZrr.jpg!web

View demo Download Source

Today we are going to explore a playful animated landscape with a psychedelic look. The idea is to show how an experimentation on art and design with a generative process can lead to interesting interactive visuals which can be used in a variety of mediums like web, print, illustration, VJing, installations, games and many others. We made 3 variants of the landscape to show you how small changes in parameters can change a lot in visuals.

The demos are made with three.js and the animations and colors are controlled in a custom GLSL shader. For the letter animations we are using TweenMax .

yaqIZrr.jpg!web

The cool thing about doing this with WebGL is that it’s widely supported and with GLSL shaders we can animate thousands, even millions of vertices at 60 FPS on the major desktop and mobile web browsers.

If you’re not familiar with three.js and GLSL shaders, you can start by creating a scene and reading this introduction to Shaders .

Let’s go through the main build up of the demo.

Breaking down the demo

1. Creating terrain with a plane

Let’s make a basic three.js scene, place a plane with a nice amount of vertices, rotate it 90 degrees is the x-axis, and lift the camera a little bit:

fYbYbiM.jpg!web

Create custom vertex and fragment shaders and bind them to a ShaderMaterial. The objective is to displace vertices up in the vertex shader with a perlin noise and multiply it with a height value:

// pseudo-code for noise implementation

vec3 coord = vec3(uv, 1.0)*10.0;
float noise = 1 + pnoise( vec3( coord.x, coord.y + time, coord.z ));

float height = h * noise;

// we apply height to z because the plane is rotated on x-axis
vec4 pos = vec4( position.x, position.y, height, 1.0 );

// output the final position
gl_Position = projectionMatrix * modelViewMatrix * pos;

b2Yrumf.jpg!web

2. Create a road with some math

Now we’ll use a little bit of math. We’ll implement the formula below, where x is the vertex x-coordinate, h is the maximum height of terrain, c is the center of road and w is the width of road:

fIzEFjn.jpg!web

Playing with those variables, we can get different results, as we can see in the graphs:

EzYnqaQ.gif

I3eymya.gif

zu6n2i6.gif

Now, applied in vertex-shader code, multiplied by the previously calculated noise it looks as follows:

// pseudo-code for formula implementation
float height = h * pow( abs( uv.x + c ), w ) * noise;

// we apply height to z because the plane is rotated on x-axis
vec4 pos = vec4( position.x, position.y, height, 1.0 );

// output the final position
gl_Position = projectionMatrix * modelViewMatrix * pos;

2mY3uif.jpg!web

To make a curved road, we use uv.y as angle and take the sin of it to oscillate the center along the y-axis (the plane is rotated on the x-axis, remember?).

7BRNN36.jpg!web

3. Adding color layers

Let’s colorize the terrain with a nice trick. First, create a color pallete image like this one:

And then we’ll use it as a lookup texture in the fragment shader, getting the color value from the height calculated in the vertex shader as texture uv.y coordinate:

// pseudo-code for getting the color
vec2 coord = vec2( 0.0, normalize( height ) );
vec4 color = texture2D( palleteTexture, coord );

gl_FragColor = color

r6jU3eb.jpg!web

4. Having fun adding interactivity

Now we’ve done the heaviest part, it’s easy to use mouse, touch or whatever input you want, to control the formula’s variables and get interesting forms of interactivity:

// JS pseudo-code in the render loop for uniforms manipulation with mouse
terrain.material.uniforms.c.value = (mouseX / window.innerWidth - 0.5) * 0.1;
terrain.material.uniforms.w.value = (mouseY / window.innerHeight - 0.5) * 4;

5. Final touches

Let’s adjust the camera position, add a nice color pallete, fog, a sky background, and we are done!

UBNzaa2.jpg!web

We hope you enjoy this walk-through and find the experiment inspirational!

References and Credits

Find this project on Github


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK