三、opengles画三角形

第一部分Java端

1)界面

<?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:id="@+id/gl_surface"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

2)自定义MyGLSurfaceView

MyGLSurfaceView集成GLSurfaceView实现父类方法,并加载opengl相关参数和设置

自定义MyGLRender类实现GLSurfaceView.Renderer接口,并在其中引入jni相关的类方法

package com.example.onedrawtri2;

import android.content.Context;
import android.opengl.GLSurfaceView;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class MyGLSurfaceView extends GLSurfaceView {
    private MyRenderer renderer;

    public MyGLSurfaceView(Context context) {
        super(context);
        setEGLContextClientVersion(3);
        renderer = new MyRenderer();
        setRenderer(renderer);
        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
    }
    private class MyRenderer implements GLSurfaceView.Renderer {
        @Override
        public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
            NativeImpl.NativeImpl_init();
        }

        @Override
        public void onSurfaceChanged(GL10 gl10, int width, int height) {
            NativeImpl.NativeImpl_OnSurfaceChanged(width, height);
        }

        @Override
        public void onDrawFrame(GL10 gl10) {
            NativeImpl.NativeImpl_draw();
        }
    }
}

3)jni方法

package com.example.onedrawtri2;

public class NativeImpl {
    static {
        System.loadLibrary("native-lib");
    }

    public static native void NativeImpl_init();
    public static native void NativeImpl_OnSurfaceChanged(int width,int height);
    public static native void NativeImpl_draw();
}

4)MainActivity引入加载MyGLSurfaceView

package com.example.onedrawtri2;

import androidx.appcompat.app.AppCompatActivity;

import android.opengl.GLSurfaceView;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    private GLSurfaceView gLView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        gLView = new MyGLSurfaceView(this);

        setContentView(gLView);
    }
}

第二部分C++端

1)native动态加载jni方法

//
// Created by CreatWall_zhouwen on 2023/4/11.
//

#include "jni.h"
#include <android/log.h>
#include <GLES2/gl2.h>
#include "Util.h"
#include "DrawTriangle.h"
#define NATIVE_RENDER_CLASS_NAME "com/example/onedrawtri2/NativeImpl"
#define TAG "GLTRIANGLE"
#ifdef __cplusplus
extern "C" {
#endif

/*
 * Class:     com_example_onedrawtri2_NativeImpl
 * Method:    init
 * Signature: ()V
 */
JNIEXPORT void JNICALL NativeImpl_init(JNIEnv *env, jobject instance)
{
    DrawTriangle::GetInstance();
    DrawTriangle::GetInstance()->CreateProgram();
}

/*
 * Class:     com_example_onedrawtri2_NativeImpl
 * Method:    OnSurfaceChanged
 * Signature: (II)V
 */
JNIEXPORT void JNICALL NativeImpl_OnSurfaceChanged(JNIEnv *env, jobject instance, jint width, jint height)
{
    glViewport(0, 0, width, height);
}

/*
 * Class:     com_example_onedrawtri2_NativeImpl
 * Method:    draw
 * Signature: ()V
 */
JNIEXPORT void JNICALL NativeImpl_draw(JNIEnv *env, jobject instance)
{
    DrawTriangle::GetInstance()->Draw();
}


#ifdef __cplusplus
}
#endif

static JNINativeMethod g_RenderMethods[] = {
		{"NativeImpl_init",             "()V",       (void *)(NativeImpl_init)},
		{"NativeImpl_OnSurfaceChanged",   "(II)V",     (void *)(NativeImpl_OnSurfaceChanged)},
		{"NativeImpl_draw",        "()V",       (void *)(NativeImpl_draw)},
};

static int RegisterNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int methodNum)
{
	LOGD("RegisterNativeMethods");
	jclass clazz = env->FindClass(className);
	if (clazz == NULL)
	{
		LOGD("RegisterNativeMethods fail. clazz == NULL");
		return JNI_FALSE;
	}
	if (env->RegisterNatives(clazz, methods, methodNum) < 0)
	{
		LOGD("RegisterNativeMethods fail");
		return JNI_FALSE;
	}
	return JNI_TRUE;
}

static void UnregisterNativeMethods(JNIEnv *env, const char *className)
{
	LOGD("UnregisterNativeMethods");
	jclass clazz = env->FindClass(className);
	if (clazz == NULL)
	{
		LOGD("UnregisterNativeMethods fail. clazz == NULL");
		return;
	}
	if (env != NULL)
	{
		env->UnregisterNatives(clazz);
	}
}

// call this func when loading lib
extern "C" jint JNI_OnLoad(JavaVM *jvm, void *p)
{
	LOGD("===== JNI_OnLoad =====");
	jint jniRet = JNI_ERR;
	JNIEnv *env = NULL;
	if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK)
	{
		return jniRet;
	}

	jint regRet = RegisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME, g_RenderMethods,
										sizeof(g_RenderMethods) /
										sizeof(g_RenderMethods[0]));
	if (regRet != JNI_TRUE)
	{
		return JNI_ERR;
	}

	return JNI_VERSION_1_6;
}

extern "C" void JNI_OnUnload(JavaVM *jvm, void *p)
{
	JNIEnv *env = NULL;
	if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK)
	{
		return;
	}

	UnregisterNativeMethods(env, NATIVE_RENDER_CLASS_NAME);
}

2)opengles画三角形类

在里面实现了编写shader着色器,附加编译链接绑定着色器等相关操作。

DrawTriangle.h文件

//
// Created by CreatWall_zhouwen on 2023/4/3.
//

#ifndef ONEDRAWTRIANGLE_DRAWTRIANGLE_H
#define ONEDRAWTRIANGLE_DRAWTRIANGLE_H

#include <GLES3/gl3.h>
class DrawTriangle {
public:
    DrawTriangle(){};
    ~DrawTriangle(){};
    void CreateProgram();
    void Draw();
    static DrawTriangle* GetInstance();
    static void DestroyInstance();
private:
    GLuint program;
    GLuint vertexShaderHandle;
    GLuint fragShaderHandle;
    GLuint VBO, VAO;
};


#endif //ONEDRAWTRIANGLE_DRAWTRIANGLE_H

DrawTriangle.cpp文件

//
// Created by CreatWall_zhouwen on 2023/4/3.
//

#include "DrawTriangle.h"
#include <android/log.h>

#include "Util.h"
#define TAG "DRAWTRINGLE"
DrawTriangle* m_pContext = nullptr;
//编写顶点着色器代码
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.0f, 0.2f, 0.2f, 1.0f );  \n"
        "}                                            \n";
float vertices[] = {
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.0f, 0.5f, 0.0f
};
void DrawTriangle::CreateProgram()
{
    LOGD("CreateProgram Enter");
    //程序中加载编译链接顶点着色器
    vertexShaderHandle = glCreateShader(GL_VERTEX_SHADER);//创建顶点着色器
    const char * s = vShaderStr;
    glShaderSource(vertexShaderHandle, 1, &s, NULL);//绑定源码
    glCompileShader(vertexShaderHandle);//编译
    GLint compiled = 0;
    glGetShaderiv(vertexShaderHandle, GL_COMPILE_STATUS, &compiled);//检查编译是否成功
    if (!compiled)
    {
        LOGD("CreateProgram vertexShaderHandle error");
        return;
    }

    //程序中加载编译链接片段着色器
    fragShaderHandle = glCreateShader(GL_FRAGMENT_SHADER);//创建顶片段着色器
    const char *s1 = fShaderStr;
    glShaderSource(fragShaderHandle, 1, &s1, NULL);//绑定源码
    glCompileShader(fragShaderHandle);//编译
    glGetShaderiv(fragShaderHandle, GL_COMPILE_STATUS, &compiled);//检查编译是否成功
    if (!compiled)
    {
        LOGD("CreateProgram fragShaderHandle error");
        return;
    }

    //创建程序
    program = glCreateProgram();
    if (program)
    {
        GLint AttachStatus = GL_FALSE;
        glAttachShader(program, vertexShaderHandle);//添加顶点着色器
        glGetProgramiv(program, GL_ATTACHED_SHADERS, &AttachStatus);//检查链接是否成功GL_ATTACHED_SHADERS
        if (AttachStatus != 1)
        {
            LOGD("AttachStatus vertexShaderHandle error");
            return;
        }
        GLint AttachStatus1 = GL_FALSE;
        glAttachShader(program, fragShaderHandle);//添加片段着色器
        glGetProgramiv(program, GL_ATTACHED_SHADERS, &AttachStatus1);//检查链接是否成功
        if (AttachStatus1 != 2)
        {
            LOGD("AttachStatus fragShaderHandle error glError (0x%x)  %d",glGetError(),AttachStatus1);
            return;
        }
        glLinkProgram(program);//链接
        GLint linkStatus = GL_FALSE;
        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);//检查链接是否成功
        if (linkStatus != GL_TRUE)
        {
            LOGD("CreateProgram glLinkProgram error");
            return;
        }
        //成功之后可以解绑着色器并删除调,使用完则删除内存
        glDetachShader(program, vertexShaderHandle);
        glDeleteShader(vertexShaderHandle);
        vertexShaderHandle = 0;
       glDetachShader(program, fragShaderHandle);
        glDeleteShader(fragShaderHandle);
        fragShaderHandle = 0;
    }

    glUseProgram(program);//使用着色器程序
    glGenVertexArrays(1, &VAO);//创建一个顶点数组 与顶点属性相绑定
    glGenBuffers(1, &VBO);//创建顶点缓冲对象
    glBindVertexArray(VAO);//绑定顶点数组

    glBindBuffer(GL_ARRAY_BUFFER, VBO);//将GL_ARRAY_BUFFER类型的缓存与VBO绑定
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//之前定义的顶点数据复制到缓冲的内存

    /*
        0;指定我们要配置的顶点属性 就是顶点着色器里面location那个
    */
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *)0);
    glEnableVertexAttribArray(0);//以顶点属性位置值0作为参数,启用顶点属性

    //glBindBuffer(GL_ARRAY_BUFFER, 0);//VBO 已经与顶点属性数组VAO进行绑定了 那么GL_ARRAY_BUFFER就可以解除绑定
    //glBindVertexArray(0);//您可以在之后解除绑定VAO,这样其他VAO调用就不会意外地修改这个VAO*/
    LOGD("CreateProgram End");
    return;
}
void DrawTriangle::Draw()
{
    LOGD("Draw Enter");
    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//使用状态函数
    glClearColor(0.2f, 0.9f, 0.3f, 1.0f); //设置状态函数



    glUseProgram(program);//使用着色器程序
    glBindVertexArray(VAO);//绑定顶点数组  就是使用顶点属性
    /*
    我们希望绘制的是一个三角形,这里传递GL_TRIANGLES给它。
    第二个参数指定了顶点数组的起始索引,我们这里填0。
    最后一个参数指定我们打算绘制多少个顶点,这里是3
    (我们只从我们的数据中渲染一个三角形,它只有3个顶点长)
    */
    glDrawArrays(GL_TRIANGLES, 0, 3);
    glBindVertexArray(0);
    LOGD("Draw end");
}

DrawTriangle *DrawTriangle::GetInstance() {
    if (m_pContext == nullptr)
    {
        m_pContext = new DrawTriangle();
    }
    return m_pContext;
}

void DrawTriangle::DestroyInstance() {
    if (m_pContext)
    {
        delete m_pContext;
        m_pContext = nullptr;
    }
}

第三部分安卓配置文件配置

1)bulid.gradle(app)引入cmake

defaultConfig {
    ...
    externalNativeBuild {
        cmake {
            cppFlags ''
            abiFilters "arm64-v8a"
            //arguments "-DANDROID_STL=c++_shared"
        }
    }
}
externalNativeBuild {
    cmake {
        path file('src/main/cpp/CMakeLists.txt')
        version '3.10.2'
    }
}

2)settings.gradle文件配置链接

jcenter()

3)cmake文件

# 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.10.2)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

# Declares and names the project.
set(jnilibs ${CMAKE_SOURCE_DIR}/../jniLibs)
set(libname native-lib)

include_directories(
        include
        ${CMAKE_SOURCE_DIR}
)

link_directories(
        ${jnilibs}/${ANDROID_ABI})

file(GLOB src-files
        ${CMAKE_SOURCE_DIR}/*.cpp
        ${CMAKE_SOURCE_DIR}/drawTriangle.cpp
        )
# 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.

add_library( # Sets the name of the library.
        ${libname}

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        ${src-files}
        )

# 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.

#set(third-party-libs
#        GLES
#        )
set(native-libs
        android
        log
        m
        z
        )
target_link_libraries( # Specifies the target library.
        ${libname}

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

第四部分将着色器代码放到assets中引入

1)新建assets文件夹添加文件

在main文件夹上新建directory选择assets。

新建vertex.vs顶点着色器文件编写顶点着色器代码

#version 300 es
layout(location = 0) in vec4 vPosition;
void main()
{
    gl_Position = vPosition;
}

新建fragment.fs片段着色器文件编写片段着色器代码

#version 300 es
precision mediump float;
out vec4 fragColor;
void main()
{
    fragColor = vec4 ( 1.0f, 0.2f, 0.2f, 1.0f );
}

2)Java部分

private AssetManager mrg;
mrg = getResources().getAssets();
再调用native函数将mrg句柄传到native层次
NativeImpl.NativeImpl_InitScene(mrg);
JNI定义接口
public static native void NativeImpl_InitScene(Object mrg);

3)C++部分

创建一个读取assets资源的文件的接口

#ifndef C_NDKTEST_READFILEUTIL_H
#define C_NDKTEST_READFILEUTIL_H
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include "Util.h"
#define TAG "READFILEUTIL"
const char *LoadFileContent(const char *filepath);
AAssetManager *g_mrg;

const char *LoadFileContent(const char *filepath) {
    // read shader code form asset
    char *fileContent = nullptr;
    AAsset *asset = AAssetManager_open(g_mrg, filepath, AASSET_MODE_UNKNOWN);
    if (asset == nullptr) {
        // LOGE("LoadFileContent asset is null, load shader error ");
        LOGD("LoadFileContent asset is null, load shader error ");
    }
    int filesSize_v = AAsset_getLength(asset);
    fileContent = new char[filesSize_v];
    AAsset_read(asset, fileContent, filesSize_v);
    fileContent[filesSize_v] = '\0';
    AAsset_close(asset);
    LOGD("LoadFileContent asset is %s", fileContent);
    return fileContent;
}

#endif //C_NDKTEST_READFILEUTIL_H

在jni中使用

JNI函数native接口是实现
/*
 * Class:     com_example_onedrawtri2_NativeImpl
 * Method:    NativeImpl_InitScene
 * Signature: (Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL NativeImpl_InitScene(JNIEnv *env, jobject instance, jobject msg)
{
   g_mrg = AAssetManager_fromJava(env, msg);
}

//使用读取内容
/*
 * Class:     com_example_onedrawtri2_NativeImpl
 * Method:    init
 * Signature: ()V
 */
JNIEXPORT void JNICALL NativeImpl_init(JNIEnv *env, jobject instance)
{
    DrawTriangle::GetInstance();
    DrawTriangle::GetInstance()->CreateProgram(LoadFileContent("vertex.vs"), LoadFileContent("fragment.fs"));
}

第五部分多种颜色的三角形

添加 vColor属性

1)顶点着色器

#version 300 es
layout(location = 0) in vec4 vPosition;
layout(location = 1) in vec3 vColor;
out vec3 ourColor;
void main()
{
    gl_Position = vPosition;
    ourColor = vColor;
}

片段着色器

#version 300 es
precision mediump float;
out vec4 fragColor;
in vec3 ourColor;
void main()
{
    fragColor = vec4 ( ourColor.rgb, 1.0 );
}

顶点坐标添加颜色属性

float verticesCor[] = {
        // positions         // colors
        0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,   // bottom right
        -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,   // bottom left
        0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f    // top
};

2)添加颜色属性绑定顶点坐标

/*
    0;指定我们要配置的顶点属性 就是顶点着色器里面location那个
*/
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void *)0);
glEnableVertexAttribArray(0);//以顶点属性位置值0作为参数,启用顶点属性

/*
 * 1、配置颜色属性
 */
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void *)(3*sizeof(float)));
glEnableVertexAttribArray(1);//以顶点属性位置值0作为参数,启用顶点属性

参考链接:

https://blog.csdn.net/one_chow_chow/article/details/125888904 NDK OpenGL ES 3.0 :画个三角形

在这里插入图片描述

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值