Home / 2015 / December

Simple environment map

Just want to share a simple technique I used in my christmas experiment this year. I was trying to create some image based lighting. I found myself often in a situation that I just need a background. However I don’t have enough photoshop skill to make a custom background. I’ve always want to put more colours into my project and like to have some beautiful gradient background instead of just a plain colour. So I discover this trick : I want the colour to look nature in my work, so why don’t I just grab the colour from the nature itself ?

It’s simple : search images for ‘sky gradient’ and you’ll get tons of beautiful gradients colour for you :


some of them have some clouds but you can just apply a massive blur on it and it’ll look smooth.


After get this in there’s a really easy way to make an image based lighting that doesn’t require a cube map. I found an amazing article here :

and this super useful shader  :

vec2 envMapEquirect(vec3 wcNormal, float flipEnvMap) {
  //I assume envMap texture has been flipped the WebGL way (pixel 0,0 is a the bottom)
  //therefore we flip wcNorma.y as acos(1) = 0
  float phi = acos(-wcNormal.y);
  float theta = atan(flipEnvMap * wcNormal.x, wcNormal.z) + PI;
  return vec2(theta / TwoPI, phi / PI);

vec2 envMapEquirect(vec3 wcNormal) {
    //-1.0 for left handed coordinate system oriented texture (usual case)
    return envMapEquirect(wcNormal, -1.0);

With this you only need the normal to get the reflect colour from an image, combine this with the gradient colour image we got, you can produce a very nature look environment lighting.

Ultimately you’ll probably want to go for cube map + PBR but I think this could be useful for some smaller projects.

And lastly here is the link to my christmas experiment this year :


and the source code is here :


the sound cloud loader I was using is from here :
Really glad to be part of it again and merry christmas everyone !

Codevember and ray marching



Still can’t believe that I’ve made it, but really glad I did. I decided to do this because I feel I never pushed myself hard enough, and want to challenge myself. It was easier at the beginning, while you hare a lot of ideas from the past. And then as the time goes you start to run out of ideas, that’s where the panic starts. I want to say thank you to all my friends who provides me ideas and inspirations. In this month everyday is like this : finish the experiment of the day just before I go to bed, then start to think about what I can do next day. It’s really intense, however it helped me a lot. In order to create work quickly I need to gather tools first, and save more tools while building them. The more tools you have, the quicker you can build.


Ray marching

A great part of my codevember experiments are ray marchings. I really like it. It was a huge mystery to me and seems super complicated. I am lucky to come across this live coding tutorial just before the codevember starts.

I’m so glad that my french hasn’t completely gone so I am still able to understand the most part of it. It’s a really wonder tutorial that guide you step by step to build your first ray marching experiment. Once finished this you’ll be able to start understand better the codes on shadertoy.com. And need to mention this amazing blog post of iq. It has all the basic tools you need. With this you are already able to create some amazing stuff.

I really like ray marching. It’s really simple: everything happens in 1 fragment shader. All the effects you need is just one function call, e.g. AO, Shadow, Lighting ( Diffuse, Specular), Spherical reflections … etc. For me it feels much simpler and easier to deal with. Besides, there’s already tons of tools on shadertoy that you can use. All you need is just to figure out what the arguments you need to pass in to the function, and most of the time they are really simple.

Also here are some other interesting videos related to ray marching :

also some useful links :



My latest project finally gone live. I spend some efforts working on the liquid/fluid looks of the bubble and found some interesting techniques. Really thankful for the people who create these techniques and willing to share with everyone.

Here is a demo link to the bubble, you can click on the bubble to launch a wave as well.




Animate bubble in shader and normal

The first task is to animate the bubble and getting the right normal. The way we’ve done it is to put everything to the vertex shader and then calculate the normals based on the vertices positions. This approach makes it really easy for us when we decide to add the ripples in the bubble. We only need to calculate the position offset caused by the ripple and added to the vertex position, then the normal map is updated.
In order to do so, in the positions buffer instead of putting in the position of the vertex, I put the rotation of x , rotation of y and the size of the bubble. And to get the position of vertex you can use this function :

vec3 getPosition(vec3 values) {
  float rx = values.y / numSeg * PI - PI;
  float ry = values.x / numSeg * PI * 2.0;

  vec3 pos = vec3(0.0);
  pos.y = cos(rx) * values.z;
  float r = sin(rx) * values.z;
  pos.x = cos(ry) * r;
  pos.z = sin(ry) * r;
  return pos;

Then using the position to get the 3D noise ( I’m using this noise function) and the ripple height.
At the end, the final position of the vertex is the original position (sphere) + noise + ripple.

Because we are using the rotation X and rotation Y to get the vertex position so we can get the neighbor position just by offset this rotation X and rotation Y. And with the position of the neighbors, we can calculate a simple normal by using cross product. The shader code looks like this:

vec3 currPos = getFinalPosition(position); // getPosition() + noise + ripple
vec3 rightPos = getFinalPosition(position+vec3(1.0, 0.0, 0.0);
vec3 bottomPos = getFinalPosition(position+vec3(0.0, 1.0, 0.0);
vec3 vRight = rightPos - currPos;
vec3 vBottom = bottomPos - currPos;
vec3 normal = normalize(cross(vBottom, vRight));

This way you could get a animate bubble and a normal with it.



Distortion with background image

The second task is to distort the background behind the bubble. I started with the refract function but that requires a cube map, we’ve only got an image. So i start look around to see if there’s a simpler way to create the refraction effect, then I found this article :
In short you can create a refraction effect by just using the normal.xy as a displacement map.

vec2 newUV =uv + normal * distortionRate;
gl_FragColor = texture2D(texture, newUV);

with this you can achieve a good simulate refraction effect with just a background image instead of a cube map.




At the beginning of the project we started with the traditional diffuse and specular lighting. It works however the bubble lacks one important feature : reflection. I went back to search for possible solutions and then found this amazing article :
using this effect add a lots to the bubble and gives it a very strong glassy/fluid look, which is exactly what the client after.



Small Details

We also add 2 small detail to the bubble :

  1. Distorted a bit more toward the edge of the bubble.
  2. Darker on the edge of the bubble.

These 2 works in the same way and I need a value that changes from the center of the bubble to the edge. A quick way to do it is to get the dot product of the normal and the vector(0.0, 0.0, 1.0). Once you got this you can add this to the distrotionRate and get the different distortion between the center and the edge.



It is really fun and good learning process to go through all these steps in order to create the final look of it. I believe there are more ways to achieve this look but we really happy with this one. I’m also trying and learning cubemap now. For the next time I might try with the cubemap to recreate this fresnel effect. And even more a dynamic cubemap could be an interesting effect to add on this.

One of my codevember experiment is based on this technique. I only remove the noise animation also replace the lighting map with a much simpler one ( just a glow on the edge )



and also the case study of the whole project on stink digital’s site :