proofread chapter 05

This commit is contained in:
Mouse
2019-10-09 23:55:23 +08:00
parent 817caae81c
commit 9036e661e7
2 changed files with 36 additions and 30 deletions

View File

@@ -1,17 +1,15 @@
# 渲染补充More on Rendering # 渲染补充More on Rendering
本章中,我们将继续讨论OpenGL如何渲染物体。为了整理代码我们要创建一个名为`Mesh`的新类,把一个坐标数组作为输入创建VBO和VAO对象把VBO和VAO对象加载到显卡中 本章我们将继续讲述OpenGL如何渲染物体。为了整理代码我们要创建一个名为`Mesh`的新类,把一个位置数组作为输入,为需要加载到显卡中的模型创建VBO和VAO对象。
```java ```java
package org.lwjglb.engine.graph; package org.lwjglb.engine.graph;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL20.*;
import static org.lwjgl.opengl.GL30.*;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import static org.lwjgl.opengl.GL30.*;
public class Mesh { public class Mesh {
private final int vaoId; private final int vaoId;
@@ -66,7 +64,7 @@ public class Mesh {
} }
``` ```
我们将在`DummyGame`类中实例化`Mesh``Renderer``init`方法中删除VAO和VBO代码。在`Renderer`类的渲染方法中将接收一个`Mesh`对象来渲染。`cleanup`方法也被简化,因为`Mesh`类已经提供了一个释放VAO和VBO资源的方法。 我们将在`DummyGame`类中实例化`Mesh`然后将`Renderer``init`方法中VAO和VBO代码删除。在`Renderer`类的渲染方法中将接收一个`Mesh`对象来渲染。`cleanup`方法也被简化,因为`Mesh`类已经提供了一个释放VAO和VBO资源的方法。
```java ```java
public void render(Mesh mesh) { public void render(Mesh mesh) {
@@ -104,11 +102,11 @@ public void cleanup() {
glDrawArrays(GL_TRIANGLES, 0, mesh.getVertexCount()); glDrawArrays(GL_TRIANGLES, 0, mesh.getVertexCount());
``` ```
`Mesh`类通过将坐标数组除以3来计算顶点的数目因为我们使用XY和Z坐标。现在我们可以渲染更复杂的形状。来渲染一个正方形吧。一个正方形可以用两个三角形来组成,如图所示 `Mesh`类通过将位置数组除以3来计算顶点的数目因为我们使用XY和Z坐标。现在我们可以渲染更复杂的形状。来试试渲染一个四边形,一个四边形可以用两个三角形来组成,如图所示
![Quad coordinates](_static/05/quad_coordinates.png) ![四边形坐标](_static/05/quad_coordinates.png)
如你所看到的这两个三角形中的每一个都由三个顶点组成。第一个三角形由顶点V1、V2和V4橙色的点组成第二个三角形由顶点V4V2和V3绿色的点组成。顶点以逆时针顺序连接因此要传递的浮点数数组应该是[V1, V2, V4, V4, V2, V3]。因此,`DummyGame``init`方法将是这样的: 如你所这两个三角形中的每一个都由三个顶点组成。第一个三角形由顶点V1、V2和V4橙色的点组成第二个三角形由顶点V4V2和V3绿色的点组成。顶点以逆时针顺序连接因此要传递的浮点数数组应该是[V1, V2, V4, V4, V2, V3]。因此,`DummyGame``init`方法将是这样的:
```java ```java
@Override @Override
@@ -126,15 +124,15 @@ public void init() throws Exception {
} }
``` ```
现在你应该可以看到这样一个正方形: 现在你应该可以看到这样一个四边形:
![Quad rendered](_static/05/quad_rendered.png) ![四边形渲染](_static/05/quad_rendered.png)
我们完了吗?没有。上面的代码仍存在一些问题。我们使用了重复的坐标来表示正方形。我们传递了两次V2和V4坐标。这是个小形它可能不是什么大问题但想象一个更复杂的3D模型我们会多次重复传递坐标。记住我们使用三个浮点数表示顶点的位置稍后我们将需要更多的数据来表示纹理等。考虑到在更复杂的形状中,三角形直接共享的顶点数量可以更高,如图所示(其顶点可以在六个三角形之间共享) 我们完了吗?没有,上述代码仍存在一些问题。我们使用了重复的坐标来表示四边形,传递了两次V2和V4坐标。这是个小形,它可能不是什么大问题,但想象一个更复杂的3D模型,我们会多次重复传递坐标。记住,我们使用三个浮点数表示顶点的位置,但此后将需要更多的数据来表示纹理等。考虑到在更复杂的形状中,三角形直接共享的顶点数量甚至更高,如图所示(其顶点可以在六个三角形之间共享)
![Dolphin](_static/05/dolphin.png) ![海豚](_static/05/dolphin.png)
最后,我们需要更多的内存来储存重复的数据,这就是索引缓冲区(`Index Buffer`)发挥作用的地方。为了绘制正方我们只需要以这样的方式指定每个顶点V1, V2, V3, V4。每个顶点在数组中都有一个位置。V1在位置0上V2在位置1上等。 最后,我们需要更多的内存来储存重复的数据,这就是索引缓冲区(`Index Buffer`)大显身手的时候。为了绘制四边我们只需要以这样的方式指定每个顶点V1, V2, V3, V4。每个顶点在数组中都有一个位置。V1在位置0上V2在位置1上,等等:
| V1 | V2 | V3 | V4 | | V1 | V2 | V3 | V4 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
@@ -153,7 +151,7 @@ public Mesh(float[] positions, int[] indices) {
vertexCount = indices.length; vertexCount = indices.length;
``` ```
在创建了储存坐标的VBO之后我们需要创建另一个VBO来存索引。因此,重命名持有坐标的VBO的ID的变量名并为索引VBO`idxVboId`创建一个ID。创建VBO的过程相似但现在的类型是`GL_ELEMENT_ARRAY_BUFFER` 在创建了储存位置的VBO之后我们需要创建另一个VBO来存索引。因此,重命名储存位置的VBO的ID的变量名并为索引VBO`idxVboId`创建一个ID。创建VBO的过程相似但现在的类型是`GL_ELEMENT_ARRAY_BUFFER`
```java ```java
idxVboId = glGenBuffers(); idxVboId = glGenBuffers();
@@ -164,9 +162,9 @@ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_STATIC_DRAW);
memFree(indicesBuffer); memFree(indicesBuffer);
``` ```
因为我们是在处理整数,所需要创建一个`IntBuffer`而不是一个`FloatBuffer` 因为我们是在处理整数,所需要创建一个`IntBuffer`而不是一个`FloatBuffer`
就是这样。现在VAO包含两个VBO一个储存坐标,另一个储存索引。`Mesh`类的`cleanUp`方法也必须考虑到要释放另一个VBO。 就是这样。现在VAO包含两个VBO一个储存位置,另一个储存索引。`Mesh`类的`cleanUp`方法也必须考虑到要释放另一个VBO。
```java ```java
public void cleanUp() { public void cleanUp() {
@@ -183,7 +181,7 @@ public void cleanUp() {
} }
``` ```
最后,我们需要修改`glDrawArrays`调用的方法: 最后,我们需要修改在绘制时调用的`glDrawArrays`方法:
```java ```java
glDrawArrays(GL_TRIANGLES, 0, mesh.getVertexCount()); glDrawArrays(GL_TRIANGLES, 0, mesh.getVertexCount());
@@ -196,12 +194,12 @@ glDrawElements(GL_TRIANGLES, mesh.getVertexCount(), GL_UNSIGNED_INT, 0);
``` ```
方法的参数如下: 方法的参数如下:
* mode: 指定渲染的图元类型,现在是三角形没有什么变化。 * mode: 指定渲染的图元类型,现在是三角形没有变化。
* count: 指定要渲染的顶点数。 * count: 指定要渲染的顶点数。
* type: 指定索引数据的类型现在是无符号整数型。 * type: 指定索引数据的类型现在是无符号整数型。
* indices: 指定要开始使用索引渲染的数据偏移量。 * indices: 指定要开始使用索引渲染的数据偏移量。
现在可以使用新和更有效的方法来绘制复杂的模型了,仅需指定索引。 现在可以使用新和更有效的方法来绘制复杂的模型了,仅需指定索引。
```java ```java
public void init() throws Exception { public void init() throws Exception {
@@ -219,7 +217,7 @@ public void init() throws Exception {
} }
``` ```
现在示例代码加颜色吧。我们把另一组浮点数传递给`Mesh`类,它储存了正方形中每个顶点的颜色。 现在示例代码加颜色吧。我们把另一组浮点数传递给`Mesh`类,它储存了四边形中每个顶点的颜色。
```java ```java
public Mesh(float[] positions, float[] colours, int[] indices) { public Mesh(float[] positions, float[] colours, int[] indices) {
@@ -238,9 +236,9 @@ memFree(colourBuffer);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 0); glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 0);
``` ```
请注意`glVertexAttribPointer`方法的调用第一个参数现在是“1”这是着色器望数据的位置。当然因为增加了一个VBO所以我们需要在`cleanUp`方法中释放它。 请注意`glVertexAttribPointer`方法的调用第一个参数现在是“1”这是着色器望数据的位置。当然因为增加了一个VBO所以我们需要在`cleanUp`方法中释放它。
下一步是修改着色器。顶点着色器现在需要两个参数坐标位置0和颜色位置1。顶点着色器将只输出接收到的颜色因此这可以由片元着色器处理。 接下来是修改着色器。顶点着色器现在需要两个参数坐标位置0和颜色位置1。顶点着色器将只输出接收到的颜色以便片元着色器可以对其进行处理。
```glsl ```glsl
#version 330 #version 330
@@ -257,7 +255,7 @@ void main()
} }
``` ```
现在,片元着色器输入由顶点着色器处理的颜色,并使用它来生成颜色。 现在,片元着色器接收由顶点着色器处理的颜色,并使用它来生成颜色。
```glsl ```glsl
#version 330 #version 330
@@ -271,7 +269,7 @@ void main()
} }
``` ```
最后要做的是修改渲染代码,使其使用第二个数据数组: 最后要做的是修改渲染代码使用第二个数据数组:
```java ```java
public void render(Window window, Mesh mesh) { public void render(Window window, Mesh mesh) {
@@ -284,7 +282,7 @@ public void render(Window window, Mesh mesh) {
shaderProgram.bind(); shaderProgram.bind();
// Draw the mesh // 绘制网格
glBindVertexArray(mesh.getVaoId()); glBindVertexArray(mesh.getVaoId());
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
@@ -292,7 +290,7 @@ public void render(Window window, Mesh mesh) {
// ... // ...
``` ```
你可以看到,在渲染过程中我们需要启用位于位置1的VAO属性。现在可以把颜色传递`Mesh`类,以便给正方形添加颜色。 在渲染过程中,你可以看到我们需要启用位于位置1的VAO属性。现在可以将如下所示颜色数组传`Mesh`类,给四边形添加颜色。
```java ```java
float[] colours = new float[]{ float[] colours = new float[]{
@@ -303,7 +301,7 @@ float[] colours = new float[]{
}; };
``` ```
然后会得到这样一个色彩鲜艳的正方形。 然后会得到一个色彩鲜艳的四边形。
![Coloured quad](_static/05/coloured_quad.png) ![色彩鲜艳的四边形](_static/05/coloured_quad.png)

View File

@@ -28,6 +28,8 @@
**几何处理阶段Geometry Processing** 图形管线阶段之一,此阶段将由顶点着色器变换的顶点连接成三角形。 **几何处理阶段Geometry Processing** 图形管线阶段之一,此阶段将由顶点着色器变换的顶点连接成三角形。
**三角形Triangle** 显卡的基本工作单元之一,最简单的二维几何形状。
**光栅化Rasterization** 图形管线阶段之一,此阶段将几何处理阶段生成的三角形剪辑并将其转换为像素大小的片元。 **光栅化Rasterization** 图形管线阶段之一,此阶段将几何处理阶段生成的三角形剪辑并将其转换为像素大小的片元。
**片元处理阶段Fragment Processing** 图形管线阶段之一,生成写入到帧缓冲区的像素的最终颜色。 **片元处理阶段Fragment Processing** 图形管线阶段之一,生成写入到帧缓冲区的像素的最终颜色。
@@ -45,3 +47,9 @@
**顶点缓冲对象Vertex Buffer ObjectVBO** 显存中存储顶点或其他数据的内存缓冲区。 **顶点缓冲对象Vertex Buffer ObjectVBO** 显存中存储顶点或其他数据的内存缓冲区。
**顶点数组对象Vertex Array ObjectVAO** 用于储存一个或多个顶点缓冲对象的对象,便于使用显卡中的储存的数据。 **顶点数组对象Vertex Array ObjectVAO** 用于储存一个或多个顶点缓冲对象的对象,便于使用显卡中的储存的数据。
**四边形Quad** 可由两个三角形组成的几何形状,由四个顶点组成。
**网格Mesh** 游戏开发中常见概念之一通常用于包装顶点数组对象VAO储存模型的位置、顶点索引、颜色等数据。
**索引缓冲区Index Buffer** 用于指定顶点绘制顺序的缓冲区。