在上一篇文章 OpenGLES系列demo之框架简介 (后文简称“框架文章”)中,我们先介绍了框架,本文基于这个框架上,简述使用openGL ES绘制一个三角形的大致步骤。
一、绘制三角形的步骤
绘制三角形的一般步骤如下:
- 创建 OpenGLES 环境(可以借助于 GLSurfaceView 创建的上下文对象);
- 编译并链接着色器程序;
- 指定着色器程序,为着色器程序中的变量赋值;
- 绘制。
二、创建OpenGLES环境
这个创建在上一篇框架文章中搭建的框架基本上已经实现了openGLES环境,这里我们再简单过一下。
1、简单自定义GLSurfackView。-- 参考“框架文章”中的MyGLSurfaceView;
2、自定义Render实现GLSurfaceView.Renderer接口。 -- 参考“框架文章”中的MyGLRender;
以上两步基本就创建好了openGLES环境,
3、由于我们在c++层完成绘制,因此还需要与jni的一些接口调用。 -- 参考“框架文章”中的MyNativeRender等;
三、编译链接着色器程序,实现绘制类
以下部分我们是在c++层去操作,实现绘制。
1、编译和链接着色器程序的类
在我们的“框架文章”中,已经讲到将编译和绘制着色器相关的东西,提出到一个工具类GLUtils,这个类是通用的,实现编译和链接着色器程序等功能。这里不再赘述,看参考“框架”文章。
2、三角形的绘制实现类
这个便是本文的重点,在框架的基础上,每个demo最重要的区别就是这里。在这个三角形的绘制实现类TriangleSample中,我们会实现三角形的绘制。包括它的顶点着色器等等的定义。
三角形的顶点着色器脚本:
#version 300 es
layout(location = 0) in vec4 vPosition;
void main()
{
gl_Position = vPosition;
}
片元着色器脚本:
#version 300 es
precision mediump float;
out vec4 fragColor;
void main()
{
fragColor = vec4 ( 0.0, 0.0, 1.0, 1.0 ); //填充三角形区域为蓝色
}
这两个脚本我们定义到字符串数组后,在绘制类的Init初始化函数中调用GLUtils工具类的创建程序进行相关绑定,如下:
void TriangleSample::Init()
{
if(m_ProgramObj != 0)
return;
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 vPosition; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"} \n";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"out vec4 fragColor; \n"
"void main() \n"
"{ \n"
" fragColor = vec4 ( 0.0, 0.0, 1.0, 1.0 ); \n"
"} \n";
m_ProgramObj = GLUtils::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);
}
先来看下opengles 坐标系中三角形顶点坐标:
接下来在Draw函数中指定着色器程序,为着色器程序中的变量赋值,传入顶点坐标信息,然后绘制三角形。如下:
void TriangleSample::Draw(int screenW, int screenH)
{
LOGCATE("TriangleSample::Draw");
GLfloat vVertices[] = {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
};
if(m_ProgramObj == 0)
return;
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(1.0, 1.0, 1.0, 1.0);
// Use the program object
glUseProgram (m_ProgramObj);
// Load the vertex data
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
glEnableVertexAttribArray (0);
glDrawArrays (GL_TRIANGLES, 0, 3);
glUseProgram (GL_NONE);
}
三角形的实现绘制类TriangleSample中最重要就是这两个函数,初始化和绘制。
它们的调用是在MyGLRenderContext类中调用,并提高给JNI,最终到java层去调用。
MyGLRenderContext::MyGLRenderContext()
{
m_pCurSample = new TriangleSample();
m_pBeforeSample = nullptr;
}
MyGLRenderContext::~MyGLRenderContext()
{
if (m_pCurSample)
{
delete m_pCurSample;
m_pCurSample = nullptr;
}
if (m_pBeforeSample)
{
delete m_pBeforeSample;
m_pBeforeSample = nullptr;
}
}
void MyGLRenderContext::OnSurfaceCreated()
{
LOGCATE("MyGLRenderContext::OnSurfaceCreated");
glClearColor(1.0f,1.0f,1.0f, 1.0f);
}
void MyGLRenderContext::OnSurfaceChanged(int width, int height)
{
LOGCATE("MyGLRenderContext::OnSurfaceChanged [w, h] = [%d, %d]", width, height);
glViewport(0, 0, width, height);
m_ScreenW = width;
m_ScreenH = height;
}
void MyGLRenderContext::OnDrawFrame()
{
LOGCATE("MyGLRenderContext::OnDrawFrame");
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
if (m_pBeforeSample)
{
m_pBeforeSample->Destroy();
delete m_pBeforeSample;
m_pBeforeSample = nullptr;
}
if (m_pCurSample)
{
m_pCurSample->Init();
m_pCurSample->Draw(m_ScreenW, m_ScreenH);
}
}
到这里demo基本就做完了。
四、运行demo
运行一下demo,可以看到效果如下:
该demo已放到github上,有需要的可以下载看看:
https://github.com/weekend-y/openGL_Android_demo/tree/master/OpenGL_Triangle