相关文章推荐


Android使用NDK  OpenGL ES3.0绘制一个三角形


网上已经有很多OpenCV的教程,不过大都是基于Java层调用openGL接口,若使用Java层openGL接口绘制三角形,还是比较简单的,但要是使用NDK C++ 实现,还是有点复杂。

本文将使用Android NDK开发,利用C++的 OpenGL ES3.0绘制一个三角形。绘制三角形的C/C++源码大部分是参考:《 OPENGL ES 3.0编程指南 》第二章的代码,但该书只有源码,没有工程项目,是用Android.mk配置,要做成Android Studio Demo还是要花点力气的。本博客的OpenGL的开发,其配置文件使用CMakeLists.txt,Android Studio 2.3以上NDK开发很容易啦,其配置方法使用CMakeLists.txt会比使用Android.mk更容易。

这里不具体分析绘制三角形的代码实现过程了,毕竟《 OPENGL ES 3.0编程指南 》这本书已经很详细啦。

本项目源码下载地址:​ ​https://github.com/PanJinquan/openGL-Demo​ ​ ,要是觉得不错,给个” Star “哈

开发环境:

1、新建项目:

新建Android工程一定要勾选“Include C++ support”,这样新建的Android工程会直接支持NDK开发,避免各种配置问题,如果提示没有NDK,请下载NDK,并在工程“Project Structure”中导入即可。

Android使用NDK  OpenGL ES3.0绘制一个三角形_OpenGL ES3.0

我的工程目录是这样的:

Android使用NDK  OpenGL ES3.0绘制一个三角形_android_02

2、新建RendererJNI类

package opengl.panjq.com.opengl_demo;

import android.opengl.GLSurfaceView.Renderer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.content.res.AssetManager;
import android.opengl.GLSurfaceView;
import android.util.Log;

public class RendererJNI implements GLSurfaceView.Renderer {
static {
System.loadLibrary("gltest-lib");
}
private AssetManager mAssetMgr = null;
private final String mLogTag = "ndk-build";

public native void glesInit();
public native void glesRender();
public native void glesResize(int width, int height);

public native void readShaderFile(AssetManager assetMgr);

public RendererJNI(Context context) {
mAssetMgr = context.getAssets();
if (null == mAssetMgr) {
Log.e(mLogTag, "getAssets() return null !");
}
}

/**
* 当创建 GLSurfaceView时,系统调用这个方法.使用这个方法去执行只需要发生一次的动作,
* 例如设置OpenGL环境参数或者初始化OpenGL graphic 对象.
* @param gl
* @param config
*/
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
readShaderFile(mAssetMgr);
glesInit();
}

/**
* 当GLSurfaceView 几何学发生改变时系统调用这个方法.包括 GLSurfaceView 的大小发生改变或者横竖屏发生改变.
* 使用这个方法去响应GLSurfaceView 容器的改变
* @param gl
* @param width
* @param height
*/
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
glesResize(width, height);
}

/**
* 执行渲染工作:当系统每一次重画 GLSurfaceView 时调用.使用这个方法去作为主要的绘制和重新绘制graphic 对象的执行点.
* @param gl
*/
@Override
public void onDrawFrame(GL10 gl) {
glesRender();
}
}

3、修改MainActivity.java文件

package opengl.panjq.com.opengl_demo;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import android.app.ActivityManager;
import android.content.pm.ConfigurationInfo;
import android.util.Log;

import static android.opengl.GLSurfaceView.RENDERMODE_WHEN_DIRTY;


public class MainActivity extends AppCompatActivity {
private final int CONTEXT_CLIENT_VERSION = 3;
private GLSurfaceView mGLSurfaceView;
RendererJNI mRenderer;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mGLSurfaceView = new GLSurfaceView(this);
mRenderer=new RendererJNI(this);
if (detectOpenGLES30()) {
// 设置OpenGl ES的版本
mGLSurfaceView.setEGLContextClientVersion(CONTEXT_CLIENT_VERSION);
// 设置与当前GLSurfaceView绑定的Renderer
mGLSurfaceView.setRenderer(mRenderer);
// 设置渲染的模式
mGLSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);
} else {
Log.e("opengles30", "OpenGL ES 3.0 not supported on device. Exiting...");
finish();
}

setContentView(mGLSurfaceView);
}

@Override
protected void onResume() {
super.onResume();
mGLSurfaceView.onResume();
}

@Override
protected void onPause() {
super.onPause();
mGLSurfaceView.onPause();
}

private boolean detectOpenGLES30() {
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo();

return (info.reqGlEsVersion >= 0x30000);
}
}

4.新建C++ JNI文件

RendererJNI.h头文件

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class opengl_panjq_com_opengl_demo_RendererJNI */

#ifndef _Included_opengl_panjq_com_opengl_demo_RendererJNI
#define _Included_opengl_panjq_com_opengl_demo_RendererJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: opengl_panjq_com_opengl_demo_RendererJNI
* Method: glesInit
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesInit
(JNIEnv *, jobject);

/*
* Class: opengl_panjq_com_opengl_demo_RendererJNI
* Method: glesRender
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesRender
(JNIEnv *, jobject);

/*
* Class: opengl_panjq_com_opengl_demo_RendererJNI
* Method: glesResize
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesResize
(JNIEnv *, jobject, jint, jint);


JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_readShaderFile
(JNIEnv *env, jobject self, jobject assetManager);

#ifdef __cplusplus
}
#endif
#endif

RendererJNI.cpp源文件

这里提供一个方法char* readShaderSrcFile(char *shaderFile, AAssetManager *pAssetManager),用于获取assets资源文件*.glsl文件:

char *pVertexShader = readShaderSrcFile("shader/vs.glsl", g_pAssetManager);
char *pFragmentShader = readShaderSrcFile("shader/fs.glsl", g_pAssetManager);

当然,也可以写死在文件中,如:

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 ( 1.0, 0.0, 0.0, 1.0 ); \n"
"} \n";

再用LoadShader加载:

vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );
fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );

完整的代码如下

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include "RendererJNI.h"
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <GLES3/gl3.h>
#include <android/asset_manager_jni.h>
#include <android/log.h>

#define LOG_TAG "ndk-build"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
GLint g_programObject;
jint g_width;
jint g_height;

AAssetManager* g_pAssetManager = NULL;
char* readShaderSrcFile(char *shaderFile, AAssetManager *pAssetManager)
{
AAsset *pAsset = NULL;
char *pBuffer = NULL;
off_t size = -1;
int numByte = -1;

if (NULL == pAssetManager)
{
LOGE("pAssetManager is null!");
return NULL;
}
pAsset = AAssetManager_open(pAssetManager, shaderFile, AASSET_MODE_UNKNOWN);
//LOGI("after AAssetManager_open");

size = AAsset_getLength(pAsset);
LOGI("after AAssetManager_open");
pBuffer = (char *)malloc(size+1);
pBuffer[size] = '\0';

numByte = AAsset_read(pAsset, pBuffer, size);
LOGI("%s : [%s]", shaderFile, pBuffer);
AAsset_close(pAsset);

return pBuffer;
}


GLuint LoadShader ( GLenum type, const char *shaderSrc )
{
GLuint shader;
GLint compiled;

// Create the shader object
shader = glCreateShader ( type );

if ( shader == 0 )
{
return 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 = (char *)malloc ( sizeof ( char ) * infoLen );

glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
LOGE("Error compiling shader:[%s]", infoLog );

free ( infoLog );
}

glDeleteShader ( shader );
return 0;
}

return shader;

}

//*********************************************************************************
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesInit
(JNIEnv *pEnv, jobject obj){
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 ( 1.0, 0.0, 0.0, 1.0 ); \n"
"} \n";

char *pVertexShader = readShaderSrcFile("shader/vs.glsl", g_pAssetManager);
char *pFragmentShader = readShaderSrcFile("shader/fs.glsl", g_pAssetManager);

GLuint vertexShader;
GLuint fragmentShader;
GLuint programObject;
GLint linked;

// Load the vertex/fragment shaders
//vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );
//fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );
vertexShader = LoadShader ( GL_VERTEX_SHADER, pVertexShader );
fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, pFragmentShader );

// Create the program object
programObject = glCreateProgram ( );

if ( programObject == 0 )
{
return;
}

glAttachShader ( programObject, vertexShader );
glAttachShader ( programObject, fragmentShader );

// 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 = (char *)malloc ( sizeof ( char ) * infoLen );

glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
LOGE("Error linking program:[%s]", infoLog );

free ( infoLog );
}

glDeleteProgram ( programObject );
return;
}

// Store the program object
g_programObject = programObject;

glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
}

/*
* Class: opengl_panjq_com_opengl_demo_RendererJNI
* Method: glesRender
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesRender
(JNIEnv *pEnv, jobject obj){
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, g_width, g_height );

// Clear the color buffer
glClear ( GL_COLOR_BUFFER_BIT );

// Use the program object
glUseProgram ( g_programObject );

// Load the vertex data
glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
glEnableVertexAttribArray ( 0 );

glDrawArrays ( GL_TRIANGLES, 0, 3 );

}

/*
* Class: opengl_panjq_com_opengl_demo_RendererJNI
* Method: glesResize
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_glesResize
(JNIEnv *pEnv, jobject obj, jint width, jint height){
g_width = width;
g_height = height;

}


JNIEXPORT void JNICALL Java_opengl_panjq_com_opengl_1demo_RendererJNI_readShaderFile
(JNIEnv *env, jobject self, jobject assetManager){
if (assetManager && env)
{
//LOGI("before AAssetManager_fromJava");
g_pAssetManager = AAssetManager_fromJava(env, assetManager);
//LOGI("after AAssetManager_fromJava");
if (NULL == g_pAssetManager)
{
LOGE("AAssetManager_fromJava() return null !");
}
}
else
{
LOGE("assetManager is null !");
}
}

5、修改CMakeLists.txt文件

OpenGL ES开发需要把OpenGL的相关依赖库导入进来,其方法很简单,直接在target_link_libraries中添加GLESv2 或者GLESv3都可以,由于需要在NDK使用AAssetManager操作asset资源,因此需要在target_link_libraries中,也把android添加进来,否则会出错:Error: undefined reference to 'AAssetManager_fromJava'。

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
include_directories(${CMAKE_SOURCE_DIR} src/main/cpp)
add_library( # Sets the name of the library.
gltest-lib

# Sets the library as a shared library.
SHARED

# Provides a relative path to your source file(s).
src/main/cpp/RendererJNI.cpp )

add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED

# Provides a relative path to your source file(s).
src/main/cpp/native-lib.cpp )



# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

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 )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
gltest-lib
android # 错误:Error: undefined reference to 'AAssetManager_fromJava'
GLESv3 # 把opengl库文件添加进来,GLESv3
# Links the target library to the log library
# included in the NDK.
${log-lib} )
target_link_libraries( # Specifies the target library.
native-lib

# Links the target library to the log library
# included in the NDK.
${log-lib} )

Run,Run,Run,效果图:

Android使用NDK  OpenGL ES3.0绘制一个三角形_OpenGL NDK开发

九宫格python代码 九宫格拼图代码

有一个需求九张图片拼接在一起,图片类型有P类型(索引图)、灰度图、RGB、RGBA类型 九张图片代码如下import glob from PIL import Image def image_concat(image_names): """ image_names: list, 存放的是图片的绝对路径 """ # 1.创建一块背景布 image = Image.open(

springboot接入redis序列化的坑 springboot redis序列化

背景在springboot中使用redis缓存结合spring缓存注解,当缓存成功后使用gui界面查看redis中的数据原因springboot中默认的序列化是jdk提供的 Serializable 方式解决方法如果想要序列化成json格式的数据,可以自定义一个redis的config类,设置序列化规则即可,如下:@Configuration public class RedisConfig ex

spark 将监控信息推送到prometheus sparkstreaming怎么进行监控

SparkStream 监控文件目录时,只能监控文件内是否添加新的文件,如果文件名没有改变只是文件内容改变,那么不会检测出有文件进行了添加。object SparkStreaming_TextFile { def main(args: Array[String]): Unit = { Logger.getLogger("org.apache.spark").setLevel(Level.

python怎么打印二维数组的元素个数 python3二维数组

文章目录1、简介2、功能实现2.1、 一个表面上看起来是的 数组2.2 直接赋值的列表可以实现2.3 在列表中 使用 for 循环赋值2.3 使用numpy 包 1、简介python 实现 二维 、三维数组 ,并且能够改变里面的数值2、功能实现2.1、 一个表面上看起来是的 数组list = [0]*2 print(list) list1 = [[0]*2]*2 print(list1)

 
推荐文章