OpenGL 坐标系统:OpenGL 坐标系中每个顶点的 x,y,z 坐标都应该在 -1.0 到 1.0 之间,超出这个坐标范围的顶点都将不可见。将一个物体(图像)渲染到屏幕上,通常经过将物体坐标转换为标准化设备坐标,然后再将标准化设备坐标转化为屏幕坐标的过程。
**物体显示:**该过程通常涉及多个坐标系统的变换,将所有顶点转换为片段之前,顶点需要处于不同的坐标系统进行计算,对我们来说比较重要的有 5 个坐标系统:
局部空间:是指对象所在的空间,原点由自己定义,模型的所有顶点对于你的对象来说都是局部的。
世界空间:它可以实现物体的平移,缩放,旋转等操作,就是将他们放在我们指定位置。这些变换是通过模型矩阵(Model Matrix)实现的。在 C/C++ 中可以利用 GLM 构建模型矩阵(直接百度下载开源库,只用把头文件文件夹放入到工程中,进行引用就可以使用了)
glm::mat4 Model = glm::mat4(1.0f); //单位矩阵
Model = glm::scale(Model, glm::vec3(2.0f, 2.0f, 2.0f)); //缩放
Model = glm::rotate(Model, MATH_PI/2, glm::vec3(1.0f, 0.0f, 0.0f)); //沿 x 轴旋转 90 度
Model = glm::translate(Model, glm::vec3(0.0f, 1.0f, 0.0f)); //沿 y 轴正方向平移一个单位
观察空间:称为OpenGL相机空间,就是从摄像机的角度观察得到的空间,他将对象的世界坐标转换为观察者视野前面的坐标,通常可以由一系列的平移和旋转来实现这种方式将对象移到摄像机面前。
// View matrix
glm::mat4 View = 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) // Head is up (set to 0,-1,0 to look upside-down) 相机 up 方向,即相机头部朝向
);
裁剪空间:用来裁剪观察对象的空间,在顶点着色器运行的最后,OpenGL期望所有的坐标都能落在一个给定的范围内,则这个范围外的点需要被裁剪掉。
前两个参数指定了平截头体的左右坐标,
第三和第四参数指定了平截头体的底部和上部。通过这四个参数我们定义了近平面和远平面的大小,
然后第五和第六个参数则定义了近平面和远平面的距离。这个指定的投影矩阵将处于这些 x,y,z 范围之间的坐标转换到标准化设备坐标系中。
glm::mat4 Projection = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f, 100.0f); //ratio 一般表示视口的宽高比,width/height
第一个参数定义了 fov 的值,它表示的是视野(Field of View),并且设置了观察空间的大小。对于一个真实的观察效果,它的值经常设置为 45.0,但想要看到更多结果你可以设置一个更大的值。
第二个参数设置了宽高比,由视口的高除以宽。
第三和第四个参数设置了平截头体的近和远平面。我们经常设置近距离为 0.1 而远距离设为 100.0 。所有在近平面和远平面的顶点且处于平截头体内的顶点都会被渲染。
glm::mat4 Projection = glm::perspective(45.0f, ratio, 0.1f, 100.f); //ratio 一般表示视口的宽高比,width/height,
整个坐标系统的变换矩阵可以用一个矩阵表示 MVPMatrix = Projection * View * Model
工程包名
com.example.basiclighting8code
实现 OpenGL 3D 效果最简单的方式是在顶点着色器中将顶点坐标与 MVP 变换矩阵相乘:
java代码和环境部分与之前学习到的opengl显示图片的工程代码是一致的,但是可以引入通过触屏来改变图片位置的参数,从而更形象。C++部分只有顶点的shader不一样,还有在绘画的时候需要对顶点着色器里面的uniform mat4 u_MVPMatrix;//变化矩阵进行设置。
顶点着色器
#version 300 es
layout (location = 0) in vec4 a_position;
layout (location = 1) in vec2 a_texCoord;
uniform mat4 u_MVPMatrix;//变化矩阵
out vec2 v_texCoord;
void main()
{
gl_Position = u_MVPMatrix * a_position;
v_texCoord = a_texCoord;
}
片段着色器
#version 300 es
precision mediump float;
layout(location = 0) out vec4 outColor;
in vec2 v_texCoord;
uniform sampler2D s_TextureMap;
void main()
{
outColor = texture(s_TextureMap, v_texCoord);
}
NativeGL.cpp
//
// Created by CreatWall_zhouwen on 2023/4/11.
//
#include "jni.h"
#include
#include
#include "Util.h"
#include "CoordSystem.h"
#include "ReadFileUtil.h"
#define NATIVE_RENDER_CLASS_NAME "com/example/basiclighting8code/NativeImpl"
#define TAG "GLTRIANGLE"
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_sevencoordsystem_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_sevencoordsystem_NativeImpl
* Method: init
* Signature: ()V
*/
JNIEXPORT void JNICALL NativeImpl_init(JNIEnv *env, jobject instance)
{
CoordSystem::GetInstance();
int width = 0, height = 0;
unsigned char *img = ReadBMP("awesomeface.bmp", width, height);
CoordSystem::GetInstance()->getTexturedata(img, width, height);
CoordSystem::GetInstance()->CreateProgram(
reinterpret_cast(LoadFileContent("vertex.vs")),
reinterpret_cast(LoadFileContent("fShader.fs")));
}
/*
* Class: com_example_twodrawtexture_NativeImpl
* Method: OnSurfaceChanged
* Signature: (II)V
*/
JNIEXPORT void JNICALL NativeImpl_OnSurfaceChanged(JNIEnv *env, jobject instance, jint width, jint height)
{
glViewport(0, 0, width, height);
CoordSystem::GetInstance()->OnSurfaceChanged(width, height);
}
/*
* Class: com_example_twodrawtexture_NativeImpl
* Method: OnSurfaceChanged
* Signature: (FFFF)V
*/
JNIEXPORT void JNICALL native_UpdateTransformMatrix(JNIEnv *env, jobject instance, jfloat rotateX, jfloat rotateY, jfloat scaleX, jfloat scaleY)
{
//通过这个方法来改变图片的坐标
CoordSystem::GetInstance()->UpdateTransformMatrix(rotateX, rotateY, scaleX, scaleY);
}
/*
* Class: com_example_twodrawtexture_NativeImpl
* Method: draw
* Signature: ()V
*/
JNIEXPORT void JNICALL NativeImpl_draw(JNIEnv *env, jobject instance)
{
CoordSystem::GetInstance()->Draw();
}
#ifdef __cplusplus
}
#endif
static JNINativeMethod g_RenderMethods[] = {
{"NativeImpl_InitScene", "(Ljava/lang/Object;)V", (void *)(NativeImpl_InitScene)},
{"NativeImpl_init", "()V", (void *)(NativeImpl_init)},
{"NativeImpl_OnSurfaceChanged", "(II)V", (void *)(NativeImpl_OnSurfaceChanged)},
{"NativeImpl_draw", "()V", (void *)(NativeImpl_draw)},
{"native_UpdateTransformMatrix", "(FFFF)V", (void *)(native_UpdateTransformMatrix)},
};
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);
}
CoordSystem.h
//
// Created by CreatWall_zhouwen on 2023/4/13.
//
#ifndef TWODRAWTEXTURE_TEXTUREDEMO_H
#define TWODRAWTEXTURE_TEXTUREDEMO_H
#include
#include
#include
#define MATH_PI 3.1415926535897932384626433832802
class CoordSystem {
public:
CoordSystem(){
program = 0;
vertexShaderHandle = 0;
fragShaderHandle = 0;
};
~CoordSystem(){};
void CreateProgram(const char *ver, const char *frag);
void Draw();
void getTexturedata(unsigned char *data, int width, int height);
static CoordSystem* GetInstance();
static void DestroyInstance();
void OnSurfaceChanged(int width, int height);
void UpdateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY);
void UpdateMVPMatrix(glm::mat4 &mvpMatrix, int angleX, int angleY, float ratio);
private:
GLuint program;
GLuint vertexShaderHandle;
GLuint fragShaderHandle;
GLuint m_VaoId;//存放顶点数据
GLuint m_VboIds[3];//0表示顶点坐标缓冲区,1表示离屏渲染纹理坐标缓冲区,2表示纹理索引坐标缓冲区
unsigned int m_TextureId;
unsigned char *texturedata;
int texturewidth, textureheight;
int srceenWidth, srceenHeight;//屏幕宽高
GLint m_SamplerLoc;
GLint m_MVPMatLoc;
glm::mat4 m_MVPMatrix;
int m_AngleX;
int m_AngleY;
float m_ScaleX;
float m_ScaleY;
};
#endif //TWODRAWTEXTURE_TEXTUREDEMO_H
CoordSystem.cpp
//
// Created by CreatWall_zhouwen on 2023/4/13.
//
#include "CoordSystem.h"
#include "Util.h"
#include "GLUtil.h"
#include
CoordSystem* m_pContext = nullptr;
#define TAG "DRAWTEXTURE"
float vertices[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
//纹理坐标
GLfloat vTexCoors[] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
//索引数组
unsigned int indices[] = {
0, 1, 2, 1, 3, 2
};
void CoordSystem::CreateProgram(const char *ver, const char *frag)
{
LOGD("CreateProgram Enter");
// 编译链接用于离屏渲染的着色器程序
program = CreateGLProgram(ver, frag, vertexShaderHandle, fragShaderHandle);
if (program == GL_NONE)
{
LOGD("FBOSample::Init m_ProgramObj == GL_NONE");
return;
}
LOGD("CreateGLProgram Success");
m_SamplerLoc = glGetUniformLocation(program, "s_TextureMap");
m_MVPMatLoc = glGetUniformLocation(program, "u_MVPMatrix");
/* -----顶点相关------ */
glGenBuffers(4, m_VboIds);
glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vTexCoors), vTexCoors, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VboIds[2]);//最后一个为纹理的索引缓冲数据
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
LOGD("glGenBuffers Success");
glGenVertexArrays(1, &m_VaoId);
//初始化离屏渲染的VAO
glBindVertexArray(m_VaoId);
glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[0]);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (const void *)0);
glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
glBindBuffer(GL_ARRAY_BUFFER, m_VboIds[1]);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (const void *)0);
glBindBuffer(GL_ARRAY_BUFFER, GL_NONE);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_VboIds[2]);
glBindVertexArray(GL_NONE);
LOGD("m_VaoIds[1] Success");
/* -----创建加载纹理------ */
//创建纹理
glGenTextures(1, &m_TextureId);
//将纹理绑定到GL_TEXTURE_2D
glBindTexture(GL_TEXTURE_2D, m_TextureId);
//为当前绑定的纹理对象设定纹理环绕方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);//重复纹理的填充方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//为当前绑定的纹理对象设定纹理过滤方式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//缩小时线性插值
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//放到就是线性
//绑定纹理数据
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texturewidth, textureheight, 0, GL_RGB, GL_UNSIGNED_BYTE, texturedata);
LOGD("CreateProgram %s", texturedata);
glGenerateMipmap(GL_TEXTURE_2D);//为当前绑定的纹理自动生成所有需要的多级渐远纹理
LOGD("CreateProgram END");
}
void CoordSystem::Draw()
{
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClearColor(0.2f, 0.9f, 0.3f, 1.0f);
UpdateMVPMatrix(m_MVPMatrix, m_AngleX, m_AngleY, (float)srceenWidth / srceenHeight);
glUseProgram (program);
glBindVertexArray(m_VaoId);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
// Bind the RGBA map
//glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glUniform1i(m_SamplerLoc, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (const void *)0);
glBindVertexArray(0);
}
CoordSystem* CoordSystem::GetInstance()
{
if (m_pContext == nullptr)
{
m_pContext = new CoordSystem();
}
return m_pContext;
}
void CoordSystem::DestroyInstance()
{
if (m_pContext)
{
delete m_pContext;
m_pContext = nullptr;
}
}
void CoordSystem::getTexturedata(unsigned char *data, int width, int height)
{
texturedata = data;
texturewidth = width;
textureheight = height;
}
void CoordSystem::OnSurfaceChanged(int width, int height) {
glViewport(0, 0, width, height);
srceenWidth = width;
srceenHeight = height;
}
/**
* @param angleX 绕X轴旋转度数
* @param angleY 绕Y轴旋转度数
* @param ratio 宽高比
* */
void CoordSystem::UpdateMVPMatrix(glm::mat4 &mvpMatrix, int angleX, int angleY, float ratio)
{
LOGD("CoordSystemSample::UpdateMVPMatrix angleX = %d, angleY = %d, ratio = %f", angleX, angleY, ratio);
angleX = angleX % 360;
angleY = angleY % 360;
//转化为弧度角
float radiansX = static_cast(MATH_PI / 180.0f * angleX);
float radiansY = static_cast(MATH_PI / 180.0f * angleY);
// Projection matrix
//glm::mat4 Projection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, 0.1f, 100.0f);
//glm::mat4 Projection = glm::frustum(-ratio, ratio, -1.0f, 1.0f, 4.0f, 100.0f);
glm::mat4 Projection = glm::perspective(45.0f,ratio, 0.1f,100.f);
// View matrix
glm::mat4 View = glm::lookAt(
glm::vec3(0, 0, 4), // Camera is at (0,0,1), in World Space
glm::vec3(0, 0, 0), // and looks at the origin
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
// Model matrix
glm::mat4 Model = glm::mat4(1.0f);
Model = glm::scale(Model, glm::vec3(m_ScaleX, m_ScaleY, 1.0f));//缩放
Model = glm::rotate(Model, radiansX, glm::vec3(1.0f, 0.0f, 0.0f));
Model = glm::rotate(Model, radiansY, glm::vec3(0.0f, 1.0f, 0.0f));
Model = glm::translate(Model, glm::vec3(0.0f, 0.0f, 0.0f));
mvpMatrix = Projection * View * Model;
for (int i = 0; i < 4; ++i) {
LOGD("CoordSystemSample::UpdateMVPMatrix angleX = %f %f %f %f",mvpMatrix[i][0],mvpMatrix[i][1],mvpMatrix[i][2],mvpMatrix[i][3]);
}
}
void CoordSystem::UpdateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY) {
m_AngleX = static_cast(rotateX);
m_AngleY = static_cast(rotateY);
m_ScaleX = scaleX;
m_ScaleY = scaleY;
}
MyGLSurfaceView.java
package com.example.basiclighting8code;
import android.content.Context;
import android.content.res.AssetManager;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyGLSurfaceView extends GLSurfaceView implements ScaleGestureDetector.OnScaleGestureListener{
private MyRenderer renderer;
private AssetManager mrg;
private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
private float mPreviousY;
private float mPreviousX;
private int mXAngle;
private int mYAngle;
private int mRatioWidth = 0;
private int mRatioHeight = 0;
private ScaleGestureDetector mScaleGestureDetector;
private float mPreScale = 1.0f;
private float mCurScale = 1.0f;
private long mLastMultiTouchTime;
public MyGLSurfaceView(Context context) {
super(context);
mrg = getResources().getAssets();
setEGLContextClientVersion(3);
setEGLConfigChooser(8, 8, 8, 8, 16, 8);
renderer = new MyRenderer();
setRenderer(renderer);
setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
mScaleGestureDetector = new ScaleGestureDetector(context, this);
}
//屏幕触摸事件
public boolean onTouchEvent(MotionEvent e) {
if (e.getPointerCount() == 1) {
consumeTouchEvent(e);
long currentTimeMillis = System.currentTimeMillis();
if (currentTimeMillis - mLastMultiTouchTime > 200) {
float y = e.getY();
float x = e.getX();
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
float dy = y - mPreviousY;
float dx = x - mPreviousX;
mYAngle += dx * TOUCH_SCALE_FACTOR;
mXAngle += dy * TOUCH_SCALE_FACTOR;
}
mPreviousY = y;
mPreviousX = x;
//更新xy的角度
renderer.updateTransformMatrix(mXAngle, mYAngle, mCurScale, mCurScale);
requestRender();
}else {
mScaleGestureDetector.onTouchEvent(e);
}
}
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (0 == mRatioWidth || 0 == mRatioHeight) {
setMeasuredDimension(width, height);
} else {
if (width < height * mRatioWidth / mRatioHeight) {
setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
} else {
setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
}
}
}
public void setAspectRatio(int width, int height) {
if (width < 0 || height < 0) {
throw new IllegalArgumentException("Size cannot be negative.");
}
mRatioWidth = width;
mRatioHeight = height;
requestLayout();
}
public void consumeTouchEvent(MotionEvent e) {
dealClickEvent(e);
float touchX = -1, touchY = -1;
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
touchX = e.getX();
touchY = e.getY();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
touchX = -1;
touchY = -1;
break;
default:
break;
}
//滑动、触摸
/*switch (mGLRender.getSampleType()) {
case SAMPLE_TYPE_KEY_SCRATCH_CARD:
mGLRender.setTouchLoc(touchX, touchY);
requestRender();
break;
default:
break;
}*/
//点击
switch (e.getAction()) {
case MotionEvent.ACTION_MOVE:
//touchX = e.getX();
//touchY = e.getY();
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_CANCEL:
break;
default:
break;
}
}
public void dealClickEvent(MotionEvent e) {
float touchX = -1, touchY = -1;
switch (e.getAction()) {
case MotionEvent.ACTION_UP:
touchX = e.getX();
touchY = e.getY();
break;
default:
break;
}
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float preSpan = detector.getPreviousSpan();
float curSpan = detector.getCurrentSpan();
if (curSpan < preSpan) {
mCurScale = mPreScale - (preSpan - curSpan) / 200;
} else {
mCurScale = mPreScale + (curSpan - preSpan) / 200;
}
mCurScale = Math.max(0.05f, Math.min(mCurScale, 80.0f));
renderer.updateTransformMatrix(mXAngle, mYAngle, mCurScale, mCurScale);
requestRender();
return false;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
return false;
}
@Override
public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
mPreScale = mCurScale;
mLastMultiTouchTime = System.currentTimeMillis();
}
private class MyRenderer implements Renderer {
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
NativeImpl.NativeImpl_InitScene(mrg);
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();
}
public void updateTransformMatrix(float rotateX, float rotateY, float scaleX, float scaleY)
{
NativeImpl.native_UpdateTransformMatrix(rotateX, rotateY, scaleX, scaleY);
}
}
}