UV坐标,2D贴图,冯氏光照模型和材质
2D贴图的UV坐标
- 2D贴图一般使用正方形贴图,OpenGL也仅接受正方形的2D贴图。
- U指横向坐标,V指纵向坐标
- 2D贴图 的UV坐标范围为:从左到右[0,1],从下到上[0,1]。
- 2D贴图 的四角分别对应:
- 左上[0,1],左下[0,0],右上[1,1],右下[1,0]。

- 在使用UV坐标贴合片元时,先默认2D片元的坐标在OpenGL标准坐标系内,且垂直于z轴。
-
- 先仅为[x,y]指定一个UV坐标:[0.5,1],[0,0],[1,0] > 这里指定使用 [逆时针] 绘制正面
- 使用 glFrontFace() 可以设置正面的绘制顺序:顺时针 | 逆时针
- 使用 glCullFace() 可以设置不绘制:背面 | 正面
- 先仅为[x,y]指定一个UV坐标:[0.5,1],[0,0],[1,0] > 这里指定使用 [逆时针] 绘制正面
-
- 之后再沿OpenGL左手系x轴旋转片元,得到拥有纵深的图形:

-
- 它看起来好像扁了一样,实际上也确实是因为旋转后 X,Y,Z坐标发生了变化。
- 虽然旋转后看起来好像扁了,但在OpenGL标准坐标空间中,它依然是原来那个形状的三角形。
- 只是此时还未对它使用 [透视变换],无法得到那种看起来更贴合现实的景深感。
- 它看起来好像扁了一样,实际上也确实是因为旋转后 X,Y,Z坐标发生了变化。
2D贴图的填充方式
- 当顶点围城的片元,尚处在 [2D贴图的UV坐标范围] 内时,贴图尚且足够填充片元,但当超出UV坐标范围后呢?
- 使用 glTexParameteri(
- GL_TEXTURE_2D, //Flags ,可以是2D贴图,或者3D贴图,
- GL_TEXTURE_WRAP_S, //横向(S),也可以是纵向(T)
- GL_REPEAT); //填充方式。
- 可以设置当前 [绑定GL_TEXTURE_2D的贴图] 的填充方式。
- 使用 glTexParameteri(
2D贴图的过滤方式
- 当缩放&旋转 2D片元时,2D片元的材质,可能也会跟着“形变”,此时:
- 屏幕上原来范围的像素,会发生变化,变化后的颜色,需要计算机运算得出。
- 过滤方式,也就是计算方式,有:
- 临近插值:GL_NEAREST
- 很粗糙的取值办法,取值办法和它的名字一致。
- 不适合放大时使用,会出现颗粒状,即便你是8bit爱好者,也不建议你这么用,效果是真的不好。
- 缩小时,可以使用这种办法,毕竟缩小虽然不会引起图像模糊,但粗糙的插值算法会使图像失真。
- 临近插值:GL_NEAREST
-
-
- 线性插值:GL_LINEAR
- maybe它内部就是三线性插值?大概吧,放大时,材质就会模糊,但至少很平滑。
- 缩小时,不必使用这种插值方法,浪费性能。
- 线性插值:GL_LINEAR
- 使用 glTexParameteri(
- GL_TEXTURE_2D, // Flags ,可以是2D贴图,或者3D贴图,
- GL_TEXTURE_MAG_FILTER, // [放大] 时的过滤方式,或者缩小时的过滤方式
- GL_LINEAR); // 过滤方式 FLAGS
- 可以设置当前 [绑定GL_TEXTURE_2D的贴图] 的过滤方式。
-
- 多级渐远纹理
- 考虑缩小缩放时,无论使用何种过滤方式,都会引起图像失真(放大缩放仅需准备更加精细的贴图即可),
- 那不如就为各个级别的缩放级 仔细的单独计算出 属于自己的贴图。
- 在创建完一个纹理后,调用:glGenerateMipmaps(GL_TEXTURE_2D)
- 可以为当前绑定 GL_TEXTURE_2D 的贴图创建多级渐远纹理。
- 创建多级渐远纹理会消耗性能,请尽量对需要更多重复使用的纹理创建,对于那些无伤大雅的细节贴图,可以考虑不使用多级渐远纹理。
- 再使用线性插值&临近插值,就可以使插值更加精确一些。
- GL_NEAREST_MIPMAP_NEAREST
- 使用临近插值进行采样,采样源为最邻近级别
- GL_LINEAR_MIPMAP_NEAREST
- 使用线性插值进行采样,采样源为最邻近级别
- GL_NEAREST_MIPMAP_LINEAR
- 使用临近插值进行采样,采样源来自:两个 [临近的多级渐远纹理] 的线性插值结果
- GL_LINEAR_MIPMAP_LINEAR
- 使用线性插值进行采样,采样源来自:两个 [临近的多级渐远纹理] 的线性插值结果
- GL_NEAREST_MIPMAP_NEAREST
- 越向下,越精准,性能消耗越大。
- 那不如就为各个级别的缩放级 仔细的单独计算出 属于自己的贴图。
- 考虑缩小缩放时,无论使用何种过滤方式,都会引起图像失真(放大缩放仅需准备更加精细的贴图即可),
-
- 多级渐远纹理仅用于纹理缩小,错误用于纹理放大时,不会产生任何效果,还会返回GL_INVALID_ENUM错误代码。
- 使用 glTexParameteri(
- GL_TEXTURE_2D, // Flags ,可以是2D贴图,或者3D贴图,
- GL_TEXTURE_MIN_FILTER, // [缩小] 时的过滤方式,[放大不使用这种过滤方式]
- GL_LINEAR_MIPMAP_LINEAR); // 过滤方式 FLAGS
- 可以设置当前 [绑定GL_TEXTURE_2D的贴图] 的过滤方式。
- 使用 glTexParameteri(
- 多级渐远纹理仅用于纹理缩小,错误用于纹理放大时,不会产生任何效果,还会返回GL_INVALID_ENUM错误代码。
2D贴图的加载
- 使用stbimage.h可以从贴图文件中加载贴图。
- 加载代码如下:
-
1 #define STB_IMAGE_IMPLEMENTATION //stb_image.h库中提示,如需使用stb_image.h则必须定义此内容 2 #include<stb_image.h> 3 4 unsigned int TextureFromFile(const char *path, 5 const string &directory, //由main函数提供的directory 6 bool gamma) 7 { 8 string filename = string(path); 9 filename = directory + '/' + filename; 10 11 unsigned int textureID; 12 glGenTextures(1, &textureID); 13 //申请一个 [textureID],并为其分配存放贴图的内存 14 15 int width, height, nrComponents; 16 unsigned char *data = stbi_load(filename.c_str(), &width, &height, &nrComponents, 0); 17 //将文件初始化到文件指针data 18 if (data) 19 { 20 GLenum format; 21 if (nrComponents == 1) 22 format = GL_RED; 23 else if (nrComponents == 3) 24 format = GL_RGB; 25 else if (nrComponents == 4) 26 format = GL_RGBA; 27 //根据贴图文件的通道数决定接下来 初始化glTexImage2D要用的参数. 28 29 glBindTexture(GL_TEXTURE_2D, textureID); 30 glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); 31 glGenerateMipmap(GL_TEXTURE_2D); 32 33 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //设定横向填充方式 34 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //设定纵向填充方式 35 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); //设置缩放--时的过滤方式 36 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //设置缩放++时的过滤方式 37 38 stbi_image_free(data); 39 //初始化贴图后,销毁文件指针 40 } 41 else 42 { 43 //如果data初始化失败,未分配地址则: 44 std::cout << "Texture failed to load at path: " << path << std::endl; 45 stbi_image_free(data); 46 //销毁文件指针 47 } 48 49 return textureID; 50 }
- 点击stb_image.h获取 库文件。
光照渲染,冯氏光照模型:
- 补色原理:
- 因为所有的颜色,都是不同浓度的RGB基色混合而成的,
- 所以使用向量 glm::vec3 Color(R,G,B) 来表达任何颜色。
- R,G,B分别是 [0,1] 的值,用来标识 红绿蓝 的亮度。
- 因为所有的颜色,都是不同浓度的RGB基色混合而成的,
-
- 用乘法来描述 光线照射片元后,片元的颜色。
- 设:glm::vec3 LightColor(LR,LG,LB) 是光线颜色。
- 则:片元颜色 = Color(R,G,B)*LightColor(LR,LG,LB) = glm::vec3(R*LR,G*LG,B*LB)
- 用乘法来描述 光线照射片元后,片元的颜色。
-
- 用加法来描述不同光线的组合:
- 设:glm::vec3 LightColor() 是光线颜色。
- subLightColor_1(LR_1,LG_1,LB_1) + subLightColor_2(LR_2,LG_2,LB_2) = glm::vec3 LightColor(LR_1+LR_2,LG_1+LG_2,LB_1+LB_2)
- 用加法来描述不同光线的组合:
- 光照渲染,其实就是通过 [补色原理] 在片元上 [叠加着色] 来模拟光照效果。
- 法向量及其缩放:
- 法向量在OpenGL光照中充当 法线的作用
- 法向量(glm::vec3) 一般在模型文件中都存在此值,可以在[Assimp数据结构]中解析到。
- Assimp是一个用于解析模型数据的库,在nuget包管理器中可以找得到。
- 法向量一般通过VAO传送到shader。
- 法向量(glm::vec3) 一般在模型文件中都存在此值,可以在[Assimp数据结构]中解析到。
- 对模型的不等比缩放,可能会引起顶点法向量的形变,因此要在
- 法向量在OpenGL光照中充当 法线的作用
- 冯氏光照模型:
- 通过混合 [三种光照渲染],来模拟现实世界光照在片元上的效果,如图:

-
- 三种光照渲染包括:
- 漫反射光照,高光光照,环境光照。
- 三种光照渲染包括:
-
- 漫反射光照:
- 模拟的情况:
- 物体在被光照时,首先会被整体点亮。
- 存在折射率,因此存在损耗,最终从不同角度反射回的光量便不同。
- 模拟的情况:
- 漫反射光照:
-
- 高光光照:
- 模拟的情况:
- 不管何种物体的表面,都可以反射回光源的情况。
- 根据物体的光滑程度不同,最终会影响高光的散射度。
- 更光滑的,也就更闪闪发光,它的散射度也就越小,反之越大。
- 模拟的情况:
- 高光光照:
-
- 环境光照:
- 模拟的情况:
- 在没有任何光源的时候,人眼依旧可以看得见物体,环境光照模拟的就是这种情况。
- 模拟的情况:
- 环境光照:
- 点光源的冯氏光照样例:
- 因为光照渲染可以直接在Shader中完成,因此此处展示两个subShader:
- vertexShader:
-
1 #version 450 core 2 layout (location = 0) in vec3 aPos; //原始顶点位置数据 3 layout (location = 1) in vec3 aNormal; //原始顶点法向量 4 layout (location = 2) in vec2 aTexCoords; //顶点UV坐标 5 6 out vec3 FragPos; //model变换之后的 > 顶点位置数据 7 out vec3 Normal; //归一化之后的顶点法向量 8 out vec2 TexCoords; //UV坐标 9 10 uniform mat4 model; //model变换矩阵 11 uniform mat4 view; //view(camera)变换矩阵 12 uniform mat4 projection; //透视裁剪变换矩阵 13 14 void main() 15 { 16 //计算model变换后的顶点位置: 17 FragPos = vec3(model * vec4(aPos, 1.0)); 18 19 //法向量归一化,防止不等比缩放影响法向量: 20 Normal = mat3(transpose(inverse(model))) * aNormal; 21 22 //数据本地化: 23 TexCoords = aTexCoords; 24 25 //顶点变换,以及数据交付: 26 gl_Position = projection * view * vec4(FragPos, 1.0); 27 }
- fragmentShader:
-
1 #version 450 core 2 3 //顶点按组绘制,每组构成一个片元,shader每执行一次绘制一个片元(一组顶点) 4 out vec4 FragColor; 5 6 //材质--------------------------- 7 //意思就是片元表面的渲染属性。 8 struct Material { 9 sampler2D diffuse; 10 sampler2D specular; 11 float shininess; 12 }; 13 //此处仅包括片元的贴图和高光反射级别。 14 15 //光线--------------------------- 16 //光线属性,渲染光照时需要使用。 17 struct Light { 18 vec3 position; 19 20 vec3 ambient; 21 vec3 diffuse; 22 vec3 specular; 23 }; 24 //此处的光线属性包括: 光源位置,三种光照强度。 25 26 /*-------------以上是glsl自定义结构体类型,glsl是类c语言,结构体也和c一致------------*/ 27 28 29 //来自之前的subShader的值。 30 in vec3 FragPos; 31 in vec3 Normal; 32 in vec2 TexCoords; 33 34 //摄像机在世界空间坐标系中的坐标,即【OpenGL标准坐标系原点】在世界空间坐标系中的位置 35 uniform vec3 viewPos; 36 37 //外部虽然没有 Material&Light 的定义, 38 //但可以根据实例名 material.StructuralComponent向内传值 39 uniform Material material; 40 uniform Light light; 41 42 void main() 43 { 44 45 //渲染前置数据准备: 46 //法向量归一化(标准化,不归一化方向可能会不同) 47 vec3 norm = normalize(Normal); 48 //更新光照路径,归一化(不归一化方向可能会不同) 49 vec3 lightDir = normalize(light.position - FragPos); 50 //更新视角路径(渲染specular光照时会使用),归一化(不归一化方向可能会不同) 51 vec3 viewDir = normalize(viewPos - FragPos); 52 //更新反射路径(渲染specular光照时会使用),归一化(不归一化方向可能会不同) 53 vec3 reflectDir = reflect(-lightDir, norm); 54 55 // 计算出光照后的片元渲染颜色 56 // ----------------------------------------- 57 // ambient光照---------------------------------------------------------- 58 // ambient作用于 diffuseTexture,因此使用:material.diffuse, 59 vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb; 60 61 // diffuse光照---------------------------------------------------------- 62 // 计算此片元 漫反射强度 63 //根据光源位置不同,折射现象对反射强度的影响也不同 > 此处仅考虑这种情况 64 //根据折射率(来自材质)不同,漫反射强度也会有所衰减 > 此处不考录这种情况,默认所有材质的折射率都是最小值 65 float diff = max(dot(norm, lightDir), 0.0); 66 // diffuse作用于 diffuseTexture,因此使用:material.diffuse, 67 vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb; 68 69 // specular光照--------------------------------------------------------- 70 // 计算此片元 高光反射强度 71 //根据视线位置不同,以及反射路径,就会影响高光反射在不同位置的强度,进而形成“光晕”效果 72 //不同物体的散射程度不同,越光滑,散射越低,同时越亮 73 float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); 74 // specular作用于 specularTexture,因此使用:material.specular, 75 vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb; 76 77 //组合结果: 78 vec3 result = ambient + diffuse + specular; 79 FragColor = vec4(result, 1.0); 80 }
- 材质:
- 材质你可以认为是:来自渲染目标的,影响渲染的因素。
- 以上样例中的材质为:
- struct Material {
- sampler2D diffuse
- sampler2D specular
- float shininess;
- };
- struct Material {

浙公网安备 33010602011771号