Skip to content

Commit

Permalink
update opengl part
Browse files Browse the repository at this point in the history
  • Loading branch information
CharonChui committed Apr 27, 2024
1 parent a7cd783 commit d8b28c6
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 2 deletions.
58 changes: 58 additions & 0 deletions VideoDevelopment/OpenGL/13.实例化.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
## 13.实例化

实例化(instancing)提供了一种机制,可以只用一个C++/OpenGL调用就告诉显卡渲染一个对象的多个副本。这可以带来显著的性能优势,特别是在绘制有数千甚至数百万个对象时,例如渲染在场地中的许多花朵。

实例化最常见的应用就是做一些粒子效果,例如一些烟花的效果。。


在渲染多个对象时,OpenGL使用Z-buffer算法来进行隐藏面消除。通常情况下,通过选择最接近相机的相应片段的颜色作为像素的颜色,这种方法可决定哪些物体的曲面可见并呈现到屏幕,而位于其他物体后面的曲面不应该被渲染。
然而,有时候场景中的两个物体表面重叠并位于重合的平面中,这使得深度缓冲区算法难以确定应该渲染两个表面中的哪一个(因为两者都不“最接近”相机)。发生这种情况时,浮点舍入误差可能会导致渲染表面的某些部分使用其中一个对象的颜色,而其他部分则使用另一个对象的颜色。这种不自然的伪影称为Z冲突(Z-fighting)或深度冲突(depth-fighting),是渲染的片段在深度缓冲区中相互对应的像素条目上“斗争”的结果。


![image](https://github.com/CharonChui/Pictures/blob/master/opengl_z_fighting.png?raw=true)



提高渲染效率的另一种方法是利用OpenGL的背面剔除能力。当3D模型完全“闭合”时,意味着内部永远不可见(例如对于立方体和四棱锥),那么外表面的那些与观察者背离且呈一定角度的部分将始终被同一模型的其他部分遮挡。也就是说,那些背离观察者的三角形不可能被看到(无论如何它们都会在隐藏面消除的过程中被覆盖),因此没有理由栅格化或渲染它们。
我们可以使用命令glEnable(GL_CULL_FACE)要求OpenGL识别并“剔除”(不渲染)背向的三角形。我们还可以使用glDisable(GL_CULL_FACE)禁用背面剔除。默认情况下,背面剔除是关闭的,因此如果你希望OpenGL剔除背向三角形,必须手动启用它。




[上一篇: 10.GLSurfaceView+MediaPlayer播放视频](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/10.GLSurfaceView%2BMediaPlayer%E6%92%AD%E6%94%BE%E8%A7%86%E9%A2%91.md)

---

- 邮箱 :charon.chui@gmail.com
- Good Luck!































11 changes: 9 additions & 2 deletions VideoDevelopment/OpenGL/5.OpenGL ES绘制三角形.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ someOpenGLFunctionThatDrawsOurTriangle();
IntBuffer arrays = IntBuffer.allocate(1);
GLES30.glGenVertexArrays(1, arrays);
```
要想使用VAO,要做的只是使用glBindVertexArray绑定VAO。从绑定之后起,我们应该绑定和配置对应的VBO和属性指针,之后解绑VAO供之后使用。
要想使用VAO,要做的只是使用glBindVertexArray绑定VAO(glBindVertexArrays()命令的目的是将指定的VAO标记为活跃,这样生成的缓冲区就会和这个VAO相关联)。从绑定之后起,我们应该绑定和配置对应的VBO和属性指针,之后解绑VAO供之后使用。
当我们打算绘制一个物体的时候,我们只要在绘制物体前简单地把VAO绑定到希望使用的设定上就行了。这段代码应该看起来像这样:

VAO小助理偷偷帮我们记录一切:
Expand Down Expand Up @@ -272,6 +272,12 @@ Preferences -> Plugins -> 搜GLSL Support安装就可以了。

- 顶点着色器(triangle_vertex_shader.glsl)

关键字in意思是输入(input),表示这个顶点属性将会从缓冲区(C++或Java代码中的VBO、VAO等)中接收数值。
顶点属性还可以改为被声明为out,这意味着它们会将值发送到管线中的下一个阶段。

layout(location=0)称为layout修饰符。也就是我们把顶点属性和特定缓冲区关联起来的方法,这意味着这个顶点属性的识别号是0.


```glsl
// 声明着色器的版本
#version 300 es
Expand Down Expand Up @@ -445,11 +451,12 @@ public class TriangleRender implements GLSurfaceView.Renderer {
//把颜色缓冲区设置为我们预设的颜色,绘图设计到多种缓冲区类型:颜色、深度和模板。这里只是向颜色缓冲区中绘制图形
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
// glVertexAttribPointer是把顶点位置属性赋值给着色器程序
//0是上面着色器中写的vPosition的变量位置(location = 0)。意思就是绑定vertex坐标数据,然后将在vertextBuffer中的顶点数据传给vPosition变量。
// 0是上面着色器中写的vPosition的变量位置(location = 0)。意思就是绑定vertex坐标数据,然后将在vertextBuffer中的顶点数据传给vPosition变量。
// 你肯定会想,如果我在着色器中不写呢?int vposition = glGetAttribLocation(program, "vPosition");就可以获得他的属性位置了
// 第二个size是3,是因为上面我们triangleCoords声明的属性就是3位,xyz
GLES30.glVertexAttribPointer(0, 3, GLES30.GL_FLOAT, false, 3 * Float.BYTES, vertexBuffer);
//启用顶点变量,这个0也是vPosition在着色器变量中的位置,和上面一样,在着色器文件中的location=0声明的
// 也就是说由于vPosition在着色器中的位置被指定为0,因此可以简单的通过glVertexAttribPointer()函数调用中的第一个参数和在glEnableVertexAttribArray()函数调用中使用0来引用此变量
GLES30.glEnableVertexAttribArray(0);

//准备颜色数据
Expand Down
9 changes: 9 additions & 0 deletions VideoDevelopment/OpenGL/6.OpenGL ES绘制矩形及圆形.md
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,15 @@ public class CircleRender extends BaseGLSurfaceViewRenderer {
}
```


### OpenGL支持的图元


![image](https://github.com/CharonChui/Pictures/blob/master/opengl_tuyuan.png?raw=true)




[上一篇: 5.OpenGL ES绘制三角形](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/5.OpenGL%20ES%E7%BB%98%E5%88%B6%E4%B8%89%E8%A7%92%E5%BD%A2.md)
[下一篇: 7.OpenGL ES着色器语言GLSL](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/7.OpenGL%20ES%E7%9D%80%E8%89%B2%E5%99%A8%E8%AF%AD%E8%A8%80GLSL.md)

Expand Down
45 changes: 45 additions & 0 deletions VideoDevelopment/OpenGL/7.OpenGL ES着色器语言GLSL.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,14 @@ glUniform4f(vertexColorLocation, 0.0f, greenValue, 0.0f, 1.0f);
现在你知道如何设置uniform变量的值了,我们可以使用它们来渲染了。如果我们打算让颜色慢慢变化,我们就要在游戏循环的每一次迭代中(所以他会逐帧改变)更新这个uniform,否则三角形就不会改变颜色。


顶点着色器中的乘法将矩阵变换应用于顶点,将其转换为相机空间(请注意从右到左的计算顺序)。这些值被放入内置的OpenGL输出变量gl_Position中,然后继续通过管线,并由光栅着色器进行插值。
插值后的像素位置(称为片段)被发送到片段着色器(fragment shader)。回想一下,片段着色器的主要目的是设置输出像素的颜色。与顶点着色器的方式类似,片段着色器逐个处理像素,并对每个像素单独调用。


![image](https://github.com/CharonChui/Pictures/blob/master/opengl_progress_11.png?raw=true)




### GLSL的特点

Expand Down Expand Up @@ -468,6 +476,43 @@ glVertexAttribPointer函数的前几个参数比较明了。这次我们配置
同样,这次我们必须指定一个偏移量。对于每个顶点来说,位置顶点属性在前,所以它的偏移量是0。颜色属性紧随位置数据之后,所以偏移量就是Float.BYTES,用字节来计算就是12字节。


### 着色器示例

```
顶点着色器如下:
#version 430
layout (location=0) in vec3 position;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
out vec4 varyingColor;
void main(void)
{ gl_Position = proj_matrix * mv_matrix * vec4(position,1.0);
varyingColor = vec4(position,1.0) * 0.5 + vec4(0.5, 0.5, 0.5, 0.5);
}
着色器如下:
#version 430
in vec4 varyingColor;
out vec4 color;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
void main(void)
{ color = varyingColor;
}
请注意,因为颜色是从顶点着色器的顶点属性varyingColor中发出的,所以它们也由光栅着色器进行插值!
```

请注意,代码中将位置坐标乘1/2,然后加1/2,以将取值区间从[−1, +1]转换为[0, 1]。此外,由程序员定义的插值顶点属性变量名称中通常包含单词“varying”,这是一种约定俗成的做法。修改的具体位置已突出显示。




[上一篇: 6.OpenGL ES绘制矩形及圆形](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/6.OpenGL%20ES%E7%BB%98%E5%88%B6%E7%9F%A9%E5%BD%A2%E5%8F%8A%E5%9C%86%E5%BD%A2.md)
[下一篇: 8.GLES类及Matrix类](https://github.com/CharonChui/AndroidNote/blob/master/VideoDevelopment/OpenGL/8.GLES%E7%B1%BB%E5%8F%8AMatrix%E7%B1%BB.md)
Expand Down
25 changes: 25 additions & 0 deletions VideoDevelopment/OpenGL/9.OpenGL ES纹理.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ OpenGL要操作一个纹理,那么是将纹理ID装进纹理单元这个容器



纹理贴图是在栅格化的模型表面上覆盖图像的技术。它是为渲染场景添加真实感的最基本和最重要的方法之一。
纹理贴图非常重要,因此硬件也为它提供了支持,使得它具备实现实时的照片级真实感的超高性能。纹理单元是专为纹理设计的硬件组件,现代显卡通常带有数个纹理单元。
为了在OpenGL/GLSL中有效地完成纹理贴图,需要协调好以下几个不同的数据集和机制:
·用于保存纹理图像的纹理对象(在本章中我们仅考虑2D图像);
·特殊的统一采样器变量,以便顶点着色器访问纹理;
·用于保存纹理坐标的缓冲区;
·用于将纹理坐标传递给管线的顶点属性;
·显卡上的纹理单元。



### 纹理与渐变色的区别

渐变色:光栅化过程中计算出颜色值,然后在使用片段着色器的时候可以直接赋值。
Expand Down Expand Up @@ -77,6 +88,12 @@ V0(-1,0.5),V1(-1, -0.5),V2(1,-0.5),V3(1,0.5)



纹理坐标是对纹理图像(通常是2D图像)中的像素的引用。纹理图像中的像素被称为纹元(texel),以便将它们与在屏幕上呈现的像素区分开。纹理坐标用于将3D模型上的点映射到纹理中的位置。除了将它定位在3D空间中的坐标(x,y,z)之外,模型表面上的每个点还具有纹理坐标(s,t),用来指定纹理图像中的哪个纹元为它提供颜色。这样,物体的表面被按照纹理图像“涂画”。纹理在对象表面上的朝向由分配给对象顶点的纹理坐标确定。
要使用纹理贴图,必须为要添加纹理的对象中的每个顶点提供纹理坐标。OpenGL将使用这些纹理坐标,查找存储在纹理图像中的引用的纹元的颜色,来确定模型中每个栅格化像素的颜色。为了确保渲染模型中的每个像素都使用纹理图像中的适当纹元进行绘制,纹理坐标也需要被放入顶点属性中,以便由光栅着色器进行插值。





### 文件读取

Expand Down Expand Up @@ -291,6 +308,14 @@ void main() {
}
```


为了最大限度地提高性能,我们希望在硬件中执行纹理处理。这意味着片段着色器需要一种访问我们在C++/OpenGL应用程序中创建的纹理对象的方法。它的实现机制是通过一个叫作统一采样器变量的特殊GLSL工具。这是一个变量,用于指示显卡上的纹理单元,从加载的纹理对象中提取或“采样”纹元。
要实际执行纹理处理,我们需要修改片段着色器输出颜色的方式。以前,我们的片段着色器要么输出一个固定的颜色常量,要么从顶点属性获取颜色,而这次我们需要使用从顶点着色器(通过光栅着色器)接收的插值纹理坐标来对纹理对象进行采样。调用texture()函数如下:
```
in vec2 tc; // 纹理坐标
...
color = texture(samp, tc);
```


- render实现类
Expand Down

0 comments on commit d8b28c6

Please sign in to comment.