潍坊手机网站建设,陕西注册公司的具体流程,WordPress手机APP源码,订票网站开发公司天空和背景
对于 3D 场景#xff0c;通常可以通过在远处的地平线附近创造一些逼真的效果#xff0c;来增强其真实感。我们可以采用天空盒、天空柱#xff08;Skydome#xff09;或天空穹#xff08;Skydome#xff09;等技术来模拟天空。
天空盒
天空盒#xff08;Sk…天空和背景
对于 3D 场景通常可以通过在远处的地平线附近创造一些逼真的效果来增强其真实感。我们可以采用天空盒、天空柱Skydome或天空穹Skydome等技术来模拟天空。
天空盒
天空盒Skybox是一种在3D图形渲染中用于模拟远处背景的技术。它通过将场景包裹在一个巨大的立方体或球体中并在其内表面贴上纹理来实现。天空盒通常用于表示天空、云、山脉或其他远景背景。
工作原理
立方体模型天空盒通常是一个立方体摄像机位于其中心。纹理贴图立方体的六个面分别贴上对应的纹理前、后、左、右、上、下这些纹理拼接在一起形成完整的背景。固定位置天空盒始终跟随摄像机移动但不会旋转或缩放从而给人一种背景无限远的错觉。渲染顺序天空盒通常在渲染场景之前绘制并禁用深度测试以确保它始终位于场景的最远处。
优点
高效天空盒的实现简单性能开销低。真实感可以通过高质量纹理提供逼真的背景效果。灵活性适用于各种场景如白天、夜晚、宇宙等。
缺点
分辨率限制纹理分辨率过低可能导致模糊或失真。接缝问题如果纹理拼接不当可能会在立方体的边缘出现接缝。
天空盒广泛应用于游戏和虚拟现实中用于增强场景的沉浸感和视觉效果。
对于天空盒可以有两下两种实现方式
采用6张图片对应立方体的六个面分别贴上图片然后渲染。采用一张图片将图片贴在立方体的六个面然后渲染。
我们先采用第二种方式实现天空盒。 下面是将6张图片放到一张图片上形成的纹理
其与立方体六个面的关系如下
实现思路
创建一个立方体模型设置其纹理坐标使其与天空盒纹理对应。创建一个纹理对象将天空盒纹理加载到该对象中。在渲染循环中将纹理对象绑定到着色器并绘制立方体模型。立方体的中心位置始终与摄像机的位置相同。在摄像机移动时更新立方体的位置使其始终跟随摄像机。渲染时不要启用深度测试以确保天空盒始终位于场景的最远处。由于摄像机是在内部而我们定义立方体时是从外部定义外部立方体三角形是逆时针当我们从内部看时需要将三角形定义为顺时针 立方体的坐标
float cubeVertexPositions[108] { -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f,1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f,1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f,-1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f,-1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f,1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f,-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f,1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f};float cubeTextureCoord[72] { 1.00f, 0.6666666f, 1.00f, 0.3333333f, 0.75f, 0.3333333f, // back face lower right0.75f, 0.3333333f, 0.75f, 0.6666666f, 1.00f, 0.6666666f, // back face upper left0.75f, 0.3333333f, 0.50f, 0.3333333f, 0.75f, 0.6666666f, // right face lower right0.50f, 0.3333333f, 0.50f, 0.6666666f, 0.75f, 0.6666666f, // right face upper left0.50f, 0.3333333f, 0.25f, 0.3333333f, 0.50f, 0.6666666f, // front face lower right0.25f, 0.3333333f, 0.25f, 0.6666666f, 0.50f, 0.6666666f, // front face upper left0.25f, 0.3333333f, 0.00f, 0.3333333f, 0.25f, 0.6666666f, // left face lower right0.00f, 0.3333333f, 0.00f, 0.6666666f, 0.25f, 0.6666666f, // left face upper left0.25f, 0.3333333f, 0.50f, 0.3333333f, 0.50f, 0.0000000f, // bottom face upper right0.50f, 0.0000000f, 0.25f, 0.0000000f, 0.25f, 0.3333333f, // bottom face lower left0.25f, 1.0000000f, 0.50f, 1.0000000f, 0.50f, 0.6666666f, // top face upper right0.50f, 0.6666666f, 0.25f, 0.6666666f, 0.25f, 1.0000000f // top face lower left};渲染代码部分 绘制立方体
void display()
{//...//立方体的位置始终同摄像机位置相同mMat glm::translate(glm::mat4(1.0f), glm::vec3(cameraX, cameraY, cameraZ))glDisable(GL_DEPTH_TEST); // 关闭深度测试glEnable(GL_CULL_FACE); // 开启面剔除glFrontFace(GL_CCW); // 设置正面为顺时针glDrawArrays(GL_TRIANGLES, 0, 36); // 绘制三角形}顶点着色器代码
顶点着色器相对简单只是将顶点位置和纹理坐标传递给片段着色器。
#version 430
// 指定 GLSL 的版本为 4.30layout (location0) in vec3 position;
layout (location1) in vec2 texCoord; // 输入变量表示顶点的颜色绑定到 location 1uniform mat4 mv_matrix;
// uniform 变量表示模型-视图矩阵用于将顶点从模型空间变换到视图空间uniform mat4 proj_matrix;
// uniform 变量表示投影矩阵用于将顶点从视图空间变换到裁剪空间out vec2 tc;
// 输出变量表示顶点的颜色绑定到 location 0
void main(void)
// 主函数计算顶点的最终位置
{gl_Position proj_matrix * mv_matrix * vec4(position,1.0);// 将顶点位置从模型空间依次变换到视图空间和裁剪空间// 最终结果存储在内置变量 gl_Position 中用于后续的光栅化阶段tc texCoord;}片段着色器代码
#version 430
// 指定 GLSL 的版本为 4.30in vec2 tc;out vec4 color;
// 输出变量表示片段的最终颜色uniform mat4 mv_matrix;
// uniform 变量模型-视图矩阵未使用uniform mat4 proj_matrix;
// uniform 变量投影矩阵未使用
layout (binding0) uniform sampler2D tex0;
//uniform sampler2D tex0;void main(void)
// 主函数计算片段的最终颜色
{color texture(tex0, tc);
}
下图上方能看到立方体的接缝
使用 OpenGL 立方体贴图
用 OpenGL 立方体贴图有自己的优点例如可以减少接缝以及支持环境贴图 OpenGL 纹理立方体贴图类似于稍后将要研究的3D 纹理它们都使用带有3 个变量的纹理坐标访问——通常标记为**(s, t, r)**而不是我们目前为止用到的带有两个变量的纹理坐标。OpenGL立方体贴图的另一个特性是其中的图像以纹理图像的左上角而不是通常的左下角作为纹理坐标(0, 0, 0)
实现思路
创建一个立方体模型无需额外立方体纹理坐标立方体顶点坐标就是纹理坐标。创建一个纹理对象片段着色器中 samplerCube将6张天空盒图片加载到该对象中。在渲染循环中将纹理对象绑定到着色器并绘制立方体模型。立方体的中心位置始终与摄像机的位置相同。在摄像机移动时更新立方体的位置使其始终跟随摄像机。渲染时不要启用深度测试以确保天空盒始终位于场景的最远处。由于摄像机是在内部而我们定义立方体时是从外部定义外部立方体三角形是逆时针当我们从内部看时需要将三角形定义为顺时针
采样器类型
采样器类型维度主要用途特点sampler2D2D普通2D纹理采样• 用于常规2D纹理映射• 返回(r,g,b,a)四个分量• 最常用的纹理采样器类型samplerCube3D立方体贴图采样• 用于环境映射、天空盒等• 使用3D向量作为采样坐标• 六个面的纹理组合成立方体sampler2DShadow2D阴影贴图采样• 专门用于阴影映射• 返回单个深度值(0.0到1.0)• 自动进行深度值比较• 通常与深度纹理配合使用
代码实现
以下是运行效果
加载6张天空盒图片
GLuint Utils::loadCubeMap(const char* mapDir) {GLuint textureRef;string xp mapDir; xp xp /xp.jpg;string xn mapDir; xn xn /xn.jpg;string yp mapDir; yp yp /yp.jpg;string yn mapDir; yn yn /yn.jpg;string zp mapDir; zp zp /zp.jpg;string zn mapDir; zn zn /zn.jpg;textureRef SOIL_load_OGL_cubemap(xp.c_str(), xn.c_str(), yp.c_str(), yn.c_str(), zp.c_str(), zn.c_str(),SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS);if (textureRef 0) cout didnt find cube map image file endl;// glBindTexture(GL_TEXTURE_CUBE_MAP, textureRef);// reduce seams// glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);// glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);// glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);return textureRef;
}渲染立方体
此部份与之前代码基本相同只是绑定 GL_TEXTURE_CUBE_MAP glActiveTexture(GL_TEXTURE0); // 激活纹理单元 glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture); // 绑定纹理对象glDisable(GL_DEPTH_TEST); // 关闭深度测试glEnable(GL_CULL_FACE); // 开启面剔除glFrontFace(GL_CCW); // 设置正面为顺时针顶点着色器
此处采用 mat4(mat3(mv_matrix)) 来将模型-视图矩阵转换为模型-视图矩阵去除平移部分这样确保天空盒与摄像机始终处于同一位置 #version 430
// 指定 GLSL 的版本为 4.30
layout (location0) in vec3 position; // 输入变量表示顶点的三维位置绑定到 location 0out vec3 texCoord; // 输出变量uniform mat4 mv_matrix;
// uniform 变量表示模型-视图矩阵用于将顶点从模型空间变换到视图空间
uniform mat4 proj_matrix;
// uniform 变量表示投影矩阵用于将顶点从视图空间变换到裁剪空间
void main(void)
// 主函数计算顶点的最终位置
{mat4 vrot_matrixmat4(mat3(mv_matrix)); //remove the translation partgl_Position proj_matrix * vrot_matrix * vec4(position,1.0);// 将顶点位置从模型空间依次变换到视图空间和裁剪空间// 最终结果存储在内置变量 gl_Position 中用于后续的光栅化阶段texCoord position;
}片段着色器
片段着色器中 只是进行纹理采样
#version 430
// 指定 GLSL 的版本为 4.30in vec3 texCoord; // 输入变量表示顶点对应的纹理坐标
out vec4 fragColor; // 输出变量表示片元最终的颜色
uniform samplerCube texCube; // 纹理采样器表示立方体贴图
void main(void)
{fragColor texture(texCube, texCoord); // 采样立方体贴图得到片元的颜色
}环境贴图 环境贴图概述
环境贴图是一种模拟物体表面反射周围环境的渲染技术主要用于实现镜面反射、金属材质等效果。
工作原理
反射原理
通过采集物体周围环境的图像信息根据视角和表面法线计算反射向量使用反射向量从立方体贴图中采样颜色
主要应用场景 镜面物体 镜子金属表面光滑水面 金属材质 车身漆面金属器皿珠宝首饰
优缺点
优点
渲染效率高可以实现逼真的反射效果适合实时渲染
缺点
无法实现真实的反射折射环境贴图分辨率限制细节表现难以实现动态场景的实时反射
常见变体 球形环境贴图 使用单张球形投影的图像实现简单但有畸变 立方体环境贴图 使用六张图构成立方体质量更好无畸变问题 动态环境贴图 实时渲染场景到环境贴图可实现动态反射效果
相应实现原理 顶点着色器
#version 430
// 指定 GLSL 的版本为 4.30layout (location0) in vec3 position;
layout (location1) in vec2 texCoord; // 输入变量表示顶点的颜色绑定到 location 1
layout (location2) in vec3 normal; // 输入变量表示顶点的法线绑定到 location 2
// 输入变量表示顶点的三维位置绑定到 location 0uniform mat4 mv_matrix;
// uniform 变量表示模型-视图矩阵用于将顶点从模型空间变换到视图空间uniform mat4 proj_matrix;
// uniform 变量表示投影矩阵用于将顶点从视图空间变换到裁剪空间uniform mat4 normal_matrix;
out vec2 tc;out vec3 fragNormal;out vec3 vertPos;
void main(void)
// 主函数计算顶点的最终位置
{vertPos(mv_matrix*vec4(position,1.0)).xyz;gl_Position proj_matrix * mv_matrix * vec4(position,1.0);// 将顶点位置从模型空间依次变换到视图空间和裁剪空间// 最终结果存储在内置变量 gl_Position 中用于后续的光栅化阶段tc texCoord;fragNormal mat3(normal_matrix) * normal;// 将法线从模型空间变换到视图空间}片段着色器
核心代码为 vec3 R -reflect(V, N); 其中 reflect 函数的第一个参数为入射向量第二个参数为法线向量返回值为反射向量。
#version 430
// 指定 GLSL 的版本为 4.30in vec2 tc;in vec3 fragNormal;
in vec3 vertPos;
out vec4 color;
// 输出变量表示片段的最终颜色uniform mat4 mv_matrix;
// uniform 变量模型-视图矩阵未使用uniform mat4 proj_matrix;
// uniform 变量投影矩阵未使用
layout (binding0) uniform samplerCube tex0;void main(void)
// 主函数计算片段的最终颜色
{vec3 N normalize(fragNormal);vec3 V normalize(-vertPos); // 视线方向vec3 R -reflect(V, N); // 反射方向color texture(tex0, R);// 采样环境贴图获取反射颜色//colorvec4(R,1.0); // 仅用于调试显示反射方向
}参考
学习笔记完整代码下载OpenGL shader开发实战学习笔记第十一章 立方体贴图和天空盒_opengl 天空盒-CSDN博客