• CSharpGL(43)环境映射(Environment Mapping)-天空盒(Skybox)反射(Reflection)和折射(Refraction)


    CSharpGL(43)环境映射(Environment Mapping)-天空盒(Skybox)反射(Reflection)和折射(Refraction)

    开始

    如图所示,本文围绕GLSL里的samplerCube记录天空盒(Skybox)、反射(reflection)、折射(refraction)的实现。

    下载

    CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入(https://github.com/bitzhuwei/CSharpGL

    天空盒(Skybox)

    samplerCube

    想在三维场景里渲染出天空和大地,可以利用一个巨大的立方体,把6个连接的图片分别贴在立方体的6个面上。

     

    这样的立方体就是所谓的天空盒(Skybox)。

    OpenGL提供了一个GL_TEXTURE_CUBE_MAP类型的纹理,其本身就是一个立方体,自带6个纹理面。它对应的GLSL里的类型就是samplerCube。SamplerCube正适合做天空盒。

     

    SkyboxNode

    渲染天空盒,实际上就是渲染一个巨大的立方体,并且用samplerCube为其上色。

    其vertex shader如下:

     1 #version 330 core
     2 
     3 layout(location = 0) in vec3 inPosition;// 顶点位置
     4 
     5 uniform mat4 mvpMatrix;
     6 
     7 out vec3 texCoord;// 立方体纹理在此顶点处的坐标值
     8 
     9 void main()
    10 {
    11     vec4 position = mvpMatrix * vec4(inPosition, 1.0); 
    12     gl_Position = position.xyww;// 保证天空盒的深度始终为最深
    13     texCoord = inPosition;// 立方体纹理的特殊情况
    14 }

    注意,这里的gl_Position = position.xyww;,是为了保证天空盒的深度始终为最深。这样就不会遮挡住场景里的其他物体。再注意,texCoord = inPosition;这句,就要求我们的天空盒模型必须是中心在坐标原点的立方体,这样才能保证inPosition在数值上等于此顶点的纹理坐标值

    其fragment shader如下:

     1 #version 330 core
     2 
     3 uniform samplerCube skybox;
     4 
     5 in vec3 texCoord;
     6 
     7 out vec4 color;
     8 
     9 void main()
    10 {
    11     color = texture(skybox, texCoord);
    12 }

    极其简单,就是从skybox纹理中取出对应位置的颜色,写入Framebuffer。

    如果把镜头拉远,你会看到所谓的天空盒是这样的:一个剔除了正面的立方体 

    反射(Reflection)

    利用samplerCube,可以实现一个反射效果——根据反射原理,把天空盒的纹理贴到模型上,看上去的感觉是,模型像镜子一样反射了周围的东西。此即为环境映射的一种。

     

    GLSL自带了反射函数reflect(,);

    实现反射的vertex shader如下:

     1 #version 330 core
     2 
     3 layout (location = 0) in vec3 inPosition;
     4 layout (location = 1) in vec3 inNormal;
     5 
     6 uniform mat4 projection;
     7 uniform mat4 view;
     8 uniform mat4 model;
     9 
    10 out vec3 passNormal;
    11 out vec3 passPosition;
    12 
    13 void main()
    14 {
    15     gl_Position = projection * view * model * vec4(inPosition, 1.0);
    16 
    17     passNormal = mat3(transpose(inverse(model))) * inNormal;
    18     passPosition = vec3(model * vec4(inPosition, 1.0));
    19 }

    此vertex shader做了3件事:1.给gl_Position赋值。2.传递world space里的法线passNormal。3.传递world space里的位置passPosition。

    下面根据反射原理为模型上色(fragment shader):

     1 #version 330 core
     2 
     3 uniform vec3 cameraPos;
     4 uniform samplerCube skybox;
     5 
     6 in vec3 passNormal;
     7 in vec3 passPosition;
     8 
     9 out vec4 FragColor;
    10 
    11 void main()
    12 {             
    13     vec3 I = normalize(passPosition - cameraPos);
    14     vec3 R = reflect(I, normalize(passNormal));
    15     FragColor = vec4(texture(skybox, R).rgb, 1.0);
    16 }

    这里利用reflect函数找到反射方向(即纹理坐标),从而找到目标颜色。

    折射(Refraction)

     

    折射与反射类似,也是一种环境映射方式。其vertex shader与反射相同,fragment shader也只有一点点不同:利用GLSL内置的refract()函数找到折射方向。

     1 #version 330 core
     2 
     3 uniform vec3 cameraPos;
     4 uniform samplerCube skybox;
     5 
     6 in vec3 passNormal;
     7 in vec3 passPosition;
     8 
     9 out vec4 FragColor;
    10 
    11 void main()
    12 {             
    13     float ratio = 1.00 / 1.52;
    14     vec3 I = normalize(passPosition - cameraPos);
    15     vec3 R = refract(I, normalize(passNormal), ratio);
    16     FragColor = vec4(texture(skybox, R).rgb, 1);
    17 }

    注意,这里有个ratio是指两种透明物体的折射率。1.52是玻璃对空气的折射率。再注意,这里我们只计算了一个面的折射,然而本文的模型有光线的进入和穿出两次折射。不过一般这样也没关系,最终效果还是不错的。

    总结

    没什么可总结的。

  • 相关阅读:
    【连载】【FPGA黑金开发板】Verilog HDL那些事儿低级建模的基础实例(七)
    【连载】【黑金动力社区原创力作】《液晶驱动与GUI 基础教程》 第二章 颜色模型(三)
    更新 EVGA86 模块手册
    【连载】【FPGA黑金开发板】Verilog HDL那些事儿低级建模的基础(二)
    NIOS II JTAG UART通讯
    【连载】【FPGA黑金开发板】Verilog HDL那些事儿听听低级建模的故事(五)
    NIOS II LCD上面显示时间
    治疗Quartus绝症的方法
    【连载】【黑金动力社区原创力作】《液晶驱动与GUI 基础教程》 序言(一)
    《NIOSII那些事儿》REV6.0 最新版发布
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/CSharpGL-43-environment-mapping-skybox-reflection-refraction.html
Copyright © 2020-2023  润新知