mirror of
https://github.com/LearnOpenGL-CN/LearnOpenGL-CN.git
synced 2025-08-23 04:35:28 +08:00
Fix error in chapter 03
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
|
||||
先来复习一点目前学到知识,考虑一个网格最少需要哪些数据。一个网格应该至少需要一组顶点,每个顶点包含一个位置向量,一个法线向量,一个纹理坐标向量。一个网格也应该包含一个索引绘制用的索引,以纹理(diffuse/specular map)形式表现的材质数据。
|
||||
|
||||
为了在OpenGL中定义一个顶点,现在我们设置有最少需求一个网格类:
|
||||
现在,为了在OpenGL中设置一个满足最低需求的网格类,我们定义一个顶点:
|
||||
|
||||
|
||||
```c++
|
||||
@@ -33,7 +33,7 @@ struct Texture
|
||||
};
|
||||
```
|
||||
|
||||
我们储存纹理的id和它的类型,比如`diffuse`纹理或者`specular`纹理。
|
||||
我们储存纹理的id和它的类型,比如漫反射贴图或者镜面贴图。
|
||||
|
||||
知道了顶点和纹理的实际表达,我们可以开始定义网格类的结构:
|
||||
|
||||
@@ -75,7 +75,7 @@ Mesh(vector<Vertex> vertices, vector<GLuint> indices, vector<Texture> textures)
|
||||
|
||||
## 初始化
|
||||
|
||||
现在我们有一大列的网格数据可用于渲染,这要感谢构造函数。我们确实需要设置合适的缓冲,通过顶点属性指针(vertex attribute pointers)定义顶点着色器layout。现在你应该对这些概念很熟悉,但是我们我们通过介绍了结构体中使用顶点数据,所以稍微有点不一样:
|
||||
现在我们有一大列的网格数据可用于渲染,这要感谢构造函数。我们确实需要设置合适的缓冲,通过顶点属性指针(vertex attribute pointers)定义顶点着色器layout。现在除了将顶点数据传入结构体以外你应该对其它概念很熟悉:
|
||||
|
||||
|
||||
```c++
|
||||
@@ -112,7 +112,7 @@ void setupMesh()
|
||||
}
|
||||
```
|
||||
|
||||
如你所想代码没什么特别不同的地方,在`Vertex`结构体的帮助下有了一些小把戏。
|
||||
这里的代码和你设想的没什么特别不同的地方,但是向`Vertex`结构体传入数据需要有一些小技巧。
|
||||
|
||||
C++的结构体有一个重要的属性,那就是在内存中它们是连续的。如果我们用结构体表示一列数据,这个结构体只包含结构体的连续的变量,它就会直接转变为一个`float`(实际上是byte)数组,我们就能用于一个数组缓冲(array buffer)中了。比如,如果我们填充一个`Vertex`结构体,它在内存中的排布等于:
|
||||
|
||||
@@ -150,7 +150,7 @@ glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
||||
|
||||
我们需要为`Mesh`类定义的最后一个函数,是它的Draw函数。在真正渲染前我们希望绑定合适的纹理,然后调用`glDrawElements`。可因为我们从一开始不知道这个网格有多少纹理以及它们应该是什么类型的,所以这件事变得很困难。所以我们该怎样在着色器中设置纹理单元和采样器呢?
|
||||
|
||||
解决这个问题,我们需要假设一个特定的名称惯例:每个`diffuse`纹理被命名为`texture_diffuseN`,每个`specular`纹理应该被命名为`texture_specularN`。N是一个从1到纹理才抢其允许使用的最大值之间的数。可以说,在一个网格中我们有3个`diffuse`纹理和2个`specular`纹理,它们的纹理采样器应该这样被调用:
|
||||
解决这个问题,我们需要假设一个特定的名称惯例:每个漫反射贴图被命名为`texture_diffuseN`,每个镜面贴图应该被命名为`texture_specularN`。N是一个从1到纹理采样器允许使用的最大值之间的数。比如说,在一个网格中我们有3个漫反射贴图和2个镜面贴图,它们的纹理采样器应该在这之后被调用:
|
||||
|
||||
|
||||
```c++
|
||||
@@ -197,7 +197,7 @@ void Draw(Shader shader)
|
||||
}
|
||||
```
|
||||
|
||||
这不是最漂亮的代码,但是这主要归咎于C++转换类型时的丑陋,比如`int`转`string`时。我们首先计算N-元素每个纹理类型,把它链接到纹理类型字符串来获取合适的uniform名。然后查找合适的采样器位置,给它位置值对应当前激活纹理单元,绑定纹理。这也是我们需要在`Draw`方法是用`shader`的原因。我们添加`material.`到作为结果的uniform名,因为我们通常把纹理储存进材质结构体(对于每个实现也许会有不同)。
|
||||
这不是最漂亮的代码,但是这部分归咎于C++转换类型时的丑陋,比如`int`转`string`时。我们首先计算N-元素每个纹理类型,把它链接到纹理类型字符串来获取合适的uniform名。然后查找合适的采样器位置,给它位置值对应当前激活纹理单元,绑定纹理。这也是我们需要在`Draw`方法是用`shader`的原因。我们添加`material.`到作为结果的uniform名,因为我们通常把纹理储存进材质结构体(对于每个实现也许会有不同)。
|
||||
|
||||
!!! Important
|
||||
|
||||
@@ -205,4 +205,4 @@ void Draw(Shader shader)
|
||||
|
||||
你可以从这里得到[Mesh类的源码](http://learnopengl.com/code_viewer.php?code=mesh&type=header)。
|
||||
|
||||
Mesh类是对我们前面的教程里讨论的很多话题的的简洁的抽象在下面的教程里,我们会创建一个模型,它用作乘放多个网格物体的容器,真正的实现Assimp的加载接口。
|
||||
Mesh类是对我们前面教程里讨论过的很多话题的简洁抽象。在下面的教程里,我们会创建一个用作盛放多个网格物体的容器模型,真正的实现Assimp的加载接口。
|
Reference in New Issue
Block a user