OpenGL教程翻译 第十七课 环境光(Ambient Lighting)

第十七课 环境光(Ambient Lighting)

原文地址:http://ogldev.atspace.co.uk/(源码请从原文主页下载)

背景

光照是 3D 图形学的最重要的研究领域之一。对光照得体的模拟会使渲染的场景增加很多视觉吸引力。之所以使用“模拟”这个词是因为你无法完全准确的计算出光在自然界中的表现。真正的光是由大量的称为“光子”的粒子组成的,并且同时表现出波和粒子的特性(光的“波粒二象性”)。如果你在程序中试图序计算每一个光子的作用,那么你将很快用光电脑的计算力。

因此,这些年来出现了一些光照模型,它们可以近似的模拟自然界中光照的部分效果。随着 3D 图形学领域的发展和计算机计算能力的提高,这些光照模型变得越来越复杂。在接下来的几章教程中我们将完成对基础光照模型的学习,这些模型虽然实现起来比较简单,不过对场景的整体效果的提升会有很大的提升。

基本的光照模型叫做 “环境光/漫反射光/镜面反射光”(’Ambient / Diffuse / Specular’)。环境光是当你在平常晴天时在室外看到的光的类型。虽然太阳的光线在一天的不同时刻以不同角度照射这个世界,但是大多数的东西都是可见的,即使它们在阴影中。因为光线能从任何物体上反弹,最终照射到所有物体,所以不被太阳光直接照射的物体也会被照亮。从这个角度来说上,甚至是房间里的灯泡也像表现得如同太阳一样传播环境光,因为如果房间不是很大的话,每一件物体都会被均等的照亮。环境光被描述为没有原点,没有方向,并且对场景中的所有物体都有相同效果的光。

漫反射光强调了光线照射到物体表面的角度与物体被照亮程度的关系。物体有光照射的一面比另一面(不直接面向光源的一面)更亮。我们只看到太阳散播的环境光没有明确的方向,然而,在太阳光中也有漫反射光。当他照射到一个高的建筑物的时候你通常能看到建筑物的一侧比另一侧亮一些。漫反射光的最重要的特性就是他的方向。

镜面反射光相对于光本身更强调是物体的属性。当光线以特定的角度照射物体时,反射光使物体的某一部分闪光,而观察者只有从特定的方向看过去才能看见这个闪光。金属材质的物体经常会有一些镜面反射特性。例如,晴天的时候一辆汽车的边缘会闪闪发光。计算镜面反射光照不仅需要考虑光照射的方向(并且反射),也要考虑观察者的位置。

在 3D 应用程序中,你通常不需直接创建环境、漫反射、或镜面反射光。相反的,我们要使用光源,例如太阳(在室外)、一个灯泡(在室内)或者一个手电筒(在洞穴)。不同的光源类型有不同的环境光、漫反射光、镜面反射光强度组合和一些其他的特性。例如,手电筒有一个锥形的光束,距离较远的物体根本不会被照亮。

在以下的教程中我们将会使用一些比较实用的光源类型,同时学习基础光照模型。

我们将从一种叫做“平行光”的光源开始。平行光有方向但是没有具体的原点。这就意味着所有的光线彼此平行。光线的方向由一个向量确定,这个向量用来计算在场景中所有物体表面上的光,无论他们的位置在哪里。太阳光很好的符合了平行光的特性。如果你尝试计算太阳光照射两个相邻的建筑的光线的入射角度,你会得到两个几乎完全一样的值(即他们之间的不同仅仅是一个微小的分数)。这是因为太阳距离地球大概 1.5 亿千米远的地方,因此,我们简单地忽略它的位置而只需考虑它的方向。

平行光的另一个特性是无论与发光的物体距离多远,他的亮度都保持相同。这和我们在接下来的教程中学习的另一个光源 —— 点光源不同。点光源随着距离增大亮度变得越来越弱(例如灯泡)。

下面这张图片阐明了平行光的特性:

这里写图片描述

我们已经看到在太阳中既有环境光也有漫反射光。我们在这一部分中讲述环境光,而在下一章中学习漫反射光。

在之前的教程中我们学习了如何从纹理中提取像素的颜色。颜色有三个通道(红、绿和蓝),每一个通道都是一个字节。这就意味着颜色取值范围是0到255。通道之间不同的组合可以产生不同的颜色。当所有的通道都为 0 时颜色为黑色。当他们都为 255 时颜色为白色。其他的颜色在两者之间。通过以相同的缩放因子同时缩放三个颜色通道的值,我们可以得到相同的颜色,只不过其明暗度不一样(取决于缩放因子)

当白光接触物体表面,反射的光仅仅是物体表面的颜色。反射光可能会比物体本来的颜色亮或者暗一点,这取决于光源的强度,不过还是相同的基色。如果光源是纯粹的红色(255,0,0),反射光只能是红色中的某一类型。这是因为纯红光没有绿色和蓝色

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个基于OpenGL的旋转茶壶的代码,包含了环境: ```c++ #include <GL/glut.h> #include <cmath> // 定义三维向量结构体 struct Vector3 { GLfloat x, y, z; }; // 法向量计算函数 void calculateNormal(Vector3 p1, Vector3 p2, Vector3 p3, Vector3& normal) { Vector3 v1, v2; v1.x = p2.x - p1.x; v1.y = p2.y - p1.y; v1.z = p2.z - p1.z; v2.x = p3.x - p1.x; v2.y = p3.y - p1.y; v2.z = p3.z - p1.z; normal.x = v1.y * v2.z - v1.z * v2.y; normal.y = v1.z * v2.x - v1.x * v2.z; normal.z = v1.x * v2.y - v1.y * v2.x; } void display() { static GLfloat angle = 0.0f; // 设置源位置 GLfloat lightPosition[] = { 0.0f, 0.0f, 1.0f, 0.0f }; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // 设置相机位置 gluLookAt(0.0f, 0.0f, 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); // 设置旋转角度 glRotatef(angle, 1.0f, 1.0f, 1.0f); // 绘制茶壶 GLfloat ambient[] = { 0.0f, 0.0f, 1.0f, 1.0f }; GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat shininess[] = { 50.0f }; glMaterialfv(GL_FRONT, GL_AMBIENT, ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, specular); glMaterialfv(GL_FRONT, GL_SHININESS, shininess); glutSolidTeapot(2.0f); // 开启照 glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // 设置源参数 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition); // 设置环境 GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight); // 绘制法向量 glColor3f(1.0f, 0.0f, 0.0f); glBegin(GL_LINES); for (int i = 0; i < 325; i += 3) { Vector3 p1, p2, p3, normal; p1.x = glutSolidTeapot_data[i]; p1.y = glutSolidTeapot_data[i + 1]; p1.z = glutSolidTeapot_data[i + 2]; p2.x = glutSolidTeapot_data[i + 3]; p2.y = glutSolidTeapot_data[i + 4]; p2.z = glutSolidTeapot_data[i + 5]; p3.x = glutSolidTeapot_data[i + 6]; p3.y = glutSolidTeapot_data[i + 7]; p3.z = glutSolidTeapot_data[i + 8]; calculateNormal(p1, p2, p3, normal); glVertex3f(p1.x, p1.y, p1.z); glVertex3f(p1.x + normal.x, p1.y + normal.y, p1.z + normal.z); } glEnd(); // 关闭照 glDisable(GL_LIGHTING); // 更新旋转角度 angle += 0.5f; if (angle >= 360.0f) { angle = 0.0f; } glutSwapBuffers(); } void reshape(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, (float)width / height, 0.1f, 100.0f); } void init() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(640, 480); glutCreateWindow("Rotating Teapot with Lighting"); glutDisplayFunc(display); glutReshapeFunc(reshape); init(); glutMainLoop(); return 0; } ``` 注:该代码使用了OpenGL的固定函数管线,不过仍然可以用现代OpenGL的着色器来实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值