不積跬步,無以至千里;不積小流,無以成江海。要沉下心來,詩和遠(yuǎn)方的路費(fèi)真的很貴!
OpenGL ES 學(xué)習(xí)——3D
顏色的簡單搭配:
不紅+不綠+不藍(lán) = 黑
紅+綠+藍(lán) = 白
紅+綠 = 黃
紅+藍(lán) = 紫
綠+藍(lán) = 青藍(lán)
投影矩陣
投影主要分為正交投影
和透視投影
兩種。
正交投影
沒有近大遠(yuǎn)小的效果,是平行投影,投影顯示的大小就是物體的大小。
Matrix.orthoM方法
- 這是在
Java
中設(shè)置正交投影的函數(shù)。
Matrix.orthoM(mProjectMatrix, 0, left, right, bottom, top, near, far);
glm::ortho方法
- 在
C++
語言中,沒有專門的數(shù)學(xué)庫來處理矩陣,所以我們需要自己引入第三方庫GLM
。 - 在官網(wǎng)下載
GLM
庫,然后解壓,將glm
文件夾加入到C++
下面的include
文件夾中,然后在文件中書寫頭文件即可使用。
template<typename T>
GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top, T zNear, T zFar)
{
if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO)
return orthoLH_ZO(left, right, bottom, top, zNear, zFar);
else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO)
return orthoLH_NO(left, right, bottom, top, zNear, zFar);
else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO)
return orthoRH_ZO(left, right, bottom, top, zNear, zFar);
else if(GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO)
return orthoRH_NO(left, right, bottom, top, zNear, zFar);
}
- 還是和
Java
中方法相似,就是無偏移量參數(shù),數(shù)據(jù)保存在矩陣中了,無需再一個(gè)內(nèi)存來保存數(shù)據(jù)了。
透視投影
特點(diǎn)是近大遠(yuǎn)小,模擬人的眼球,近的物體顯示大,遠(yuǎn)的物體顯示小,發(fā)散光。
相機(jī)位置
相機(jī)位置,就是所謂的人所在位置,即觀察者所在的位置。
在
Java
和c++
中都有函數(shù)來設(shè)置相機(jī)位置,來觀察物體。通過改變相機(jī)位置,可以使我們觀察到物體的每一個(gè)位置。
Matrix.setLookAtM方法
- 這是在
Java
中設(shè)置相機(jī)位置的函數(shù)。
Matrix.setLookAtM(
mVMatrix,0,
cx,cy,cz, //相機(jī)位置
tx,ty,tz, //目標(biāo)點(diǎn)坐標(biāo)
upx,upy,upz); //視點(diǎn)位置,即眼睛位置
- 第二個(gè)參數(shù)是偏移量,大多數(shù)情況都默認(rèn)為
0
。 - 最后將這些數(shù)據(jù)都存入
mVMatrix
中。
glm::lookAt方法
template<typename T, qualifier Q>
GLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAt(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)
{
GLM_IF_CONSTEXPR(GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT)
return lookAtLH(eye, center, up);
else
return lookAtRH(eye, center, up);
}
- 返回一個(gè)
mat4
的矩陣。 - 參數(shù)就是三個(gè)
vec3
的向量:第一個(gè)就是相機(jī)位置,第二個(gè)就是目標(biāo)點(diǎn)坐標(biāo),第三個(gè)是視點(diǎn)位置。
變換
我們熟知的變換方式有平移
,旋轉(zhuǎn)
,縮放
。
平移
旋轉(zhuǎn)
縮放
多個(gè)彩色三角形利用相機(jī)和矩陣形成立體效果
繪制立方體
對(duì)于三維圖形來說,相機(jī)的朝向和角度是關(guān)鍵,看的視角很關(guān)鍵,不然你繪制是個(gè)立體圖形,但是只能看到一個(gè)平面。
- 頂點(diǎn)著色器
#version 300 es
in vec4 vPosition;
in vec4 vColor;
uniform mat4 vMatrix;
out vec4 aColor;
void main() {
gl_Position = vMatrix*vPosition;
gl_PointSize = 10.0;
aColor = vColor;
}
- 片元著色器
#version 300 es
precision mediump float;
in vec4 aColor;
out vec4 fragColor;
void main() {
fragColor = aColor;
}
JAVA版本
Renderer類
package com.example.openglndk;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
//渲染器,把3D物體繪制到屏幕上
public class MyRenderer implements GLSurfaceView.Renderer {
//坐標(biāo)系xyz
private final static int COORDS_PER_VERTEX = 3;
//顏色通道(RGBA)
private final static int COORDS_PER_COLOR = 4;
//頂點(diǎn)之間的偏移量
private final int vertexStride = COORDS_PER_VERTEX * 4; // 每個(gè)頂點(diǎn)四個(gè)字節(jié)
//顏色之間的偏移量
private final int colorStride = COORDS_PER_COLOR * 4; // 每個(gè)顏色四個(gè)字節(jié)
//聲明內(nèi)存分配的數(shù)據(jù)類型
private FloatBuffer vertexBuffer, colorBuffer;
private ShortBuffer indexBuffer;
//著色器和管理程序
private int vertexShader;
private int fragmentShader;
private int mProgram;
//彩色數(shù)據(jù)
private float colors[] = {
0f,1f,1f,1f,
1f,1f,0f,1f,
1f,0f,1f,1f,
0f,1f,0f,1f,
1f,0f,0f,1f,
0f,0f,1f,1f,
1f,1f,1f,1f,
0f,0f,0f,1f,
};
//定義點(diǎn)坐標(biāo)
private float vertexPoints[] = {
0.5f, 0.5f, 0.5f, //右面左上0
0.5f, 0.5f, -0.5f, //右面左下1
-0.5f, 0.5f, 0.5f, //右面右上2
-0.5f, 0.5f, -0.5f, //右面右下3
0.5f, -0.5f, 0.5f, //左面右上4
0.5f, -0.5f, -0.5f, //左面右下5
-0.5f, -0.5f, 0.5f, //左面左上6
-0.5f, -0.5f, -0.5f, //左面左下7
};
//索引
private short index[] = {
//上
0, 1, 2,
1, 2, 3,
//下
4, 5, 6,
5, 6, 7,
//左
2, 3, 6,
3, 6, 7,
//右
0, 1, 4,
1, 4, 5,
//前
0, 2, 4,
2, 4, 6,
//后
1, 3, 7,
1, 7, 5
};
//點(diǎn)數(shù)量
private int vertexCount = vertexPoints.length / COORDS_PER_VERTEX;
//頂點(diǎn)著色器代碼
private String vertexShaderCode = "#version 300 es\n" +
"in vec4 vPosition;\n" +
"in vec4 vColor;\n" +
"uniform mat4 vMatrix;\n" +
"out vec4 aColor;\n" +
"void main() {\n" +
" gl_Position = vMatrix*vPosition;\n" +
" gl_PointSize = 10.0;\n" +
" aColor = vColor;\n" +
"}\n";
//片元著色器代碼
private String fragmentShaderCode = "#version 300 es\n" +
"precision mediump float;\n" +
"in vec4 aColor;\n" +
"out vec4 fragColor;\n" +
"void main() {\n" +
" fragColor = aColor;\n" +
"}\n";
//構(gòu)造函數(shù)
public MyRenderer() {
//分配頂點(diǎn)內(nèi)存
vertexBuffer = ByteBuffer.allocateDirect(vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
//傳入指定的坐標(biāo)數(shù)據(jù)
//將語法推送給GPU
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
//分配顏色內(nèi)存
colorBuffer = ByteBuffer.allocateDirect(colors.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
//傳入指定的數(shù)據(jù)
colorBuffer.put(colors);
colorBuffer.position(0);
//索引
indexBuffer = ByteBuffer.allocateDirect(index.length * 2)
.order(ByteOrder.nativeOrder())
.asShortBuffer();
indexBuffer.put(index);
indexBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
//設(shè)置背景顏色為白色
GLES30.glClearColor(1, 1, 1, 1);
//創(chuàng)建頂點(diǎn)著色器
vertexShader = LoadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode);
//創(chuàng)建片元著色器
fragmentShader = LoadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode);
//將頂點(diǎn)著色器和片元著色器交給統(tǒng)一程序管理
mProgram = linkProgram(vertexShader, fragmentShader);
}
/**
* 圖形尺寸
*
* @param gl10
* @param width
* @param height
*/
private float mProjectionMatrix[] = new float[16];
private float mViewMatrix[] = new float[16];
private float mMVPMatrix[] = new float[16];
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
//設(shè)置視口
GLES30.glViewport(0, 0, width, height);
//寬高比
float ratio = (float) width / height;
//正交投影只能看見一個(gè)面
//設(shè)置透視投影矩陣
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
//設(shè)置相機(jī)角度(核心)
Matrix.setLookAtM(mViewMatrix, 0, 3, 3, 3, 0f, 0f, 0f, 1f, 0f, 1.0f);
//矩陣合并
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
/**
* @param gl10 渲染
*/
@Override
public void onDrawFrame(GL10 gl10) {
//清除顏色緩沖區(qū)和深度緩沖區(qū)
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);
//開啟深度測(cè)試
GLES30.glEnable(GLES30.GL_DEPTH_TEST);
//使用統(tǒng)一的管理程序
GLES30.glUseProgram(mProgram);
//獲取變換矩陣vMatrix成員句柄
//圖形參數(shù)
int mMatrixHandler = GLES30.glGetUniformLocation(mProgram, "vMatrix");
//指定vMatrix的值
GLES30.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0);
//獲取頂點(diǎn)著色器的vPosition成員句柄
int mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
//啟用頂點(diǎn)的句柄
GLES30.glEnableVertexAttribArray(mPositionHandle);
//準(zhǔn)備坐標(biāo)數(shù)據(jù)
GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES30.GL_FLOAT, false,
vertexStride, vertexBuffer);
//獲取片元著色器的vColor成員的句柄
//因?yàn)槭遣噬瑪?shù)據(jù)類型和頂點(diǎn)類似,所以必須是glGetAttribLocation方法
//glGetUniformLocation方法畫不全顏色,會(huì)變成黑色
int mColorHandle = GLES30.glGetAttribLocation(mProgram, "vColor");
//啟動(dòng)顏色的句柄
GLES30.glEnableVertexAttribArray(mColorHandle);
//設(shè)置圖形的顏色
//準(zhǔn)備顏色數(shù)據(jù)
GLES30.glVertexAttribPointer(mColorHandle, COORDS_PER_COLOR,
GLES30.GL_FLOAT, false,
colorStride, colorBuffer);
// GLES30.glUniform4fv(mColorHandle, 1, colors, 0);
//繪制圖形
GLES30.glLineWidth(10.0f);
// GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, vertexCount);
//索引法繪制圖形,索引繪制三角形,無需在用扇形,直接繪制即可
GLES30.glDrawElements(GLES30.GL_TRIANGLES, index.length,
GLES30.GL_UNSIGNED_SHORT, indexBuffer);
//禁止顏色數(shù)組的句柄
GLES30.glDisableVertexAttribArray(mColorHandle);
//禁止頂點(diǎn)數(shù)組的句柄
GLES30.glDisableVertexAttribArray(mPositionHandle);
}
/**
* 編譯
*
* @param type 頂點(diǎn)著色器:GLES30.GL_VERTEX_SHADER
* 片段著色器:GLES30.GL_FRAGMENT_SHADER
* @param shaderCode
* @return
*/
private static int LoadShader(int type, String shaderCode) {
//創(chuàng)建一個(gè)著色器
final int shaderId = GLES30.glCreateShader(type);
if (shaderId != 0) {
//加載到著色器
GLES30.glShaderSource(shaderId, shaderCode);
//編譯著色器
GLES30.glCompileShader(shaderId);
//檢測(cè)狀態(tài)
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0) {
String logInfo = GLES30.glGetShaderInfoLog(shaderId);
System.err.println(logInfo);
//創(chuàng)建失敗
GLES30.glDeleteShader(shaderId);
return 0;
}
return shaderId;
} else {
//創(chuàng)建失敗
return 0;
}
}
/**
* 鏈接小程序
*
* @param vertexShaderId 頂點(diǎn)著色器
* @param fragmentShaderId 片段著色器
* @return
*/
public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
if (programId != 0) {
//將頂點(diǎn)著色器加入到程序
GLES30.glAttachShader(programId, vertexShaderId);
//將片元著色器加入到程序中
GLES30.glAttachShader(programId, fragmentShaderId);
//鏈接著色器程序
GLES30.glLinkProgram(programId);
final int[] linkStatus = new int[1];
GLES30.glGetProgramiv(programId, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0) {
String logInfo = GLES30.glGetProgramInfoLog(programId);
System.err.println(logInfo);
GLES30.glDeleteProgram(programId);
return 0;
}
return programId;
} else {
//創(chuàng)建失敗
return 0;
}
}
}
C++版本
.cpp文件
//
// Created by lvjunkai on 2022/2/21.
//
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#include <malloc.h>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
//聲明自定義函數(shù)
//創(chuàng)建編譯加載
GLuint LoadShader(int type, char *shaderCode);
//鏈接統(tǒng)一程序
GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);
//模板技術(shù)定義的函數(shù)
//用于求數(shù)組長度
template<class T>
GLsizei getArrayLen(T &array) {
return (sizeof(array) / sizeof(array[0]));
}
//坐標(biāo)個(gè)數(shù)(xyz)
const GLint COORDS_PER_VERTEX = 3;
const GLint COORDS_PER_COLOR = 4;
//頂點(diǎn)之間的偏移量
const GLsizei vertexStride = COORDS_PER_VERTEX * 4; // 每個(gè)頂點(diǎn)四個(gè)字節(jié)
//顏色之間的偏移量
const GLsizei colorStride = COORDS_PER_COLOR * 4; // 每個(gè)頂點(diǎn)四個(gè)字節(jié)
//聲明頂點(diǎn)著色器
GLuint vertexShader;
//聲明片元著色器
GLuint fragmentShader;
//聲明著色器管理程序
GLuint mProgram;
//顏色
float colors[] = {
0.0f,1.0f,1.0f,1.0f,
1.0f,1.0f,0.0f,1.0f,
1.0f,0.0f,1.0f,1.0f,
0.0f,1.0f,0.0f,1.0f,
1.0f,0.0f,0.0f,1.0f,
0.0f,0.0f,1.0f,1.0f,
1.0f,1.0f,1.0f,1.0f,
0.0f,0.0f,0.0f,1.0f,
};
//定義點(diǎn)坐標(biāo)
float vertexPoints[] = {
0.5f, 0.5f, 0.5f, //右面左上0
0.5f, 0.5f, -0.5f, //右面左下1
-0.5f, 0.5f, 0.5f, //右面右上2
-0.5f, 0.5f, -0.5f, //右面右下3
0.5f, -0.5f, 0.5f, //左面右上4
0.5f, -0.5f, -0.5f, //左面右下5
-0.5f, -0.5f, 0.5f, //左面左上6
-0.5f, -0.5f, -0.5f, //左面左下7
};
//索引
short index[] = {
//上
0, 1, 2,
1, 2, 3,
//下
4, 5, 6,
5, 6, 7,
//左
2, 3, 6,
3, 6, 7,
//右
0, 1, 4,
1, 4, 5,
//前
0, 2, 4,
2, 4, 6,
//后
1, 3, 7,
1, 7, 5
};
//頂點(diǎn)個(gè)數(shù)
GLsizei vertexCount = getArrayLen(vertexPoints) / COORDS_PER_VERTEX;
//頂點(diǎn)著色器代碼
char vertexShaderCode[] = "#version 300 es\n"
"in vec4 vPosition;\n"
"in vec4 vColor;\n"
"uniform mat4 vMatrix;\n"
"out vec4 aColor;\n"
"void main() {\n"
" gl_Position = vMatrix*vPosition;\n"
" gl_PointSize = 10.0;\n"
" aColor = vColor;\n"
"}";
//片段著色器代碼
char fragmentShaderCode[] = "#version 300 es\n"
"precision mediump float;\n"
"in vec4 aColor;\n"
"out vec4 fragColor;\n"
"void main() {\n"
" fragColor = aColor;\n"
"}";
JNIEXPORT void JNICALL init(JNIEnv *env, jobject obj) {
}
//書寫本地方法的具體邏輯
/**初始化
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL surfaceCreated(JNIEnv *env, jobject obj) {
//設(shè)置背景顏色為黑色
glClearColor(0, 0, 0, 0);
//創(chuàng)建頂點(diǎn)著色器
vertexShader = LoadShader(GL_VERTEX_SHADER, vertexShaderCode);
//創(chuàng)建片元著色器
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
//將頂點(diǎn)著色器和片元著色器交給統(tǒng)一程序管理
mProgram = linkProgram(vertexShader, fragmentShader);
}
/**圖形尺寸
*
* @param env
* @param obj
* @param width
* @param height
*/
glm::mat4 mProjectionMatrix;
glm::mat4 mViewMatrix;
glm::mat4 mMVPMatrix;
float mMVPMatrixArray[16];
JNIEXPORT void JNICALL surfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) {
//設(shè)置視口
glViewport(0, 0, width, height);
//寬高比
float ratio = (float) width / height;
//透視投影矩陣
mProjectionMatrix = glm::frustum(-ratio, ratio, -1.0f, 1.0f, 3.0f,
7.0f); //ratio 一般表示視口的寬高比,width/height
//相機(jī)位置
mViewMatrix = glm::lookAt(glm::vec3(3, 3, 3), // 相機(jī)位置
glm::vec3(0, 0, 0), // 觀察點(diǎn)坐標(biāo)
glm::vec3(1, 0, 1));
//矩陣合并
mMVPMatrix = mProjectionMatrix * mViewMatrix;
//矩陣轉(zhuǎn)換成數(shù)組
int m = 0;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
mMVPMatrixArray[m] = mMVPMatrix[i][j];
m++;
}
}
/**渲染繪制
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL drawFrame(JNIEnv *env, jobject obj) {
//清除顏色緩沖區(qū)和深度緩沖區(qū)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//開啟深度測(cè)試
glEnable(GL_DEPTH_TEST);
//使用統(tǒng)一的管理程序
glUseProgram(mProgram);
//獲取變換矩陣vMatrix成員句柄
//圖形參數(shù)
GLint mMatrixHandler = glGetUniformLocation(mProgram, "vMatrix");
//指定vMatrix的值
glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrixArray);
//獲取頂點(diǎn)著色器的vPosition成員句柄
GLint mPositionHandle = glGetAttribLocation(mProgram, "vPosition");
//啟用頂點(diǎn)的句柄
glEnableVertexAttribArray(mPositionHandle);
//準(zhǔn)備坐標(biāo)數(shù)據(jù)
glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GL_FLOAT, false,
vertexStride, vertexPoints);
//獲取片元著色器的vColor成員的句柄
//因?yàn)槭遣噬?,?shù)據(jù)類型和頂點(diǎn)類似,所以必須是glGetAttribLocation方法
//glGetUniformLocation方法畫不全顏色,會(huì)變成黑色
GLint mColorHandle = glGetAttribLocation(mProgram, "vColor");
//啟動(dòng)顏色的句柄
glEnableVertexAttribArray(mColorHandle);
//設(shè)置圖形的顏色
//準(zhǔn)備顏色數(shù)據(jù)
glVertexAttribPointer(mColorHandle, COORDS_PER_COLOR,
GL_FLOAT, false,
colorStride, colors);
//繪制圖形
glLineWidth(10.0f);
//索引法繪制圖形,索引繪制三角形,無需在用扇形,直接繪制即可
glDrawElements(GL_TRIANGLES, getArrayLen(index),
GL_UNSIGNED_SHORT, index);
//禁止顏色數(shù)組的句柄
glDisableVertexAttribArray(mColorHandle);
//禁止頂點(diǎn)數(shù)組的句柄
glDisableVertexAttribArray(mPositionHandle);
}
/**加載著色器
*
*/
JNIEXPORT GLuint LoadShader(int type, char *shaderCode) {
//創(chuàng)建一個(gè)著色器
GLuint shader = glCreateShader(type);
if (shader != 0) {
//加載到著色器
glShaderSource(shader, 1, &shaderCode, NULL);
//編譯著色器
glCompileShader(shader);
//檢測(cè)狀態(tài)
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == 0) {
//聲明log長度變量
GLint infoLen = 0;
//獲取長度并賦值
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
//創(chuàng)建成功小于等于1
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
printf("SHADER ERROR!");
free(infoLog);
}
//創(chuàng)建失敗
glDeleteShader(shader);
return 0;
}
return shader;
} else {
//創(chuàng)建失敗
return 0;
}
}
/**鏈接著色器
*
*/
JNIEXPORT GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
if (program != 0) {
//將頂點(diǎn)著色器加入到程序
glAttachShader(program, vertexShader);
//將片元著色器加入到程序中
glAttachShader(program, fragmentShader);
//鏈接著色器程序
glLinkProgram(program);
//檢測(cè)狀態(tài)
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) {
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetProgramInfoLog(program, infoLen, NULL, infoLog);
printf("PROGRAM ERROR!");
free(infoLog);
}
glDeleteProgram(program);
return 0;
}
return program;
} else {
//創(chuàng)建失敗
return 0;
}
}
/** 動(dòng)態(tài)注冊(cè)
* @param env
* @return
*/
//本地方法聲明和具體邏輯連接
JNINativeMethod methods[] = {
{"init", "()V", (void *) init},
{"surfaceCreated", "()V", (void *) surfaceCreated},
{"surfaceChanged", "(II)V", (void *) surfaceChanged},
{"drawFrame", "()V", (void *) drawFrame}
};
/** 動(dòng)態(tài)注冊(cè)
* @param env
* @return
*/
jint registerNativeMethod(JNIEnv *env) {
//到本地方法存在的類找出其方法聲明
jclass cl = env->FindClass("com/example/openglndk/WaveRenderer");
if ((env->RegisterNatives(cl, methods, sizeof(methods) / sizeof(methods[0]))) < 0) {
return -1;
}
return 0;
}
/** 加載默認(rèn)回調(diào)
* @param vm
* @param reserved
* @return
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
//注冊(cè)方法
if (registerNativeMethod(env) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
繪制球體
JAVA版本
Renderer類
package com.example.openglndk;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRenderer implements GLSurfaceView.Renderer {
//坐標(biāo)個(gè)數(shù)(xyz)
private final static int COORDS_PER_VERTEX = 3;
//頂點(diǎn)之間的偏移量
private final int vertexStride = COORDS_PER_VERTEX * 4; // 每個(gè)頂點(diǎn)四個(gè)字節(jié)
private float radius = 0.5f; //半徑
private FloatBuffer vertexBuffer;
private int vertexShader;
private int fragmentShader;
private int mProgram;
private int vertexCount;
//定義點(diǎn)坐標(biāo)
private float vertexPoints[];
//設(shè)置顏色,依次為紅綠藍(lán)和透明通道
private float color[] = {0.1f, 0.9f, 1.0f, 0.0f};
//根據(jù)經(jīng)緯度創(chuàng)建球體頂點(diǎn)坐標(biāo)
private float[] createPositions() {
//球以(0,0,0)為中心,以R為半徑,則球上任意一點(diǎn)的坐標(biāo)為
// 其中,a為圓心到點(diǎn)的線段與xz平面的夾角,b為圓心到點(diǎn)的線段在xz平面的投影與z軸的夾角
ArrayList<Float> data = new ArrayList<>();
float r1, r2;
float h1, h2;
float sin, cos;
float step = 1.0f;
// 遍歷緯度
for (float i = -90; i < 90 + step; i += step) {
//Math.sin(x) x 的正玄值。返回值在 -1.0 到 1.0 之間;X 都是指的“弧度”而非“角度”,弧度的計(jì)算公式為: 2*PI/360*角度
//計(jì)算當(dāng)前點(diǎn)與圓心連線,與Y軸夾角θ的正余弦值(此坐標(biāo)系為openGL坐標(biāo)系)
/**
* 以下坐標(biāo)系為openGl坐標(biāo)系
* 此處計(jì)算當(dāng)前緯度與Z軸夾角的正余弦值,由于根據(jù)公式,應(yīng)該計(jì)算與Y軸的正余弦,但因?yàn)榛ビ鄪A角sin與cos相等,所以按此計(jì)算沒有問題
* 后續(xù)的X的坐標(biāo)就變成了x=R*cos*cos,所有關(guān)于θ的角的sin值都變換為cos計(jì)算
*/
r1 = (float) (radius * Math.cos(i * Math.PI / 180.0));
r2 = (float) (radius * Math.cos((i + step) * Math.PI / 180.0));
h1 = (float) (radius * Math.sin(i * Math.PI / 180.0));
h2 = (float) (radius * Math.sin((i + step) * Math.PI / 180.0));
// 固定緯度, 360 度旋轉(zhuǎn)遍歷一條緯線
float step2 = step * 2;
for (float j = 0.0f; j < 360.0f + step; j += step2) {
// 計(jì)算當(dāng)前點(diǎn)在XZ平面投影,與Z軸的夾角φ的正余弦值(此坐標(biāo)系為openGL坐標(biāo)系)
cos = (float) Math.cos(j * Math.PI / 180.0);
sin = (float) Math.sin(j * Math.PI / 180.0);
data.add(r2 * cos);
data.add(h2);
data.add(r2 * sin);
data.add(r1 * cos);
data.add(h1);
data.add(r1 * sin);
}
}
float[] f = new float[data.size()];
for (int i = 0; i < f.length; i++) {
f[i] = data.get(i);
}
return f;
}
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"void main() {" +
" gl_Position = vMatrix*vPosition;" +
" gl_PointSize = 10.0;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
public MyRenderer() {
vertexPoints = createPositions();
vertexCount = vertexPoints.length / COORDS_PER_VERTEX;
//坐標(biāo)
vertexBuffer = ByteBuffer.allocateDirect(
vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
GLES30.glClearColor(1, 1, 1, 1);
vertexShader = LoadShader(GLES30.GL_VERTEX_SHADER,
vertexShaderCode);
fragmentShader = LoadShader(GLES30.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = linkProgram(vertexShader, fragmentShader);
}
private float mProjectionMatrix[] = new float[16];
private float mViewMatrix[] = new float[16];
private float mMVPMatrix[] = new float[16];
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
GLES30.glViewport(0, 0, width, height);
//寬高比
float ratio = (float) width / height;
//設(shè)置投影矩陣
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
//設(shè)置相機(jī)角度
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//矩陣合并
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
//每20ms刷新
@Override
public void onDrawFrame(GL10 gl10) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
//將程序加入
GLES30.glUseProgram(mProgram);
//獲取變換矩陣vMatrix成員句柄
//圖形參數(shù)
int mMatrixHandler = GLES30.glGetUniformLocation(mProgram, "vMatrix");
//指定vMatrix的值
GLES30.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0);
//獲取頂點(diǎn)著色器的vPosition成員句柄
int mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
//啟用頂點(diǎn)的句柄
GLES30.glEnableVertexAttribArray(mPositionHandle);
//準(zhǔn)備坐標(biāo)數(shù)據(jù)
GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES30.GL_FLOAT, false,
vertexStride, vertexBuffer);
//獲取片元著色器的vColor成員的句柄
int mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");
//設(shè)置圖形的顏色
GLES30.glUniform4fv(mColorHandle, 1, color, 0);
//頂點(diǎn)法繪制圖形
// GLES30.glLineWidth(10.0f);
GLES30.glDrawArrays(GLES30.GL_LINE_LOOP, 0, vertexCount);
//禁止頂點(diǎn)數(shù)組的句柄
GLES30.glDisableVertexAttribArray(mPositionHandle);
}
/**
* 編譯
*
* @param type 頂點(diǎn)著色器:GLES30.GL_VERTEX_SHADER
* 片段著色器:GLES30.GL_FRAGMENT_SHADER
* @param shaderCode
* @return
*/
private static int LoadShader(int type, String shaderCode) {
//創(chuàng)建一個(gè)著色器
final int shaderId = GLES30.glCreateShader(type);
if (shaderId != 0) {
//加載到著色器
GLES30.glShaderSource(shaderId, shaderCode);
//編譯著色器
GLES30.glCompileShader(shaderId);
//檢測(cè)狀態(tài)
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0) {
String logInfo = GLES30.glGetShaderInfoLog(shaderId);
System.err.println(logInfo);
//創(chuàng)建失敗
GLES30.glDeleteShader(shaderId);
return 0;
}
return shaderId;
} else {
//創(chuàng)建失敗
return 0;
}
}
/**
* 鏈接小程序
*
* @param vertexShaderId 頂點(diǎn)著色器
* @param fragmentShaderId 片段著色器
* @return
*/
public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
if (programId != 0) {
//將頂點(diǎn)著色器加入到程序
GLES30.glAttachShader(programId, vertexShaderId);
//將片元著色器加入到程序中
GLES30.glAttachShader(programId, fragmentShaderId);
//鏈接著色器程序
GLES30.glLinkProgram(programId);
final int[] linkStatus = new int[1];
GLES30.glGetProgramiv(programId, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0) {
String logInfo = GLES30.glGetProgramInfoLog(programId);
System.err.println(logInfo);
GLES30.glDeleteProgram(programId);
return 0;
}
return programId;
} else {
//創(chuàng)建失敗
return 0;
}
}
}
C++版本
.cpp文件
//
// Created by lvjunkai on 2022/2/21.
//
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#include <malloc.h>
#include <vector>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
//命名空間
using namespace std;
//定義宏
//#define PI 3.1415926;
//常數(shù)Π
const double PI = acos(-1.0);
//聲明自定義函數(shù)
//創(chuàng)建編譯加載
GLuint LoadShader(int type, char *shaderCode);
//鏈接統(tǒng)一程序
GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);
//模板技術(shù)定義的函數(shù)
//用于求數(shù)組長度
template<class T>
GLsizei getArrayLen(T &array) {
return (sizeof(array) / sizeof(array[0]));
}
//坐標(biāo)個(gè)數(shù)(xyz)
const GLint COORDS_PER_VERTEX = 3;
//頂點(diǎn)之間的偏移量
const GLsizei vertexStride = COORDS_PER_VERTEX * 4; // 每個(gè)頂點(diǎn)四個(gè)字節(jié)
//聲明頂點(diǎn)著色器
GLuint vertexShader;
//聲明片元著色器
GLuint fragmentShader;
//聲明著色器管理程序
GLuint mProgram;
//定義圖形坐標(biāo)
vector<float> vertexVector; //存放頂點(diǎn)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)
float vertexPoints[196566]; //頂點(diǎn)數(shù)組
float radius = 0.5f; //半徑
//頂點(diǎn)個(gè)數(shù)
GLsizei vertexCount = getArrayLen(vertexPoints) / COORDS_PER_VERTEX;
//設(shè)置顏色,依次為紅綠藍(lán)和透明通道
float color[] = {0.1f, 0.9f, 1.0f, 0.0f};
//頂點(diǎn)著色器代碼
char vertexShaderCode[] = "attribute vec4 vPosition;"
"uniform mat4 vMatrix;"
"void main() {"
" gl_Position = vMatrix*vPosition;"
" gl_PointSize = 10.0;"
"}";
//片段著色器代碼
char fragmentShaderCode[] = "precision mediump float;"
"uniform vec4 vColor;"
"void main() {"
" gl_FragColor = vColor;"
"}";
//創(chuàng)建頂點(diǎn)坐標(biāo)放入vector數(shù)據(jù)結(jié)構(gòu)中
vector<float> createPositions() {
//球以(0,0,0)為中心,以R為半徑,則球上任意一點(diǎn)的坐標(biāo)為
// 其中,a為圓心到點(diǎn)的線段與xz平面的夾角,b為圓心到點(diǎn)的線段在xz平面的投影與z軸的夾角
vector<float> data;
float r1, r2;
float h1, h2;
float sin1, cos1;
float step = 1.0f;
// 遍歷緯度
for (float i = -90; i < 90 + step; i += step) {
//Math.sin(x) x 的正玄值。返回值在 -1.0 到 1.0 之間;X 都是指的“弧度”而非“角度”,弧度的計(jì)算公式為: 2*PI/360*角度
//計(jì)算當(dāng)前點(diǎn)與圓心連線,與Y軸夾角θ的正余弦值(此坐標(biāo)系為openGL坐標(biāo)系)
/**
* 以下坐標(biāo)系為openGl坐標(biāo)系
* 此處計(jì)算當(dāng)前緯度與Z軸夾角的正余弦值,由于根據(jù)公式,應(yīng)該計(jì)算與Y軸的正余弦,但因?yàn)榛ビ鄪A角sin與cos相等,所以按此計(jì)算沒有問題
* 后續(xù)的X的坐標(biāo)就變成了x=R*cos*cos,所有關(guān)于θ的角的sin值都變換為cos計(jì)算
*/
r1 = (float) (radius * cos(i * PI / 180.0));
r2 = (float) (radius * cos((i + step) * PI / 180.0));
h1 = (float) (radius * sin(i * PI / 180.0));
h2 = (float) (radius * sin((i + step) * PI / 180.0));
// 固定緯度, 360 度旋轉(zhuǎn)遍歷一條緯線
float step2 = step * 2;
for (float j = 0.0f; j < 360.0f + step; j += step2) {
// 計(jì)算當(dāng)前點(diǎn)在XZ平面投影,與Z軸的夾角φ的正余弦值(此坐標(biāo)系為openGL坐標(biāo)系)
cos1 = (float) cos(j * PI / 180.0);
sin1 = (float) sin(j * PI / 180.0);
data.push_back(r2 * cos1);
data.push_back(h2);
data.push_back(r2 * sin1);
data.push_back(r1 * cos1);
data.push_back(h1);
data.push_back(r1 * sin1);
}
}
return data;
}
JNIEXPORT void JNICALL init(JNIEnv *env, jobject obj) {
//拿到頂點(diǎn)數(shù)據(jù)
vertexVector = createPositions();
//創(chuàng)建迭代器
vector<float>::iterator t;
int i = 0;
//迭代器遍歷vector中的數(shù)據(jù)
//將其中數(shù)據(jù)放入數(shù)組中,形成頂點(diǎn)坐標(biāo)
for (t = vertexVector.begin(); t != vertexVector.end(); t++) {
vertexPoints[i] = *t;
i++;
}
}
//書寫本地方法的具體邏輯
/**初始化
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL surfaceCreated(JNIEnv *env, jobject obj) {
//設(shè)置背景顏色為黑色
glClearColor(0, 0, 0, 0);
//創(chuàng)建頂點(diǎn)著色器
vertexShader = LoadShader(GL_VERTEX_SHADER, vertexShaderCode);
//創(chuàng)建片元著色器
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
//將頂點(diǎn)著色器和片元著色器交給統(tǒng)一程序管理
mProgram = linkProgram(vertexShader, fragmentShader);
}
/**圖形尺寸
*
* @param env
* @param obj
* @param width
* @param height
*/
glm::mat4 mProjectionMatrix;
glm::mat4 mViewMatrix;
glm::mat4 mMVPMatrix;
JNIEXPORT void JNICALL surfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) {
//設(shè)置視口
glViewport(0, 0, width, height);
//寬高比
float ratio = (float) width / height;
//二維圖形設(shè)置正交投影矩陣即可
//frustum投影看不見圖像,ortho投影才看的到球
mProjectionMatrix = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f,
100.0f); //ratio 一般表示視口的寬高比,width/height
//相機(jī)位置
mViewMatrix = glm::lookAt(glm::vec3(0, 0, -3), // 相機(jī)位置
glm::vec3(0, 0, 0), // 觀察點(diǎn)坐標(biāo)
glm::vec3(0, 1, 0));
//矩陣合并
mMVPMatrix = mProjectionMatrix * mViewMatrix;
}
/**渲染繪制
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL drawFrame(JNIEnv *env, jobject obj) {
//清除顏色緩沖區(qū)
glClear(GL_COLOR_BUFFER_BIT);
//使用程序
glUseProgram(mProgram);
//獲取變換矩陣vMatrix成員句柄
GLint mMatrixHandler = glGetUniformLocation(mProgram, "vMatrix");
//矩陣轉(zhuǎn)換成數(shù)組
float mMVPMatrixArray[16];
int m = 0;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
mMVPMatrixArray[m] = mMVPMatrix[i][j];
m++;
}
//指定vMatrix的值
glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrixArray);
//獲取頂點(diǎn)著色器的vPosition成員句柄
GLint mPositionHandle = glGetAttribLocation(mProgram, "vPosition");
//啟用圖形頂點(diǎn)的句柄
glEnableVertexAttribArray(mPositionHandle);
//準(zhǔn)備圖形的坐標(biāo)數(shù)據(jù)
glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GL_FLOAT, GL_FALSE, vertexStride,
vertexPoints);
//獲取片元著色器的vColor成員的句柄
GLint mColorHandle = glGetUniformLocation(mProgram, "vColor");
//設(shè)置繪制圖形的顏色
glUniform4fv(mColorHandle, 1, color);
//繪制圖形
glLineWidth(0.5f);
glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
//禁止頂點(diǎn)數(shù)組的句柄
glDisableVertexAttribArray(mPositionHandle);
}
/**加載著色器
*
*/
JNIEXPORT GLuint LoadShader(int type, char *shaderCode) {
//創(chuàng)建一個(gè)著色器
GLuint shader = glCreateShader(type);
if (shader != 0) {
//加載到著色器
glShaderSource(shader, 1, &shaderCode, NULL);
//編譯著色器
glCompileShader(shader);
//檢測(cè)狀態(tài)
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == 0) {
//聲明log長度變量
GLint infoLen = 0;
//獲取長度并賦值
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
//創(chuàng)建成功小于等于1
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
printf("SHADER ERROR!");
free(infoLog);
}
//創(chuàng)建失敗
glDeleteShader(shader);
return 0;
}
return shader;
} else {
//創(chuàng)建失敗
return 0;
}
}
/**鏈接著色器
*
*/
JNIEXPORT GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
if (program != 0) {
//將頂點(diǎn)著色器加入到程序
glAttachShader(program, vertexShader);
//將片元著色器加入到程序中
glAttachShader(program, fragmentShader);
//鏈接著色器程序
glLinkProgram(program);
//檢測(cè)狀態(tài)
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) {
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetProgramInfoLog(program, infoLen, NULL, infoLog);
printf("PROGRAM ERROR!");
free(infoLog);
}
glDeleteProgram(program);
return 0;
}
return program;
} else {
//創(chuàng)建失敗
return 0;
}
}
/** 動(dòng)態(tài)注冊(cè)
* @param env
* @return
*/
//本地方法聲明和具體邏輯連接
JNINativeMethod methods[] = {
{"init", "()V", (void *) init},
{"surfaceCreated", "()V", (void *) surfaceCreated},
{"surfaceChanged", "(II)V", (void *) surfaceChanged},
{"drawFrame", "()V", (void *) drawFrame}
};
/** 動(dòng)態(tài)注冊(cè)
* @param env
* @return
*/
jint registerNativeMethod(JNIEnv *env) {
//到本地方法存在的類找出其方法聲明
jclass cl = env->FindClass("com/example/openglndk/WaveRenderer");
if ((env->RegisterNatives(cl, methods, sizeof(methods) / sizeof(methods[0]))) < 0) {
return -1;
}
return 0;
}
/** 加載默認(rèn)回調(diào)
* @param vm
* @param reserved
* @return
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
//注冊(cè)方法
if (registerNativeMethod(env) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
繪制圓環(huán)
JAVA版本
Renderer類
package com.example.openglndk;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRenderer implements GLSurfaceView.Renderer {
//坐標(biāo)個(gè)數(shù)(xyz)
private final static int COORDS_PER_VERTEX = 3;
//頂點(diǎn)之間的偏移量
private final int vertexStride = COORDS_PER_VERTEX * 4; // 每個(gè)頂點(diǎn)四個(gè)字節(jié)
private FloatBuffer vertexBuffer;
private int vertexShader;
private int fragmentShader;
private int mProgram;
//聲明點(diǎn)坐標(biāo)
private float vertexPoints[];
//點(diǎn)的數(shù)量
private int vertexCount;
//設(shè)置顏色,依次為紅綠藍(lán)和透明通道
//黑色
private float color[] = {0.0f, 0.0f, 0.0f, 0.0f};
//創(chuàng)建所有點(diǎn)
private float[] createPositions() {
List<Float> coords = new ArrayList<Float>();
float Rinner = 0.2f;//內(nèi)圓半徑
float Rring = 0.3f;//環(huán)半徑
int count = 20;//循環(huán)次數(shù)
float alpha = 0;//外圓角度
float x0, x1, y0, y1, z0, z1;
float alphaStep = (float) (2 * Math.PI / count);//alpha角的步長(外部圓環(huán))
float betaStep = (float) (2 * Math.PI / count);//beta角的步長(每個(gè)切片)
float beta = 0;//切片循環(huán)角度
int count0 = 20;//循環(huán)次數(shù)
/***************************外層循環(huán)主要負(fù)責(zé)把圓環(huán)切成幾個(gè)部分*******************************/
for (int i = 0; i < count; i++) {
alpha = i * alphaStep;
/***************************內(nèi)層循環(huán)主要負(fù)責(zé)把每個(gè)部分畫出來*******************************/
for (int j = 0; j <= count0; j++) {
beta = j * betaStep;
x0 = (float) (Math.cos(alpha) * (Rring + Rinner + Rinner * Math.cos(beta)));
y0 = (float) (Math.sin(alpha) * (Rring + Rinner + Rinner * Math.cos(beta)));
z0 = (float) -(Rring * Math.sin(beta));
x1 = (float) (Math.cos(alpha + alphaStep) * (Rring + Rinner + Rinner * Math.cos(beta)));
y1 = (float) (Math.sin(alpha + alphaStep) * (Rring + Rinner + Rinner * Math.cos(beta)));
z1 = (float) (-Rring * Math.sin(beta));
coords.add(x0);
coords.add(y0);
coords.add(z0);
coords.add(x1);
coords.add(y1);
coords.add(z1);
}
}
float[] f = new float[coords.size()]; //所有的頂點(diǎn)
for (int i = 0; i < f.length; i++) {
f[i] = coords.get(i);
}
return f;
}
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"void main() {" +
" gl_Position = vMatrix*vPosition;" +
" gl_PointSize = 10.0;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
public MyRenderer() {
vertexPoints = createPositions();
vertexCount = vertexPoints.length / COORDS_PER_VERTEX;
//坐標(biāo)
vertexBuffer = ByteBuffer.allocateDirect(
vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
}
@Override
public void onSurfaceCreated (GL10 gl10, EGLConfig eglConfig){
//設(shè)置背景為白色
GLES30.glClearColor(1, 1, 1, 1);
vertexShader = LoadShader(GLES30.GL_VERTEX_SHADER,
vertexShaderCode);
fragmentShader = LoadShader(GLES30.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = linkProgram(vertexShader, fragmentShader);
}
private float mProjectionMatrix[] = new float[16];
private float mViewMatrix[] = new float[16];
private float mMVPMatrix[] = new float[16];
@Override
public void onSurfaceChanged (GL10 gl10,int width, int height){
GLES30.glViewport(0, 0, width, height);
//寬高比
float ratio = (float) width / height;
//設(shè)置投影矩陣
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
//設(shè)置相機(jī)角度(核心)
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
//矩陣合并
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
//每20ms刷新
@Override
public void onDrawFrame (GL10 gl10){
//清除顏色緩沖區(qū)
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
//將程序加入
GLES30.glUseProgram(mProgram);
//獲取變換矩陣vMatrix成員句柄
//圖形參數(shù)
int mMatrixHandler = GLES30.glGetUniformLocation(mProgram, "vMatrix");
//指定vMatrix的值
GLES30.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0);
//獲取頂點(diǎn)著色器的vPosition成員句柄
int mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
//啟用頂點(diǎn)的句柄
GLES30.glEnableVertexAttribArray(mPositionHandle);
//準(zhǔn)備坐標(biāo)數(shù)據(jù)
GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES30.GL_FLOAT, false,
vertexStride, vertexBuffer);
//獲取片元著色器的vColor成員的句柄
int mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");
//設(shè)置圖形的顏色
GLES30.glUniform4fv(mColorHandle, 1, color, 0);
//繪制圖形
GLES30.glDrawArrays(GLES30.GL_LINE_STRIP, 0, vertexCount);
//禁止頂點(diǎn)數(shù)組的句柄
GLES30.glDisableVertexAttribArray(mPositionHandle);
}
/**
* 編譯
*
* @param type 頂點(diǎn)著色器:GLES30.GL_VERTEX_SHADER
* 片段著色器:GLES30.GL_FRAGMENT_SHADER
* @param shaderCode
* @return
*/
private static int LoadShader ( int type, String shaderCode){
//創(chuàng)建一個(gè)著色器
final int shaderId = GLES30.glCreateShader(type);
if (shaderId != 0) {
//加載到著色器
GLES30.glShaderSource(shaderId, shaderCode);
//編譯著色器
GLES30.glCompileShader(shaderId);
//檢測(cè)狀態(tài)
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0) {
String logInfo = GLES30.glGetShaderInfoLog(shaderId);
System.err.println(logInfo);
//創(chuàng)建失敗
GLES30.glDeleteShader(shaderId);
return 0;
}
return shaderId;
} else {
//創(chuàng)建失敗
return 0;
}
}
/**
* 鏈接小程序
*
* @param vertexShaderId 頂點(diǎn)著色器
* @param fragmentShaderId 片段著色器
* @return
*/
public static int linkProgram ( int vertexShaderId, int fragmentShaderId){
final int programId = GLES30.glCreateProgram();
if (programId != 0) {
//將頂點(diǎn)著色器加入到程序
GLES30.glAttachShader(programId, vertexShaderId);
//將片元著色器加入到程序中
GLES30.glAttachShader(programId, fragmentShaderId);
//鏈接著色器程序
GLES30.glLinkProgram(programId);
final int[] linkStatus = new int[1];
GLES30.glGetProgramiv(programId, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0) {
String logInfo = GLES30.glGetProgramInfoLog(programId);
System.err.println(logInfo);
GLES30.glDeleteProgram(programId);
return 0;
}
return programId;
} else {
//創(chuàng)建失敗
return 0;
}
}
}
C++版本
.cpp文件
//
// Created by lvjunkai on 2022/2/21.
//
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#include <malloc.h>
#include <vector>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
//命名空間
using namespace std;
//定義宏
//#define PI 3.1415926;
//常數(shù)Π
const double PI = acos(-1.0);
//聲明自定義函數(shù)
//創(chuàng)建編譯加載
GLuint LoadShader(int type, char *shaderCode);
//鏈接統(tǒng)一程序
GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);
//模板技術(shù)定義的函數(shù)
//用于求數(shù)組長度
template<class T>
GLsizei getArrayLen(T &array) {
return (sizeof(array) / sizeof(array[0]));
}
//坐標(biāo)個(gè)數(shù)(xyz)
const GLint COORDS_PER_VERTEX = 3;
//頂點(diǎn)之間的偏移量
const GLsizei vertexStride = COORDS_PER_VERTEX * 4; // 每個(gè)頂點(diǎn)四個(gè)字節(jié)
//聲明頂點(diǎn)著色器
GLuint vertexShader;
//聲明片元著色器
GLuint fragmentShader;
//聲明著色器管理程序
GLuint mProgram;
//定義圖形坐標(biāo)
vector<float> vertexVector; //存放頂點(diǎn)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)
float vertexPoints[196566]; //頂點(diǎn)數(shù)組
//頂點(diǎn)個(gè)數(shù)
GLsizei vertexCount = getArrayLen(vertexPoints) / COORDS_PER_VERTEX;
//設(shè)置顏色,依次為紅綠藍(lán)和透明通道
float color[] = {0.1f, 0.9f, 1.0f, 0.0f};
//頂點(diǎn)著色器代碼
char vertexShaderCode[] = "attribute vec4 vPosition;"
"uniform mat4 vMatrix;"
"void main() {"
" gl_Position = vMatrix*vPosition;"
" gl_PointSize = 10.0;"
"}";
//片段著色器代碼
char fragmentShaderCode[] = "precision mediump float;"
"uniform vec4 vColor;"
"void main() {"
" gl_FragColor = vColor;"
"}";
//創(chuàng)建頂點(diǎn)坐標(biāo)放入vector數(shù)據(jù)結(jié)構(gòu)中
vector<float> createPositions() {
vector<float> coords;
float Rinner = 0.2f;//環(huán)半徑
float Rring = 0.2f;//內(nèi)圓半徑
int count = 20;//循環(huán)次數(shù)
float alpha = 0;//外圓角度
float x0, x1, y0, y1, z0, z1;
float alphaStep = (float) (2 * PI / count);//alpha角的步長(外部圓環(huán))
float betaStep = (float) (2 * PI / count);//beta角的步長(每個(gè)切片)
float beta = 0;//切片循環(huán)角度
int count0 = 20;//循環(huán)次數(shù)
/***************************外層循環(huán)主要負(fù)責(zé)把圓環(huán)切成幾個(gè)部分*******************************/
for (int i = 0; i < count; i++) {
alpha = i * alphaStep;
/***************************內(nèi)層循環(huán)主要負(fù)責(zé)把每個(gè)部分畫出來*******************************/
for (int j = 0; j <= count0; j++) {
beta = j * betaStep;
x0 = (float) (cos(alpha) * (Rring + Rinner + Rinner * cos(beta)));
y0 = (float) (sin(alpha) * (Rring + Rinner + Rinner * cos(beta)));
z0 = (float) -(Rring * sin(beta));
x1 = (float) (cos(alpha + alphaStep) * (Rring + Rinner + Rinner * cos(beta)));
y1 = (float) (sin(alpha + alphaStep) * (Rring + Rinner + Rinner * cos(beta)));
z1 = (float) (-Rring * sin(beta));
coords.push_back(x0);
coords.push_back(y0);
coords.push_back(z0);
coords.push_back(x1);
coords.push_back(y1);
coords.push_back(z1);
}
}
return coords;
}
JNIEXPORT void JNICALL init(JNIEnv *env, jobject obj) {
//拿到頂點(diǎn)數(shù)據(jù)
vertexVector = createPositions();
//創(chuàng)建迭代器
vector<float>::iterator t;
int i = 0;
//迭代器遍歷vector中的數(shù)據(jù)
//將其中數(shù)據(jù)放入數(shù)組中,形成頂點(diǎn)坐標(biāo)
for (t = vertexVector.begin(); t != vertexVector.end(); t++) {
vertexPoints[i] = *t;
i++;
}
}
//書寫本地方法的具體邏輯
/**初始化
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL surfaceCreated(JNIEnv *env, jobject obj) {
//設(shè)置背景顏色為黑色
glClearColor(0, 0, 0, 0);
//創(chuàng)建頂點(diǎn)著色器
vertexShader = LoadShader(GL_VERTEX_SHADER, vertexShaderCode);
//創(chuàng)建片元著色器
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
//將頂點(diǎn)著色器和片元著色器交給統(tǒng)一程序管理
mProgram = linkProgram(vertexShader, fragmentShader);
}
/**圖形尺寸
*
* @param env
* @param obj
* @param width
* @param height
*/
glm::mat4 mProjectionMatrix;
glm::mat4 mViewMatrix;
glm::mat4 mMVPMatrix;
JNIEXPORT void JNICALL surfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) {
//設(shè)置視口
glViewport(0, 0, width, height);
//寬高比
float ratio = (float) width / height;
//二維圖形設(shè)置正交投影矩陣即可
//frustum投影看不見圖像,ortho投影才看的到球
mProjectionMatrix = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f,
100.0f); //ratio 一般表示視口的寬高比,width/height
//相機(jī)位置
mViewMatrix = glm::lookAt(glm::vec3(0, 0, -3), // 相機(jī)位置
glm::vec3(0, 0, 0), // 觀察點(diǎn)坐標(biāo)
glm::vec3(0, 1, 0));
//矩陣合并
mMVPMatrix = mProjectionMatrix * mViewMatrix;
}
/**渲染繪制
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL drawFrame(JNIEnv *env, jobject obj) {
//清除顏色緩沖區(qū)
glClear(GL_COLOR_BUFFER_BIT);
//使用程序
glUseProgram(mProgram);
//獲取變換矩陣vMatrix成員句柄
GLint mMatrixHandler = glGetUniformLocation(mProgram, "vMatrix");
//矩陣轉(zhuǎn)換成數(shù)組
float mMVPMatrixArray[16];
int m = 0;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
mMVPMatrixArray[m] = mMVPMatrix[i][j];
m++;
}
//指定vMatrix的值
glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrixArray);
//獲取頂點(diǎn)著色器的vPosition成員句柄
GLint mPositionHandle = glGetAttribLocation(mProgram, "vPosition");
//啟用圖形頂點(diǎn)的句柄
glEnableVertexAttribArray(mPositionHandle);
//準(zhǔn)備圖形的坐標(biāo)數(shù)據(jù)
glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GL_FLOAT, GL_FALSE, vertexStride,
vertexPoints);
//獲取片元著色器的vColor成員的句柄
GLint mColorHandle = glGetUniformLocation(mProgram, "vColor");
//設(shè)置繪制圖形的顏色
glUniform4fv(mColorHandle, 1, color);
//繪制圖形
glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
//禁止頂點(diǎn)數(shù)組的句柄
glDisableVertexAttribArray(mPositionHandle);
}
/**加載著色器
*
*/
JNIEXPORT GLuint LoadShader(int type, char *shaderCode) {
//創(chuàng)建一個(gè)著色器
GLuint shader = glCreateShader(type);
if (shader != 0) {
//加載到著色器
glShaderSource(shader, 1, &shaderCode, NULL);
//編譯著色器
glCompileShader(shader);
//檢測(cè)狀態(tài)
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == 0) {
//聲明log長度變量
GLint infoLen = 0;
//獲取長度并賦值
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
//創(chuàng)建成功小于等于1
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
printf("SHADER ERROR!");
free(infoLog);
}
//創(chuàng)建失敗
glDeleteShader(shader);
return 0;
}
return shader;
} else {
//創(chuàng)建失敗
return 0;
}
}
/**鏈接著色器
*
*/
JNIEXPORT GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
if (program != 0) {
//將頂點(diǎn)著色器加入到程序
glAttachShader(program, vertexShader);
//將片元著色器加入到程序中
glAttachShader(program, fragmentShader);
//鏈接著色器程序
glLinkProgram(program);
//檢測(cè)狀態(tài)
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) {
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetProgramInfoLog(program, infoLen, NULL, infoLog);
printf("PROGRAM ERROR!");
free(infoLog);
}
glDeleteProgram(program);
return 0;
}
return program;
} else {
//創(chuàng)建失敗
return 0;
}
}
/** 動(dòng)態(tài)注冊(cè)
* @param env
* @return
*/
//本地方法聲明和具體邏輯連接
JNINativeMethod methods[] = {
{"init", "()V", (void *) init},
{"surfaceCreated", "()V", (void *) surfaceCreated},
{"surfaceChanged", "(II)V", (void *) surfaceChanged},
{"drawFrame", "()V", (void *) drawFrame}
};
/** 動(dòng)態(tài)注冊(cè)
* @param env
* @return
*/
jint registerNativeMethod(JNIEnv *env) {
//到本地方法存在的類找出其方法聲明
jclass cl = env->FindClass("com/example/openglndk/WaveRenderer");
if ((env->RegisterNatives(cl, methods, sizeof(methods) / sizeof(methods[0]))) < 0) {
return -1;
}
return 0;
}
/** 加載默認(rèn)回調(diào)
* @param vm
* @param reserved
* @return
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
//注冊(cè)方法
if (registerNativeMethod(env) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
繪制圓柱體
圓柱和圓錐比,只修改了點(diǎn)的數(shù)量和坐標(biāo),其他都沒變。
//創(chuàng)建圓柱的所有點(diǎn)
private float[] createPositions() {
ArrayList<Float> data = new ArrayList<>();
//兩個(gè)圓上點(diǎn)
float angDegSpan = 360f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan) {
data.add((float) (radius * Math.sin(i * Math.PI / 180f)));
data.add((float) (radius * Math.cos(i * Math.PI / 180f)));
data.add(0.0f);
data.add((float) (radius * Math.sin(i * Math.PI / 180f)));
data.add((float) (radius * Math.cos(i * Math.PI / 180f)));
data.add(height);
}
float[] f = new float[data.size()]; //所有的頂點(diǎn)
for (int i = 0; i < f.length; i++) {
f[i] = data.get(i);
}
return f;
}
繪制圓錐體
根據(jù)我近幾日所學(xué),查找資料,找不到為什么我的總是一個(gè)圓,而不是圓錐。然后我回復(fù)了一下所學(xué)東西,回想每一個(gè)函數(shù)意義,回想學(xué)過的立體幾何的數(shù)學(xué)知識(shí),最后發(fā)現(xiàn),是相機(jī)的朝向角度問題,因?yàn)槭菑腪軸往下看的,所以就相當(dāng)于從圓錐頂部看下去,就是一個(gè)圓了。改變相機(jī)角度,讓其從y軸,即側(cè)面看去,就可以看出其圓錐的近似模樣。點(diǎn)是沒有錯(cuò)的,就一個(gè)錐點(diǎn)和底部圓面點(diǎn)。
C++版本
-
還差相機(jī)設(shè)置不會(huì),投影也不會(huì)。文章來源:http://www.zghlxwxcb.cn/news/detail-405204.html
-
.cpp文件
文章來源地址http://www.zghlxwxcb.cn/news/detail-405204.html
//
// Created by lvjunkai on 2022/2/21.
//
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <jni.h>
#include <malloc.h>
#include <vector>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>
//命名空間
using namespace std;
//常數(shù)Π
const double PI = acos(-1.0);
//聲明自定義函數(shù)
//創(chuàng)建編譯加載
GLuint LoadShader(int type, char *shaderCode);
//鏈接統(tǒng)一程序
GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader);
//模板技術(shù)定義的函數(shù)
//用于求數(shù)組長度
template<class T>
GLsizei getArrayLen(T &array) {
return (sizeof(array) / sizeof(array[0]));
}
//坐標(biāo)個(gè)數(shù)(xyz)
const GLint COORDS_PER_VERTEX = 3;
//頂點(diǎn)之間的偏移量
const GLsizei vertexStride = COORDS_PER_VERTEX * 4; // 每個(gè)頂點(diǎn)四個(gè)字節(jié)
//聲明頂點(diǎn)著色器
GLuint vertexShader;
//聲明片元著色器
GLuint fragmentShader;
//聲明著色器管理程序
GLuint mProgram;
//定義正方形四點(diǎn)坐標(biāo)
vector<float> vertexVector; //存放頂點(diǎn)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)
float vertexPoints[1086]; //頂點(diǎn)數(shù)組
float radius = 0.5f; //半徑
float height = 1.0f; //高度
int n = 360; //切割份數(shù)
//頂點(diǎn)個(gè)數(shù)
GLsizei vertexCount = getArrayLen(vertexPoints) / COORDS_PER_VERTEX;
//設(shè)置顏色,依次為紅綠藍(lán)和透明通道
float color[] = {1.0f, 1.0f, 0.0f, 0.0f};
//頂點(diǎn)著色器代碼
char vertexShaderCode[] = "attribute vec4 vPosition;"
"uniform mat4 vMatrix;"
"void main() {"
" gl_Position = vMatrix*vPosition;"
" gl_PointSize = 10.0;"
"}";
//片段著色器代碼
char fragmentShaderCode[] = "precision mediump float;"
"uniform vec4 vColor;"
"void main() {"
" gl_FragColor = vColor;"
"}";
//創(chuàng)建頂點(diǎn)坐標(biāo)放入vector數(shù)據(jù)結(jié)構(gòu)中
vector<float> createPositions() {
vector<float> data;
//錐點(diǎn)
data.push_back(0.0f);
data.push_back(0.0f);
data.push_back(height);
//圓上點(diǎn)
float angDegSpan = 360.0f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan) {
data.push_back((float) (radius * sin(i * PI / 180.0f)));
data.push_back((float) (radius * cos(i * PI / 180.0f)));
data.push_back(0.0f);
}
return data;
}
JNIEXPORT void JNICALL init(JNIEnv *env, jobject obj) {
//拿到頂點(diǎn)數(shù)據(jù)
vertexVector = createPositions();
//創(chuàng)建迭代器
vector<float>::iterator t;
int i = 0;
//迭代器遍歷vector中的數(shù)據(jù)
//將其中數(shù)據(jù)放入數(shù)組中,形成頂點(diǎn)坐標(biāo)
for (t = vertexVector.begin(); t != vertexVector.end(); t++) {
vertexPoints[i] = *t;
i++;
}
}
//書寫本地方法的具體邏輯
/**初始化
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL surfaceCreated(JNIEnv *env, jobject obj) {
//設(shè)置背景顏色為黑色
glClearColor(0, 0, 0, 0);
//創(chuàng)建頂點(diǎn)著色器
vertexShader = LoadShader(GL_VERTEX_SHADER, vertexShaderCode);
//創(chuàng)建片元著色器
fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentShaderCode);
//將頂點(diǎn)著色器和片元著色器交給統(tǒng)一程序管理
mProgram = linkProgram(vertexShader, fragmentShader);
}
/**圖形尺寸
*
* @param env
* @param obj
* @param width
* @param height
*/
glm::mat4 mProjectionMatrix;
glm::mat4 mViewMatrix;
glm::mat4 mMVPMatrix;
float mMVPMatrixArray[16];
JNIEXPORT void JNICALL surfaceChanged(JNIEnv *env, jobject obj, jint width, jint height) {
//設(shè)置視口
glViewport(0, 0, width, height);
//寬高比
float ratio = (float) width / height;
//正交投影矩陣
mProjectionMatrix = glm::ortho(-ratio, ratio, -1.0f, 1.0f, 0.0f,
100.0f); //ratio 一般表示視口的寬高比,width/height
//透視投影矩陣
// glm::mat4 Projection = glm::perspective(45.0f, ratio, 0.1f, 100.f); //ratio 一般表示視口的寬高比,width/height
//相機(jī)位置
mViewMatrix = glm::lookAt(glm::vec3(1, 1, 0.7), // 相機(jī)位置
glm::vec3(0, 0, 0), // 觀察點(diǎn)坐標(biāo)
glm::vec3(0, 0, 1));
//矩陣合并
mMVPMatrix = mProjectionMatrix * mViewMatrix;
//矩陣轉(zhuǎn)換成數(shù)組
int m = 0;
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
mMVPMatrixArray[m] = mMVPMatrix[i][j];
m++;
}
}
/**渲染繪制
*
* @param env
* @param obj
*/
JNIEXPORT void JNICALL drawFrame(JNIEnv *env, jobject obj) {
//清除顏色緩沖區(qū)
glClear(GL_COLOR_BUFFER_BIT);
//使用程序
glUseProgram(mProgram);
//獲取變換矩陣vMatrix成員句柄
GLint mMatrixHandler = glGetUniformLocation(mProgram, "vMatrix");
//指定vMatrix的值
glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrixArray);
//獲取頂點(diǎn)著色器的vPosition成員句柄
GLint mPositionHandle = glGetAttribLocation(mProgram, "vPosition");
//啟用圖形頂點(diǎn)的句柄
glEnableVertexAttribArray(mPositionHandle);
//準(zhǔn)備圖形的坐標(biāo)數(shù)據(jù)
glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GL_FLOAT, GL_FALSE, vertexStride,
vertexPoints);
//獲取片元著色器的vColor成員的句柄
GLint mColorHandle = glGetUniformLocation(mProgram, "vColor");
//設(shè)置繪制圖形的顏色
glUniform4fv(mColorHandle, 1, color);
//繪制圖形
glLineWidth(3.0f);
glDrawArrays(GL_LINE_LOOP, 0, vertexCount);
//禁止頂點(diǎn)數(shù)組的句柄
glDisableVertexAttribArray(mPositionHandle);
}
/**加載著色器
*
*/
JNIEXPORT GLuint LoadShader(int type, char *shaderCode) {
//創(chuàng)建一個(gè)著色器
GLuint shader = glCreateShader(type);
if (shader != 0) {
//加載到著色器
glShaderSource(shader, 1, &shaderCode, NULL);
//編譯著色器
glCompileShader(shader);
//檢測(cè)狀態(tài)
GLint compileStatus;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == 0) {
//聲明log長度變量
GLint infoLen = 0;
//獲取長度并賦值
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
//創(chuàng)建成功小于等于1
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
printf("SHADER ERROR!");
free(infoLog);
}
//創(chuàng)建失敗
glDeleteShader(shader);
return 0;
}
return shader;
} else {
//創(chuàng)建失敗
return 0;
}
}
/**鏈接著色器
*
*/
JNIEXPORT GLuint linkProgram(GLuint vertexShader, GLuint fragmentShader) {
GLuint program = glCreateProgram();
if (program != 0) {
//將頂點(diǎn)著色器加入到程序
glAttachShader(program, vertexShader);
//將片元著色器加入到程序中
glAttachShader(program, fragmentShader);
//鏈接著色器程序
glLinkProgram(program);
//檢測(cè)狀態(tài)
GLint linkStatus;
glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
if (linkStatus == 0) {
GLint infoLen = 0;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
if (infoLen > 1) {
char *infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
glGetProgramInfoLog(program, infoLen, NULL, infoLog);
printf("PROGRAM ERROR!");
free(infoLog);
}
glDeleteProgram(program);
return 0;
}
return program;
} else {
//創(chuàng)建失敗
return 0;
}
}
/** 動(dòng)態(tài)注冊(cè)
* @param env
* @return
*/
//本地方法聲明和具體邏輯連接
JNINativeMethod methods[] = {
{"init", "()V", (void *) init},
{"surfaceCreated", "()V", (void *) surfaceCreated},
{"surfaceChanged", "(II)V", (void *) surfaceChanged},
{"drawFrame", "()V", (void *) drawFrame}
};
/** 動(dòng)態(tài)注冊(cè)
* @param env
* @return
*/
jint registerNativeMethod(JNIEnv *env) {
//到本地方法存在的類找出其方法聲明
jclass cl = env->FindClass("com/example/openglndk/WaveRenderer");
if ((env->RegisterNatives(cl, methods, sizeof(methods) / sizeof(methods[0]))) < 0) {
return -1;
}
return 0;
}
/** 加載默認(rèn)回調(diào)
* @param vm
* @param reserved
* @return
*/
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
//注冊(cè)方法
if (registerNativeMethod(env) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}
JAVA版本
Renderer類
package com.example.openglndk;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class MyRenderer implements GLSurfaceView.Renderer {
/**
* 坐標(biāo)個(gè)數(shù)(xyz)
*/
private final static int COORDS_PER_VERTEX = 3;
//頂點(diǎn)之間的偏移量
private final int vertexStride = COORDS_PER_VERTEX * 4; // 每個(gè)頂點(diǎn)四個(gè)字節(jié)
private float radius = 0.5f; //半徑
private float height = 1.0f; //圓錐高度
private int n = 360; //切割份數(shù)
private FloatBuffer vertexBuffer;
private int vertexShader;
private int fragmentShader;
private int mProgram;
//聲明點(diǎn)坐標(biāo)
private float vertexPoints[];
//點(diǎn)的數(shù)量
private int vertexCount;
//設(shè)置顏色,依次為紅綠藍(lán)和透明通道
//黑色
private float color[] = {0.0f, 0.0f, 0.0f, 0.0f};
//創(chuàng)建圓錐的所有點(diǎn)
private float[] createPositions() {
ArrayList<Float> data = new ArrayList<>();
//錐上那個(gè)點(diǎn)
data.add(0.0f);
data.add(0.0f);
data.add(height); //給圓心相對(duì)圓邊增加高度,使之形成錐面
//底部圓上點(diǎn)
float angDegSpan = 360f / n;
for (float i = 0; i < 360 + angDegSpan; i += angDegSpan) {
data.add((float) (radius * Math.sin(i * Math.PI / 180f)));
data.add((float) (radius * Math.cos(i * Math.PI / 180f)));
data.add(0.0f);
}
float[] f = new float[data.size()]; //所有的頂點(diǎn)
for (int i = 0; i < f.length; i++) {
f[i] = data.get(i);
}
return f;
}
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"uniform mat4 vMatrix;" +
"void main() {" +
" gl_Position = vMatrix*vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
public MyRenderer() {
vertexPoints = createPositions();
vertexCount = vertexPoints.length / COORDS_PER_VERTEX;
//坐標(biāo)
vertexBuffer = ByteBuffer.allocateDirect(
vertexPoints.length * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
vertexBuffer.put(vertexPoints);
vertexBuffer.position(0);
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
//設(shè)置背景為白色
GLES30.glClearColor(1, 1, 1, 1);
vertexShader = LoadShader(GLES30.GL_VERTEX_SHADER,
vertexShaderCode);
fragmentShader = LoadShader(GLES30.GL_FRAGMENT_SHADER,
fragmentShaderCode);
mProgram = linkProgram(vertexShader, fragmentShader);
}
private float mProjectionMatrix[] = new float[16];
private float mViewMatrix[] = new float[16];
private float mMVPMatrix[] = new float[16];
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
GLES30.glViewport(0, 0, width, height);
//寬高比
float ratio = (float) width / height;
//設(shè)置投影矩陣
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
//設(shè)置相機(jī)角度(核心)
Matrix.setLookAtM(mViewMatrix, 0, 1, -3, -1, 0f, 0f, 0f, 0f, 0.0f, 1.0f);
//矩陣合并
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
}
//每20ms刷新
@Override
public void onDrawFrame(GL10 gl10) {
//清除顏色緩沖區(qū)
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
//將程序加入
GLES30.glUseProgram(mProgram);
//獲取變換矩陣vMatrix成員句柄
//圖形參數(shù)
int mMatrixHandler = GLES30.glGetUniformLocation(mProgram, "vMatrix");
//指定vMatrix的值
GLES30.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0);
//獲取頂點(diǎn)著色器的vPosition成員句柄
int mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
//啟用頂點(diǎn)的句柄
GLES30.glEnableVertexAttribArray(mPositionHandle);
//準(zhǔn)備坐標(biāo)數(shù)據(jù)
GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES30.GL_FLOAT, false,
vertexStride, vertexBuffer);
//獲取片元著色器的vColor成員的句柄
int mColorHandle = GLES30.glGetUniformLocation(mProgram, "vColor");
//設(shè)置圖形的顏色
GLES30.glUniform4fv(mColorHandle, 1, color, 0);
//繪制圖形
GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, vertexCount);
//禁止頂點(diǎn)數(shù)組的句柄
GLES30.glDisableVertexAttribArray(mPositionHandle);
}
/**
* 編譯
*
* @param type 頂點(diǎn)著色器:GLES30.GL_VERTEX_SHADER
* 片段著色器:GLES30.GL_FRAGMENT_SHADER
* @param shaderCode
* @return
*/
private static int LoadShader(int type, String shaderCode) {
//創(chuàng)建一個(gè)著色器
final int shaderId = GLES30.glCreateShader(type);
if (shaderId != 0) {
//加載到著色器
GLES30.glShaderSource(shaderId, shaderCode);
//編譯著色器
GLES30.glCompileShader(shaderId);
//檢測(cè)狀態(tài)
final int[] compileStatus = new int[1];
GLES30.glGetShaderiv(shaderId, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] == 0) {
String logInfo = GLES30.glGetShaderInfoLog(shaderId);
System.err.println(logInfo);
//創(chuàng)建失敗
GLES30.glDeleteShader(shaderId);
return 0;
}
return shaderId;
} else {
//創(chuàng)建失敗
return 0;
}
}
/**
* 鏈接小程序
*
* @param vertexShaderId 頂點(diǎn)著色器
* @param fragmentShaderId 片段著色器
* @return
*/
public static int linkProgram(int vertexShaderId, int fragmentShaderId) {
final int programId = GLES30.glCreateProgram();
if (programId != 0) {
//將頂點(diǎn)著色器加入到程序
GLES30.glAttachShader(programId, vertexShaderId);
//將片元著色器加入到程序中
GLES30.glAttachShader(programId, fragmentShaderId);
//鏈接著色器程序
GLES30.glLinkProgram(programId);
final int[] linkStatus = new int[1];
GLES30.glGetProgramiv(programId, GLES30.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] == 0) {
String logInfo = GLES30.glGetProgramInfoLog(programId);
System.err.println(logInfo);
GLES30.glDeleteProgram(programId);
return 0;
}
return programId;
} else {
//創(chuàng)建失敗
return 0;
}
}
}
到了這里,關(guān)于【OpenGL ES】三維圖形繪制的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!