上图就是m x a 的矩阵
1x3+0x2+2x1 :为左侧第一行乘以右侧第一列。
1x1+0x1+2x0 :为左侧第一行乘以右侧第二列。
-1x3+3x2+1x1:为左侧第二行乘以右侧第一列。
-1x1+3x1+1x0:为左侧第二行乘以右侧第二列。
A*表示伴随矩阵
Vulkan(google推出的代替OpenGL,可以了解下)
CMakeLists的配置
cmake_minimum_required(VERSION 3.10)
MESSAGE(STATUS "${FFMPENG_DIR}/include")
MESSAGE(STATUS "${FFMPENG_DIR}/lib")
add_library(Test221123 SHARED src/main/cpp/MyRender.cpp)
find_library(log-lib log)
#增加 -lGLESv1_CM -lGLESv2库的支持
target_link_libraries(Test221123 -lGLESv1_CM -lGLESv2 ${log-lib})
MainActivity
package com.example.testndkempty;
import androidx.appcompat.app.AppCompatActivity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private GLSurfaceView glSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
glSurfaceView = new GLSurfaceView(this);
glSurfaceView.setRenderer(new MyRender());
setContentView(glSurfaceView);
}
}
package com.example.testndkempty;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRender implements GLSurfaceView.Renderer {
static {
System.loadLibrary("Test221123");
}
private native void initOpenGL();
private native void paintGL();
private native void resizeGL(int width,int height);
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
initOpenGL();
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
resizeGL(width,height);
}
@Override
public void onDrawFrame(GL10 gl) {
paintGL();
}
}
com_example_testndkempty_MyRender.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_example_testndkempty_MyRender */
#ifndef _Included_com_example_testndkempty_MyRender
#define _Included_com_example_testndkempty_MyRender
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_testndkempty_MyRender
* Method: initOpenGL
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_testndkempty_MyRender_initOpenGL
(JNIEnv *, jobject);
/*
* Class: com_example_testndkempty_MyRender
* Method: paintGL
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_testndkempty_MyRender_paintGL
(JNIEnv *, jobject);
/*
* Class: com_example_testndkempty_MyRender
* Method: resizeGL
* Signature: (II)V
*/
JNIEXPORT void JNICALL Java_com_example_testndkempty_MyRender_resizeGL
(JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
MyRender.cpp文件
//
// Created by 王学岗 on 2022/11/24.
//
#include "com_example_testndkempty_MyRender.h"
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_example_testndkempty_MyRender_initOpenGL
(JNIEnv *env, jobject obj) {
//glClear函数来自OPENGL,其中它是通过glClear使用红,绿,蓝以及AFA值来清除颜色缓冲区的,
//并且都被归一化在(0,1)之间的值,其实就是清空当前的所有颜色。
//初始化的时候给一个颜色,R为1,GB为0,Alpha为1.0
glClearColor(1.0,0.0,0.0,1.0);
//清空深度缓存
// glClearDepthf指定glClear用于清除深度缓冲区的深度值。 glClearDepthf指定的值被限制在0 1范围内
glClearDepthf(1.0);
//用来开启更新深度缓冲区的功能,也就是,如果通过比较后深度值发生变化了,
//会进行更新深度缓冲区的操作。启动它,OpenGL就可以跟踪再Z轴上的像素,这样,它只会再那个像素前方没有东西时,才会绘画这个像素。
//在做绘画3D时,这个功能最好启动,视觉效果比较真实。
//启动深度测试
glEnable(GL_DEPTH_TEST);
//指定“目标像素与当前像素在z方向上值大小比较”(即深度的比较)的函数,
//符合该函数关系的目标像素才进行绘制(渲染),否则对目标像素不予绘制,可以取下值:
//在什么情况下使用深度测试
glDepthFunc(GL_LEQUAL);//GL_LEQUAL,如果目标像素<=当前像素z值,则绘制目标像素
}
JNIEXPORT void JNICALL Java_com_example_testndkempty_MyRender_paintGL
(JNIEnv *env, jobject obj) {
//清空颜色缓冲区,和深度缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//重置
glLoadIdentity();
}
JNIEXPORT void JNICALL Java_com_example_testndkempty_MyRender_resizeGL
(JNIEnv *env, jobject obj, jint width, jint height) {
//glViewport在默认情况下,视口被设置为占据打开窗口的整个像素矩形,窗口大小和设置视口大小相同,
//所以为了选择一个更小的绘图区域,就可以用glViewport函数来实现这一变换,在窗口中定义一个像素矩形,
//最终将图像映射到这个矩形中。例如可以对窗口区域进行划分,在同一个窗口中显示分割屏幕的效果,以显示多个视图。
glViewport(0,0,width,height);
//投影矩阵[点击查看详细意义](https://blog.csdn.net/caoshangpa/article/details/80266028)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
[点击查看详细意义](https://blog.csdn.net/wsq198760/article/details/84080253)
glOrthof(-1,1,-1,1,0.1,1000.0);
}
#ifdef __cplusplus
}
#endif
这是一个头文件
//
// Created by 王学岗 on 2022/11/24.
//
#ifndef TESTNDKEMPTY_MYNDKLOG_H
#define TESTNDKEMPTY_MYNDKLOG_H
#ifdef __cplusplus
extern "C" {
#endif
#include
#define LOG "王学岗"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG,__VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif
使用的时候导入这个头文件就行了。
1,glFrustumf()透视投影
2,
glm::mat4x4 cubeMat;
glm::mat4x4 cubeTransMat = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -0.5));
glm::mat4x4 cubeRotMat = glm::rotate(glm::mat4(1.0f),m_angle,glm::vec3(0.5f, 0.5f, 1.0) );
glm::mat4x4 cubeScaleMat = glm::scale(glm::mat4(1.0f),glm::vec3(0.5f, 0.4f, 0.5) );
cubeMat = cubeTransMat * cubeRotMat * cubeScaleMat;
mat4(1.0f)为单位矩阵。
3,UV坐标
4,纹理贴图:
getActiveTexture
代表第几张图片,
5,VBO
stb_image:加载图片的c库,
#ifndef CCIMAGE_H
#define CCIMAGE_H
#define STB_IMAGE_IMPLEMENTATION
#include
#include
extern "C"{
#include "stb_image.h"
}
#ifndef U8_t
#define U8_t unsigned char
#endif
class CCImage
{
public:
CCImage(int w, int h,int type, U8_t* imgData){
m_width =w;
m_height =h;
m_type = type;
int imgSize = m_width * m_height * 4;
if(imgSize >0 && imgData != nullptr){
m_pImgData =(U8_t*) malloc(imgSize);
memcpy(m_pImgData,imgData,imgSize);
}else{
m_pImgData = NULL;
}
}
~CCImage()
{
if(m_pImgData)
{
free(m_pImgData);
}
}
static CCImage* ReadFromFile(const char* fileName){
int type = 0;
int width = 0;
int height = 0;
//stbi_set_flip_vertically_on_load(true);
U8_t* picData = stbi_load(fileName, &width, &height, &type, STBI_rgb_alpha);
CCImage* image = new CCImage(width, height, type, (U8_t*)picData);
stbi_image_free(picData);
return image;
}
static CCImage* ReadFromBuffer(unsigned char * dataBuff,int length){
int type = 0;
int width = 0;
int height = 0;
stbi_set_flip_vertically_on_load(true);
U8_t* picData = stbi_load_from_memory(dataBuff, length, &width, &height, &type, 0);
CCImage* image = new CCImage(width, height, type, (U8_t*)picData);
stbi_image_free(picData);
return image;
}
int GetWidth() const {return m_width; }
int GetHeight() const { return m_height; }
int GetType() const {return m_type; }
U8_t* GetData() const { return m_pImgData; }
private:
int m_width =0;
int m_height =0;
int m_type =0;
U8_t* m_pImgData =NULL;
};
#endif // CCIMAGE_H
//
// Created by chenchao on 2021/8/10.
//
#include "com_example_ccopengles_CCGLRender.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "CCNDKLogDef.h"
#include "CCGLPrimitivesDef.h"
#include "CCImage.h"
#ifdef __cplusplus
extern "C" {
#endif
float m_angle =0.0f;
GLuint m_texID;
GLuint createOpenGLTexture(CCImage* pImg);
void Java_com_example_ccopengles_CCGLRender_ndkInitGL(JNIEnv *env, jobject obj)
{
glClearColor(0.0,0.0,0.0,1.0);
glClearDepthf(1.0);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
}
void Java_com_example_ccopengles_CCGLRender_ndkPaintGL(JNIEnv *env, jobject obj)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//glCullFace(GL_BACK);
//UV坐标与顶点相结合
CCFloat5 planVertices[] =
{
{ -1.0f, -1.0f, 1.0f, 0, 0 },//x,y,z,u,v
{ -1.0f,1.0f, 1.0f, 0, 1 },//
{ 1.0f,-1.0f, 1.0f, 1, 0 },//
{ 1.0f, 1.0f, 1.0f, 1, 1 },//
};
glBindTexture(GL_TEXTURE_2D,m_texID);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);//GL_TEXTURE_COORD_ARRAY 不是Render
glVertexPointer(3,GL_FLOAT,sizeof(CCFloat5),planVertices);
glTexCoordPointer(2,GL_FLOAT,sizeof(CCFloat5),&planVertices[0].u);
//m_angle += 0.05f;
glm::mat4x4 cubeMat;
glm::mat4x4 cubeTransMat = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -0.5));
glm::mat4x4 cubeRotMat = glm::rotate(glm::mat4(1.0f),m_angle,glm::vec3(0.0f, 0.0f, 1.0) );
glm::mat4x4 cubeScaleMat = glm::scale(glm::mat4(1.0f),glm::vec3(1.0f, 0.7f, 0.5) );
cubeMat = cubeTransMat * cubeRotMat * cubeScaleMat;
glLoadMatrixf(glm::value_ptr(cubeMat));
glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
void Java_com_example_ccopengles_CCGLRender_ndkResizeGL(JNIEnv *env, jobject obj, jint width, jint height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-1,1,-1,1,0.1,1000.0);
//glFrustumf(-1,1,-1,1,0.1,1000.0);
}
//fName 图片的名字,图片在assets下面
int Java_com_example_ccopengles_CCGLRender_ndkReadResourceFile
(JNIEnv *env, jobject obj, jobject assetManager, jstring fName)
{
//获取AssetManager
AAssetManager *mAssetManager = AAssetManager_fromJava (env, assetManager);
if (NULL == mAssetManager){
LOGF("assetManager is NULL");
return -1;
}
const char *fileName = env->GetStringUTFChars(fName, 0);
if (NULL == fileName){
LOGF("fileName is NULL");
return -1;
}
LOGD ("FileName is %s", fileName);
AAsset *asset = AAssetManager_open (mAssetManager, fileName, AASSET_MODE_UNKNOWN);
if (NULL == asset){
LOGF("asset is NULL");
return -1;
}
//获取文件buffer大小
off_t bufferSize = AAsset_getLength(asset);
LOGD("buffer size is %ld", bufferSize);
unsigned char *imgBuff = (unsigned char *)malloc(bufferSize + 1);
if (NULL == imgBuff){
LOGF("imgBuff alloc failed");
return -1;
}
memset(imgBuff, 0, bufferSize + 1);
int readLen = AAsset_read(asset, imgBuff, bufferSize);
LOGD("Picture read: %d", readLen);
CCImage* glImage = CCImage::ReadFromBuffer(imgBuff,readLen);
m_texID = createOpenGLTexture(glImage);
delete glImage;
if (imgBuff){
free(imgBuff);
imgBuff = NULL;
}
AAsset_close(asset);
env->ReleaseStringUTFChars(fName, fileName);
return 0;
}
GLuint createOpenGLTexture(CCImage* pImg)
{
if(pImg == NULL){
return -1;
}
GLuint textureID;//纹理索引
glEnable(GL_TEXTURE_2D);
glGenTextures(1,&textureID);//产生纹理索引
glBindTexture(GL_TEXTURE_2D,textureID);//绑定纹理索引,之后的操作都针对当前纹理索引
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//指当纹理图象被使用到一个大于它的形状上时
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//指当纹理图象被使用到一个小于或等于它的形状上时
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);//s方向拉伸到边缘
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);//t方向拉伸到边缘
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,pImg->GetWidth(),pImg->GetHeight(),0,GL_RGBA,GL_UNSIGNED_BYTE,pImg->GetData());//指定参数,生成纹理
return textureID;
}
#ifdef __cplusplus
}
#endif
package com.example.ccopengles;
import android.content.Context;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.res.AssetManager;
public class CCGLRender implements GLSurfaceView.Renderer {
CCGLRender(Context ctx){
m_glContex = ctx;
}
private Context m_glContex;
private native void ndkInitGL();
private native void ndkPaintGL();
private native void ndkResizeGL(int width,int height);
private native int ndkReadResourceFile(AssetManager assetManager, String fileName);
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config){
AssetManager assetManager = m_glContex.getAssets();
ndkInitGL();
ndkReadResourceFile(assetManager,"rabit.png");
}
@Override
public void onSurfaceChanged(GL10 gl, int width,int height){
ndkResizeGL(width, height);
}
@Override
public void onDrawFrame(GL10 gl){
ndkPaintGL();
}
static {
System.loadLibrary("CCOpenGLRender");
}
}
//
// Created by chenchao on 2021/8/10.
//
#ifndef CCOPENGLES_CCGLPRIMITIVESDEF_H
#define CCOPENGLES_CCGLPRIMITIVESDEF_H
#ifdef __cplusplus
extern "C" {
#endif
struct CCFloat7{
float x;
float y;
float z;
float r;
float g;
float b;
float a;
};
struct CCFloat3{
float x;
float y;
float z;
};
struct CCFloat4{
float r;
float g;
float b;
float a;
};
struct CCFloat5{
float x;
float y;
float z;
float u;
float v;
};
#ifdef __cplusplus
}
#endif
#endif //CCOPENGLES_CCGLPRIMITIVESDEF_H