如何使用opengles 渲染管线ES 2.0 进行离屏渲染

请教关于OpenGL es 2.0离屏渲染问题。
[问题点数:40分]
请教关于OpenGL es 2.0离屏渲染问题。
[问题点数:40分]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。3862人阅读
介绍基本概念的OpenGL ES 2.0,我们首先从一个简单的例子。在这一章里,我们将展示什么是需要创建一个OpenGL ES 2.0一个三角形的项目、。我们要编写的程序是最基本的例子,一个OpenGL
ES 2.0应用程序,绘制几何。有数量的概念,我们将介绍在本章:
1.创建一个屏幕渲染表面与EGL。
2.加载片段着色器和定点。
3.创建程序的对象,附着顶点和片段着色器,连接程序对象。
4.设置窗口。
5.清除颜色缓冲。
6.渲染一个简单的例子。
7.使内容的颜色缓冲可见在EGL窗口表面。
事实证明,我们可以开始画一个三角形之前,有相当数量的步骤需要做。这个章节将涵盖的每一个步骤。在您的书中,我们补充了每个步骤的细节和进一步的文档API。我们的目的是让你运行你的第一个简单的例子,让您了解如何创建一个应用程序与OpenGL
Code Framework & &代码框架
在本书中,我们将构建一个图书馆的实用工具函数,形成一个框架有用的功能,以编写OpenGL
ES 2.0 程序。为了发展示例程序,我们有几个目标,这段代码框架:
1。它是简单的,小的,容易理解。我们希望把我们的例子在相关的OpenGL ES 2.0调用,而不是在一个大型的我们所方明的代码框架。相反,我们尽力事我们的示例程序易于读和理解。这个框架的目的是为了让你集中精力在每个示例的重要的OpenGL ES 2.0 API概念。
2。它可以移植。尽管我们开发我们的示例程序在使用微软的Windows操作系统,我们想要的样本程序容易地移植到其他操作系统和环境。此外,我们选择使用C语言而不是c++,由于不同的c++的局限在许多手持平台。我们也避免使用全局数据,由于他它不允许在许多手持平台使用。
当我们阅读本书的例子,我们引用一些新的代码框架函数。此外,你可以在附录d找到完整的代码文档。你看到的示例代码中任何函数,任何以es开头的函数是我们写的代码框架的一部分。
Where to Download the Examples & &哪里下载例子
您可以下载示例从这本书网站在www.。
这个例子都是针对运行在微软Windows XP或Vista MicrosoftWindows与桌面图形处理单元(GPU)支持OpenGL 2.0。示例程序以源代码的形式提供、 Visual Studio 2005项目的解决方案。这个例子构建和运行在AMD的OpenGL ES 2.0模拟器。一些高级在这本书的渲染例子是用RenderMonkey实现,一个材质developmenttool从AMD。这本书网站提供链接在何处downloadany所需的工具。OpenGL ES 2.0的模拟器和RenderMonkeyare都免费提供的工具。读者没有自己的Visual
Studio,可以免费获得微软Visual Studio 2008 Express Edition,在 /express/ for download。
Hello Triangle Example & &你好三角形例子
让我们看看我们的完整源代码示例项目-你好三角形,这是2 - 1中列出的例子。对于那些熟悉固定功能的桌面版本OpenGL的读者,你可能会认为这是一个一堆代码只是为了画一个简单的三角形。对于那些不熟悉的桌面OpenGL的人,你可能也会认为这是一个很多代码只是为了画一个三角形!记住,OpenGL
ES 2.0是完全基于着色器的,这意味着你在没有适当的着色加载和边框的情况下,你不能画任何图形。这意味着相比较桌面版的openGL使用固定的函数处理,你需要使用更多的需要渲染的代码。
Example 2-1Hello
Triangle Example & &
#include &esUtil.h&
typedef struct
// Handle to a program object GLuint programO
// Create a shader object, load the shader source, and // compile the shader.
GLuint LoadShader(const char *shaderSrc, GLenum type) {
// Create the shader object shader = glCreateShader(type);
if(shader == 0)
// Load the shader source glShaderSource(shader, 1, &shaderSrc, NULL);
// Compile the shader glCompileShader(shader);
// Check the compile status
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if(!compiled) {
GLint infoLen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen & 1)
char* infoLog = malloc(sizeof(char) * infoLen);
glGetShaderInfoLog(shader, infoLen, NULL, infoLog); esLogMessage(&Error compiling shader:\n%s\n&, infoLog); free(infoLog);
glDeleteShader(shader);
return 0; }
// Initialize the shader and program object //
int Init(ESContext *esContext)
UserData *userData = esContext-&userD GLbyte vShaderStr[] =
&attribute vec4 vP &void main()
& gl_Position = vP &}
GLbyte fShaderStr[] =
&void main()
& gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n& &} \n&;
GLuint vertexS GLuint fragmentS GLuint programO GL
// Load the vertex/fragment shaders
vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr); fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr);
// Create the program object programObject = glCreateProgram();
if(programObject == 0) return 0;
glAttachShader(programObject, vertexShader); glAttachShader(programObject, fragmentShader);
// Bind vPosition to attribute 0 glBindAttribLocation(programObject, 0, &vPosition&);
// Link the program glLinkProgram(programObject);
// Check the link status
glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
if(!linked)
GLint infoLen = 0;
glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen);
if(infoLen & 1)
char* infoLog = malloc(sizeof(char) * infoLen);
glGetProgramInfoLog(programObject, infoLen, NULL, infoLog); esLogMessage(&Error linking program:\n%s\n&, infoLog);
free(infoLog); }
glDeleteProgram(programObject);
return FALSE;
// Store the program object userData-&programObject = programO
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
return TRUE;
// Draw a triangle using the shader pair created in Init() //
void Draw(ESContext *esContext)
UserData *userData = esContext-&userD GLfloat vVertices[] = {0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f};
// Set the viewport
glViewport(0, 0, esContext-&width, esContext-&height);
// Clear the color buffer glClear(GL_COLOR_BUFFER_BIT);
// Use the program object glUseProgram(userData-&programObject);
// Load the vertex data
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices); glEnableVertexAttribArray(0);
glDrawArrays(GL_TRIANGLES, 0, 3);
eglSwapBuffers(esContext-&eglDisplay, esContext-&eglSurface); }
int main(int argc, char *argv[]) {
ESContext esC UserData userD
esInitialize(&esContext); esContext.userData = &userD
esCreateWindow(&esContext, &Hello Triangle&, 320, 240, ES_WINDOW_RGB);
if(!Init(&esContext)) return 0;
esRegisterDrawFunc(&esContext, Draw);
esMainLoop(&esContext);&}
Building and Running the Examples & &编译和运行例子
在这本书中所有的示例程序开发全部都在AMD’sOpenGL ES 2.0模拟器的上层运行。这个模拟器提供了一个运行EGL 1.3和OpenGL ES 2.0 api的窗口。标准GL2和EGL的头文件是被Khronos提供的,它曾经被作为模拟器的接口&&。模拟器是一个完全可以运行OpenGL
ES 2.0,这意味着在模拟器上编写的绘图代码可以无缝地在真机上运行。注意,模拟器要求您拥有一个支持桌面OpenGL 2.0 API的桌面GPU。
我们设计的代码框架,可以移植到多种平台。但是,为了这本书的所有示例都使用微软Visual Studio 2005。OpenGL ES 2.0的例子——都在以下的文件夹里:
Common/—包括&OpenGL ES 2.0框架项目,代码.
Chapter_X/—包括每章的代码。&每一章VisualStudio 2005 的启动项.
为了运行你好三角形的例子。请打开Chapter_2/Hello_Triangle/Hello_Triangle.sln&in
Visual Studio 2005这个文件。这个程序可以直接用&Visual Studio 2005执行。运行起来你可以看到如表&#的这张图片。
请注意下另外提供的简单代码。本书后面提供的很多例子用的是AMD的免费着色开发工具RenderMonkey1.80v.RenderMonkey使用在我们应该仅仅注意着色器代码的例子种。RenderMonkey对于开发着色效果提供了一个非常灵活的继承开发环境。所有后缀是.rfx的例子可以用&RenderMonkey
v1.80进行开发。&RenderMonkey v1.80IDE 使用的效果截图在Color Plate 2种可以看见。
Using the OpenGL ES 2.0 Framework & & 用openGLES 2.0框架
在你好三角形的主函数里面,你可以看见很多的调用ESutility的函数。主函数的第一件事情是声明一个 ESContext并且初始化它。
ESContext esCUserData userD
esInitialize(&esContext);esContext.userData = &userD&
这本书里的每一个例子都在做同样的事情。ESContextis包含了ES框架所需要的所有程序的必要信息,并且ES框架工具函数都会传递给它。因为是一个简单的程序,所以所有的传递都围绕这context,ES框架不需要全局变量。
许多的掌上设备平台不允许程序声明全局静态变量。例如BREW和塞班。正因如此我们避免在例子种或者在框架种在两个函数传递context的时候,代码中声明全局变量。
ESContext有一个空指针类的成员变量userData。每个程序例子将会在user data中存储应用所需要的数据。
The ESContext
has a member variable named
that is a void*.Each of the sample programs will store any of
the data that are needed forthe application in userData.
The esInitialize
function is called by thesample program to initialize the context and the ES code framework. Theother elements in the
structure are described in the header fileand are intended only to be read by the user application. Other data in theESContext
structure include information such as the window width andheight, EGL context, and callback function pointers.&
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:149613次
积分:1718
积分:1718
排名:第15811名
原创:20篇
转载:23篇
评论:21条
(1)(1)(2)(3)(1)(4)(6)(7)(2)(4)(2)(2)(7)(5)零基础开发OpenGL ES 2.0学习笔记-Android篇(一) | Imagination中文技术社区OpenGL ES 2.0 -- 制作 3D 彩色旋转三角形 - 顶点着色器
片元着色器 使用详解
最近开始关注OpenGL ES 2.0 这是真正意义上的理解的第一个3D程序 , 从零开始学习 .
一. 程序介绍
1. 样例展示
该程序打开之后会出现一个旋转的三角形, 该三角形一直绕x轴z方向旋转 如图 :
2. 程序结构
本程序中定义了四个类 : ShaderUtil , Triangle , MyTDView , MainActivity .
在Activity中加载myTDView对象, MyTDView对象中绘制Triangle 三角形图形, Triangle调用ShaderUtil加载着色脚本并创建着色程序.
四个类之间的关系 :
3. 方法介绍
(1) ShaderUtil方法
a. 加载着色器方法 : 根据着色器类型 和 着色器脚本字符串获取着色器
public static int loadShader(int shaderType , String source)
流程 : 创建着色器 -& 加载着色器脚本 -& 编译着色器 -& 获取着色器编译结果
b. 检查错误方法 : 检查每一步是否出现错误
public static void checkGLError(String op)
流程 : 循环获取错误信息, 知道出现异常将异常信息打印出来
c. 创建着色器方法 : 根据顶点着色器和片元着色器创建着色程序
public static int createProgram(String vertexSource , String fragmentSource)
流程 : 调用loadShader()加载顶点,片元着色器 -& 创建着色程序 -& 向着色程序中加载顶点,片元着色器 -& 连接程序 -& 获取链接结果
d. 获取着色脚本 : 从assets目录中的着色脚本中获取着色脚本的字符串信息
public static String loadFromAssetsFile(String fileName, Resources resources)
流程 : 打开assets输入流 -& 创建带缓冲区的输出流 -& 读取输入流信息放入缓冲区 -& 将缓冲区数据转为字符
(2)Triangle方法
二 ShaderUtils类介绍
1.安卓基本API
(1) 创建assets目录中文件的输入流
InputStream is = resources.getAssets().open(fileName);
参数 : assets目录中着色脚本的文件名;
返回值 : 着色脚本文件的输入流;
作用 : 使用该输入流可以读取着色脚本信息
(2)带缓冲区的输出流
创建一个带缓冲区的输出流, 每次读取一个字节, 注意这里字节读取用的是int类型
ByteArrayOutputStream baos = new ByteArrayOutputStream();
逐个字节读取数据, 并将读取的数据放入缓冲器中
while((ch = is.read()) != -1){
baos.write(ch);
将缓冲区中的数据转为字节数组, 并将字节数组转换为字符串
byte[] buffer = baos.toByteArray();
读写单位 : 这个输出流读取字节的单位是int, 这里要特别注意;
读取方法 : read()方法每次读取一个字节, 并返回读取到的字节;
写出方法 : write()方法将一个字节写入到ByteArrayOutputStream的缓冲区中;
导出数据 : 调用toByteArray()方法可以将缓冲区中的数据转为字节数组, 并返回这个数组;
2.着色器相关API介绍
加载着色器流程 :创建着色器 --&加载着色器脚本 --&编译着色器 --&获取着色器编译结果
(1)创建着色程器
int shader = GLES20.glCreateShader(shaderType);
参数 : 这个函数的作用根据着色器类型 , 着色器的类型有两种 , GLES20.GL_VERTEX_SHADER 顶点着色器 , GLES20.GL_FRAGMENT_SHADER 片元着色器
返回值 : 该方法返回的是着色器的引用
(2)加载着色器源代码
GLES20.glShaderSource(shader, source);
参数 : shader是着色器的引用 , 是glCreateShader()方法的返回值 ; source是着色器脚本的字符串形式 . 返回值 : 该方法没有返回值 这样就相当于将代码添加到了着色器中, 注意此时着色器还不能使用 , 还要编译之后才能使用.
(3)编译着色器
GLES20.glCompileShader(shader);
参数 : shader是着色器的引用 返回值 : 该方法没有返回值类型 执行这个方法的前提是 , 该着色器已经加载了着色器脚本字符串, 否则会编译错误
(4)获取着色器编译情况
int complied[] = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, complied, 0);
shader : 着色器引用 , 这个着色器已经加载了着色脚本字符串以及经过了编译 ;pname : GLES20.GL_COMPILE_STATUS : 获取信息类型代码 : 我们要获取编译情况 , 这里是编译状态的代码params[] : compile : 存放结果数组index : 存放结果索引 , 将编译成功的脚本数放在数组的哪个索引下 返回值 : 该方法没有返回值
(5)删除着色器
GLES20.glDeleteShader(shader);
参数 : shader 是着色器的引用 返回值 : 该方法没有返回值 如果着色器编译没有通过 , 那么就删除这个着色器
3.着色程序相关的API
创建着色程序流程 :加载顶点着色器 --&加载片元着色器 --&创建着色程序 --&将顶点着色器加入着色程序 --&将片元着色器加入着色程序 --&链接着色程序 --&获取链接着色程序结果
(1)创建OpenGL程序
int program = GLES20.glCreateProgram();
调用GLES20.glCreateProgram()方法 , 可以创建一个3D程序 , 返回程序的引用 , 如果不返回0 , 说明没有创建成功.
(2)获取OpenGL中的错误信息
GLES20.glGetError();
返回一个int类型的错误码 , 如果没有错误 , 就会返回 GLES20.GL_NO_ERROR 常量.
(3)向程序中加入着色器
GLES20.glAttachShader(program, vertextShader);
参数 : program 是调用GLES20.glCreateProgram()方法创建程序的返回值 , 这是程序的引用 . vertextShader是着色器的引用 , 注意 这个着色器是加载了着色脚本并且成功编译的着色器引用 . 返回值 : 该方法没有返回值;
(4)连接程序
GLES20.glLinkProgram(program);
参数 : 需要链接的程序的引用, 即着色程序容器的句柄; 作用 : 着色程序中存放定点着色器与片元着色器;
(5)获取链接程序结果
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
参数 : program , 程序的引用 ; GLES20.GL_LINK_STATUS , 想要获取的信息的类别; linkStatus , 存放结果的数组; index , 将结果存放的数组的下标;
作用 : 这个方法可以获取到链接程序操作是否成功, 如果结果不为1, 说明链接程序失败;
(6)删除着色程序
GLES20.glDeleteProgram(program);
参数 : 着色程序的引用; 作用 : 删除链接失败的着色程序;
package shuliang.han.
import java.io.ByteArrayOutputS
import java.io.InputS
import android.content.res.R
import android.opengl.GLES20;
import android.util.L
* 这个工具类用来加载定点着色器与片元着色器
public class ShaderUtil {
* 加载着色器方法
* ① 创建着色器
* ② 加载着色器脚本
* ③ 编译着色器
* ④ 获取着色器编译结果
* @param shaderType 着色器类型,顶点着色器(GLES20.GL_FRAGMENT_SHADER), 片元着色器(GLES20.GL_FRAGMENT_SHADER)
* @param source 着色脚本字符串
* @return 返回的是着色器的引用, 返回值可以代表加载的着色器
public static int loadShader(int shaderType , String source){
//1.创建一个着色器, 并记录所创建的着色器的id, 如果id==0, 那么创建失败
int shader = GLES20.glCreateShader(shaderType);
if(shader != 0){
//2.如果着色器创建成功, 为创建的着色器加载脚本代码
GLES20.glShaderSource(shader, source);
//3.编译已经加载脚本代码的着色器
GLES20.glCompileShader(shader);
int[] compiled = new int[1];
//4.获取着色器的编译情况, 如果结果为0, 说明编译失败
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
if(compiled[0] == 0){
Log.e(ES20_ERROR, Could not compile shader
+ shaderType + :);
Log.e(ES20_ERROR, GLES20.glGetShaderInfoLog(shader));
//编译失败的话, 删除着色器, 并显示log
GLES20.glDeleteShader(shader);
shader = 0;
* 检查每一步的操作是否正确
* 使用GLES20.glGetError()方法可以获取错误代码, 如果错误代码为0, 那么就没有错误
* @param op 具体执行的方法名, 比如执行向着色程序中加入着色器,
使glAttachShader()方法, 那么这个参数就是glAttachShader
public static void checkGLError(String op){
//错误代码不为0, 就打印错误日志, 并抛出异常
while( (error = GLES20.glGetError()) != GLES20.GL_NO_ERROR ){
Log.e(ES20_ERROR, op + : glError
throw new RuntimeException(op + : glError
* 创建着色程序
* ① 加载顶点着色器
* ② 加载片元着色器
* ③ 创建着色程序
* ④ 向着色程序中加入顶点着色器
* ⑤ 向着色程序中加入片元着色器
* ⑥ 链接程序
* ⑦ 获取链接程序结果
* @param vertexSource
定点着色器脚本字符串
* @param fragmentSource 片元着色器脚本字符串
public static int createProgram(String vertexSource , String fragmentSource){
//1. 加载顶点着色器, 返回0说明加载失败
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
if(vertexShader == 0)
//2. 加载片元着色器, 返回0说明加载失败
int fragShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
if(fragShader == 0)
//3. 创建着色程序, 返回0说明创建失败
int program = GLES20.glCreateProgram();
if(program != 0){
//4. 向着色程序中加入顶点着色器
GLES20.glAttachShader(program, vertexShader);
checkGLError(glAttachShader);
//5. 向着色程序中加入片元着色器
GLES20.glAttachShader(program, fragShader);
checkGLError(glAttachShader);
//6. 链接程序
GLES20.glLinkProgram(program);
int[] linkStatus = new int[1];
//获取链接程序结果
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
if(linkStatus[0] != GLES20.GL_TRUE){
Log.e(ES20.ERROR, 链接程序失败 : );
Log.e(ES20.ERROR, GLES20.glGetProgramInfoLog(program));
//如果链接程序失败删除程序
GLES20.glDeleteProgram(program);
program = 0;
* 从assets中加载着色脚本
* ① 打开assets目录中的文件输入流
* ② 创建带缓冲区的输出流
* ③ 逐个字节读取文件数据, 放入缓冲区
* ④ 将缓冲区中的数据转为字符串
* @param fileName assets目录中的着色脚本文件名
* @param resources 应用的资源
public static String loadFromAssetsFile(String fileName, Resources resources){
String result =
//1. 打开assets目录中读取文件的输入流, 相当于创建了一个文件的字节输入流
InputStream is = resources.getAssets().open(fileName);
int ch = 0;
//2. 创建一个带缓冲区的输出流, 每次读取一个字节, 注意这里字节读取用的是int类型
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//3. 逐个字节读取数据, 并将读取的数据放入缓冲器中
while((ch = is.read()) != -1){
baos.write(ch);
//4. 将缓冲区中的数据转为字节数组, 并将字节数组转换为字符串
byte[] buffer = baos.toByteArray();
baos.close();
is.close();
result = new String(buffer, UTF-8);
result = result.replaceAll(\r\n,
} catch (Exception e) {
e.printStackTrace();
三. Triangle 3D三角形数据
1. 顶点数据容器相关api
初始化顶点数据流程 :创建ByteBuffer对象 -&设置ByteBuffer对象顺序 -&将ByteBuffer对象转为FloatBuffer对象 -&设置FloatBuffer对象值 -&设置FloatBuffer对象起始位置
(1) 创建ByteBuffer对象
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4)
allocateDirect()方法创建ByteBuffer对象, 同时分配该字节缓冲去的大小, 注意这个对象最终要转为FloatBuffer对象, 每个float占4个字节, 一共有vertices.length个浮点数, 因此要分配vertices.length * 4 个字节大小.
(2) 设置字节缓冲区顺序
vbb.order(ByteOrder.nativeOrder());
设置字节缓冲区的顺序为本地顺序.
(3) 将字节缓冲区转为浮点缓冲区
mVertexBuffer = vbb.asFloatBuffer();
(4) 向字节缓冲区中存入数据
mColorBuffer.put(colors);
直接调用put方法, 将浮点型数组放入缓冲区.
(5)指定浮点型缓冲区起始位置
mColorBuffer.position(0);
2. 初始化着色器相关api
初始化着色器流程 :获取顶点,片元着色器 -&创建着色程序 -&从着色程序中的顶点着色器获取顶点位置,颜色,投影矩阵引用
(1) 获取着色器属性变量引用
int maPositionHandle = GLES20.glGetAttribLocation(mProgram, aPosition);
该方法从着色程序中的顶点着色器中获取属性变量(Attribute) aPosition.
(2) 获取着色器一直变量引用
float[] muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, uMVPMatrix);
该方方法从着色程序中的顶点着色器获取一致变量
3. 绘制3D图形相关api
绘制三角形流程 :
(1) 指定着色器程序
GLES20.glUseProgram(mProgram);
参数 : 着色程序的引用id 作用 : 该方法的作用是指定程序中要使用的着色器
(2) 设置旋转初始情况
Matrix.setRotateM(float[] rm, int rmOffset, float a, float x, float y, float z)
参数 : rm 变换矩阵; rmOffset 变换矩阵的索引; a 旋转角度; 剩下的三个是旋转的轴 这个方法的作用是设置旋转变化矩阵
(3) 设置位移
Matrix.translateM(float[] m, int mOffset, float x, float y, float z)
参数 : m 变换矩阵; mOffset 变换矩阵的起始位置; 剩下的三个是位移向量.
(4) 设置旋转矩阵
Matrix.rotateM(float[] m, int mOffset, float a, float x, float y, float z)
参数 : m 变换矩阵; mOffset 变换矩阵起始位置; a 旋转的角度; 剩下的三个参数是旋转的轴;
(5) 应用投影和视口变换
GLES20.glUniformMatrix4fv(int location, int count, boolean transpose, float[] value, int offset)
(6) 将顶点数据传进渲染管线
GLES20.glVertexAttribPointer(
maPositionHandle,
GLES20.GL_FLOAT,
mVertexBuffer
参数 : 顶点位置数据引用 几个一组 单位 false 个数 数据缓冲区.
(7) 启用传入的数据
GLES20.glEnableVertexAttribArray(maPositionHandle);
参数 : 从着色程序中获取的数据引用 作用 : 将刚才传入渲染管线的数据启用;
(8) 执行绘制方法
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
该方法绘制三角形
4. 矩阵计算相关api
Matrix.multiplyMM(float[] result, int resultOffset, float[] lhs, int lhsOffset, float[] rhs, int rhsOffset)
参数 : 三组, 一个矩阵带着一个起始位置. 作用 : 计算投影变换矩阵, 将前两个矩阵计算结果存入第三个矩阵;
package shuliang.han.
import java.nio.ByteB
import java.nio.ByteO
import java.nio.FloatB
import android.opengl.GLES20;
import android.opengl.M
public class Triangle {
public static float[] mProjMatrix = new float[16]; //4 * 4 投影矩阵
public static float[] mVMatrix = new float[16];
//摄影机位置朝向参数矩阵
public static float[] mMVPM
//最后起作用的总变换矩阵
//自定义渲染管线着色程序id
* 下面的三个变量是顶点着色器中定义的三个变量
* 其中的总变换矩阵属性 是 一致变量
* 顶点位置 和 颜色属性 是 属性变量
int muMVPMatrixH
//总变换矩阵的引用
int maPositionH
//顶点位置属性引用
int maColorH
//顶点颜色属性引用
String mVertexS
//顶点着色器脚本代码
String mFragmentS
//片元着色器脚本代码
* 这个变换矩阵 在设置变换 , 位移 , 旋转的时候 将参数设置到这个矩阵中去
static float[] mMMatrix = new float[16];
//具体物体的3D变换矩阵, 包括旋转, 平移, 缩放
* 这两个缓冲获得方法
* ①创建ByteBuffer, 创建时赋予大小 设置顺序
* ②将ByteBuffer 转为FloatBuffer
* ③给FloatBuffer设置值, 设置起始位置
FloatBuffer mVertexB
//顶点坐标数据缓冲
FloatBuffer mColorB
//顶点着色数据缓冲
int vCount = 0;
//顶点数量
float xAngle = 0;
//绕x轴旋转角度
* 构造方法
* @param mv GLSurfaceView子类对象, 显示3D画面的载体
public Triangle(MyTDView mv){
initVertexData();
initShader(mv);
* 初始化顶点数据
* 该方法制定顶点坐标和颜色数据, 并将数据输入到缓冲区
* 创建一个ByteBuffer缓冲区, 然后将ByteBuffer缓冲区转为FloatBuffer缓冲区
* a. 创建float数组, 将对应的顶点(颜色)数据放到数组中去;
* b. 创建ByteBuffer对象, 根据之前创建的float数组的字节大小创建这个ByteBuffer对象,使用allocateDirect(int)分配大小
* c. 设置ByteBuffer对象的顺序, 调用order(ByteOrder.nativeOrder),设置为本地操作系统顺序
* d. 将ByteBuffer对象转为FloatBuffer对象, 调用asFloatBuffer()方法;
* e. 给FloatBuffer对象设置数组, 将开始创建的float数组设置给FloatBuffer对象;
* f. 设置FloatBuffer对象缓冲区的起始位置为0
public void initVertexData() {
//设置定点数为3
vCount = 3;
//计算三角形顶点的单位
final float UNIT_SIZE = 0.2f;
* 这个float数组9个浮点数, 每3个为一个顶点的坐标
float vertices[] = new float[]{
-4 * UNIT_SIZE, 0 , 0, //x轴左边的坐标
0, -4 * UNIT_SIZE, 0, //y轴坐标
4 * UNIT_SIZE, 0, 0
//x轴右边的坐标
* 创建一个ByteBuffer对象, 这个对象中缓冲区大小为vertices数组大小的4倍
* 因为每个float占4个字节, 创建的缓冲区大小正好将vertices装进去
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
//设置字节顺序为本地操作系统顺序
vbb.order(ByteOrder.nativeOrder());
//将该缓冲区转换为浮点型缓冲区
mVertexBuffer = vbb.asFloatBuffer();
//将顶点的位置数据写入到顶点缓冲区数组中
mVertexBuffer.put(vertices);
//设置缓冲区的起始位置为0
mVertexBuffer.position(0);
* 顶点颜色数组
* 每四个浮点值代表一种颜色
float colors[] = new float[]{
1, 1, 1, 0,
0, 0, 1, 0,
0, 1, 0, 0
ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length * 4);//创建ByteBuffer
cbb.order(ByteOrder.nativeOrder());//设置字节顺序
mColorBuffer = cbb.asFloatBuffer();//将字节缓冲转为浮点缓冲
mColorBuffer.put(colors);
mColorBuffer.position(0);
* 初始化着色器
① 从资源中获取顶点 和 片元着色器脚本
② 根据获取的顶点 片元着色器脚本创建着色程序
③ 从着色程序中获取顶点位置引用 , 顶点颜色引用,
总变换矩阵引用
* @param mv MyTDView对象, 是GLSurfaceView对象
public void initShader(MyTDView mv){
* mVertextShader是顶点着色器脚本代码
* 调用工具类方法获取着色器脚本代码, 着色器脚本代码放在assets目录中
* 传入的两个参数是 脚本名称 和 应用的资源
* 应用资源Resources就是res目录下的那写文件
mVertexShader = ShaderUtil.loadFromAssetsFile(vertex.sh, mv.getResources());
mFragmentShader = ShaderUtil.loadFromAssetsFile(frag.sh, mv.getResources());
* 创建着色器程序, 传入顶点着色器脚本 和 片元着色器脚本 注意顺序不要错
mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
* 从着色程序中获取 属性变量 顶点坐标(颜色)数据的引用
* 其中的aPosition是顶点着色器中的顶点位置信息
* 其中的aColor是顶点着色器的颜色信息
maPositionHandle = GLES20.glGetAttribLocation(mProgram, aPosition);
maColorHandle = GLES20.glGetAttribLocation(mProgram, aColor);
* 从着色程序中获取一致变量
总变换矩阵
* uMVPMatrix 是顶点着色器中定义的一致变量
muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, uMVPMatrix);
* 绘制三角形方法
* 绘制流程 :
① 指定着色程序
② 设置变换矩阵
③ 将顶点位置 颜色 数据传进渲染管线
④ 启动顶点位置 颜色 数据
⑤ 执行绘制
public void drawSelf(){
//根据着色程序id 指定要使用的着色器
GLES20.glUseProgram(mProgram);
* 设置旋转变化矩阵
* 参数介绍 : ① 3D变换矩阵 ② 矩阵数组的起始索引 ③旋转的角度 ④⑤⑥
Matrix.setRotateM(mMMatrix, 0, 0, 0, 1, 0);
* 设置沿z轴正方向位移
* 参数介绍 : ① 变换矩阵 ② 矩阵索引开始位置 ③④⑤设置位移方向z轴
Matrix.translateM(mMMatrix, 0, 0, 0, 1);
* 设置绕x轴旋转
* 参数介绍 : ① 变换矩阵 ② 索引开始位置 ③ 旋转角度 ④⑤⑥ 设置绕哪个轴旋转
Matrix.rotateM(mMMatrix, 0, xAngle, 1, 0, 0);
* 应用投影和视口变换
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, Triangle.getFianlMatrix(mMMatrix), 0);
* 将顶点位置数据传送进渲染管线, 为画笔指定定点的位置数据
GLES20.glVertexAttribPointer(
maPositionHandle,
//顶点位置数据引用
//每3个数字代表一个坐标
GLES20.GL_FLOAT,
//坐标的单位是浮点型
//每组数据有多少个字节
mVertexBuffer
* 将顶点颜色数据传送进渲染管线, 为画笔指定定点的颜色数据
GLES20.glVertexAttribPointer(
maColorHandle,
GLES20.GL_FLOAT,
mColorBuffer
//启用顶点位置数据
GLES20.glEnableVertexAttribArray(maPositionHandle);
//启用顶点颜色数据
GLES20.glEnableVertexAttribArray(maColorHandle);
//执行绘制
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vCount);
* 计算最终投影的矩阵
* @param spec
public static float[] getFianlMatrix(float[] spec){
mMVPMatrix = new float[16];
* 计算矩阵变换投影
* 参数介绍 :
① 总变换矩阵
② 总变换矩阵起始索引
③ 摄像机位置朝向矩阵
④ 摄像机朝向矩阵起始索引
⑤ 投影变换矩阵
⑥ 投影变换矩阵起始索引
Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, spec, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
return mMVPM
四. GLSurfaceView相关api
GLSurfaceView主要是创建渲染器, 实现其中的三个方法 onSurfaceCreated(), onSurfaceChanged(), onDrawFrame();
1. 相关api
(1) 设置OpenGL版本
GLSurfaceView.setEGLContextClientVersion(int version)
作用 : 设置OPenGL的版本号, version 是 2 , 就是设置OpenGLES2.0;
(2) 设置背景颜色
GLES20.glClearColor(0, 0, 0, 1.0f);
(3) 设置视口大小
GLES20.glViewport(int x, int y, int width, int height)
(4) 设置透视矩阵
Matrix.frustumM(float[] m, int offset, float left, float right, float bottom, float top, float near, float far)
参数 : m 投影矩阵; offset 投影矩阵起始位置; 剩下的参数为 左 右 下 上 近视点 远视点; 左 右 的值是宽高比, 左边为负数, 右边为正数;
(5) 设置摄像机参数
Matrix.setLookAtM(float[] rm, int rmOffset, float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)
参数 : rm 摄像机参数矩阵; rmOffset 摄像机参数矩阵起始位置; 剩下的三个一组, 分别是 摄像机位置 摄像机朝向摄像机上方朝向 ;
(6) 清除深度缓冲与颜色缓冲
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
package shuliang.han.
import javax.microedition.khronos.egl.EGLC
import javax.microedition.khronos.opengles.GL10;
import android.content.C
import android.opengl.GLES20;
import android.opengl.GLSurfaceV
import android.opengl.M
public class MyTDView extends GLSurfaceView {
private final float ANGLE_SPAN = 0.375f;
//三角形每次旋转的角度
private RotateThread mRotateT
//该线程用来改变图形角度
private SceneRenderer mSceneR
public MyTDView(Context context) {
super(context);
//设置OpenGLES版本为2.0
this.setEGLContextClientVersion(2);
//设置渲染器 渲染模式
mSceneRender = new SceneRenderer();
this.setRenderer(mSceneRender);
this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
* 实现了下面三个方法 :
界面创建 :
界面改变 :
界面绘制 :
* @author HanShuliang
private class SceneRenderer implements Renderer{
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//设置屏幕背景色
GLES20.glClearColor(0, 0, 0, 1.0f);
//创建三角形对象
triangle = new Triangle(MyTDView.this);
//打开深度检测
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
mRotateThread = new RotateThread();
mRotateThread.start();
public void onSurfaceChanged(GL10 gl, int width, int height) {
//设置视窗大小及位置
GLES20.glViewport(0, 0, width, height);
//计算GLSurfaceView的宽高比
float ratio = (float)width/
* 产生透视矩阵
* 参数介绍 :
* ① 4 * 4 投影矩阵
* ② 投影矩阵的起始位置
* 后面的四个参数分别是 左 右 下 上 的距离
* 最后两个参数是 近视点 和 远视点 距离
Matrix.frustumM(Triangle.mProjMatrix, 0,
-ratio, ratio,
* 设置摄像机参数矩阵
* 参数介绍 :
* 前两个参数是摄像机参数矩阵 和 矩阵数组的起始位置
* 后面三个一组是三个空间坐标 先后依次是 摄像机的位置
看的方向 摄像机上方朝向
Matrix.setLookAtM(Triangle.mVMatrix, 0,
0f,1.0f,0.0f);
public void onDrawFrame(GL10 gl) {
//清除深度缓冲与颜色缓冲
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
//绘制三角形
triangle.drawSelf();
* 这个线程是用来改变三角形角度用的
public class RotateThread extends Thread{
public boolean flag =
public void run() {
while(flag){
mSceneRender.triangle.xAngle = mSceneRender.triangle.xAngle + ANGLE_SPAN;
Thread.sleep(20);
} catch (Exception e) {
e.printStackTrace();
五 MainActivity相关
1. 相关api
(1) 设置界面为竖屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
(2) 界面获取焦点
View.requestFocus()
(3) 设置可获取焦点
View.setFocusableInTouchMode(boolean focusableInTouchMode)
作用 : 在触摸的时候获取焦点
package shuliang.han.
import android.app.A
import android.content.pm.ActivityI
import android.os.B
public class MainActivity extends Activity {
private MyTDView myTDV
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//设置界面显示为竖屏
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
//创建OpenGL的显示界面
myTDView = new MyTDView(this);
myTDView.requestFocus();
myTDView.setFocusableInTouchMode(true);
//将OpenGL显示界面设置给Activity
setContentView(myTDView);
public void onResume() {
super.onResume();
myTDView.onResume();
public void onPause() {
super.onPause();
myTDView.onPause();
六. 着色器脚本
顶点着色器 :
uniform mat4 uMVPM //总变换矩阵
attribute vec3 aP
//顶点位置
attribute vec4 aC
//顶点颜色
//用于传递给片元着色器的变量
void main()
gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点位置
vColor = aC//将接收的颜色传递给片元着色器
片元着色器 :
vec4 vC //接收从顶点着色器过来的参数
void main()
gl_FragColor = vC//给此片元颜色值
案例地址 : http://download.csdn.net/detail/han1095 需要SDK-10 版本2.3.3
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'

我要回帖

更多关于 opengles 渲染文字 的文章

 

随机推荐