mirror of
https://github.com/LearnOpenGL-CN/LearnOpenGL-CN.git
synced 2025-08-23 04:35:28 +08:00
05-01, fix #108, update readme
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
原文 | [OpenGL](http://learnopengl.com/#!Getting-started/OpenGL)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | gjy_1992, Meow J
|
||||
翻译 | gjy_1992, Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Creating a window](http://learnopengl.com/#!Getting-started/Creating-a-window)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | gjy_1992, Meow J
|
||||
翻译 | gjy_1992, Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
!!! note "译注"
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Hello Window](http://learnopengl.com/#!Getting-started/Hello-Window)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Geequlim, Meow J
|
||||
翻译 | Geequlim, Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
让我们试试能不能让GLFW正常工作。首先,新建一个`.cpp`文件,然后把下面的代码粘贴到该文件的最前面。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Hello Triangle](http://www.learnopengl.com/#!Getting-started/Hello-Triangle)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [Django](http://bullteacher.com/), Meow J, Geequlim
|
||||
翻译 | [Django](http://bullteacher.com/), Krasjet, Geequlim
|
||||
校对 | 暂未校对
|
||||
|
||||
!!! note "译注"
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Shaders](http://learnopengl.com/#!Getting-started/Shaders)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [Django](http://bullteacher.com/), Meow J, Geequlim
|
||||
翻译 | [Django](http://bullteacher.com/), Krasjet, Geequlim
|
||||
校对 | 暂未校对
|
||||
|
||||
在[Hello Triangle](04 Hello Triangle.md)教程中提到,着色器(Shader)是运行在GPU上的小程序。这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说,着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Textures](http://learnopengl.com/#!Getting-started/Textures)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [Django](http://bullteacher.com/), Meow J, Geequlim, [BLumia](https://github.com/blumia/)
|
||||
翻译 | [Django](http://bullteacher.com/), Krasjet, Geequlim, [BLumia](https://github.com/blumia/)
|
||||
校对 | 暂未校对
|
||||
|
||||
!!! note "译注"
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Transformations](http://learnopengl.com/#!Getting-started/Transformations)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Django, Meow J, [BLumia](https://github.com/blumia/)
|
||||
翻译 | Django, Krasjet, [BLumia](https://github.com/blumia/)
|
||||
校对 | 暂未校对
|
||||
|
||||
尽管我们现在已经知道了如何创建一个物体、着色、加入纹理,给它们一些细节的表现,但因为它们都还是静态的物体,仍是不够有趣。我们可以尝试着在每一帧改变物体的顶点并且重配置缓冲区从而使它们移动,但这太繁琐了,而且会消耗很多的处理时间。我们现在有一个更好的解决方案,使用(多个)<def>矩阵</def>(Matrix)对象可以更好的<def>变换</def>(Transform)一个物体。当然,这并不是说我们会去讨论武术和数字虚拟世界(译注:Matrix同样也是电影「黑客帝国」的英文名,电影中人类生活在数字虚拟世界,主角会武术)。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Coordinate Systems](http://learnopengl.com/#!Getting-started/Coordinate-Systems)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | linkoln, Geequlim, Meow J, [BLumia](https://github.com/blumia/)
|
||||
翻译 | linkoln, Geequlim, Krasjet, [BLumia](https://github.com/blumia/)
|
||||
校对 | 暂未校对
|
||||
|
||||
在上一个教程中,我们学习了如何有效地利用矩阵的变换来对所有顶点进行变换。OpenGL希望在每次顶点着色器运行后,我们可见的所有顶点都为标准化设备坐标(Normalized Device Coordinate, NDC)。也就是说,每个顶点的**x**,**y**,**z**坐标都应该在**-1.0**到**1.0**之间,超出这个坐标范围的顶点都将不可见。我们通常会自己设定一个坐标的范围,之后再在顶点着色器中将这些坐标变换为标准化设备坐标。然后将这些标准化设备坐标传入光栅器(Rasterizer),将它们变换为屏幕上的二维坐标或像素。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Camera](http://learnopengl.com/#!Getting-started/Camera)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [Django](http://bullteacher.com/), Meow J, Geequlim, [BLumia](https://github.com/blumia/)
|
||||
翻译 | [Django](http://bullteacher.com/), Krasjet, Geequlim, [BLumia](https://github.com/blumia/)
|
||||
校对 | 暂未校对
|
||||
|
||||
前面的教程中我们讨论了观察矩阵以及如何使用观察矩阵移动场景(我们向后移动了一点)。OpenGL本身没有**摄像机**(Camera)的概念,但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,产生一种**我们**在移动的感觉,而不是场景在移动。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Review](https://learnopengl.com/#!Getting-started/Review)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | Geequlim
|
||||
|
||||
恭喜您完成了本章的学习,至此为止你应该能够创建一个窗口,创建并且编译着色器,通过缓冲对象或者uniform发送顶点数据,绘制物体,使用纹理,理解向量和矩阵,并且可以综合上述知识创建一个3D场景并可以通过摄像机来移动。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Colors](http://learnopengl.com/#!Lighting/Colors)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [Geequlim](http://geequlim.com/), Meow J
|
||||
翻译 | [Geequlim](http://geequlim.com/), Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
在前面的教程中我们已经简要提到过该如何在OpenGL中使用颜色(Color),但是我们至今所接触到的都是很浅层的知识。本节我们将会更深入地讨论什么是颜色,并且还会为接下来的光照(Lighting)教程创建一个场景。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Basic Lighting](http://learnopengl.com/#!Lighting/Basic-Lighting)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [Django](http://bullteacher.com/), Meow J, Geequlim, [BLumia](https://github.com/blumia/)
|
||||
翻译 | [Django](http://bullteacher.com/), Krasjet, Geequlim, [BLumia](https://github.com/blumia/)
|
||||
校对 | 暂未校对
|
||||
|
||||
现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是我们有限的计算能力所无法模拟的。因此OpenGL的光照使用的是简化的模型,对现实的情况进行近似,这样处理起来会更容易一些,而且看起来也差不多一样。这些光照模型都是基于我们对光的物理特性的理解。其中一个模型被称为<def>冯氏光照模型</def>(Phong Lighting Model)。冯氏光照模型的主要结构由3个分量组成:环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。下面这张图展示了这些光照分量看起来的样子:
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Materials](http://learnopengl.com/#!Lighting/Materials)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
在现实世界里,每个物体会对光产生不同的反应。比如说,钢看起来通常会比陶瓷花瓶更闪闪发光,木头箱子也不会像钢制箱子那样对光产生很强的反射。每个物体对镜面高光也有不同的反应。有些物体反射光的时候不会有太多的散射(Scatter),因而产生一个较小的高光点,而有些物体则会散射很多,产生一个有着更大半径的高光点。如果我们想要在OpenGL中模拟多种类型的物体,我们必须为每个物体分别定义一个<def>材质</def>(Material)属性。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Lighting maps](http://learnopengl.com/#!Lighting/Lighting-maps)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
在[上一节](03 Materials.md)中,我们讨论了让每个物体都拥有自己独特的材质从而对光照做出不同的反应的方法。这样子能够很容易在一个光照的场景中给每个物体一个独特的外观,但是这仍不能对一个物体的视觉输出提供足够多的灵活性。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Light casters](http://www.learnopengl.com/#!Lighting/Light-casters)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
我们目前使用的光照都来自于空间中的一个点。它能给我们不错的效果,但现实世界中,我们有很多种类的光照,每种的表现都不同。将光**投射**(Cast)到物体的光源叫做<def>投光物</def>(Light Caster)。在这一节中,我们将会讨论几种不同类型的投光物。学会模拟不同种类的光源是又一个能够进一步丰富场景的工具。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Multiple lights](http://learnopengl.com/#!Lighting/Multiple-lights)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [Geequlim](http://geequlim.com), Meow J
|
||||
翻译 | [Geequlim](http://geequlim.com), Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
我们在前面的教程中已经学习了许多关于OpenGL中光照的知识,其中包括冯氏着色(Phong Shading)、材质(Material)、光照贴图(Lighting Map)以及不同种类的投光物(Light Caster)。在这一节中,我们将结合之前学过的所有知识,创建一个包含六个光源的场景。我们将模拟一个类似太阳的定向光(Directional Light)光源,四个分散在场景中的点光源(Point Light),以及一个手电筒(Flashlight)。
|
||||
|
@@ -3,8 +3,8 @@
|
||||
原文 | [Review](http://learnopengl.com/#!Lighting/Review)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
校对 | [Geequlim](http://geequlim.com), Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | [Geequlim](http://geequlim.com), Krasjet
|
||||
|
||||
恭喜您已经学习到了这个地方!辛苦啦!不知道你有没有注意到,总的来说我们在学习光照教程的时候关于OpenGL本身并没有什么新东西,除了想访问uniform数组这样细枝末节的知识。目前为止的所有教程都是关于使用一些技巧或者公式来操作着色器,达到真实的光照效果。这再一次想你展示了着色器的威力。着色器是非常灵活的,你也亲眼见证了我们仅仅使用一些3D向量和可配置的变量就能够创造出惊人的图像这一点。
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Assimp](http://learnopengl.com/#!Model-Loading/Assimp)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Cocoonshu, Meow J, [Geequlim](http://geequlim.com)
|
||||
翻译 | Cocoonshu, Krasjet, [Geequlim](http://geequlim.com)
|
||||
校对 | 暂未校对
|
||||
|
||||
到目前为止的所有场景中,我们一直都在滥用我们的箱子朋友,但时间久了甚至是我们最好的朋友也会感到无聊。在日常的图形程序中,通常都会使用非常复杂且好玩的模型,它们比静态的箱子要好看多了。然而,和箱子对象不同,我们不太能够对像是房子、汽车或者人形角色这样的复杂形状手工定义所有的顶点、法线和纹理坐标。我们想要的是将这些模型(Model)**导入**(Import)到程序当中。模型通常都由3D艺术家在[Blender](http://www.blender.org/)、[3DS Max](http://www.autodesk.nl/products/3ds-max/overview)或者[Maya](http://www.autodesk.com/products/autodesk-maya/overview)这样的工具中精心制作。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Mesh](http://learnopengl.com/#!Model-Loading/Mesh)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
通过使用Assimp,我们可以加载不同的模型到程序中,但是载入后它们都被储存为Assimp的数据结构。我们最终仍要将这些数据转换为OpenGL能够理解的格式,这样才能渲染这个物体。我们从上一节中学到,网格(Mesh)代表的是单个的可绘制实体,我们现在先来定义一个我们自己的网格类。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Model](http://learnopengl.com/#!Model-Loading/Model)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
现在是时候接触Assimp并创建实际的加载和转换代码了。这个教程的目标是创建另一个类来完整地表示一个模型,或者说是包含多个网格,甚至是多个物体的模型。一个包含木制阳台、塔楼、甚至游泳池的房子可能仍会被加载为一个模型。我们会使用Assimp来加载模型,并将它转换(Translate)至多个在[上一节](02 Mesh.md)中创建的<var>Mesh</var>对象。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Depth testing](http://learnopengl.com/#!Advanced-OpenGL/Depth-testing)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
在[坐标系统](../01 Getting started/08 Coordinate Systems.md)小节中,我们渲染了一个3D箱子,并且运用了<def>深度缓冲</def>(Depth Buffer)来防止被阻挡的面渲染到其它面的前面。在这一节中,我们将会更加深入地讨论这些储存在深度缓冲(或z缓冲(z-buffer))中的<def>深度值</def>(Depth Value),以及它们是如何确定一个片段是处于其它片段后方的。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Stencil testing](http://learnopengl.com/#!Advanced-OpenGL/Stencil-testing)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
当片段着色器处理完一个片段之后,<def>模板测试</def>(Stencil Test)会开始执行,和深度测试一样,它也可能会丢弃片段。接下来,被保留的片段会进入深度测试,它可能会丢弃更多的片段。模板测试是根据又一个缓冲来进行的,它叫做<def>模板缓冲</def>(Stencil Buffer),我们可以在渲染的时候更新它来获得一些很有意思的效果。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Blending](http://learnopengl.com/#!Advanced-OpenGL/Blending)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J, [Django](http://bullteacher.com/)
|
||||
翻译 | Krasjet, [Django](http://bullteacher.com/)
|
||||
校对 | 暂无校对
|
||||
|
||||
OpenGL中,<def>混合</def>(Blending)通常是实现物体<def>透明度</def>(Transparency)的一种技术。透明就是说一个物体(或者其中的一部分)不是纯色(Solid Color)的,它的颜色是物体本身的颜色和它背后其它物体的颜色的不同强度结合。一个有色玻璃窗是一个透明的物体,玻璃有它自己的颜色,但它最终的颜色还包含了玻璃之后所有物体的颜色。这也是混合这一名字的出处,我们<def>混合</def>(Blend)(不同物体的)多种颜色为一种颜色。所以透明度能让我们看穿物体。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Face culling](http://learnopengl.com/#!Advanced-OpenGL/Face-culling)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
尝试在脑子中想象一个3D立方体,数数你从任意方向最多能同时看到几个面。如果你的想象力不是过于丰富了,你应该能得出最大的面数是3。你可以从任意位置和任意方向看向这个球体,但你永远不能看到3个以上的面。所以我们为什么要浪费时间绘制我们不能看见的那3个面呢?如果我们能够以某种方式丢弃这几个看不见的面,我们能省下超过50%的片段着色器执行数!
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Framebuffers](http://learnopengl.com/#!Advanced-OpenGL/Framebuffers)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
到目前为止,我们已经使用了很多屏幕缓冲了:用于写入颜色值的颜色缓冲、用于写入深度信息的深度缓冲和允许我们根据一些条件丢弃特定片段的模板缓冲。这些缓冲结合起来叫做<def>帧缓冲</def>(Framebuffer),它被储存在内存中。OpenGL允许我们定义我们自己的帧缓冲,也就是说我们能够定义我们自己的颜色缓冲,甚至是深度缓冲和模板缓冲。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Cubemaps](http://learnopengl.com/#!Advanced-OpenGL/Cubemaps)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
我们已经使用2D纹理很长时间了,但除此之外仍有更多的纹理类型等着我们探索。在本节中,我们将讨论的是将多个纹理组合起来映射到一张纹理上的一种纹理类型:<def>立方体贴图</def>(Cube Map)。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Advanced Data](http://learnopengl.com/#!Advanced-OpenGL/Advanced-Data)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
我们在OpenGL中大量使用缓冲来储存数据已经有很长时间了。操作缓冲其实还有更有意思的方式,而且使用纹理将大量数据传入着色器也有更有趣的方法。这一节中,我们将讨论一些更有意思的缓冲函数,以及我们该如何使用纹理对象来储存大量的数据(纹理的部分还没有完成)。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Advanced GLSL](http://learnopengl.com/#!Advanced-OpenGL/Advanced-GLSL)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
这一小节并不会向你展示非常先进非常酷的新特性,也不会对场景的视觉质量有显著的提高。但是,这一节会或多或少涉及GLSL的一些有趣的地方以及一些很棒的技巧,它们可能在今后会帮助到你。简单来说,它们就是在组合使用OpenGL和GLSL创建程序时的一些**最好要知道的东西**,和一些**会让你生活更加轻松的特性**。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Geometry Shader](http://learnopengl.com/#!Advanced-OpenGL/Geometry-Shader)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
在顶点和片段着色器之间有一个可选的<def>几何着色器</def>(Geometry Shader),几何着色器的输入是一个图元(如点或三角形)的一组顶点。几何着色器可以在顶点发送到下一着色器阶段之前对它们随意变换。然而,几何着色器最有趣的地方在于,它能够将(这一组)顶点变换为完全不同的图元,并且还能生成比原来更多的顶点。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Instancing](http://learnopengl.com/#!Advanced-OpenGL/Instancing)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
假设你有一个绘制了很多模型的场景,而大部分的模型包含的是同一组顶点数据,只不过进行的是不同的世界空间变换。想象一个充满草的场景:每根草都是一个包含几个三角形的小模型。你可能会需要绘制很多根草,最终在每帧中你可能会需要渲染上千或者上万根草。因为每一根草仅仅是由几个三角形构成,渲染几乎是瞬间完成的,但上千个渲染函数调用却会极大地影响性能。
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Anti Aliasing](http://learnopengl.com/#!Advanced-OpenGL/Anti-Aliasing)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J, [Django](http://bullteacher.com/)
|
||||
翻译 | Krasjet, [Django](http://bullteacher.com/)
|
||||
校对 | 暂未校对
|
||||
|
||||
在学习渲染的旅途中,你可能会时不时遇到模型边缘有锯齿的情况。这些<def>锯齿边缘</def>(Jagged Edges)的产生和光栅器将顶点数据转化为片段的方式有关。在下面的例子中,你可以看到,我们只是绘制了一个简单的立方体,你就能注意到它存在锯齿边缘了:
|
||||
|
@@ -3,38 +3,35 @@
|
||||
原文 | [Advanced Lighting](http://learnopengl.com/#!Advanced-Lighting/Advanced-Lighting)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [Django](http://bullteacher.com/)
|
||||
校对 | gjy_1992
|
||||
翻译 | Krasjet
|
||||
校对 | 暂未校对
|
||||
|
||||
!!! note
|
||||
|
||||
本节暂未进行完全的重写,错误可能会很多。如果可能的话,请对照原文进行阅读。如果有报告本节的错误,将会延迟至重写之后进行处理。
|
||||
|
||||
在光照教程中,我们简单的介绍了Phong光照模型,它给我们的场景带来的基本的现实感。Phong模型看起来还不错,但本章我们把重点放在一些细微差别上。
|
||||
在[光照](../02 Lighting/02 Basic Lighting.md)小节中,我们简单地介绍了冯氏光照模型,它让我们的场景有了一定的真实感。虽然冯氏模型看起来已经很不错了,但是使用它的时候仍然存在一些细节问题,我们将在这一节里讨论它们。
|
||||
|
||||
## Blinn-Phong
|
||||
|
||||
Phong光照很棒,而且性能较高,但是它的镜面反射在某些条件下会失效,特别是当发光值属性低的时候,对应一个非常大的粗糙的镜面区域。下面的图片展示了,当我们使用镜面的发光值为1.0时,一个带纹理地板的效果:
|
||||
冯氏光照不仅对真实光照有很好的近似,而且性能也很高。但是它的镜面反射会在一些情况下出现问题,特别是物体反光度很低时,会导致大片(粗糙的)高光区域。下面这张图展示了当反光度为1.0时地板会出现的效果:
|
||||
|
||||

|
||||
|
||||
你可以看到,镜面区域边缘迅速减弱并截止。出现这个问题的原因是在视线向量和反射向量的角度不允许大于90度。如果大于90度的话,点乘的结果就会是负数,镜面的贡献成分就会变成0。你可能会想,这不是一个问题,因为大于90度时我们不应看到任何光,对吧?
|
||||
可以看到,在镜面高光区域的边缘出现了一道很明显的断层。出现这个问题的原因是观察向量和反射向量间的夹角不能大于90度。如果点积的结果为负数,镜面光分量会变为0.0。你可能会觉得,当光线与视线夹角大于90度时你应该不会接收到任何光才对,所以这不是什么问题。
|
||||
|
||||
错了,这只适用于漫散射部分,当法线和光源之间的角度大于90度时意味着光源在被照亮表面的下方,这样光的散射成分就会是0.0。然而,对于镜面光照,我们不会测量光源和法线之间的角度,而是测量视线和反射方向向量之间的。看看下面的两幅图:
|
||||
然而,这种想法仅仅只适用于漫反射分量。当考虑漫反射光的时候,如果法线和光源夹角大于90度,光源会处于被照表面的下方,这个时候光照的漫反射分量的确是为0.0。但是,在考虑镜面高光时,我们测量的角度并不是光源与法线的夹角,而是视线与反射光线向量的夹角。看一下下面这两张图:
|
||||
|
||||

|
||||
|
||||
现在看来问题就很明显了。左侧图片显示Phong反射的θ小于90度的情况。我们可以看到右侧图片视线和反射之间的角θ大于90度,这样镜面反射成分将会被消除。通常这也不是问题,因为视线方向距离反射方向很远,但如果我们使用一个数值较低的发光值参数的话,镜面半径就会足够大,以至于能够贡献一些镜面反射的成份了。在例子中,我们在角度大于90度时消除了这个贡献(如第一个图片所示)。
|
||||
现在问题就应该很明显了。左图中是我们熟悉的冯氏光照中的反射向量,其中$\theta$角小于90度。而右图中,视线与反射方向之间的夹角明显大于90度,这种情况下镜面光分量会变为0.0。这在大多数情况下都不是什么问题,因为观察方向离反射方向都非常远。然而,当物体的镜面光分量非常小时,它产生的镜面高光半径足以让这些相反方向的光线对亮度产生足够大的影响。在这种情况下就不能忽略它们对镜面光分量的贡献了。
|
||||
|
||||
1977年James F. Blinn引入了Blinn-Phong着色,它扩展了我们目前所使用的Phong着色。Blinn-Phong模型很大程度上和Phong是相似的,不过它稍微改进了Phong模型,使之能够克服我们所讨论到的问题。它放弃使用反射向量,而是基于我们现在所说的一个叫做半程向量(halfway vector)的向量,这是个单位向量,它在视线方向和光线方向的中间。半程向量和表面法线向量越接近,镜面反射成份就越大。
|
||||
1977年,James F. Blinn在冯氏着色模型上加以拓展,引入了<def>Blinn-Phong</def>着色模型。Blinn-Phong模型与冯氏模型非常相似,但是它对镜面光模型的处理上有一些不同,让我们能够解决之前提到的问题。Blinn-Phong模型不再依赖于反射向量,而是采用了所谓的<def>半程向量</def>(Halfway Vector),即光线与视线夹角一半方向上的一个单位向量。当半程向量与法线向量越接近时,镜面光分量就越大。
|
||||
|
||||

|
||||
|
||||
当视线方向恰好与(想象中的)反射向量对齐时,半程向量就与法线向量重合。这样观察者的视线越接近原本的反射方向,镜面反射的高光就会越强。
|
||||
当视线正好与(现在不需要的)反射向量对齐时,半程向量就会与法线完美契合。所以当观察者视线越接近于原本反射光线的方向时,镜面高光就会越强。
|
||||
|
||||
这里,你可以看到无论观察者往哪里看,半程向量和表面法线之间的夹角永远都不会超过90度(当然除了光源远远低于表面的情况)。这样会产生和Phong反射稍稍不同的结果,但这时看起来会更加可信,特别是发光值参数比较低的时候。Blinn-Phong着色模型也正是早期OpenGL固定函数输送管道(fixed function pipeline)所使用的着色模型。
|
||||
现在,不论观察者向哪个方向看,半程向量与表面法线之间的夹角都不会超过90度(除非光源在表面以下)。它产生的效果会与冯氏光照有些许不同,但是大部分情况下看起来会更自然一点,特别是低高光的区域。Blinn-Phong着色模型正是早期固定渲染管线时代时OpenGL所采用的光照模型。
|
||||
|
||||
得到半程向量很容易,我们将光的方向向量和视线向量相加,然后将结果归一化(normalize);
|
||||
获取半程向量的方法很简单,只需要将光线的方向向量和观察向量加到一起,并将结果正规化(Normalize)就可以了:
|
||||
|
||||
$$
|
||||
\(\bar{H} = \frac{\bar{L} + \bar{V}}{||\bar{L} + \bar{V}||}\)
|
||||
@@ -43,37 +40,33 @@ $$
|
||||
翻译成GLSL代码如下:
|
||||
|
||||
```c++
|
||||
vec3 lightDir = normalize(lightPos - FragPos);
|
||||
vec3 viewDir = normalize(viewPos - FragPos);
|
||||
vec3 lightDir = normalize(lightPos - FragPos);
|
||||
vec3 viewDir = normalize(viewPos - FragPos);
|
||||
vec3 halfwayDir = normalize(lightDir + viewDir);
|
||||
```
|
||||
|
||||
实际的镜面反射的计算,就成为计算表面法线和半程向量的点乘,并对其结果进行约束(大于或等于0),然后获取它们之间角度的余弦,再添加上发光值参数:
|
||||
接下来,镜面光分量的实际计算只不过是对表面法线和半程向量进行一次约束点乘(Clamped Dot Product),让点乘结果不为负,从而获取它们之间夹角的余弦值,之后我们对这个值取反光度次方:
|
||||
|
||||
```c++
|
||||
float spec = pow(max(dot(normal, halfwayDir), 0.0), shininess);
|
||||
vec3 specular = lightColor * spec;
|
||||
```
|
||||
|
||||
除了我们刚刚讨论的,Blinn-Phong没有更多的内容了。Blinn-Phong和Phong的镜面反射唯一不同之处在于,现在我们要测量法线和半程向量之间的角度,而半程向量是视线方向和反射向量之间的夹角。
|
||||
除此之外Blinn-Phong模型就没什么好说的了,Blinn-Phong与冯氏模型唯一的区别就是,Blinn-Phong测量的是法线与半程向量之间的夹角,而冯氏模型测量的是观察方向与反射向量间的夹角。
|
||||
|
||||
!!! Important
|
||||
|
||||
Blinn-Phong着色的一个附加好处是,它比Phong着色性能更高,因为我们不必计算更加复杂的反射向量了。
|
||||
|
||||
引入了半程向量来计算镜面反射后,我们再也不会遇到Phong着色的骤然截止问题了。下图展示了两种不同方式下发光值指数为0.5时镜面区域的不同效果:
|
||||
在引入半程向量之后,我们现在应该就不会再看到冯氏光照中高光断层的情况了。下面两个图片展示的是两种方法在镜面光分量为0.5时的对比:
|
||||
|
||||

|
||||
|
||||
Phong和Blinn-Phong着色之间另一个细微差别是,半程向量和表面法线之间的角度经常会比视线和反射向量之间的夹角更小。结果就是,为了获得和Phong着色相似的效果,必须把发光值参数设置的大一点。通常的经验是将其设置为Phong着色的发光值参数的2至4倍。
|
||||
除此之外,冯氏模型与Blinn-Phong模型也有一些细微的差别:半程向量与表面法线的夹角通常会小于观察与反射向量的夹角。所以,如果你想获得和冯氏着色类似的效果,就必须在使用Blinn-Phong模型时将镜面反光度设置更高一点。通常我们会选择冯氏着色时反光度分量的2到4倍。
|
||||
|
||||
下图是Phong指数为8.0和Blinn-Phong指数为32的时候,两种specular反射模型的对比:
|
||||
下面是冯氏着色反光度为8.0,Blinn-Phong着色反光度为32.0时的一个对比:
|
||||
|
||||

|
||||
|
||||
你可以看到Blinn-Phong的镜面反射成分要比Phong锐利一些。这通常需要使用一点小技巧才能获得之前你所看到的Phong着色的效果,但Blinn-Phong着色的效果比默认的Phong着色通常更加真实一些。
|
||||
你可以看到,Blinn-Phong的镜面光分量会比冯氏模型更锐利一些。为了得到与冯氏模型类似的结果,你可能会需要不断进行一些微调,但Blinn-Phong模型通常会产出更真实的结果。
|
||||
|
||||
这里我们用到了一个简单像素着色器,它可以在普通Phong反射和Blinn-Phong反射之间进行切换:
|
||||
这里,我们使用了一个简单的片段着色器,让我们能够在冯氏反射与Blinn-Phong反射间进行切换:
|
||||
|
||||
```c++
|
||||
void main()
|
||||
@@ -92,5 +85,4 @@ void main()
|
||||
}
|
||||
```
|
||||
|
||||
你可以在这里找到这个简单的[demo的源码](http://www.learnopengl.com/code_viewer.php?code=advanced-lighting/blinn_phong)以及[顶点](http://www.learnopengl.com/code_viewer.php?code=advanced-lighting/blinn_phong&type=vertex)和[片段](http://www.learnopengl.com/code_viewer.php?code=advanced-lighting/blinn_phong&type=fragment)着色器。按下b键,这个demo就会从Phong切换到Blinn-Phong光照,反之亦然。
|
||||
|
||||
你可以在[这里](https://learnopengl.com/code_viewer_gh.php?code=src/5.advanced_lighting/1.advanced_lighting/advanced_lighting.cpp)找到这个Demo的源代码。你可以按下`B`键来切换冯氏光照与Blinn-Phong光照。
|
@@ -3,7 +3,7 @@
|
||||
原文 | [HDR](http://learnopengl.com/#!Advanced-Lighting/HDR)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 暂无
|
||||
|
||||
!!! note
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Deferred Shading](http://learnopengl.com/#!Advanced-Lighting/Deferred-Shading)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | [KenLee](https://hellokenlee.github.io/)
|
||||
|
||||
!!! note
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [SSAO](http://learnopengl.com/#!Advanced-Lighting/SSAO)
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | Meow J
|
||||
翻译 | Krasjet
|
||||
校对 | 未校对
|
||||
|
||||
!!! note
|
||||
|
@@ -3,7 +3,7 @@
|
||||
原文 | [Debugging](http://learnopengl.com/#!In-Practice/Debugging)
|
||||
----- | ----
|
||||
作者 | JoeydeVries
|
||||
翻译 | [Meow J](https://github.com/Meow-J)
|
||||
翻译 | Krasjet
|
||||
校对 | 暂无
|
||||
|
||||
图形编程可以带来很多的乐趣,然而如果什么东西渲染错误,或者甚至根本就没有渲染,它同样可以给你带来大量的沮丧感!由于我们大部分时间都在与像素打交道,当出现错误的时候寻找错误的源头可能会非常困难。调试(Debug)这样的**视觉**错误与往常熟悉的CPU调试不同。我们没有一个可以用来输出文本的控制台,在GLSL代码中也不能设置断点,更没有方法检测GPU的运行状态。
|
||||
|
@@ -4,7 +4,7 @@
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | HHz(qq:1158332489)
|
||||
校对 | Meow J
|
||||
校对 | Krasjet
|
||||
|
||||
看完前面的教程之后我们已经了解了非常多的OpenGL内部工作原理,并且我们已经能够用这些知识绘制一些复杂的图形。然而,除了之前的几个技术演示之外,我们还没有真正利用OpenGL开发一个实际应用。这篇教程为OpenGL 2D游戏制作系列教程的入门篇。这个系列教程将展示我们该如何将OpenGL应用到更大,更复杂的环境中。注意这个系列教程不一定会引入新的OpenGL概念,但会或多或少地向我们展示如何将所学的概念应用到更大的程序中去。
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [ZMANT](https://github.com/Itanq)
|
||||
校对 | Meow J
|
||||
校对 | Krasjet
|
||||
|
||||
!!! note
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
---|---
|
||||
作者 | JoeyDeVires
|
||||
翻译 | [ZMANT](https://github.com/Itanq)
|
||||
校对 | Meow J
|
||||
校对 | Krasjet
|
||||
|
||||
!!! note
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
---|---
|
||||
作者 | JoeyDeVries
|
||||
翻译 | [J.moons](https://github.com/JiangMuWen)
|
||||
校对 | Meow J(初校)
|
||||
校对 | Krasjet(初校)
|
||||
|
||||
!!! note
|
||||
|
||||
|
Reference in New Issue
Block a user