how would I do environment reflection in webgl without using a library like three.js?

10,543

Solution 1

I found a good example of this teapot here...

https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/demos/google/shiny-teapot/index.html

Looking through the source code, I found what I was looking for:

function loadCubeMap(base, suffix) {
    var texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);

    var faces = [["posx.png", gl.TEXTURE_CUBE_MAP_POSITIVE_X],
                 ["negx.png", gl.TEXTURE_CUBE_MAP_NEGATIVE_X],
                 ["posy.png", gl.TEXTURE_CUBE_MAP_POSITIVE_Y],
                 ["negy.png", gl.TEXTURE_CUBE_MAP_NEGATIVE_Y],
                 ["posz.png", gl.TEXTURE_CUBE_MAP_POSITIVE_Z],
                 ["negz.png", gl.TEXTURE_CUBE_MAP_NEGATIVE_Z]];
    for (var i = 0; i < faces.length; i++) {
        var face = faces[i][1];
        var image = new Image();
        image.onload = function(texture, face, image) {
            return function() {
                gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
                gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
                gl.texImage2D(face, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
            }
        } (texture, face, image);
        image.src = faces[i][0];
    }
    return texture;
}

... and the example fragment shader (which has more than I need for the environment reflection mapping)...

precision mediump float;
const float bumpHeight = 0.2;

uniform sampler2D normalSampler;
uniform samplerCube envSampler;

varying vec2 texCoord;
varying vec3 worldEyeVec;
varying vec3 worldNormal;
varying vec3 worldTangent;
varying vec3 worldBinorm;

void main() {
    vec2 bump = (texture2D(normalSampler texCoord.xy).xy * 2.0 - 1.0) * bumpHeight;
    vec3 normal = normalize(worldNormal);
    vec3 tangent = normalize(worldTangent);
    vec3 binormal = normalize(worldBinorm);
    vec3 nb = normal + bump.x * tangent + bump.y * binormal;
    nb = normalize(nb);
    vec3 worldEye = normalize(worldEyeVec);
    vec3 lookup = reflect(worldEye nb);
    vec4 color = textureCube(envSampler, lookup);  // <--- this was the aha! line
    gl_FragColor = color;
}

The result came out to be kinda cool...

teapot with environment mapping

Feel free to check it out at http://hristo.oskov.com/projects/cs418/mp3/. The source code is all there in its glory... the code sucks so please don't judge me :) This is the main JS file: http://hristo.oskov.com/projects/cs418/mp3/js/mp3.js. The shaders are in the index.html page so just view source.

Solution 2

The basic approach for rendering a reflective object is:

  1. Placing the camera at the center of the object, render the scene onto six textures representing the view out six faces of a cube around that object.
  2. Write a fragment shader that reflects the line of sight across the surface normal and traces out to where that intersects the cube to find the color seen in the reflection.

(I've never actually done this myself, but I've seen tutorials like this one).

Share:
10,543
Hristo
Author by

Hristo

LinkedIn JustBeamIt

Updated on June 04, 2022

Comments

  • Hristo
    Hristo almost 2 years

    I'm trying to figure out how to do environment mapping onto an object. Here's the setup:

    teapot

    How would I make the teapot's surface reflect it's surroundings? So what I mean by that is, instead of the teapot being that shade of gray, its surface should reflect its environment, so it should have the checkerboard mapped onto its surface.

    This is an example of what I'm trying to accomplish, but its using Three.js and I want to do this on my own (this is for a class).

    http://aerotwist.com/tutorials/create-your-own-environment-maps/demo/

    Does this make sense? How would I get started?


    Follow-Up

    I answered this question after finishing my homework assignment: https://stackoverflow.com/a/10093646/196921. Refer to the answer for links and code :)

  • Hristo
    Hristo about 12 years
    Yea... I get it conceptually. I'm just having trouble figuring out the code to get started with this. I'm just not that familiar with WebGL :P
  • MikaelEmtinger
    MikaelEmtinger about 12 years
    You might be interested in using i-am-glow.com as boilerplate so you can focus on the shader/FBO part.
  • gman
    gman about 12 years
    There's also this sample, which does a live reflection. It uses a library though. But the library is not hiding much. (webglsamples.googlecode.com/hg/dynamic-cubemap/…)
  • Hristo
    Hristo about 12 years
    yea I saw that one :) very impressive stuff but I dismissed it when I saw it used a library :/
  • Sungaila
    Sungaila about 5 years
    Could you include the vertex shader? All those varyings don't make much sense without it. Also the link you posted to khronos.org requires login details, so it is not viewable.