OpenGL ES应用开发实践指南

第一章

GLSurfaceView的职责包括处理OpenGL中的初始化操作,配置显示设备(display)以及在后台线程中渲染。渲染是在显示设备中一个称为surface的区域完成的,这个区域也称为视口(viewport)。

(TODO:了解图示的SDK) 当surface创建或者发生变化的时候,以及要绘制一个新的帧的时候,渲染器都会被GLSurfaceView调用。

第二章

在OpenGL中只能通过点,直线和三角形来构建复杂的图形。

运行在虚拟机上的Java代码不能直接访问本地环境,而OpenGL运行在本地环境中,需要通过特殊方式进行交互。

  • JNI
  • 把Java堆分配到本地内存堆 Java API中有个特殊的类集合可以把java数据复制到本地内存中,本地内存可以被本地环境读取并且不会被垃圾回收器回收。 (TODO:了解如何回收这些本地内存)
  • 顶点着色器(vertex shader):生成每个顶点的位置,针对每个顶点执行一次。一旦最终位置确定,OpenGL就会将这些顶点组装成点,直线和三角形。
  • 片段着色器(fragment shader):为每个顶点组装成点,直线和三角形的片段生成最终的颜色,针对每个片段都会执行一次。 一旦最后的颜色生成了,OpenGL会将它们显示到一块称为frame buffer的内存块中,Android进而将其显示在屏幕上。

第三章

使用着色器

  1. 创建着色器对象

glCreateShader()将创建一个新的着色器对象。并返回一个整形值作为OpenGL对象的引用。当需要使用该对象时,只需要把这个整型值传递给OpenGL即可获得该对象。

  1. 上传着色器代码

glShaderSource()将告诉OpenGL将创建的着色器对象和传入的shader代码关联起来。

  1. 编译着色器代码

glCompileShader()将告诉OpenGL编译上传的着色器代码。

  1. 查询编译状态
int[] compileStatus = new int[1];
glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0);
复制代码
  1. 获取编译状态的Log

glGetShaderInfoLog()。

  1. 编译失败则删除着色器对象
if (compileStatus[0] == 0) {
    glDeleteShader(shaderObjectId);
    return 0;
}
复制代码
  1. 拼接着色器 OpenGL就是将顶点着色器和片段着色器拼接起来变成单个对象的程序。
int glProgramObjectId = glCreateProgram();
if (glProgramObjectId == 0) {
    return 0;
}
glAttachShader(glProgramObjectId, vertexShaderId);
glAttachShader(glProgramObjectId, fragmentShaderId);
复制代码
  1. 链接着色器
glLinkProgram(glProgramObjectId);
int[] linkStatus = new int[1];
glGetProgramiv(glProgramObjectId, GL_LINK_STATUS, linkStatus, 0);
Log.d(TAG, "linkProgram: " + glGetProgramInfoLog(glProgramObjectId));
复制代码
  1. 编译失败则删除链接对象
if (linkStatus[0] == 0) {
    glDeleteProgram(glProgramObjectId);
    return 0;
}
复制代码
  1. 验证链接程序对象
public static boolean validateProgram(int programObjectId) {
    glValidateProgram(programObjectId);

    int[] validateStatus = new int[1];
    glGetProgramiv(programObjectId, GL_VALIDATE_STATUS, validateStatus, 0);
    Log.d(TAG, "validateProgram: " + glGetProgramInfoLog(programObjectId));
    return validateStatus[0] != 0;
}
复制代码
  1. 使用链接程序对象 glUseProgram(mProgram);

  2. 定位uniform变量的位置

当OpenGL将着色器链接成一个程序的时候,实际上用了不同的位置编号把着色器中的uniform变量都关联起来,我们需要用这些位置编号给着色器发送信息。我们需要在链接成功之后查找uniform变量的位置。即使uniform变量变量同名,但是在不同的链接对象中也不同。

private static String U_COLOR = "u_Color";
private int uColorLocation;
uColorLocation = glGetUniformLocation(mProgram, U_COLOR);
复制代码

上面程序将着色器中的u_Color变量的位置信息设置给了uColorLocation变量。

  1. 定位attribute变量位置

与使用位uniform变量一样,要操作attribute变量之前需要获得它在链接程序中的位置。

private static String A_POSITION = "a_Position";
private int aPositionLocation;
aPositionLocation = glGetAttribLocation(mProgram, A_POSITION);
复制代码

上面程序将着色器中的a_Position变量的位置信息设置给了aPositionLocation变量。

  1. 关联变量与顶点数据

在找到对应变量的位置之后就需要给变量设置数据源。

mVertexData.position(0);//从开辟的内存的首位读取
//关联a_Position变量的数据源为mVertexData
glVertexAttribPointer(aPositionLocation, POSITION_COMPOMENT_COUNT, GL_FLOAT, false, 0 ,mVertexData);
复制代码

  1. 使变量的赋值生效

glEnableVertexAttribArray(aPositionLocation);

绘制着色器

//给uColorLocation对应的变量设置颜色
glUniform4f(uColorLocation, 1.0f, 1.0f, 1.0f, 1.0f);
//根据给定的形状和指定的绘制位置进行绘制
glDrawArrays(GL_TRIANGLES, 0, 6);
复制代码

坐标的映射

OpenGL会将坐标映射到[-1,1]之间:

只有在这个范围内的绘制才会被显示出来。

第四章

第五章

正交投影能够使物体不管在远处或者近处都看起来相同。可以用于将虚拟坐标变换回归一化设备坐标,实际上定义了三维坐标中的一部分,这个区域内的内容会显示在屏幕上,区域外的内容则不会显示。

平移矩阵

orthoM(float[] m, int mOffset, float left, float right, float bottom, float top, float near, float far)
调用Matrix的上面方法将会产生下面矩阵
这个正交矩阵将会把所有左右之间,上下之间,前后之间的物体归一化到设备坐标为[-1,1]的范围内,这个范围内的物体全部可见。
归一化设备坐标使用的是左手坐标,早期OpenGL使用的是右手坐标。

第六章

从着色器到屏幕的坐标变换

剪裁空间

透视除法

视口转换

当OpenGL做映射的时候,它会把从(-1,-1,-1)到(1,1,1)的范围映射到那个预留的显示窗口中。这个范围之外的内容将会被裁减。

透视投影

视锥体

对宽高比和视野进行调整

通用的投影矩阵

实用模型矩阵移动物体

选择适当的顺序

旋转操作

旋转方向

右手握拳伸出大拇指沿着正轴方向,四指的方向就是正角度。

旋转矩阵
  • 绕X旋转的矩阵
  • 绕Y旋转的矩阵
  • 绕Z旋转的矩阵

第七章

纹理

加载纹理

  1. 创建纹理对象
int[] textureObjectIds = new int[1];
glGenTextures(1, textureObjectIds, 0);//创建一个纹理对象,并将生成对象的Id保存在textureObjectIds
if (textureObjectIds[0] == 0) {
    return 0;
}
复制代码
  1. 加载位图数据并绑定纹理

BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;//需要原始的图像信息,不要压缩
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);//解码
if (bitmap == null) {
    glDeleteTextures(1, textureObjectIds, 0);//解码失败,删除纹理对象
    return 0;
}
glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);//将生成的纹理对象作为二维纹理处理
复制代码
  1. 过滤纹理
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
复制代码

4. 加载纹理到OpenGL中并返回其ID

texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);//读入bitmap位图数据并复制绑定到当前纹理对象
bitmap.recycle();
glGenerateMipmap(GL_TEXTURE_2D);//生成MIP贴图
glBindTexture(GL_TEXTURE_2D, 0);//解绑纹理
复制代码

第八章

把一个物体放到屏幕上的三种矩阵

第九章

第十二章

创建顶点缓冲区对象,然后通过glBufferData()方法将数据传送到缓冲区对象。

public static native void glBufferData(
        int target,
        int size,
        java.nio.Buffer data,
        int usage
    );
复制代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值