如何在WebGL中进行环境反射,而不使用类似于Three.js的库?

8
我正在尝试将环境映射到物体上。以下是设置:

teapot

我该如何使茶壶表面反射其周围环境?我的意思是,茶壶不应该是灰色的,而是应该反射其环境,所以它的表面应该映射成棋盘格。

这是我想要实现的示例,但它使用了Three.js,而我想自己做(这是为了一个课程)。

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

这有意义吗?我该如何开始?


后续

我在完成作业后回答了这个问题:https://dev59.com/m2LVa4cB1Zd3GeqPw390#10093646。请参考答案中的链接和代码 :)

2个回答

12
我在这里找到了一个很好的茶壶示例...

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

浏览源代码后,我找到了我需要的内容:

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

我需要一个示例片段着色器(其中包含超出我所需的环境反射映射),请为我翻译。

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

结果有点酷...

teapot with environment mapping

请随意访问http://hristo.oskov.com/projects/cs418/mp3/查看。源代码都在那里展示......代码很烂,请不要评判我:) 这是主JS文件:http://hristo.oskov.com/projects/cs418/mp3/js/mp3.js。着色器在index.html页面中,所以只需查看源代码。


还有这个示例,它可以进行实时反射。虽然它使用了一个库,但该库并没有隐藏太多内容。(http://webglsamples.googlecode.com/hg/dynamic-cubemap/dynamic-cubemap.html) - gman
是的,我看到了那个 :) 非常令人印象深刻,但当我看到它使用了一个库时,我就将其忽略了 :/ - Hristo
你能否包含顶点着色器?没有它,所有那些varyings都没有多大意义。另外,你发布的khronos.org链接需要登录才能查看。 - Sungaila

3
渲染反射对象的基本方法如下:
  1. 将相机放置于对象中心,将场景渲染到六个纹理上,分别代表一个立方体的六个面。
  2. 编写片段着色器以反射视线,并追踪到其与立方体相交处,从而找到反射中所见颜色。
(我自己从未实际完成过这个过程,但我看过像这样的教程。)

是的... 我在概念上理解了。我只是在找出用于开始此操作的代码方面遇到了困难。我对WebGL并不是很熟悉 :P - Hristo
你可能会对使用 http://i-am-glow.com 作为样板感兴趣,这样你就可以集中精力于着色器/FBO部分。 - MikaelEmtinger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接