Opengl-光照-颜色(其实要想做出好看的东西这章最重要了)

前言

前面的基础章节说了下Opengl入门的一些基础知识,通过这些基础知识你可以制作Camera或者让物体移动啊又或者放一张图片上去当做纹理贴图丰富物体的显示
但是其实不论怎么折腾你会发现略微呆板,没有鲜活的感觉。为什么呢?就是因为我们其实想让显示的东西像真实世界一样,然而却忽略了世界上最重要的东西-光!是的没有错,生活中你睁开眼闭上眼都可以感受到光的存在,看到任何东西都会因为光的原因有所感触,反观我们做出来的不论是箱子也好还是带着贴图的箱子又或者渲染的箱子,如果我们想让它更逼真,我们就要有光(佛说要有光放在这?)


相应的同第一章一样我所写的还尽量会是一些思想以及总结,可以说是我个人的回顾,又或者说是帮助理解不了一些概念的同学尽量理解明白一些东西。同理肯定是结合我最推荐的文章 LearnOpengl这个教程去学习,如果理解不了结合我的文章,应该可以让你明白卡在哪里,或者说哪里是难点,以及如何理解如何更好的想象。


颜色

现在来想一件事,其实计算机里或者说虚拟世界里并没有光,那肯定要问了,没有光怎么办?那不是完了?但是非常聪明的前人或者说艺术家们通过在计算机中模拟光来实现我们在真实世界见到的光。有一句话我非常想说:Opengl其实就是在模拟真实世界到虚拟世界中的一个办法集合。图形学也是在做这件事
现在回忆一下,至今为止我们看到的屏幕,我们玩的游戏。展现出的图像图片颜色,或者说一些3A大作里面靓丽的世界,都是我们通过模拟光照来让你的眼镜感受到了鲜活的感觉.那么我们如何模拟光照的呢?其实就是通过颜色。有一句话大家一定要好好理解下:我们在现实生活中看到某一物体的颜色并不是这个物体真正拥有的颜色,而是它所反射的(Reflected)颜色。换句话说,那些不能被物体所吸收(Absorb)的颜色(被拒绝的颜色)就是我们能够感知到的物体的颜色。

举个列子,我们是如何在计算机中模拟光照和现实颜色的

glm::vec3 lightColor(1.0f, 1.0f, 1.0f);
glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
glm::vec3 result = lightColor * toyColor; // = (1.0f, 0.5f, 0.31f);

可以看到我们定义了光颜色(1,1,1)也就是一个白光[1最大,拉满了],然后玩具颜色(1,0.5,0.31)要想知道最终结果就是相乘就好了没有什么特别的。为什么?反射学定律啊,就是这样啊。。别钻牛角尖老哥。就像颜色为啥可以这么表示你不是也不知道么?不是理解的很好么。


举个列子:你看到的树叶是绿色的,那么是因为这个树叶反射了绿色的颜色到你的眼睛里。
从这个例子我们可以了解到,其实我们模拟光,并不需要多么复杂的操作,按照反射或者折射的现象,我们只需要给物体定义一个颜色,然后通过着色器比如顶点啊像素啊处理好显示到屏幕上,这个时候绿色的物体就会被我们看到,那我们也就感觉到这个物体是绿色的了。


虽然说了尽量不写代码,只讲思想,但是感觉稍微贴点代码可能理解的会更清楚。

顶点着色器

#version 330 core
layout (location = 0) in vec3 aPos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(aPos, 1.0);
}

片段着色器

#version 330 core
out vec4 FragColor;

uniform vec3 objectColor;
uniform vec3 lightColor;

void main()
{
    FragColor = vec4(lightColor * objectColor, 1.0);
}

相信这两个着色器大家都比较熟悉,前面基础章节也都解释过这些着色器了基本都是固定的格式,这里的变化只不过多了uniform 关于uniform的使用前面都介绍过了这里不多赘述。
可以看到我们通过外部传入两个变量一个物体颜色,一个光的颜色最后改变了内置变量FragColor也就是片段(像素)的颜色,然后你从显示器上看到的也就是你传入的颜色和物体颜色相乘的结果了。
在外部代码中传入uniform部分:

lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
lightingShader.setVec3("lightColor",  1.0f, 1.0f, 1.0f);

关于数据方面:

unsigned int lightVAO;
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);
// 只需要绑定VBO不用再次设置VBO的数据,因为箱子的VBO数据中已经包含了正确的立方体顶点数据
glBindBuffer(GL_ARRAY_BUFFER, VBO);
// 设置灯立方体的顶点属性(对我们的灯来说仅仅只有位置数据)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

最终跑出来的结果应该是像这样子的
这里写图片描述

可以看到白色的那个正是我们设置的光源

猜你喜欢

转载自blog.csdn.net/alex1992azh/article/details/81737616