Android 使用Bullet物理引擎

####一、下载bullet
由于我访问不了githubt,所以使用的是国内gitee的,

 git clone https://gitee.com/hejuncheng1/bullet3.git

####二、android引入
使用android studio创建native c++程序
Android 使用Bullet物理引擎_第1张图片

将下载的bullet的目录里的src和下面的BulletCollision、BulletDynamics、BulletSoftBody、clew、LinearMath目录,以及btBulletCollisionCommon.h和btBulletDynamicsCommon.h文件复制到cpp目录下
这里没有用bullet3和opencl保留了最基本的bullet功能
Android 使用Bullet物理引擎_第2张图片
修改最外层CMakeLists.txt的内容,将bullet的内容编译进anative共享库

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

# Declares and names the project.

project("anative")


file(GLOB_RECURSE SRC_DIR_LIST "./*.cxx" "./*.c" "./*.cpp")

#自动查找头文件路径函数(没有去重)
macro(FIND_INCLUDE_DIR result curdir)                                   #定义函数,2个参数:存放结果result;指定路径curdir;
    file(GLOB_RECURSE children "${curdir}/*.hpp" "${curdir}/*.h" )      #遍历获取{curdir}中*.hpp和*.h文件列表
    message(STATUS "children= ${children}")                             #打印*.hpp和*.h的文件列表
    set(dirlist "")                                                     #定义dirlist中间变量,并初始化
    foreach(child ${children})                                          #for循环
        string(REGEX REPLACE "(.*)/.*" "\\1" LIB_NAME ${child})         #字符串替换,用/前的字符替换/*h
        if(IS_DIRECTORY ${LIB_NAME})                                    #判断是否为路径
            LIST(APPEND dirlist ${LIB_NAME})                            #将合法的路径加入dirlist变量中
        endif()                                                         #结束判断
    endforeach()                                                        #结束for循环
    set(${result} ${dirlist})                                           #dirlist结果放入result变量中
endmacro()

#查找include目录下的所有*.hpp,*.h头文件,并路径列表保存到 INCLUDE_DIR_LIST 变量中
FIND_INCLUDE_DIR(INCLUDE_DIR_LIST ${PROJECT_SOURCE_DIR})

#将INCLUDE_DIR_LIST中路径列表加入工程
include_directories(                                                    #INCLUDE_DIR_LIST路径列表加入工程
        ${INCLUDE_DIR_LIST}
        )


ADD_LIBRARY(anative SHARED ${SRC_DIR_LIST})

# Searches for a specified prebuilt library and stores the path as a


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( # Specifies the target library.
        anative

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

修改native-lib.cpp的内容,添加bullet的helloworld程序

#include 
#include 
#include 
#include 
#include "src/btBulletDynamicsCommon.h"

#define  LOG_TAG  "test"

#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGD(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

void test();

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_anative_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";

    test();

    LOGE("dongtai=");

    return env->NewStringUTF(hello.c_str());
}



///-----includes_start-----
void test(){
    ///-----includes_end-----

    ///-----initialization_start-----

    // 创建碰撞配置对象以及碰撞调度器对象,使我们可以再各个阶段尝试不同的算法组合,目的是使用不同的算法和测试相同的碰撞
    // 碰撞配置
    ///collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration.
    btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();

    // 碰撞调度
    ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
    btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);

    // btDbvtBroadphase用来执行快速碰撞检测    目的是尽量的剔除没有相互作用的对象对
    ///btDbvtBroadphase is a good general purpose broadphase. You can also try out btAxis3Sweep.
    btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase();

    // 实际上的物理模拟器
    // 创建解算器,用于求解约束方程。得到物体在重力等作用下的最终位置的
    ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
    btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;

    // 独立场景动态世界
    btDiscreteDynamicsWorld* dynamicsWorld = new btDiscreteDynamicsWorld(
            dispatcher, overlappingPairCache, solver, collisionConfiguration);

    dynamicsWorld->setGravity(btVector3(0, -10, 0));        // 设置重力加速度 Y向下

    ///-----initialization_end-----

    //keep track of the shapes, we release memory at exit.
    //make sure to re-use collision shapes among rigid bodies whenever possible!
    btAlignedObjectArray<btCollisionShape*> collisionShapes;

    ///create a few basic rigid bodies

    //创建一个地面,并加入到场景世界中
    //the ground is a cube of side 100 at position y = -56.
    //the sphere will hit it at y = -6, with center at -5
    {
        btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(50.), btScalar(50.), btScalar(50.))); // 长方体

        collisionShapes.push_back(groundShape);

        btTransform groundTransform;
        groundTransform.setIdentity();
        groundTransform.setOrigin(btVector3(0, -56, 0));        // 设置原点位置

        btScalar mass(0.);      // 质量

        //rigidbody is dynamic if and only if mass is non zero, otherwise static
        bool isDynamic = (mass != 0.f);

        btVector3 localInertia(0, 0, 0);        // 惯性
        if (isDynamic)
            groundShape->calculateLocalInertia(mass, localInertia); //通过质量,这个函数计算出运动物体的惯性

        // 运动状态
        //using motionstate is optional, it provides interpolation capabilities, and only synchronizes 'active' objects
        btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
        // 刚体构造信息
        btRigidBody::btRigidBodyConstructionInfo  rbInfo(mass, myMotionState, groundShape, localInertia);
        // 刚体
        btRigidBody* body = new btRigidBody(rbInfo);

        // 将刚体添加至动态世界中
        //add the body to the dynamics world
        dynamicsWorld->addRigidBody(body);
    }

    {
        //创建一个球体,并加入到场景世界中
        //create a dynamic rigidbody

        //btCollisionShape* colShape = new btBoxShape(btVector3(1,1,1));
        btCollisionShape* colShape = new btSphereShape(btScalar(1.));       // 球体 半径为1
        collisionShapes.push_back(colShape);

        /// Create Dynamic Objects
        btTransform startTransform;
        startTransform.setIdentity();
        startTransform.setOrigin(btVector3(2, 10, 0));

        btScalar mass(1.f);     // 质量

        //rigidbody is dynamic if and only if mass is non zero, otherwise static
        bool isDynamic = (mass != 0.f);

        btVector3 localInertia(0,  0, 0);       // 惯性
        if (isDynamic)
            colShape->calculateLocalInertia(mass, localInertia); //通过质量,这个函数计算出运动物体的惯性

        //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
        btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
        btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, colShape, localInertia);
        btRigidBody* body = new btRigidBody(rbInfo);

        dynamicsWorld->addRigidBody(body);
    }

    /// Do some simulation
    int i = 0;
    // 步进模拟
    ///-----stepsimulation_start-----
    for (i = 0; i < 150; i++)
    {
        dynamicsWorld->stepSimulation(1.f / 5.f, 10);       // 模拟运动  每次进行物理模拟运算的时间间隔  每次能响应的最大step数

        //print positions of all objects
        for (int j = dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; j--)
        {
            btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[j];
            btRigidBody* body = btRigidBody::upcast(obj);
            btTransform trans;
            if (body && body->getMotionState())
            {
                body->getMotionState()->getWorldTransform(trans);
            }
            else
            {
                trans = obj->getWorldTransform();
            }
            printf("world pos object %d = %f,%f,%f\n", j,
                   float(trans.getOrigin().getX()), float(trans.getOrigin().getY()), float(trans.getOrigin().getZ()));
            LOGE("world pos object %d = %f,%f,%f\n", j,
                 float(trans.getOrigin().getX()), float(trans.getOrigin().getY()), float(trans.getOrigin().getZ()));
        }
        printf(" \n");
    }

    ///-----stepsimulation_end-----

    //cleanup in the reverse order of creation/initialization

    ///-----cleanup_start-----

    //清理动态世界里的刚体
    //remove the rigidbodies from the dynamics world and delete them
    for (i = dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--)
    {
        btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[i];
        btRigidBody* body = btRigidBody::upcast(obj);
        if (body && body->getMotionState())
        {
            delete body->getMotionState();
        }
        dynamicsWorld->removeCollisionObject(obj);
        delete obj;
    }

    //清理碰撞形状
    //delete collision shapes
    for (int j = 0; j < collisionShapes.size(); j++)
    {
        btCollisionShape* shape = collisionShapes[j];
        collisionShapes[j] = 0;
        delete shape;
    }

    //清理动态世界
    //delete dynamics world
    delete dynamicsWorld;

    //清理求解器
    //delete solver
    delete solver;

    //清理粗测阶段
    //delete broadphase
    delete overlappingPairCache;

    //清理调度
    //delete dispatcher
    delete dispatcher;

    delete collisionConfiguration;

    //next line is optional: it will be cleared by the destructor when the array goes out of scope
    collisionShapes.clear();
}

运行可以看到输出的效果
Android 使用Bullet物理引擎_第3张图片

三、利用openglES显示出来

添加TriangleRenderJNI类实现了GLSurfaceView.Renderer接口

package com.example.anative;

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

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

public class TriangleRenderJNI implements GLSurfaceView.Renderer {

    static {
        System.loadLibrary("anative");
    }

    public TriangleRenderJNI(Context context){
        mAssetMgr = context.getAssets();
        if (null == mAssetMgr){
            Log.e("TAG", "TriangleRenderJNI: " + "getAssets return null !");
        }
    }

    private AssetManager mAssetMgr = null;

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


    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        readShaderFile(mAssetMgr);
        glesInit();
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        glesResize(width,height);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        glesRender();
    }
}

四个本地方法需要实现
创建一个RenderJNI.cpp,实现这四个本地方法,在里面创建bullet,并用opengles绘制。这里将bullet的HelloWorld程序的一些参数进行修改,改变了物体的大小和碰撞反弹系数

//
// Created by JinTao Liu on 2022/2/4.
//
#include "RenderJNI.h"
#include 
#include 

#include 
#include 
#include 

#include "btBulletDynamicsCommon.h"
#include 
#include 
#include 

#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__)

#include 

GLint g_programObject;
jint  g_width;
jint g_height;

jint circle_x = 600;
jint circle_y = 600;

AAssetManager* g_pAssetManager = NULL;
void drawCircle(GLfloat vVertices[],float radius,int n,float x,float y);
void drawBox(GLfloat vVertices[],int pos,float x1,float y1,float x2,float y2);
void drawBoxAndSphere(float radius,float circleX,float circleY,float boxX1,float boxY1,float boxX2,float boxY2);
GLuint  LoadShader(GLenum type,const char  * shaderSrc)
{
    GLuint shader;
    GLint compiled;

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

    if ( shader == 0)
    {
        return 0;
    }

    glShaderSource(shader,1,&shaderSrc,NULL);

    glCompileShader(shader);

    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;
}
btDiscreteDynamicsWorld* dynamicsWorld;
void createBullet(){

    ///-----includes_end-----

    int i;
    ///-----initialization_start-----

    ///collision configuration contains default setup for memory, collision setup. Advanced users can create their own configuration.
    //冲突配置包含内存的默认设置,冲突设置。高级用户可以创建自己的配置
    btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();

    ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
    btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);

    ///btDbvtBroadphase is a good general purpose broadphase. You can also try out btAxis3Sweep.
    btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase();

    ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
    btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;

    dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);

    dynamicsWorld->setGravity(btVector3(0, -10, 0));

    ///-----initialization_end-----

    //keep track of the shapes, we release memory at exit.
    //make sure to re-use collision shapes among rigid bodies whenever possible!
    btAlignedObjectArray<btCollisionShape*> collisionShapes;

    ///create a few basic rigid bodies

    //the ground is a cube of side 100 at position y = -56.
    //the sphere will hit it at y = -6, with center at -5
    {
        btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(200.), btScalar(200.), btScalar(50.)));

        collisionShapes.push_back(groundShape);

        btTransform groundTransform;
        groundTransform.setIdentity();
        groundTransform.setOrigin(btVector3(0, -300, 0));

        btScalar mass(0.);

        //rigidbody is dynamic if and only if mass is non zero, otherwise static
        bool isDynamic = (mass != 0.f);

        btVector3 localInertia(0, 0, 0);
        if (isDynamic)
            groundShape->calculateLocalInertia(mass, localInertia);

        //using motionstate is optional, it provides interpolation capabilities, and only synchronizes 'active' objects
        btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
        btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, groundShape, localInertia);
        btRigidBody* body = new btRigidBody(rbInfo);
        //设置碰撞反弹系数
        body->setRestitution(btScalar(1.2));
        //add the body to the dynamics world
        dynamicsWorld->addRigidBody(body);
    }

    {
        //create a dynamic rigidbody

        //btCollisionShape* colShape = new btBoxShape(btVector3(1,1,1));
        btCollisionShape* colShape = new btSphereShape(btScalar(100));
        collisionShapes.push_back(colShape);

        /// Create Dynamic Objects
        btTransform startTransform;
        startTransform.setIdentity();

        btScalar mass(6.f);

        //rigidbody is dynamic if and only if mass is non zero, otherwise static
        bool isDynamic = (mass != 0.f);

        btVector3 localInertia(0, 0, 0);
        if (isDynamic)
            colShape->calculateLocalInertia(mass, localInertia);

        startTransform.setOrigin(btVector3(0, 600, 0));

        //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
        btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
        btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, colShape, localInertia);
        btRigidBody* body = new btRigidBody(rbInfo);
        //设置碰撞反弹系数
        body->setRestitution(btScalar(1.2));
        dynamicsWorld->addRigidBody(body);
    }

}

void drawStep(){
    dynamicsWorld->stepSimulation(1.f / 30.f, 10);
    float radius,circleX,circleY;
    float boxX1,boxY1,boxX2,boxY2;
    //print positions of all objects
    for (int j = dynamicsWorld->getNumCollisionObjects() - 1; j >= 0; j--)
    {
        btCollisionObject* obj = dynamicsWorld->getCollisionObjectArray()[j];
        btRigidBody* body = btRigidBody::upcast(obj);
        btTransform trans;
        if (body && body->getMotionState())
        {
            body->getMotionState()->getWorldTransform(trans);
        }
        else
        {
            trans = obj->getWorldTransform();
        }
        btCollisionShape* shape = body->getCollisionShape();
        glm::mat4 model = glm::mat4(1.0f);
        trans.getOpenGLMatrix(glm::value_ptr(model));
//        __android_log_print(ANDROID_LOG_ERROR,shape->getName() ," shape");
//        shape->getUserPointer();
        int shaeType = shape->getShapeType();
//        __android_log_print(ANDROID_LOG_ERROR,shape->getName() ," shapeName");
        //box
        btVector3 tempVector = shape->get();
        __android_log_print(ANDROID_LOG_ERROR,"------------" + tempVector.getX(),"--------------\n");
//        __android_log_print(ANDROID_LOG_ERROR,"TAG","world scale object %d = %f,%f,%f\n", j, float(tempVector.getX()), float(tempVector.getY()), float(tempVector.getZ()));
        if (shaeType == 0){
            btBoxShape* tempShape = static_cast<btBoxShape* >(shape);
            btVector3 tempVector = tempShape->getImplicitShapeDimensions();
            boxX1 = trans.getOrigin().getX() - tempVector.getX();
            boxY1 = trans.getOrigin().getY() - tempVector.getY();
            boxX2 = trans.getOrigin().getX() + tempVector.getX();
            boxY2 = trans.getOrigin().getY() + tempVector.getY();

        }else if (shaeType == 8){
            btSphereShape* tempShape = static_cast<btSphereShape* >(shape);
            radius = tempShape->getRadius();
            circleX = trans.getOrigin().getX();
            circleY = trans.getOrigin().getY();
        }

//        for (int l = 0;l < glm::mat4::length(); ++l) {
//
//
//            __android_log_print(ANDROID_LOG_ERROR,glm::to_string(model[l]).c_str() + l,"Need to print");
//        }
//            __android_log_print(ANDROID_LOG_ERROR,glm::to_string(model).c_str(),"Need to print");
//            __android_log_print(ANDROID_LOG_ERROR,"world pos object ","Need to print :");
//        __android_log_print(ANDROID_LOG_ERROR,"TAG","world pos object %d = %f,%f,%f\n", j, float(trans.getOrigin().getX()), float(trans.getOrigin().getY()), float(trans.getOrigin().getZ()));
//        __android_log_print(ANDROID_LOG_ERROR,"------------","-\n");
    }
    drawBoxAndSphere(radius,circleX,circleY,boxX1,boxY1,boxX2,boxY2);
//    __android_log_print(ANDROID_LOG_ERROR,"------------","--------------\n");
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_anative_TriangleRenderJNI_glesInit(JNIEnv *env, jobject thiz) {
    // TODO: implement glesInit()
    // TODO: implement glesInit()
    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 *pVertextShader = readShaderSrcFile("shader/vs.glsl",g_pAssetManager);
//    char *pFragmentShader = readShaderSrcFile("shader/fs.glsl",g_pAssetManager);

    char *pVertextShader = vShaderStr;
    char *pFragmentShader = fShaderStr;

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

    //load the vertext/fragment shaders
    //vertexShader = LoadShader (GL_VERTEX_SHADER,vShaderStr);
    //fragmentShader = LoadShader();

    vertexShader = LoadShader(GL_VERTEX_SHADER,pVertextShader);
    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 progrom object
    g_programObject = programObject;

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


void drawCircle(GLfloat vVertices[],float radius,int n,float x,float y){

    int pos = 0;


    float angDegSpan=360.0f/n;
    for(float i=0;i<360;i+=angDegSpan){
        vVertices[pos++] = x / g_width;
        vVertices[pos++] = y / g_height;
        vVertices[pos++] = 0;

        vVertices[pos++] = (float) ((x + radius*sin(i*M_PI/180.0f)) / g_width);
        vVertices[pos++] = (float)((y + radius*cos(i*M_PI/180.0f)) / g_height);
        vVertices[pos++] = 0;

        vVertices[pos++] = (float) ((x + radius*sin((i+angDegSpan)*M_PI/180.0f)) / g_width);
        vVertices[pos++] = (float)((y + radius*cos((i+angDegSpan)*M_PI/180.0f)) / g_height);
        vVertices[pos++] = 0;
    }

}

void drawBox(GLfloat vVertices[],int pos,float x1,float y1,float x2,float y2){
    //左上角
    vVertices[pos++] = x1 / g_width;
    vVertices[pos++] = y1 / g_height;
    vVertices[pos++] = 0;
    //左下角
    vVertices[pos++] = x1 / g_width;
    vVertices[pos++] = y2 / g_height;
    vVertices[pos++] = 0;
    //右下角
    vVertices[pos++] = x2 / g_width;
    vVertices[pos++] = y2 / g_height;
    vVertices[pos++] = 0;



    //左上角
    vVertices[pos++] = x1 / g_width;
    vVertices[pos++] = y1 / g_height;
    vVertices[pos++] = 0;
    //右上角
    vVertices[pos++] = x2 / g_width;
    vVertices[pos++] = y1 / g_height;
    vVertices[pos++] = 0;
    //右下角
    vVertices[pos++] = x2 / g_width;
    vVertices[pos++] = y2 / g_height;
    vVertices[pos++] = 0;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_anative_TriangleRenderJNI_glesRender(JNIEnv *env, jobject thiz) {
    // TODO: implement glesRender()
//    glDrawArrays(GL_TRIANGLES,0,6);
//    GLfloat vVertices[(180)*9 + 6*3];
//    drawCircle(vVertices,180,180,circle_x++,circle_y++);
//    drawBox(vVertices,180*9,-300,400,300,-400);
//
//    // 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,(180)*3 + 6);
    drawStep();
}

void drawBoxAndSphere(float radius,float circleX,float circleY,float boxX1,float boxY1,float boxX2,float boxY2){
    glDrawArrays(GL_TRIANGLES,0,6);
    GLfloat vVertices[(180)*9 + 6*3];
    drawCircle(vVertices,radius,180,circleX,circleY);
    drawBox(vVertices,180*9,boxX1,boxY1,boxX2,boxY2);

    // 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,(180)*3 + 6);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_anative_TriangleRenderJNI_glesResize(JNIEnv *env, jobject thiz, jint width,
                                                             jint height) {
    // TODO: implement glesResize()
    g_width = width;
    g_height = height;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_anative_TriangleRenderJNI_readShaderFile(JNIEnv *env, jobject thiz,
                                                                 jobject asset_manager) {
    // TODO: implement readShaderFile()
    if (asset_manager && env){

        g_pAssetManager = AAssetManager_fromJava(env,asset_manager);
        if (NULL == g_pAssetManager)
        {
            LOGE("AAssetManager_fromJava() return null !");
        }

    } else{
        LOGE("assetManager is null !");
    }
}

修改CMakeLists.txt

##加入
##官方标准配置
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 GLESv2)
# Declares and names the project.

#修改,添加引用库${OPENGL_LIB} android  EGL m
target_link_libraries( # Specifies the target library.
        anative

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

修改MainActivity

package com.example.anative;

import androidx.appcompat.app.AppCompatActivity;

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

import com.example.anative.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'anative' library on application startup.
    static {
        System.loadLibrary("anative");
    }

    private ActivityMainBinding binding;

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

//        binding = ActivityMainBinding.inflate(getLayoutInflater());
//        setContentView(R.layout.activity_main);
//
//        // Example of a call to a native method
//        TextView tv = findViewById(R.id.sample_text);
//        tv.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View v) {
//                stringFromJNI();
//            }
//        });
        setupViews();
    }

    private void setupViews() {
        GLSurfaceView mGlSurfaceView = new GLSurfaceView(this);
        setContentView(mGlSurfaceView);
        //设置版本
        mGlSurfaceView.setEGLContextClientVersion(2);
        GLSurfaceView.Renderer renderer = new TriangleRenderJNI(MainActivity.this);
        mGlSurfaceView.setRenderer(renderer);
        //只有在绘制数据改变时才会绘制View,可以防止GLSurfaceView帧重绘
        //该种模式下当需要重绘时需要我们手动调用glSurfaceView.requestRender();
        mGlSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
    }

    /**
     * A native method that is implemented by the 'bulletopengles' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}

最后效果

之前参考了一个opengles 绘制三角形的,链接找不到了。

代码:https://gitee.com/aaaa_sss/native.git

你可能感兴趣的:(android,android,android,studio,android-studio)