数据立方体_立方体纹理

立方体纹理就是包含6个2D纹理的纹理.6个纹理有序排列在立方体的6个面.其可以通过方向向量采样立方体纹理上的纹素.

c0c7c524cd40b3f7bee860322d6003ab.png

创建立方体贴图跟创建2D贴图一样,但是绑定到GL_TEXTURE_CUBE_MAP上.

glGenTextures(1, &CubeMapID);
glBindTexture(GL_TEXTURE_CUBE_MAP, CubeMapID);

立方体纹理右6个面,每个面都要调用一次glTexImage2D,因此共需要调用6次.每个面有特定的纹理目标.按照顺序是这样.

89910916c668936441a09f229a4a3325.png

这些纹理目标为枚举型,按照顺序他们的值是线性叠加的.因此编写代码的时候可以用for循环调用glTexImage2D,然后用循环次数作为这些纹理目标的枚举值.从GL_TEXTUREE_MAP_POSITIVE_X开始.

例如以i作为循环次数记录.

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

立方体纹理也需要设置环绕模式与过滤模式.

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);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

一般的纹理是二维的因此仅需要设定ST的环绕模式即可.但是立方体纹理是三维的因此需要对R设置.可以简单理解为z坐标.

天空盒

立方体纹理常用于天空盒.设置好纹理数据和VAO,VBO之后,编写天空盒用的shader就可以了.

#version 330 core
layout(location=0) in vec3 aPos;out vec3 TexCoords;uniform mat4 projection;
uniform mat4 view;void main()
{TexCoords=aPos;gl_Position = projection * view * vec4(aPos, 1.0);
}

片元着色器获取立方体纹理的纹素作为颜色输出.

#version 330 core
out vec4 FragColor;
in vec3 TexCoords;
uniform samplerCube skyBox;
void main()
{FragColor=texture(skyBox,TexCoords);
}

在绘制天空和的时候需要开启深度测试,以及关闭天空盒的深度写入.因为有些对象与相机的距离可能比天空盒面到相机的距离远.因此这种情况下天空盒有可能将某些物体覆盖了.并且需要注意需要先渲染天空盒再渲染其他物体.

int main()
{
glDepthMask(GL_FALSE);
//绘制天空盒
//...
glDepthMask(GL_TRUE);
//绘制其他物体
}

如果按照以往的思路将MVP矩阵参数传进去将纹理坐标设置好的话并不会得到一个良好的结果.

b56d6f7456e79027562ef3a0b848adb4.gif

因为我们不想天空盒跟场景中其他物体一样.天空盒不应受移动影响.仅受旋转和缩放影响.因此需要去掉观察矩阵的平移部分.即保留矩阵左上角部分.

view=glm::mat4(glm::mat3(view))

将这个view传进去shader可得到正确的显示.

2b47e1ceab701d48e239ddadbcc9fdb9.png

以上的做法是关闭深度写入,让天空盒不参与深度测试.让每个像素都运行一次天空盒的片元着色器.但其实将天空盒的深度值永远设置为1就可以获得正确的效果了并且参与深度测试的话也不需要每个像素都调用天空盒的着色器.因为在某些复杂的场景里面天空盒仅仅显示一小部分.为此,我们需要将天空盒深度值永远设为1.

根据流水线,在顶点着色器运行时投影矩阵会进行透视除法,并最后处于标准化设备空间(NDC)中的.

a58d62208ca4c8ff8fe94d6582c6d5ca.png

因此若想经过透视除法后的z值为1,则需要将z值定为w.

#version 330 core
layout(location=0) in vec3 aPos;out vec3 TexCoords;uniform mat4 projection;
uniform mat4 view;void main()
{TexCoords=aPos;vec4 pos = projection * view * vec4(aPos, 1.0);gl_Position = pos.xyww;
}

将z值定为w进行透视除法后就变为1.

这时候还需要开启深度测试并调用深度测试函数设置比较运算符为GL_LEQUAL.

GL_LEQUAL为片元的深度值小于等于缓存的深度值时通过测试.因为如果调用默认的GL_LESS的话基本上天空盒是不会通过测试的.这时候就不需要设置关闭深度写入了.

glDepthFunc(GL_LEQUAL);
//绘制天空盒
glDepthFunc(GL_LESS);

绘制完天空盒之后改回默认的深度运算操作符,以便其他物体进行深度测试.

如果场景里面没有需要透明度混合的物体的话则天空盒可以随便放置于主循环的某一个位置进行渲染.否则的话会出现这种情况.

0925c22ce14115bde4d3d164529a29ac.png

2B因为不需要透明度混合,因此可以获得正常的渲染效果.但是草地于窗户精灵体需要透明度混合因此会出现奇怪的效果.

这里我是先渲染场景的所有物体,最后才渲染天空盒的.因此这时候场景物体部分的深度值比1小,通过测试与默认的颜色缓存的颜色进行混合.接着天空盒与深度缓存进行测试,因为天空盒深度值为1,比场景里物体的深度值大,因此这部分片元会被抛弃.所以物体混合的颜色里面没有天空盒纹理的颜色.

为此,最好在主循环刚开始的时候渲染天空盒.让天空盒颜色代替默认颜色缓存里的颜色.

acf08c9b4d213de0d2017e1fdb89fa80.png

所以,无论是对天空盒关闭深度写入还是设置天空盒的深度值为1,都最好在主循环开始的时候渲染.

立方体纹理可以用于环境映射.常用有反射和折射.

首先是反射

56d5c06be30225a21159ae7f237e30f0.png

反射很简单.主要就是获取向量R的方向然后通过R在立方体纹理中获取纹素.

在顶点着色器获取片元的位置以及法向量输出到片元着色器.

#version 330 core 
layout (location=0) in vec3 aPos;
layout (location=1) in vec3 aNormal;out vec3 fragPos;
out vec3 Normal;uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;void main() 
{  Normal=mat3(transpose(inverse(view*model)))*aNormal;fragPos=vec3(view*model*vec4(aPos,1.0));gl_Position=projection*view*model*vec4(aPos,1.0); 
} 

这里的法线用了法线矩阵消除缩放对物体法线的影响.片元位置放置在相机空间中,因为我偏好于将这些计算放在相机空间,这样就不用在片元着色器计算观察位置到片元位置了,直接可以用片元位置代替,因为在相机空间中,摄像机的位置就是原点.

根据上面的图片,需要在片元着色器计算反射向量

.反射向量可以通过GLSL内置函数
计算,也可以用反射向量的计算方式计算
.因为在顶点着色器片元位置在相机空间下,所以向量
仅需要对片元位置归一化即可.
#version 330 core 
out vec4 FragColor; in vec3 Normal;
in vec3 fragPos;uniform samplerCube skybox;void main() 
{ //环境映射反射vec3 I=normalize(fragPos);vec3 R=reflect(I,normal);FragColor=vec4(texture(skybox,R).xyz,1.0);
} 

bfd30e599e66d1bff3dab36f6ba6b7b3.png

可以运用反射贴图使模型的仅某一部分进行反射.通过引入反射贴图并对反射贴图进行采样获得当前网格的反射系数,然后运用插值对模型的反射贴图与其他光照模型进行综合

struct Material
{sampler2D texture_diffuse0;sampler2D texture_specular0;sampler2D texture_normal0;sampler2D texture_reflection0;float shininess;//影响镜面高光的散射/半径
};

在material就结构体里面增加一个反射贴图的声明.接着求出反射系数.

float reflectRate=(texture(material.texture_reflection0,TexCoords).r+texture(material.texture_reflection0,TexCoords).g+texture(material.texture_reflection0,TexCoords).b)/3;

不过反射贴图一般颜色分量不是0就是1,所以也可以简单点

	float reflectRate=texture(material.texture_reflection0,TexCoords).r;

在总颜色输出那里做一个插值就可以了.

void main() 
{ vec3 normal=normalize(Normal);vec3 viewDir=normalize(-fragPos);//观察空间下进行vec3 Direction=CalcDirectionalLight(dirLight,normal,viewDir);vec3 Point = CalcPointLight(pointLight,normal,fragPos,viewDir);vec3 Spot=CalcSpotLight(spotLight,normal,fragPos,viewDir);//环境映射反射vec3 I=normalize(fragPos);vec3 R=reflect(I,normal);float reflectRate=texture(material.texture_reflection0,TexCoords).r;vec4 reflection=texture(skybox,R);FragColor=vec4(reflectRate*reflection.xyz+(1-reflectRate)*(Spot+Point+Direction),1.0);
} 

最终效果中可以看到身上比较闪闪的地方都有天空盒的映射,其中以眼部的镜片效果最明显.

9334831f3fe83c20abd95f225cc54e03.png

折射

折射与反射的区别不大,就是将

函数改为
函数,再加一个折射率常数.

折射用到了斯涅耳定律,斯涅耳定律很简单:

4bf6c9a40a6afc0f89a9c34efbcd1609.png

其中

,
表示两种介质的折射率,
,
表示光线方向与法线的夹角.

介质的折射率有一个固定的参数.

b6ca8b7ec692cbc26b91a1f3608b9016.png

但是!!!我们不需要自己计算斯涅尔定律,反射有内建GLSL函数.折射与反射的区别不大,就是将

函数改为
函数,再加一个折射率常数.将上述反射部分的片元着色器代码修改下.

其中

,两种折射率比例.然后作为
的第三个参数就行
float ratio=1.0/1.33;
vec3 I=normalize(fragPos);
vec3 R=refract(I,normal,ratio);FragColor=vec4(texture(skybox,R).xyz,1.0);

4fa19cd2e938eaec1b93e545e53ea82b.png

当然,

函数想要自己算也不是不行.
杨超:cg refract函数​zhuanlan.zhihu.com
ffc3cfe033c858bae6d12e43d8e5417b.png

这里有一篇折射函数的推导过程.其中

.

按照这篇文章的推导即可得到正确折射向量.

vec3 refract(vec3 I,vec3 normal,float ratio)
{vec3 OC=dot(-I,normal)*normal;vec3 CA=-I-OC;vec3 EB=-ratio*CA;float EB_length_2=EB.x*EB.x+EB.y*EB.y+EB.z+EB.z;vec3 OE=-sqrt(1-EB_length_2)*normal;return EB+OE;
}
立方体贴图 - LearnOpenGL CN​learnopengl-cn.github.io
d2d9f7640aa7b78c271d24b6b3ed5d0d.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/551784.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为官方强制线刷工具_一加8/8Pro 线刷救砖

9008线刷是高通平台设备底层的刷机模式,是降级救砖必备良品,有了它,放心刷不想自己动手或遇到困难,可在后台回复: 远程刷机如果你是新手,要9008降级或者救砖,请先准备好充足的时间和良好的心态,…

centos vsftp mysql_CentOS6.4 实现基于mysql的vsftpd

大纲一、安装所需要的软件包二、创建虚拟用户账号三、配置vsftpd四、启动vsftpd服务并查看五、关闭防火墙与SElinux六、配置虚拟用户有不同的访问权限一、安装所需要的软件包1. 安装开发环境[rootftp ~]# yum -y groupinstall "Development Tools" "Development…

java实时监听mysql_java实时监控mysql数据库变化

对于二次开发来说,很大一部分就找找文件和找数据库的变化情况对于数据库变化。还没有发现比较好用的监控数据库变化监控软件。今天,我就给大家介绍一个如何使用mysql自带的功能监控数据库变化1、打开数据库配置文件my.ini (一般在数据库安装目录)(D:\MYS…

python中cmd如何切换盘_redis 中如何切换db

redis 中如何切换dbredis数据库个数是可以配置的,默认为16个如上图我们如何切换呢?我在redis客户端查询如下 通过用select N 你想要的数据库 就能切到对应的数据库去了每个数据库的key值不会冲突,是分开存储的java代码中如何切换redis db&…

mysql max字符串报错_mysql [Warning] max_join_size报错问题解决办法

文章介绍了关于mysql [Warning] max_join_size报错问题解决办法,有需要的同学看看。100716 06:32:45 d started100716 6:32:45 [Warning] option max_join_size: unsigned value 18446744073709551615 adjusted to 4294967295100716 6:32:45 [Warning] option max_join_size: u…

jdbc odbc java mysql数据库连接_Java数据库连接之配置ODBC数据源

java使用JDBC-ODBC桥接连接SQLServer数据库需要配置ODBC数据源,配置步骤如下:1.进入控制面板,找到管理工具2.看到ODBC数据源,有64位和32位的,如果你的数据库是64位的就要选择64位的,32位的数据库也要选择对…

kali mysql停止服务器_从零开始:手把手教你黑客入门攻破服务器并获取ROOT权限...

有许多人对神秘的黑客一直感兴趣,却苦于网上资料繁杂,无法入门,在学黑客之前,你要知道什么是黑客,黑客就是那些对计算机有着强烈探索欲的人,一个真正的黑客,必须要至少掌握一门编程技术和熟悉系…

堆排序不稳定的例子_【译】Python中的堆排序

作者:Olivera Popović翻译:老齐介绍堆排序是高效排序算法的另一个例子,它的主要优点是,无论输入数据如何,它的最坏情况运行时间都是O(n*logn)。顾名思义,堆排序在很大程度上依赖于堆数据结构——优先级队列…

安卓手机备份_安卓手机数据备份与恢复方法汇总和操作详解

世界那么大,谢谢你来看我!!关注我你就是个网络、电脑、手机小达人每次使用电脑时,我们都会自觉的将重要的文件保存好并且备份起来防止丢失。那同样的,我们在使用手机时,也要养成手机备份的好习惯。今天就来…

mysql索引的使用及优化方法_MySQL中索引和优化的用法总结

1、什么是数据库中的索引?索引有什么作用?引入索引的目的是为了加快查询速度。如果数据量很大,大的查询要从硬盘加载数据到内存当中。2、InnoDB中的索引原理是怎么样的?InnoDB是MySQL的默认存储引擎,InnoDB有两种索引:…

苹果屏幕上的小圆点_苹果或明年部署miniLED屏幕 最早用在Macbook上

中关村在线消息:苹果将举行WWDC 2020开发者大会即将召开,昨日,业内人士手机晶片达人透露:“苹果明年即将在Macbook上与iPad导入Mini LED产品,效果非常非常的好。相关供应链都开始动了起来。”苹果明年即将在Macbook上与…

mysql默认字符集和排序_MySQL字符集和排序规则

MySQL在创建数据库是,需要设置数据库的字符集和排序规则,如图所示:我觉得这里有必要解释下字符集和排序规则这两个概念。字符集说到字符集,需要先提下字符、字符集和字符编码这几个词的含义。字符(Character)是各种文字和符号的总…

图形驱动程序和显卡驱动什么区别_以后你的手机也需要单独安装显卡驱动程序了...

在桌面平台制造商通常会定期发布显卡驱动优化和提高性能,对于多数用户来说安装显卡驱动应该是很平常的事。不过在智能手机方面还不需要安装额外的驱动程序,因为制造商通常会通过每年的安卓系统更新来发布新版驱动。有趣的是从明年开始我们的智能手机也要…

有向加权图 最大弱连通分支_开盘引来大涨,当下股市最大的风险是它?

何为昨天的大涨定性?昨天的大涨,上午的加权量能水平达到了2921亿元,一个非常健康的温和放量状态;下午的加权量能水平快速下降到2242亿元的水平,这是略高于五日均量的量能水平;大幅高开,集合竞价…

axure文本框提示文字_Axure教程:一个中继器实现密码验证

本文给大家介绍用一个中继器实现axure登录时账号密码验证效果,一起来看看~实现效果如下图:工具/原料:账号文本框密码文本框登录按钮中继器记录密码的文本标签(隐藏)提示框(隐藏)验证按钮(隐藏)方法/步骤步骤1设置中继器:新增列acc…

深度学习 autoencoder_笔记:李淼博士-基于模仿学习的机器人抓取与操控

说明:本文是Techbeat平台上李淼博士的讲座:“基于模仿学习的机器人抓取与操控”的总结笔记。原视频:TechBeat - 让AI大有可为​www.techbeat.net视频介绍:近四十年来,研究人员对机器人抓取的研究逐渐深入,涉…

linux临时挂载别的文件目录_linux基础05:linux系统目录有哪些?命令行界面如何切换目录?...

我们安装好linux系统后,linux系统也会像windows系统一样,自动生成很多的文件和目录,这些目录都包含了不同的含义。下面,我们就来介绍一下这些目录都代表着什么?以及,在命令行界面,我们如何在不同…

抽象方法可以有方法体_什么方法可以祛斑?祛斑的方法有哪些?

现在是一个看脸的时代,可能不那么准确,但是也说明了人们对于美好脸蛋的追求。完美的脸蛋必定是光滑白皙没有瑕疵的,而有了色斑就会损害整个人的颜值。祛斑的方法有哪些?若是您正深受长斑的烦恼,小编专门寻找了一些简单有效的祛斑…

炫界 (978) -(建工发现应用克隆漏)_除了DMA,这些漏损点检测与漏损区域识别技术你知道么?...

漏损问题在给水管网中是普遍存在且难以避免的。据《2018年城市供水统计年鉴》显示,载入年鉴的各城市在2017年的管网漏损总量超过60亿m3,平均漏损率为14.56%,这与“水十条”明确规定的控漏目标相比仍存有差距。与此同时,居高不下的…

go语言 mysql卡死_一次mysql死锁的排查过程-Go语言中文社区

一次mysql死锁的排查过程一、背景17号晚上要吃饭了,看旁边的妹子和佐哥还在调代码,就问了下什么问题啊,还在弄,妹子说,在测试环境测试给用户并发发送卡券时,出现了死锁,但看代码没有死锁&#x…