1
0
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:
Krasjet
2018-09-02 17:49:11 -04:00
parent e846221598
commit 3367f88807
42 changed files with 68 additions and 71 deletions

View File

@@ -8,8 +8,8 @@ learnopengl.com系列教程的中文翻译目前正在校对及翻译中。
**目前状态**
- 原文大部分代码都有改变(使用的新的库),需要从头开始重新校对(Meow J正在处理中,最重要的配置部分已经更新完毕)
- 2-4节之后都没有按照新版的格式来排版,而且错误极多,也没有统一译名,需要进行整体的修改(Meow J正在处理中,可能比较漫长)
- 原文大部分代码都有改变(使用的新的库),需要从头开始重新校对(Krasjet正在处理中,最重要的配置部分已经更新完毕)
- 5-2节之后都没有按照新版的格式来排版,而且错误极多,也没有统一译名,需要进行整体的修改(Krasjet正在处理中,可能比较漫长)
- 从头校对整体修改之后的文章(志愿者希望)
- PBL 章节和 In Practice 章节下还有几篇教程没有翻译(志愿者希望)

View File

@@ -3,7 +3,7 @@
原文 | [OpenGL](http://learnopengl.com/#!Getting-started/OpenGL)
---|---
作者 | JoeyDeVries
翻译 | gjy_1992, Meow J
翻译 | gjy_1992, Krasjet
校对 | 暂未校对

View File

@@ -3,7 +3,7 @@
原文 | [Creating a window](http://learnopengl.com/#!Getting-started/Creating-a-window)
---|---
作者 | JoeyDeVries
翻译 | gjy_1992, Meow J
翻译 | gjy_1992, Krasjet
校对 | 暂未校对
!!! note "译注"

View File

@@ -3,7 +3,7 @@
原文 | [Hello Window](http://learnopengl.com/#!Getting-started/Hello-Window)
---|---
作者 | JoeyDeVries
翻译 | Geequlim, Meow J
翻译 | Geequlim, Krasjet
校对 | 暂未校对
让我们试试能不能让GLFW正常工作。首先新建一个`.cpp`文件,然后把下面的代码粘贴到该文件的最前面。

View File

@@ -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 "译注"

View File

@@ -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上的小程序。这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序因为它们之间不能相互通信它们之间唯一的沟通只有通过输入和输出。

View File

@@ -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 "译注"

View File

@@ -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同样也是电影「黑客帝国」的英文名电影中人类生活在数字虚拟世界主角会武术

View File

@@ -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),将它们变换为屏幕上的二维坐标或像素。

View File

@@ -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)的概念,但我们可以通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机,产生一种**我们**在移动的感觉,而不是场景在移动。

View File

@@ -3,7 +3,7 @@
原文 | [Review](https://learnopengl.com/#!Getting-started/Review)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | Geequlim
恭喜您完成了本章的学习至此为止你应该能够创建一个窗口创建并且编译着色器通过缓冲对象或者uniform发送顶点数据绘制物体使用纹理理解向量和矩阵并且可以综合上述知识创建一个3D场景并可以通过摄像机来移动。

View File

@@ -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)教程创建一个场景。

View File

@@ -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)光照。下面这张图展示了这些光照分量看起来的样子:

View File

@@ -3,7 +3,7 @@
原文 | [Materials](http://learnopengl.com/#!Lighting/Materials)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
在现实世界里,每个物体会对光产生不同的反应。比如说,钢看起来通常会比陶瓷花瓶更闪闪发光,木头箱子也不会像钢制箱子那样对光产生很强的反射。每个物体对镜面高光也有不同的反应。有些物体反射光的时候不会有太多的散射(Scatter)因而产生一个较小的高光点而有些物体则会散射很多产生一个有着更大半径的高光点。如果我们想要在OpenGL中模拟多种类型的物体我们必须为每个物体分别定义一个<def>材质</def>(Material)属性。

View File

@@ -3,7 +3,7 @@
原文 | [Lighting maps](http://learnopengl.com/#!Lighting/Lighting-maps)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
在[上一节](03 Materials.md)中,我们讨论了让每个物体都拥有自己独特的材质从而对光照做出不同的反应的方法。这样子能够很容易在一个光照的场景中给每个物体一个独特的外观,但是这仍不能对一个物体的视觉输出提供足够多的灵活性。

View File

@@ -3,7 +3,7 @@
原文 | [Light casters](http://www.learnopengl.com/#!Lighting/Light-casters)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
我们目前使用的光照都来自于空间中的一个点。它能给我们不错的效果,但现实世界中,我们有很多种类的光照,每种的表现都不同。将光**投射**(Cast)到物体的光源叫做<def>投光物</def>(Light Caster)。在这一节中,我们将会讨论几种不同类型的投光物。学会模拟不同种类的光源是又一个能够进一步丰富场景的工具。

View File

@@ -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)。

View File

@@ -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向量和可配置的变量就能够创造出惊人的图像这一点。

View File

@@ -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)这样的工具中精心制作。

View File

@@ -3,7 +3,7 @@
原文 | [Mesh](http://learnopengl.com/#!Model-Loading/Mesh)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
通过使用Assimp我们可以加载不同的模型到程序中但是载入后它们都被储存为Assimp的数据结构。我们最终仍要将这些数据转换为OpenGL能够理解的格式这样才能渲染这个物体。我们从上一节中学到网格(Mesh)代表的是单个的可绘制实体,我们现在先来定义一个我们自己的网格类。

View File

@@ -3,7 +3,7 @@
原文 | [Model](http://learnopengl.com/#!Model-Loading/Model)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
现在是时候接触Assimp并创建实际的加载和转换代码了。这个教程的目标是创建另一个类来完整地表示一个模型或者说是包含多个网格甚至是多个物体的模型。一个包含木制阳台、塔楼、甚至游泳池的房子可能仍会被加载为一个模型。我们会使用Assimp来加载模型并将它转换(Translate)至多个在[上一节](02 Mesh.md)中创建的<var>Mesh</var>对象。

View File

@@ -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),以及它们是如何确定一个片段是处于其它片段后方的。

View File

@@ -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),我们可以在渲染的时候更新它来获得一些很有意思的效果。

View File

@@ -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)(不同物体的)多种颜色为一种颜色。所以透明度能让我们看穿物体。

View File

@@ -3,7 +3,7 @@
原文 | [Face culling](http://learnopengl.com/#!Advanced-OpenGL/Face-culling)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
尝试在脑子中想象一个3D立方体数数你从任意方向最多能同时看到几个面。如果你的想象力不是过于丰富了你应该能得出最大的面数是3。你可以从任意位置和任意方向看向这个球体但你永远不能看到3个以上的面。所以我们为什么要浪费时间绘制我们不能看见的那3个面呢如果我们能够以某种方式丢弃这几个看不见的面我们能省下超过50%的片段着色器执行数!

View File

@@ -3,7 +3,7 @@
原文 | [Framebuffers](http://learnopengl.com/#!Advanced-OpenGL/Framebuffers)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
到目前为止,我们已经使用了很多屏幕缓冲了:用于写入颜色值的颜色缓冲、用于写入深度信息的深度缓冲和允许我们根据一些条件丢弃特定片段的模板缓冲。这些缓冲结合起来叫做<def>帧缓冲</def>(Framebuffer)它被储存在内存中。OpenGL允许我们定义我们自己的帧缓冲也就是说我们能够定义我们自己的颜色缓冲甚至是深度缓冲和模板缓冲。

View File

@@ -3,7 +3,7 @@
原文 | [Cubemaps](http://learnopengl.com/#!Advanced-OpenGL/Cubemaps)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
我们已经使用2D纹理很长时间了但除此之外仍有更多的纹理类型等着我们探索。在本节中我们将讨论的是将多个纹理组合起来映射到一张纹理上的一种纹理类型<def>立方体贴图</def>(Cube Map)。

View File

@@ -3,7 +3,7 @@
原文 | [Advanced Data](http://learnopengl.com/#!Advanced-OpenGL/Advanced-Data)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
我们在OpenGL中大量使用缓冲来储存数据已经有很长时间了。操作缓冲其实还有更有意思的方式而且使用纹理将大量数据传入着色器也有更有趣的方法。这一节中我们将讨论一些更有意思的缓冲函数以及我们该如何使用纹理对象来储存大量的数据纹理的部分还没有完成

View File

@@ -3,7 +3,7 @@
原文 | [Advanced GLSL](http://learnopengl.com/#!Advanced-OpenGL/Advanced-GLSL)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
这一小节并不会向你展示非常先进非常酷的新特性也不会对场景的视觉质量有显著的提高。但是这一节会或多或少涉及GLSL的一些有趣的地方以及一些很棒的技巧它们可能在今后会帮助到你。简单来说它们就是在组合使用OpenGL和GLSL创建程序时的一些**最好要知道的东西**,和一些**会让你生活更加轻松的特性**。

View File

@@ -3,7 +3,7 @@
原文 | [Geometry Shader](http://learnopengl.com/#!Advanced-OpenGL/Geometry-Shader)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
在顶点和片段着色器之间有一个可选的<def>几何着色器</def>(Geometry Shader),几何着色器的输入是一个图元(如点或三角形)的一组顶点。几何着色器可以在顶点发送到下一着色器阶段之前对它们随意变换。然而,几何着色器最有趣的地方在于,它能够将(这一组)顶点变换为完全不同的图元,并且还能生成比原来更多的顶点。

View File

@@ -3,7 +3,7 @@
原文 | [Instancing](http://learnopengl.com/#!Advanced-OpenGL/Instancing)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂未校对
假设你有一个绘制了很多模型的场景,而大部分的模型包含的是同一组顶点数据,只不过进行的是不同的世界空间变换。想象一个充满草的场景:每根草都是一个包含几个三角形的小模型。你可能会需要绘制很多根草,最终在每帧中你可能会需要渲染上千或者上万根草。因为每一根草仅仅是由几个三角形构成,渲染几乎是瞬间完成的,但上千个渲染函数调用却会极大地影响性能。

View File

@@ -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)的产生和光栅器将顶点数据转化为片段的方式有关。在下面的例子中,你可以看到,我们只是绘制了一个简单的立方体,你就能注意到它存在锯齿边缘了:

View File

@@ -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时地板会出现的效果:
![](../img/05/01/advanced_lighting_phong_limit.png)
可以看到,镜面区域边缘迅速减弱并截止。出现这个问题的原因是在视线向量和反射向量的角度不允许大于90度。如果大于90度的话点乘的结果就会是负数镜面的贡献成分就会变成0。你可能会想这不是一个问题因为大于90度时我们不应看到任何光对吧
可以看到,镜面高光区域边缘出现了一道很明显的断层。出现这个问题的原因是观察向量和反射向量间的夹角不能大于90度。如果点积的结果为负数镜面光分量会变为0.0。你可能会觉得当光线与视线夹角大于90度时你应该不会接收到任何光才对所以这不是什么问题。
错了这只适用于漫散射部分当法线和光源之间的角度大于90度时意味着光源在被照表面的下方,这样光的散射成分就会是0.0。然而,对于镜面光照,我们不会测量光源法线之间的角度,而是测量视线反射方向向量之间的。看看下面的两幅图:
然而这种想法仅仅只适用于漫反射分量。当考虑漫反射光的时候如果法线和光源夹角大于90度光源会处于被照表面的下方,这个时候光照的漫反射分量的确是为0.0。但是,在考虑镜面高光时,我们测量的角度并不是光源法线的夹角,而是视线反射光线向量的夹角。看一下下面这两张图:
![](../img/05/01/advanced_lighting_over_90.png)
现在看来问题就很明显了。左侧图片显示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),即光线与视线夹角一半方向上的一个单位向量。当半程向量法线向量越接近,镜面光分量就越大。
![](../img/05/01/advanced_lighting_halfway_vector.png)
当视线方向恰好与(想象中的)反射向量对齐时,半程向量就与法线向量重合。这样观察者视线越接近原本反射方向,镜面反射的高光就会越强。
当视线正好与(现在不需要的)反射向量对齐时,半程向量就与法线完美契合。所以当观察者视线越接近原本反射光线的方向,镜面高光就会越强。
这里,你可以看到无论观察者往哪里看,半程向量表面法线之间的夹角永远都不会超过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}||}\)
@@ -48,32 +45,28 @@ 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时的对比:
![](../img/05/01/advanced_lighting_comparrison.png)
Phong和Blinn-Phong着色之间另一个细微差别是,半程向量表面法线之间的角度经常会比视线和反射向量之间的夹角更小。结果就是为了获得和Phong着色似的效果,必须把发光值参数设置的大一点。通常的经验是将其设置为Phong着色的发光值参数的24倍。
除此之外,冯氏模型与Blinn-Phong模型也有一些细微差别半程向量表面法线的夹角通常会小于观察与反射向量的夹角。所以,如果你想获得和冯氏着色似的效果,必须在使用Blinn-Phong模型时将镜面反光度设置更高一点。通常我们会选择冯氏着色时反光度分量的24倍。
图是Phong指数为8.0Blinn-Phong指数为32的时候两种specular反射模型的对比:
面是冯氏着色反光度为8.0Blinn-Phong着色反光度为32.0时的一个对比:
![](../img/05/01/advanced_lighting_comparrison2.png)
你可以看到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光照。

View File

@@ -3,7 +3,7 @@
原文 | [HDR](http://learnopengl.com/#!Advanced-Lighting/HDR)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 暂无
!!! note

View File

@@ -3,7 +3,7 @@
原文 | [Deferred Shading](http://learnopengl.com/#!Advanced-Lighting/Deferred-Shading)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | [KenLee](https://hellokenlee.github.io/)
!!! note

View File

@@ -3,7 +3,7 @@
原文 | [SSAO](http://learnopengl.com/#!Advanced-Lighting/SSAO)
---|---
作者 | JoeyDeVries
翻译 | Meow J
翻译 | Krasjet
校对 | 未校对
!!! note

View File

@@ -3,7 +3,7 @@
原文 | [Debugging](http://learnopengl.com/#!In-Practice/Debugging)
----- | ----
作者 | JoeydeVries
翻译 | [Meow J](https://github.com/Meow-J)
翻译 | Krasjet
校对 | 暂无
图形编程可以带来很多的乐趣,然而如果什么东西渲染错误,或者甚至根本就没有渲染,它同样可以给你带来大量的沮丧感!由于我们大部分时间都在与像素打交道,当出现错误的时候寻找错误的源头可能会非常困难。调试(Debug)这样的**视觉**错误与往常熟悉的CPU调试不同。我们没有一个可以用来输出文本的控制台在GLSL代码中也不能设置断点更没有方法检测GPU的运行状态。

View File

@@ -4,7 +4,7 @@
---|---
作者 | JoeyDeVries
翻译 | HHz(qq:1158332489)
校对 | Meow J
校对 | Krasjet
看完前面的教程之后我们已经了解了非常多的OpenGL内部工作原理并且我们已经能够用这些知识绘制一些复杂的图形。然而除了之前的几个技术演示之外我们还没有真正利用OpenGL开发一个实际应用。这篇教程为OpenGL 2D游戏制作系列教程的入门篇。这个系列教程将展示我们该如何将OpenGL应用到更大更复杂的环境中。注意这个系列教程不一定会引入新的OpenGL概念但会或多或少地向我们展示如何将所学的概念应用到更大的程序中去。

View File

@@ -4,7 +4,7 @@
---|---
作者 | JoeyDeVries
翻译 | [ZMANT](https://github.com/Itanq)
校对 | Meow J
校对 | Krasjet
!!! note

View File

@@ -4,7 +4,7 @@
---|---
作者 | JoeyDeVires
翻译 | [ZMANT](https://github.com/Itanq)
校对 | Meow J
校对 | Krasjet
!!! note

View File

@@ -4,7 +4,7 @@
---|---
作者 | JoeyDeVries
翻译 | [J.moons](https://github.com/JiangMuWen)
校对 | Meow J(初校)
校对 | Krasjet(初校)
!!! note

View File

@@ -430,6 +430,11 @@
- Resolve还原
- Blit位块传送
## 05-01
- Blinn-Phong ModelBlinn-Phong模型
- Halfway Vector半程向量
## 06-01
- Debugging调试