不积跬步,无以至千里;不积小流,无以成江海。要沉下心来,诗和远方的路费真的很贵!
OpenGL ES 3.0 学习——2D
颜色的简单搭配:
不红+不绿+不蓝 = 黑
红+绿+蓝 = 白
红+绿 = 黄
红+蓝 = 紫
绿+蓝 = 青蓝
着色器语言基础知识
这位博主是根据书本《OpenGL ES 3.0编程指南》 第五章进行书写的。
参考博客:android平台下OpenGL ES 3.0着色语言基础知识(上)
参考博客:android平台下OpenGL ES 3.0着色语言基础知识(下)
绘制纯色背景
JAVA版本
package com.example.openglndk;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGLSurfaceView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
setContentView(mGLSurfaceView);
mGLSurfaceView.setEGLContextClientVersion(3);
GLSurfaceView.Renderer renderer = new MyRenderer(Color.RED);
mGLSurfaceView.setRenderer(renderer);
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.opengl.GLSurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.example.openglndk;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRenderer implements GLSurfaceView.Renderer {
private int color;
public MyRenderer(int color){
this.color = color;
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
float redF = ((color >> 16) & 0xFF) * 1.0f / 255;
float greenF = ((color >> 8) & 0xFF) * 1.0f / 255;
float blueF = (color & 0xFF) * 1.0f / 255;
float alphaF = ((color >> 24) & 0xFF) * 1.0f / 255;
GLES30.glClearColor(redF, greenF, blueF, alphaF);
}
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
GLES30.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl10) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
}
}
CMakeLists.txt 和.cpp文件 不需要。
C++版本
package com.example.openglndk;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGLSurfaceView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
setContentView(mGLSurfaceView);
mGLSurfaceView.setEGLContextClientVersion(3);
GLSurfaceView.Renderer renderer = new WaveRenderer(Color.GREEN);
mGLSurfaceView.setRenderer(renderer);
}
}
activity_main.xml 不变。- 自定义渲染器(
JNI 类) Renderer类 (改变)
package com.example.openglndk;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class WaveRenderer implements GLSurfaceView.Renderer {
static{
System.loadLibrary("native-wave");
}
public native void init();
public native void surfaceCreated(int color);
public native void surfaceChanged(int width,int height);
public native void drawFrame();
private int color;
public WaveRenderer(int color){
this.color = color;
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
surfaceCreated(color);
}
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
surfaceChanged(width,height);
}
@Override
public void onDrawFrame(GL10 gl10) {
drawFrame();
}
}
# Sets the minimum version of CMake required to build the native library.
#cmake_minimum_required(VERSION 3.10.2)
cmake_minimum_required(VERSION 3.4.1)
##官方标准配置
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-rtti -fno-exceptions -Wall")
##ANDROID_PLATFORM_LEVEL=18
add_definitions("-DDYNAMIC_ES3")
set(OPENGL_LIB GLESv3)
# Declares and names the project.
project("openglndk")
add_library( # Sets the name of the library.
native-wave
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-wave.cpp)
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
target_link_libraries(native-wave
${OPENGL_LIB}
android
EGL
log
m)
//
// Created by lvjunkai on 2022/2/16.
//
#include <jni.h>
#include <EGL/egl.h>
#include <GLES3/gl3.h>
//书写本地方法的具体逻辑
JNIEXPORT void JNICALL init(JNIEnv *env, jobject obj) {
}
JNIEXPORT void JNICALL surfaceCreated(JNIEnv *env, jobject obj, jint color) {
//分离RGBA的百分比
GLfloat redF = ((color >> 16) & 0xFF) * 1.0f / 255;
GLfloat greenF = ((color >> 8) & 0xFF) * 1.0f / 255;
GLfloat blueF = (color & 0xFF) * 1.0f / 255;
GLfloat alphaF = ((color >> 24) & 0xFF) * 1.0f / 255;
glClearColor(redF, greenF, blueF, alphaF);
}
JNIEXPORT void JNICALL surfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) {
//设置视口
glViewport(0, 0, width, height);
}
JNIEXPORT void JNICALL drawFrame(JNIEnv *env, jobject obj) {
//把颜色缓冲区设置为我们预设的颜色
//清楚颜色缓存
glClear(GL_COLOR_BUFFER_BIT);
}
/**
* 动态注册
*/
//本地方法声明和具体逻辑连接
JNINativeMethod methods[] = {
//双引号中的方法是Renderer类中声明的本地方法名
//后面的方法是cpp文件中具体实现方法名
{"init", "()V", (void *) init},
{"surfaceCreated", "(I)V", (void *) surfaceCreated},
{"surfaceChanged", "(II)V", (void *) surfaceChanged},
{"drawFrame", "()V", (void *) drawFrame}
};
/**
* 动态注册
* @param env
* @return
*/
jint registerNativeMethod(JNIEnv *env) {
//到本地方法存在的类找出其方法声明
jclass cl = env->FindClass("com/example/openglndk/WaveRenderer");
if ((env->RegisterNatives(cl, methods, sizeof(methods) / sizeof(methods[0]))) < 0) {
return -1;
}
return 0;
}
/**
* 加载默认回调
* @param vm
* @param reserved
* @return
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
//注册方法
if (registerNativeMethod(env) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
绘制圆点、直线、三角形
attribute vec4 vPosition;
uniform mat4 vMatrix;
void main() {
gl_Position = vMatrix*vPosition;
gl_PointSize = 10.0;
}
precision mediump float;
uniform vec4 vColor;
void main() {
gl_FragColor = vColor;
}
glDrawArrays(GL_POINTS,0,3);
glLineWidth(10.0f);
glDrawArrays(GL_LINE_STRIP,0,2);
glDrawArrays(GL_TRIANGLES,0,3);
以下示例皆以三角形为例子,需要变换形状,只需修改绘制上述代码。
JAVA版本
package com.example.openglndk;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Color;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGLSurfaceView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
setContentView(mGLSurfaceView);
mGLSurfaceView.setEGLContextClientVersion(3);
GLSurfaceView.Renderer renderer = new MyRenderer();
mGLSurfaceView.setRenderer(renderer);
}
}
activity_main.xml 一直不变,后续不再赘述。- 核心类——
Renderer类
package com.example.openglndk;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRenderer implements GLSurfaceView.Renderer {
private final static int COORDS_PER_VERTEX = 3;
private final int vertexStride = COORDS_PER_VERTEX * 4;
private FloatBuffer vertexBuffer;
private int vertexShader;
private int fragmentShader;
private int mProgram;
private float color[] = {1.0f, 0.0f, 1.0f, 0.0f};
private float vertexPoints[] = {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
private int vertexCount = vertexPoints.length / COORDS_PER_VERTEX;
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"void main() {" +
" gl_Position = vMatrix*vPosition;" +
" gl_PointSize = 10.0;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
public MyRenderer() {
vertexBuffer = ByteBuffer.allocateDirect(
vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
GLES30.glClearColor(1, 1, 1, 1);
vertexShader = LoadShader(GLES30.GL_VERTEX_SHADER,
vertexShaderCode);
fragmentShader = LoadShader(GLES30.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = linkProgram(vertexShader, fragmentShader);
}
private float mProjectionMatrix[] = new float[16];
private float mViewMatrix[] = new float[16];
private float mMVPMatrix[] = new float[16];
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
GLES30.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.orthoM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 0, 5);
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl10) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glUseProgram(mProgram);
int mMatrixHandler = GLES30.glGetUniformLocation(mProgram, "vMatrix");
GLES30.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0);
int mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
GLES30.glEnableVertexAttribArray(mPositionHandle);
GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES30.GL_FLOAT, false,
vertexStride, vertexBuffer);
int mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");
GLES30.glUniform4fv(mColorHandle, 1, color, 0);
GLES30.glLineWidth(10.0f);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount);
GLES30.glDisableVertexAttribArray(mPositionHandle);
}
private static int LoadShader(int type, String shaderCode) {
final int shaderId = GLES30.glCreateShader(type);
if (shaderId != 0) {
GLES30.glShaderSource(shaderId, shaderCode);
GLES30.glCompileShader(shaderId);
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0) {
String logInfo = GLES30.glGetShaderInfoLog(shaderId);
System.err.println(logInfo);
GLES30.glDeleteShader(shaderId);
return 0;
}
return shaderId;
} else {
return 0;
}
}
public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
if (programId != 0) {
GLES30.glAttachShader(programId, vertexShaderId);
GLES30.glAttachShader(programId, fragmentShaderId);
GLES30.glLinkProgram(programId);
final int[] linkStatus = new int[1];
GLES30.glGetProgramiv(programId, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0) {
String logInfo = GLES30.glGetProgramInfoLog(programId);
System.err.println(logInfo);
GLES30.glDeleteProgram(programId);
return 0;
}
return programId;
} else {
return 0;
}
}
}
C++版本
package com.example.openglndk;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class WaveRenderer implements GLSurfaceView.Renderer {
static{
System.loadLibrary("native-wave");
}
public native void init();
public native void surfaceCreated();
public native void surfaceChanged(int width,int height);
public native void drawFrame();
public WaveRenderer(){
init();
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
surfaceCreated();
}
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
surfaceChanged(width,height);
}
@Override
public void onDrawFrame(GL10 gl10) {
drawFrame();
}
}
//
// Created by lvjunkai on 2022/2/21.
//
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#include <malloc.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
//声明自定义函数
//创建编译加载
GLuint LoadShader(int type, char *shaderCode);
//链接统一程序
GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);
//模板技术定义的函数
//用于求数组长度
template<class T>
GLsizei getArrayLen(T &array) {
return (sizeof(array) / sizeof(array[0]));
}
//坐标个数(xyz)
const GLint COORDS_PER_VERTEX = 3;
//顶点之间的偏移量
const int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节
//声明顶点着色器
GLuint vertexShader;
//声明片元着色器
GLuint fragmentShader;
//声明着色器管理程序
GLuint mProgram;
//定义点坐标
float vertexPoints[] = {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
//设置颜色,依次为红绿蓝和透明通道
float color[] = {1.0f, 1.0f, 0.0f, 0.0f};
const int vertexCount = getArrayLen(vertexPoints) / COORDS_PER_VERTEX;
//顶点着色器代码
char vertexShaderCode[] = "attribute vec4 vPosition; \n"
"uniform mat4 vMatrix;\n"
"void main() {\n"
" gl_Position = vMatrix*vPosition;\n"
" gl_PointSize = 10.0; \n"
"}";
//片段着色器代码
char fragmentShaderCode[] = "precision mediump float;"
"uniform vec4 vColor;"
"void main() {"
" gl_FragColor = vColor;"
"}";
//书写本地方法的具体逻辑
void JNICALL init(JNIEnv *env, jobject obj) {
//初始化
}
/**初始化
*
* @param env
* @param obj
*/
void JNICALL surfaceCreated(JNIEnv *env, jobject obj) {
//设置背景颜色为黑色
glClearColor(0, 0, 0, 0);
//创建顶点着色器
vertexShader = LoadShader(GL_VERTEX_SHADER, vertexShaderCode);
//创建片元着色器
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
//将顶点着色器和片元着色器交给统一程序管理
mProgram = linkProgram(vertexShader, fragmentShader);
}
/**图形尺寸
*
* @param env
* @param obj
* @param width
* @param height
*/
glm::mat4 mProjectionMatrix;
glm::mat4 mViewMatrix;
glm::mat4 mMVPMatrix;
JNIEXPORT void JNICALL surfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) {
//设置视口
glViewport(0, 0, width, height);
//宽高比
float ratio = (float) width / height;
//二维图形设置正交投影矩阵即可
mProjectionMatrix = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f,
100.0f); //ratio 一般表示视口的宽高比,width/height
//相机位置
mViewMatrix = glm::lookAt(glm::vec3(0, 0, -3), // Camera is at (0,0,1), in World Space 相机位置
glm::vec3(0, 0, 0), // and looks at the origin 观察点坐标
glm::vec3(0, 1, 0));
//矩阵合并
mMVPMatrix = mProjectionMatrix * mViewMatrix;
}
/**渲染绘制
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL drawFrame(JNIEnv *env, jobject obj) {
//清除颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//使用程序
glUseProgram(mProgram);
GLint mMatrixHandler = glGetUniformLocation(mProgram, "vMatrix");
//矩阵转换成数组
float mMVPMatrixArray[16];
int m = 0;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++){
mMVPMatrixArray[m] = mMVPMatrix[i][j];
m++;
}
//指定vMatrix的值
glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrixArray);
//获取顶点着色器的vPosition成员句柄
GLint mPositionHandle = glGetAttribLocation(mProgram, "vPosition");
//启用图形顶点的句柄
glEnableVertexAttribArray(mPositionHandle);
//准备图形的坐标数据
glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GL_FLOAT, GL_FALSE, vertexStride, vertexPoints);
//获取片元着色器的vColor成员的句柄
GLint mColorHandle = glGetUniformLocation(mProgram, "vColor");
//设置绘制图形的颜色
glUniform4fv(mColorHandle, 1, color);
//顶点法绘制图形
glLineWidth(10.0f);
glDrawArrays(GL_TRIANGLES,0,vertexCount);
//禁止顶点数组的句柄
glDisableVertexAttribArray(mPositionHandle);
}
/**加载着色器
*
*/
JNIEXPORT GLuint LoadShader(int type, char *shaderCode) {
//创建一个着色器
GLuint shader = glCreateShader(type);
if (shader != 0) {
//加载到着色器
glShaderSource(shader, 1, &shaderCode, NULL);
//编译着色器
glCompileShader(shader);
//检测状态
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == 0) {
//声明log长度变量
GLint infoLen = 0;
//获取长度并赋值
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
//创建成功小于等于1
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
printf("SHADER ERROR!");
free(infoLog);
}
//创建失败
glDeleteShader(shader);
return 0;
}
return shader;
} else {
//创建失败
return 0;
}
}
/**链接着色器
*
*/
JNIEXPORT GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
if (program != 0) {
//将顶点着色器加入到程序
glAttachShader(program, vertexShader);
//将片元着色器加入到程序中
glAttachShader(program, fragmentShader);
//链接着色器程序
glLinkProgram(program);
//检测状态
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) {
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetProgramInfoLog(program, infoLen, NULL, infoLog);
printf("PROGRAM ERROR!");
free(infoLog);
}
glDeleteProgram(program);
return 0;
}
return program;
} else {
//创建失败
return 0;
}
}
/** 动态注册
* @param env
* @return
*/
//本地方法声明和具体逻辑连接
JNINativeMethod methods[] = {
{"init", "()V", (void *) init},
{"surfaceCreated", "()V", (void *) surfaceCreated},
{"surfaceChanged", "(II)V", (void *) surfaceChanged},
{"drawFrame", "()V", (void *) drawFrame}
};
/** 动态注册
* @param env
* @return
*/
jint registerNativeMethod(JNIEnv *env) {
//到本地方法存在的类找出其方法声明
jclass cl = env->FindClass("com/example/openglndk/WaveRenderer");
if ((env->RegisterNatives(cl, methods, sizeof(methods) / sizeof(methods[0]))) < 0) {
return -1;
}
return 0;
}
/** 加载默认回调
* @param vm
* @param reserved
* @return
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
//注册方法
if (registerNativeMethod(env) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
绘制彩色三角形
#version 300 es
in vec4 vPosition;
in vec4 vColor;
uniform mat4 vMatrix;
out vec4 aColor;
void main() {
gl_Position = vMatrix*vPosition;
gl_PointSize = 10.0;
aColor = vColor;
}
#version 300 es
precision mediump float;
in vec4 aColor;
out vec4 fragColor;
void main() {
fragColor = aColor;
}
JAVA版本
package com.example.openglndk;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRenderer implements GLSurfaceView.Renderer {
private final static int COORDS_PER_VERTEX = 3;
private final static int COORDS_PER_COLOR = 4;
private final int vertexStride = COORDS_PER_VERTEX * 4;
private final int colorStride = COORDS_PER_COLOR * 4;
private FloatBuffer vertexBuffer, colorBuffer;
private int vertexShader;
private int fragmentShader;
private int mProgram;
private float colors[] = {
0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
private float[] vertexPoints = {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
private int vertexCount = vertexPoints.length / COORDS_PER_VERTEX;
private String vertexShaderCode = "#version 300 es\n" +
"in vec4 vPosition;\n" +
"in vec4 vColor;\n" +
"uniform mat4 vMatrix;\n" +
"out vec4 aColor;\n" +
"void main() {\n" +
" gl_Position = vMatrix*vPosition;\n" +
" gl_PointSize = 10.0;\n" +
" aColor = vColor;\n" +
"}\n";
private String fragmentShaderCode = "#version 300 es\n" +
"precision mediump float;\n" +
"in vec4 aColor;\n" +
"out vec4 fragColor;\n" +
"void main() {\n" +
" fragColor = aColor;\n" +
"}\n";
public MyRenderer() {
vertexBuffer = ByteBuffer.allocateDirect(vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
colorBuffer = ByteBuffer.allocateDirect(colors.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
colorBuffer.put(colors);
colorBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
GLES30.glClearColor(1, 1, 1, 1);
vertexShader = LoadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode);
fragmentShader = LoadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = linkProgram(vertexShader, fragmentShader);
}
private float mProjectionMatrix[] = new float[16];
private float mViewMatrix[] = new float[16];
private float mMVPMatrix[] = new float[16];
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
GLES30.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl10) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glUseProgram(mProgram);
int mMatrixHandler = GLES30.glGetUniformLocation(mProgram, "vMatrix");
GLES30.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0);
int mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
GLES30.glEnableVertexAttribArray(mPositionHandle);
GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES30.GL_FLOAT, false,
vertexStride, vertexBuffer);
int mColorHandle = GLES30.glGetAttribLocation(mProgram, "vColor");
GLES30.glEnableVertexAttribArray(mColorHandle);
GLES30.glVertexAttribPointer(mColorHandle, COORDS_PER_COLOR,
GLES30.GL_FLOAT, false,
colorStride, colorBuffer);
GLES30.glLineWidth(10.0f);
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount);
GLES30.glDisableVertexAttribArray(mColorHandle);
GLES30.glDisableVertexAttribArray(mPositionHandle);
}
private static int LoadShader(int type, String shaderCode) {
final int shaderId = GLES30.glCreateShader(type);
if (shaderId != 0) {
GLES30.glShaderSource(shaderId, shaderCode);
GLES30.glCompileShader(shaderId);
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0) {
String logInfo = GLES30.glGetShaderInfoLog(shaderId);
System.err.println(logInfo);
GLES30.glDeleteShader(shaderId);
return 0;
}
return shaderId;
} else {
return 0;
}
}
public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
if (programId != 0) {
GLES30.glAttachShader(programId, vertexShaderId);
GLES30.glAttachShader(programId, fragmentShaderId);
GLES30.glLinkProgram(programId);
final int[] linkStatus = new int[1];
GLES30.glGetProgramiv(programId, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0) {
String logInfo = GLES30.glGetProgramInfoLog(programId);
System.err.println(logInfo);
GLES30.glDeleteProgram(programId);
return 0;
}
return programId;
} else {
return 0;
}
}
}
C++版本
//
// Created by lvjunkai on 2022/2/21.
//
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#include <malloc.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
//声明自定义函数
//创建编译加载
GLuint LoadShader(int type, char *shaderCode);
//链接统一程序
GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);
//模板技术定义的函数
//用于求数组长度
template<class T>
GLsizei getArrayLen(T &array) {
return (sizeof(array) / sizeof(array[0]));
}
//坐标个数(xyz)
const GLint COORDS_PER_VERTEX = 3;
//颜色通道(RGBA)
const GLint COORDS_PER_COLOR = 4;
//顶点之间的偏移量
const GLsizei vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节
//颜色之间的偏移量
const GLsizei colorStride = COORDS_PER_COLOR * 4; // 每个颜色四个字节
//声明顶点着色器
GLuint vertexShader;
//声明片元着色器
GLuint fragmentShader;
//声明着色器管理程序
GLuint mProgram;
//定义圆点坐标
float vertexPoints[] = {
0.0f, 0.5f, 0.0f, //上侧点
-0.5f, -0.5f, 0.0f, //左侧点
0.5f, -0.5f, 0.0f //右侧点
};
//定义颜色数据
float colors[] = {
1.0f, 0.5f, 1.0f, 1.0f, //顶部
1.0f, 1.0f, 0.5f, 1.0f, //左侧
0.5f, 1.0f, 1.0f, 1.0f //右侧
};
//点数量
int vertexCount = getArrayLen(vertexPoints) / COORDS_PER_VERTEX;
//顶点着色器代码
char vertexShaderCode[] = "#version 300 es \n"
"in vec4 vPosition;\n"
"in vec4 vColor;\n"
"uniform mat4 vMatrix;\n"
"out vec4 aColor;\n"
"void main() {\n"
" gl_Position = vMatrix*vPosition;\n"
" gl_PointSize = 10.0;\n"
" aColor = vColor;\n"
"}";
//片段着色器代码
char fragmentShaderCode[] = "#version 300 es\n"
"precision mediump float;\n"
"in vec4 aColor;\n"
"out vec4 fragColor;\n"
"void main() {\n"
" fragColor = aColor;\n"
"}";
//书写本地方法的具体逻辑
void JNICALL init(JNIEnv *env, jobject obj) {
//初始化
}
/**初始化
*
* @param env
* @param obj
*/
void JNICALL surfaceCreated(JNIEnv *env, jobject obj) {
//设置背景颜色为黑色
glClearColor(0, 0, 0, 0);
//创建顶点着色器
vertexShader = LoadShader(GL_VERTEX_SHADER, vertexShaderCode);
//创建片元着色器
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
//将顶点着色器和片元着色器交给统一程序管理
mProgram = linkProgram(vertexShader, fragmentShader);
}
/**图形尺寸
*
* @param env
* @param obj
* @param width
* @param height
*/
glm::mat4 mProjectionMatrix;
glm::mat4 mViewMatrix;
glm::mat4 mMVPMatrix;
JNIEXPORT void JNICALL surfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) {
//设置视口
glViewport(0, 0, width, height);
//宽高比
float ratio = (float) width / height;
//二维图形设置正交投影矩阵即可
mProjectionMatrix = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f,
100.0f); //ratio 一般表示视口的宽高比,width/height
//相机位置
mViewMatrix = glm::lookAt(glm::vec3(0, 0, -3), // Camera is at (0,0,1), in World Space 相机位置
glm::vec3(0, 0, 0), // and looks at the origin 观察点坐标
glm::vec3(0, 1, 0));
//矩阵合并
mMVPMatrix = mProjectionMatrix * mViewMatrix;
}
/**渲染绘制
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL drawFrame(JNIEnv *env, jobject obj) {
//清除颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//使用统一的管理程序
glUseProgram(mProgram);
//获取变换矩阵vMatrix成员句柄
//图形参数
GLint mMatrixHandler = glGetUniformLocation(mProgram, "vMatrix");
//矩阵转换成数组
float mMVPMatrixArray[16];
int m = 0;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++){
mMVPMatrixArray[m] = mMVPMatrix[i][j];
m++;
}
//指定vMatrix的值
glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrixArray);
//获取顶点着色器的vPosition成员句柄
GLint mPositionHandle = glGetAttribLocation(mProgram, "vPosition");
//启用顶点的句柄
glEnableVertexAttribArray(mPositionHandle);
//准备坐标数据
glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GL_FLOAT, false,
vertexStride, vertexPoints);
//获取片元着色器的vColor成员的句柄
GLint mColorHandle = glGetAttribLocation(mProgram, "vColor");
//启动颜色的句柄
glEnableVertexAttribArray(mColorHandle);
//准备颜色数据
glVertexAttribPointer(mColorHandle, COORDS_PER_COLOR,
GL_FLOAT, false,
colorStride, colors);
//绘制图形
glLineWidth(10.0f);
glDrawArrays(GL_TRIANGLES, 0, vertexCount);
//禁止颜色数组的句柄
glDisableVertexAttribArray(mColorHandle);
//禁止顶点数组的句柄
glDisableVertexAttribArray(mPositionHandle);
}
/**加载着色器
*
*/
JNIEXPORT GLuint LoadShader(int type, char *shaderCode) {
//创建一个着色器
GLuint shader = glCreateShader(type);
if (shader != 0) {
//加载到着色器
glShaderSource(shader, 1, &shaderCode, NULL);
//编译着色器
glCompileShader(shader);
//检测状态
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == 0) {
//声明log长度变量
GLint infoLen = 0;
//获取长度并赋值
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
//创建成功小于等于1
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
printf("SHADER ERROR!");
free(infoLog);
}
//创建失败
glDeleteShader(shader);
return 0;
}
return shader;
} else {
//创建失败
return 0;
}
}
/**链接着色器
*
*/
JNIEXPORT GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
if (program != 0) {
//将顶点着色器加入到程序
glAttachShader(program, vertexShader);
//将片元着色器加入到程序中
glAttachShader(program, fragmentShader);
//链接着色器程序
glLinkProgram(program);
//检测状态
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) {
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetProgramInfoLog(program, infoLen, NULL, infoLog);
printf("PROGRAM ERROR!");
free(infoLog);
}
glDeleteProgram(program);
return 0;
}
return program;
} else {
//创建失败
return 0;
}
}
/** 动态注册
* @param env
* @return
*/
//本地方法声明和具体逻辑连接
JNINativeMethod methods[] = {
{"init", "()V", (void *) init},
{"surfaceCreated", "()V", (void *) surfaceCreated},
{"surfaceChanged", "(II)V", (void *) surfaceChanged},
{"drawFrame", "()V", (void *) drawFrame}
};
/** 动态注册
* @param env
* @return
*/
jint registerNativeMethod(JNIEnv *env) {
//到本地方法存在的类找出其方法声明
jclass cl = env->FindClass("com/example/openglndk/WaveRenderer");
if ((env->RegisterNatives(cl, methods, sizeof(methods) / sizeof(methods[0]))) < 0) {
return -1;
}
return 0;
}
/** 加载默认回调
* @param vm
* @param reserved
* @return
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
//注册方法
if (registerNativeMethod(env) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
绘制纯色正方形
JAVA版本
package com.example.openglndk;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRenderer implements GLSurfaceView.Renderer {
private final static int COORDS_PER_VERTEX = 3;
private final int vertexStride = COORDS_PER_VERTEX * 4;
private FloatBuffer vertexBuffer;
private ShortBuffer indexBuffer;
private int vertexShader;
private int fragmentShader;
private int mProgram;
private float vertexPoints[] = {
-0.5f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f
};
private int vertexCount = vertexPoints.length / COORDS_PER_VERTEX;
private float color[] = {0.1f, 0.7f, 1.0f, 0.0f};
private short index[] = {
0, 1, 2, 0, 2, 3
};
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"void main() {" +
" gl_Position = vMatrix*vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
public MyRenderer() {
vertexBuffer = ByteBuffer.allocateDirect(
vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
indexBuffer = ByteBuffer.allocateDirect(index.length * 2)
.order(ByteOrder.nativeOrder())
.asShortBuffer();
indexBuffer.put(index);
indexBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
GLES30.glClearColor(1, 1, 1, 1);
vertexShader = LoadShader(GLES30.GL_VERTEX_SHADER,
vertexShaderCode);
fragmentShader = LoadShader(GLES30.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = linkProgram(vertexShader, fragmentShader);
}
private float mProjectionMatrix[] = new float[16];
private float mViewMatrix[] = new float[16];
private float mMVPMatrix[] = new float[16];
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
GLES30.glViewport(0, 0, width, height);
float ratio = width > height ? (float) width / height : (float) height / width;
if(width > height){
Matrix.orthoM(mProjectionMatrix,0,-ratio,ratio,-1,1,0,5);
}else{
Matrix.orthoM(mProjectionMatrix,0,-1,1,-ratio,ratio,0,5);
}
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl10) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glUseProgram(mProgram);
int mMatrixHandler = GLES30.glGetUniformLocation(mProgram, "vMatrix");
GLES30.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0);
int mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
GLES30.glEnableVertexAttribArray(mPositionHandle);
GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES30.GL_FLOAT, false,
vertexStride, vertexBuffer);
int mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");
GLES30.glUniform4fv(mColorHandle, 1, color, 0);
GLES30.glLineWidth(10.0f);
GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, vertexCount);
GLES30.glDisableVertexAttribArray(mPositionHandle);
}
private static int LoadShader(int type, String shaderCode) {
final int shaderId = GLES30.glCreateShader(type);
if (shaderId != 0) {
GLES30.glShaderSource(shaderId, shaderCode);
GLES30.glCompileShader(shaderId);
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0) {
String logInfo = GLES30.glGetShaderInfoLog(shaderId);
System.err.println(logInfo);
GLES30.glDeleteShader(shaderId);
return 0;
}
return shaderId;
} else {
return 0;
}
}
public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
if (programId != 0) {
GLES30.glAttachShader(programId, vertexShaderId);
GLES30.glAttachShader(programId, fragmentShaderId);
GLES30.glLinkProgram(programId);
final int[] linkStatus = new int[1];
GLES30.glGetProgramiv(programId, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0) {
String logInfo = GLES30.glGetProgramInfoLog(programId);
System.err.println(logInfo);
GLES30.glDeleteProgram(programId);
return 0;
}
return programId;
} else {
return 0;
}
}
}
C++版本
//
// Created by lvjunkai on 2022/2/21.
//
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#include <malloc.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
//声明自定义函数
//创建编译加载
GLuint LoadShader(int type, char *shaderCode);
//链接统一程序
GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);
//模板技术定义的函数
//用于求数组长度
template<class T>
GLsizei getArrayLen(T &array) {
return (sizeof(array) / sizeof(array[0]));
}
//坐标个数(xyz)
const GLint COORDS_PER_VERTEX = 3;
//顶点之间的偏移量
const int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节
//声明顶点着色器
GLuint vertexShader;
//声明片元着色器
GLuint fragmentShader;
//声明着色器管理程序
GLuint mProgram;
//定义点坐标
float vertexPoints[] = {
-0.5f, 0.5f, 0.0f, //左上角
-0.5f, -0.5f, 0.0f, //左下角
0.5f, -0.5f, 0.0f, //右下角
0.5f, 0.5f, 0.0f //右上角
};
//设置颜色,依次为红绿蓝和透明通道
float color[] = {1.0f, 1.0f, 0.0f, 0.0f};
//索引
short index[] = {
0, 1, 2, 0, 2, 3
};
const int vertexCount = getArrayLen(vertexPoints) / COORDS_PER_VERTEX;
//顶点着色器代码
char vertexShaderCode[] = "attribute vec4 vPosition; \n"
"uniform mat4 vMatrix;\n"
"void main() {\n"
" gl_Position = vMatrix*vPosition;\n"
" gl_PointSize = 10.0; \n"
"}";
//片段着色器代码
char fragmentShaderCode[] = "precision mediump float;"
"uniform vec4 vColor;"
"void main() {"
" gl_FragColor = vColor;"
"}";
//书写本地方法的具体逻辑
void JNICALL init(JNIEnv *env, jobject obj) {
//初始化
}
/**初始化
*
* @param env
* @param obj
*/
void JNICALL surfaceCreated(JNIEnv *env, jobject obj) {
//设置背景颜色为黑色
glClearColor(0, 0, 0, 0);
//创建顶点着色器
vertexShader = LoadShader(GL_VERTEX_SHADER, vertexShaderCode);
//创建片元着色器
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
//将顶点着色器和片元着色器交给统一程序管理
mProgram = linkProgram(vertexShader, fragmentShader);
}
/**图形尺寸
*
* @param env
* @param obj
* @param width
* @param height
*/
glm::mat4 mProjectionMatrix;
glm::mat4 mViewMatrix;
glm::mat4 mMVPMatrix;
JNIEXPORT void JNICALL surfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) {
//设置视口
glViewport(0, 0, width, height);
//宽高比
float ratio = (float) width / height;
//二维图形设置正交投影矩阵即可
mProjectionMatrix = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f,
100.0f); //ratio 一般表示视口的宽高比,width/height
//相机位置
mViewMatrix = glm::lookAt(glm::vec3(0, 0, -3), // Camera is at (0,0,1), in World Space 相机位置
glm::vec3(0, 0, 0), // and looks at the origin 观察点坐标
glm::vec3(0, 1, 0));
//矩阵合并
mMVPMatrix = mProjectionMatrix * mViewMatrix;
}
/**渲染绘制
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL drawFrame(JNIEnv *env, jobject obj) {
//清除颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//使用程序
glUseProgram(mProgram);
//获取顶点着色器的vMatrix成员句柄
GLint mMatrixHandler = glGetUniformLocation(mProgram, "vMatrix");
//矩阵转换成数组
float mMVPMatrixArray[16];
int m = 0;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++){
mMVPMatrixArray[m] = mMVPMatrix[i][j];
m++;
}
//指定vMatrix的值
glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrixArray);
//获取顶点着色器的vPosition成员句柄
GLint mPositionHandle = glGetAttribLocation(mProgram, "vPosition");
//启用图形顶点的句柄
glEnableVertexAttribArray(mPositionHandle);
//准备图形的坐标数据
glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GL_FLOAT, GL_FALSE, vertexStride, vertexPoints);
//获取片元着色器的vColor成员的句柄
GLint mColorHandle = glGetUniformLocation(mProgram, "vColor");
//设置绘制图形的颜色
glUniform4fv(mColorHandle, 1, color);
//顶点法绘制图形
glLineWidth(10.0f);
// glDrawArrays(GL_LINE_LOOP,0,vertexCount);
//索引法绘制图形
glDrawElements(GL_TRIANGLES,getArrayLen(index),GL_UNSIGNED_SHORT,index);
//禁止顶点数组的句柄
glDisableVertexAttribArray(mPositionHandle);
}
/**加载着色器
*
*/
JNIEXPORT GLuint LoadShader(int type, char *shaderCode) {
//创建一个着色器
GLuint shader = glCreateShader(type);
if (shader != 0) {
//加载到着色器
glShaderSource(shader, 1, &shaderCode, NULL);
//编译着色器
glCompileShader(shader);
//检测状态
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == 0) {
//声明log长度变量
GLint infoLen = 0;
//获取长度并赋值
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
//创建成功小于等于1
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
printf("SHADER ERROR!");
free(infoLog);
}
//创建失败
glDeleteShader(shader);
return 0;
}
return shader;
} else {
//创建失败
return 0;
}
}
/**链接着色器
*
*/
JNIEXPORT GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
if (program != 0) {
//将顶点着色器加入到程序
glAttachShader(program, vertexShader);
//将片元着色器加入到程序中
glAttachShader(program, fragmentShader);
//链接着色器程序
glLinkProgram(program);
//检测状态
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) {
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetProgramInfoLog(program, infoLen, NULL, infoLog);
printf("PROGRAM ERROR!");
free(infoLog);
}
glDeleteProgram(program);
return 0;
}
return program;
} else {
//创建失败
return 0;
}
}
/** 动态注册
* @param env
* @return
*/
//本地方法声明和具体逻辑连接
JNINativeMethod methods[] = {
{"init", "()V", (void *) init},
{"surfaceCreated", "()V", (void *) surfaceCreated},
{"surfaceChanged", "(II)V", (void *) surfaceChanged},
{"drawFrame", "()V", (void *) drawFrame}
};
/** 动态注册
* @param env
* @return
*/
jint registerNativeMethod(JNIEnv *env) {
//到本地方法存在的类找出其方法声明
jclass cl = env->FindClass("com/example/openglndk/WaveRenderer");
if ((env->RegisterNatives(cl, methods, sizeof(methods) / sizeof(methods[0]))) < 0) {
return -1;
}
return 0;
}
/** 加载默认回调
* @param vm
* @param reserved
* @return
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
//注册方法
if (registerNativeMethod(env) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
绘制纯色圆形
JAVA版本
package com.example.openglndk;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRenderer implements GLSurfaceView.Renderer {
private final static int COORDS_PER_VERTEX = 3;
private int n = 360;
private float radius = 0.3f;
private final int vertexStride = COORDS_PER_VERTEX * 4;
private FloatBuffer vertexBuffer;
private int vertexShader;
private int fragmentShader;
private int mProgram;
private int vertexCount;
private float vertexPoints[];
private float height = 0.0f;
private float color[] = {1.0f, 0.5f, 0.7f, 0.0f};
private float[] createPositions() {
ArrayList<Float> data = new ArrayList<>();
float angDegSpan = 360f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan) {
data.add((float) (radius * Math.sin(i * Math.PI / 180f)));
data.add((float) (radius * Math.cos(i * Math.PI / 180f)));
data.add(height);
}
float[] f = new float[data.size()];
for (int i = 0; i < f.length; i++) {
f[i] = data.get(i);
}
return f;
}
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"void main() {" +
" gl_Position = vMatrix*vPosition;" +
" gl_PointSize = 10.0;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
public MyRenderer() {
vertexPoints = createPositions();
vertexCount = vertexPoints.length / COORDS_PER_VERTEX;
vertexBuffer = ByteBuffer.allocateDirect(
vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
GLES30.glClearColor(1, 1, 1, 1);
vertexShader = LoadShader(GLES30.GL_VERTEX_SHADER,
vertexShaderCode);
fragmentShader = LoadShader(GLES30.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = linkProgram(vertexShader, fragmentShader);
}
private float mProjectionMatrix[] = new float[16];
private float mViewMatrix[] = new float[16];
private float mMVPMatrix[] = new float[16];
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
GLES30.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
@Override
public void onDrawFrame(GL10 gl10) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
GLES30.glUseProgram(mProgram);
int mMatrixHandler = GLES30.glGetUniformLocation(mProgram, "vMatrix");
GLES30.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0);
int mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
GLES30.glEnableVertexAttribArray(mPositionHandle);
GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES30.GL_FLOAT, false,
vertexStride, vertexBuffer);
int mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");
GLES30.glUniform4fv(mColorHandle, 1, color, 0);
GLES30.glLineWidth(10.0f);
GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, vertexCount);
GLES30.glDisableVertexAttribArray(mPositionHandle);
}
private static int LoadShader(int type, String shaderCode) {
final int shaderId = GLES30.glCreateShader(type);
if (shaderId != 0) {
GLES30.glShaderSource(shaderId, shaderCode);
GLES30.glCompileShader(shaderId);
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0) {
String logInfo = GLES30.glGetShaderInfoLog(shaderId);
System.err.println(logInfo);
GLES30.glDeleteShader(shaderId);
return 0;
}
return shaderId;
} else {
return 0;
}
}
public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
if (programId != 0) {
GLES30.glAttachShader(programId, vertexShaderId);
GLES30.glAttachShader(programId, fragmentShaderId);
GLES30.glLinkProgram(programId);
final int[] linkStatus = new int[1];
GLES30.glGetProgramiv(programId, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0) {
String logInfo = GLES30.glGetProgramInfoLog(programId);
System.err.println(logInfo);
GLES30.glDeleteProgram(programId);
return 0;
}
return programId;
} else {
return 0;
}
}
}
C++版本
我弄了好久,一天多,从JAVA版本到C++版本。总结起来还是因为C++的基础不够牢固。C++中求数组长度没有函数,没有ArrayList数据结构,创建数组等都不太熟悉。然后就找不到错误在哪里,最后我一点一点从断点调试,才发现问题,没有拿到Vector中的数据,C++函数无法返回数组,只能返回指向数组的指针。也拿不到准确的建造数组的长度,Vector中取数据,按照数组格式,可能取不到数据,要按照迭代器进行遍历取数据。总之因为一堆原因,C++和JAVA的各种语法和数据结构的不同,导致创建不了点的坐标,拿不到那种float数据类型的数组,就没有点,绘制不了。最后我不在函数中拿到数组了,我直接返回Vector数据结构,然后在初始化中,使用迭代器遍历Vector,将其中数据直接放入到数组中,终于拿到了数据,完成了绘制。
//
// Created by lvjunkai on 2022/2/21.
//
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#include <malloc.h>
#include <math.h>
#include <vector>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
//命名空间
using namespace std;
//常数Π
const double PI = acos(-1.0);
//声明自定义函数
//创建编译加载
GLuint LoadShader(int type, char *shaderCode);
//链接统一程序
GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);
//模板技术定义的函数
//用于求数组长度
template<class T>
GLsizei getArrayLen(T &array) {
return (sizeof(array) / sizeof(array[0]));
}
//坐标个数(xyz)
const GLint COORDS_PER_VERTEX = 3;
//顶点之间的偏移量
const GLsizei vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节
//声明顶点着色器
GLuint vertexShader;
//声明片元着色器
GLuint fragmentShader;
//声明着色器管理程序
GLuint mProgram;
//定义正方形四点坐标
vector<float> vertexVector; //存放顶点数据的数据结构
float vertexPoints[1083]; //顶点数组
float radius = 0.3f; //半径
int n = 360; //切割份数
//顶点个数
GLsizei vertexCount;
//设置颜色,依次为红绿蓝和透明通道
float color[] = {1.0f, 1.0f, 0.0f, 0.0f};
//顶点着色器代码
char vertexShaderCode[] = "attribute vec4 vPosition;"
"uniform mat4 vMatrix;"
"void main() {"
" gl_Position = vMatrix*vPosition;"
" gl_PointSize = 10.0;"
"}";
//片段着色器代码
char fragmentShaderCode[] = "precision mediump float;"
"uniform vec4 vColor;"
"void main() {"
" gl_FragColor = vColor;"
"}";
//创建顶点坐标放入vector数据结构中
vector<float> createPositions() {
vector<float> data;
//圆上点
float angDegSpan = 360.0f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan) {
data.push_back((float) (radius * sin(i * PI / 180.0f)));
data.push_back((float) (radius * cos(i * PI / 180.0f)));
data.push_back(0.0f);
}
return data;
}
JNIEXPORT void JNICALL init(JNIEnv *env, jobject obj) {
//拿到顶点数据
vertexVector = createPositions();
//创建迭代器
vector<float>::iterator t;
int i = 0;
//迭代器遍历vector中的数据
//将其中数据放入数组中,形成顶点坐标
for (t = vertexVector.begin(); t != vertexVector.end(); t++) {
vertexPoints[i] = *t;
i++;
}
vertexCount = getArrayLen(vertexPoints) / COORDS_PER_VERTEX;
}
//书写本地方法的具体逻辑
/**初始化
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL surfaceCreated(JNIEnv *env, jobject obj) {
//设置背景颜色为黑色
glClearColor(0, 0, 0, 0);
//创建顶点着色器
vertexShader = LoadShader(GL_VERTEX_SHADER, vertexShaderCode);
//创建片元着色器
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
//将顶点着色器和片元着色器交给统一程序管理
mProgram = linkProgram(vertexShader, fragmentShader);
}
/**图形尺寸
*
* @param env
* @param obj
* @param width
* @param height
*/
glm::mat4 mProjectionMatrix;
glm::mat4 mViewMatrix;
glm::mat4 mMVPMatrix;
JNIEXPORT void JNICALL surfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) {
//设置视口
glViewport(0, 0, width, height);
//宽高比
float ratio = (float) width / height;
//正交投影矩阵
mProjectionMatrix = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f,
100.0f); //ratio 一般表示视口的宽高比,width/height
//透视投影矩阵
// glm::mat4 Projection = glm::perspective(45.0f, ratio, 0.1f, 100.f); //ratio 一般表示视口的宽高比,width/height
//相机位置
mViewMatrix = glm::lookAt(glm::vec3(0, 0, -3), // Camera is at (0,0,1), in World Space 相机位置
glm::vec3(0, 0, 0), // and looks at the origin 观察点坐标
glm::vec3(0, 1, 0));
//矩阵合并
mMVPMatrix = mProjectionMatrix * mViewMatrix;
}
/**渲染绘制
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL drawFrame(JNIEnv *env, jobject obj) {
//清除颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//使用程序
glUseProgram(mProgram);
//获取变换矩阵vMatrix成员句柄
GLint mMatrixHandler = glGetUniformLocation(mProgram, "vMatrix");
//矩阵转换成数组
float mMVPMatrixArray[16];
int m = 0;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++){
mMVPMatrixArray[m] = mMVPMatrix[i][j];
m++;
}
//指定vMatrix的值
glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrixArray);
//获取顶点着色器的vPosition成员句柄
GLint mPositionHandle = glGetAttribLocation(mProgram, "vPosition");
//启用图形顶点的句柄
glEnableVertexAttribArray(mPositionHandle);
//准备图形的坐标数据
glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GL_FLOAT, GL_FALSE, vertexStride,
vertexPoints);
//获取片元着色器的vColor成员的句柄
GLint mColorHandle = glGetUniformLocation(mProgram, "vColor");
//设置绘制图形的颜色
glUniform4fv(mColorHandle, 1, color);
//绘制图形
glLineWidth(10.0f);
glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
//禁止顶点数组的句柄
glDisableVertexAttribArray(mPositionHandle);
}
/**加载着色器
*
*/
JNIEXPORT GLuint LoadShader(int type, char *shaderCode) {
//创建一个着色器
GLuint shader = glCreateShader(type);
if (shader != 0) {
//加载到着色器
glShaderSource(shader, 1, &shaderCode, NULL);
//编译着色器
glCompileShader(shader);
//检测状态
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == 0) {
//声明log长度变量
GLint infoLen = 0;
//获取长度并赋值
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
//创建成功小于等于1
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
printf("SHADER ERROR!");
free(infoLog);
}
//创建失败
glDeleteShader(shader);
return 0;
}
return shader;
} else {
//创建失败
return 0;
}
}
/**链接着色器
*
*/
JNIEXPORT GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
if (program != 0) {
//将顶点着色器加入到程序
glAttachShader(program, vertexShader);
//将片元着色器加入到程序中
glAttachShader(program, fragmentShader);
//链接着色器程序
glLinkProgram(program);
//检测状态
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) {
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetProgramInfoLog(program, infoLen, NULL, infoLog);
printf("PROGRAM ERROR!");
free(infoLog);
}
glDeleteProgram(program);
return 0;
}
return program;
} else {
//创建失败
return 0;
}
}
/** 动态注册
* @param env
* @return
*/
//本地方法声明和具体逻辑连接
JNINativeMethod methods[] = {
{"init", "()V", (void *) init},
{"surfaceCreated", "()V", (void *) surfaceCreated},
{"surfaceChanged", "(II)V", (void *) surfaceChanged},
{"drawFrame", "()V", (void *) drawFrame}
};
/** 动态注册
* @param env
* @return
*/
jint registerNativeMethod(JNIEnv *env) {
//到本地方法存在的类找出其方法声明
jclass cl = env->FindClass("com/example/openglndk/WaveRenderer");
if ((env->RegisterNatives(cl, methods, sizeof(methods) / sizeof(methods[0]))) < 0) {
return -1;
}
return 0;
}
/** 加载默认回调
* @param vm
* @param reserved
* @return
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
//注册方法
if (registerNativeMethod(env) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
package com.example.openglndk;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class WaveRenderer implements GLSurfaceView.Renderer {
static{
System.loadLibrary("native-wave");
}
public native void init();
public native void surfaceCreated();
public native void surfaceChanged(int width, int height);
public native void drawFrame();
public WaveRenderer(){
init();
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
surfaceCreated();
}
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
surfaceChanged(width,height);
}
@Override
public void onDrawFrame(GL10 gl10) {
drawFrame();
}
}
波纹扩散demo
//
// Created by lvjunkai on 2022/2/21.
//
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#include <malloc.h>
#include <vector>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
//命名空间
using namespace std;
//常数Π
const double PI = acos(-1.0);
//声明自定义函数
//创建编译加载
GLuint LoadShader(int type, char *shaderCode);
//链接统一程序
GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);
//模板技术定义的函数
//用于求数组长度
template<class T>
GLsizei getArrayLen(T &array) {
return (sizeof(array) / sizeof(array[0]));
}
//坐标个数(xyz)
const GLint COORDS_PER_VERTEX = 3;
//顶点之间的偏移量
const GLsizei vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节
//声明顶点着色器
GLuint vertexShader;
//声明片元着色器
GLuint fragmentShader;
//声明着色器管理程序
GLuint mProgram;
//定义正方形四点坐标
vector<float> vertexVector; //存放顶点数据的数据结构
float vertexPoints[1083]; //顶点数组
//float radius; //半径
int n = 360; //切割份数
//顶点个数
GLsizei vertexCount;
//设置颜色,依次为红绿蓝和透明通道
float color[] = {1.0f, 1.0f, 0.0f, 0.0f};
//顶点着色器代码
char vertexShaderCode[] = "attribute vec4 vPosition;"
"uniform mat4 vMatrix;"
"void main() {"
" gl_Position = vMatrix*vPosition;"
" gl_PointSize = 10.0;"
"}";
//片段着色器代码
char fragmentShaderCode[] = "precision mediump float;"
"uniform vec4 vColor;"
"void main() {"
" gl_FragColor = vColor;"
"}";
//创建顶点坐标放入vector数据结构中
vector<float> createPositions(float radius) {
vector<float> data;
//圆上点
float angDegSpan = 360.0f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan) {
data.push_back((float) (radius * sin(i * PI / 180.0f)));
data.push_back((float) (radius * cos(i * PI / 180.0f)));
data.push_back(0.0f);
}
return data;
}
JNIEXPORT void JNICALL init(JNIEnv *env, jobject obj,float radius) {
//拿到顶点数据
vertexVector = createPositions(radius);
//创建迭代器
vector<float>::iterator t;
int i = 0;
//迭代器遍历vector中的数据
//将其中数据放入数组中,形成顶点坐标
for (t = vertexVector.begin(); t != vertexVector.end(); t++) {
vertexPoints[i] = *t;
i++;
}
vertexCount = getArrayLen(vertexPoints) / COORDS_PER_VERTEX;
}
//书写本地方法的具体逻辑
/**初始化
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL surfaceCreated(JNIEnv *env, jobject obj) {
//设置背景颜色为黑色
glClearColor(0, 0, 0, 0);
//创建顶点着色器
vertexShader = LoadShader(GL_VERTEX_SHADER, vertexShaderCode);
//创建片元着色器
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
//将顶点着色器和片元着色器交给统一程序管理
mProgram = linkProgram(vertexShader, fragmentShader);
}
/**图形尺寸
*
* @param env
* @param obj
* @param width
* @param height
*/
glm::mat4 mProjectionMatrix;
glm::mat4 mViewMatrix;
glm::mat4 mMVPMatrix;
float mMVPMatrixArray[16];
JNIEXPORT void JNICALL surfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) {
//设置视口
glViewport(0, 0, width, height);
//宽高比
float ratio = (float) width / height;
//正交投影矩阵
mProjectionMatrix = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f,
100.0f); //ratio 一般表示视口的宽高比,width/height
//透视投影矩阵
// glm::mat4 Projection = glm::perspective(45.0f, ratio, 0.1f, 100.f); //ratio 一般表示视口的宽高比,width/height
//相机位置
mViewMatrix = glm::lookAt(glm::vec3(0, 0, -3), // Camera is at (0,0,1), in World Space 相机位置
glm::vec3(0, 0, 0), // and looks at the origin 观察点坐标
glm::vec3(0, 1, 0));
//矩阵合并
mMVPMatrix = mProjectionMatrix * mViewMatrix;
//矩阵转换成数组
int m = 0;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
mMVPMatrixArray[m] = mMVPMatrix[i][j];
m++;
}
}
/**渲染绘制
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL drawFrame(JNIEnv *env, jobject obj) {
//清除颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//使用程序
glUseProgram(mProgram);
//获取变换矩阵vMatrix成员句柄
GLint mMatrixHandler = glGetUniformLocation(mProgram, "vMatrix");
//指定vMatrix的值
glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrixArray);
//获取顶点着色器的vPosition成员句柄
GLint mPositionHandle = glGetAttribLocation(mProgram, "vPosition");
//启用图形顶点的句柄
glEnableVertexAttribArray(mPositionHandle);
//准备图形的坐标数据
glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GL_FLOAT, GL_FALSE, vertexStride,
vertexPoints);
//获取片元着色器的vColor成员的句柄
GLint mColorHandle = glGetUniformLocation(mProgram, "vColor");
//设置绘制图形的颜色
glUniform4fv(mColorHandle, 1, color);
//绘制图形
glLineWidth(3.0f);
glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
//禁止顶点数组的句柄
glDisableVertexAttribArray(mPositionHandle);
}
/**加载着色器
*
*/
JNIEXPORT GLuint LoadShader(int type, char *shaderCode) {
//创建一个着色器
GLuint shader = glCreateShader(type);
if (shader != 0) {
//加载到着色器
glShaderSource(shader, 1, &shaderCode, NULL);
//编译着色器
glCompileShader(shader);
//检测状态
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == 0) {
//声明log长度变量
GLint infoLen = 0;
//获取长度并赋值
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
//创建成功小于等于1
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
printf("SHADER ERROR!");
free(infoLog);
}
//创建失败
glDeleteShader(shader);
return 0;
}
return shader;
} else {
//创建失败
return 0;
}
}
/**链接着色器
*
*/
JNIEXPORT GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
if (program != 0) {
//将顶点着色器加入到程序
glAttachShader(program, vertexShader);
//将片元着色器加入到程序中
glAttachShader(program, fragmentShader);
//链接着色器程序
glLinkProgram(program);
//检测状态
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) {
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetProgramInfoLog(program, infoLen, NULL, infoLog);
printf("PROGRAM ERROR!");
free(infoLog);
}
glDeleteProgram(program);
return 0;
}
return program;
} else {
//创建失败
return 0;
}
}
/** 动态注册
* @param env
* @return
*/
//本地方法声明和具体逻辑连接
JNINativeMethod methods[] = {
{"init", "(F)V", (void *) init},
{"surfaceCreated", "()V", (void *) surfaceCreated},
{"surfaceChanged", "(II)V", (void *) surfaceChanged},
{"drawFrame", "()V", (void *) drawFrame}
};
/** 动态注册
* @param env
* @return
*/
jint registerNativeMethod(JNIEnv *env) {
//到本地方法存在的类找出其方法声明
jclass cl = env->FindClass("com/example/openglndk/WaveRenderer");
if ((env->RegisterNatives(cl, methods, sizeof(methods) / sizeof(methods[0]))) < 0) {
return -1;
}
return 0;
}
/** 加载默认回调
* @param vm
* @param reserved
* @return
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
//注册方法
if (registerNativeMethod(env) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
package com.example.openglndk;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class WaveRenderer implements GLSurfaceView.Renderer {
static{
System.loadLibrary("native-wave");
}
public native void init(float radius);
public native void surfaceCreated();
public native void surfaceChanged(int width,int height);
public native void drawFrame();
public WaveRenderer(float radius){
init(radius);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
surfaceCreated();
}
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
surfaceChanged(width,height);
}
@Override
public void onDrawFrame(GL10 gl10) {
drawFrame();
}
}
MainActivity ——用于扩散操作,有bug
package com.example.openglndk;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView mGLSurfaceView;
private float radius = 0.1f;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
setContentView(mGLSurfaceView);
mGLSurfaceView.setEGLContextClientVersion(3);
@SuppressLint("HandlerLeak") Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
GLSurfaceView.Renderer renderer = new WaveRenderer((Float) msg.obj);
mGLSurfaceView.setRenderer(renderer);
}
}
};
Runnable runnable = new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = 1;
message.obj = radius;
while(radius <= 0.5f){
handler.sendMessage(message);
radius += 0.1f;
}
}
};
handler.post(runnable);
}
}
总结绘制整体流程
- 创建一个
Activity 作为窗口,布局只有一个GLSurfaceView 控件用来显示绘制的内容。 - 新建一个
Renderer 渲染器(核心),将3D 物体绘制到屏幕上。
- 新建渲染器,实现
GLSurfaceView.Renderer 接口。 - 声明
Native 方法,将其变成JNI 类。 - 用声明的
Native 方法复写接口的三个方法:onSurfaceCreated ,onSurfaceChanged 和onDrawFrame 方法。 - 链接到声明方法具体实现库的文件名。
- 新建声明方法具体实现库。
- 定义圆点坐标
- 定义颜色数据
- 书写着色器代码
- 创建和编译着色器
- 将着色器交给统一的程序管理
- 设置视口
- 清除颜色缓冲区
- 绘制图形
- 在库编译文件
CMakeLists.txt 中,加入该库,使其可以进行编译执行。
|