OpenGL之基礎(chǔ)
OpenGL之繪制簡單形狀
OpenGL之顏色
OpenGL之調(diào)整屏幕寬高比
OpenGL之三維
OpenGL之紋理
OpenGL之構(gòu)建簡單物體
OpenGL之觸控反饋
OpenGL之粒子
OpenGL之天空盒
OpenGL之地形
光源分類
通彻R。可以把不同的光源分為下面幾種
光源 | 說明 |
---|---|
環(huán)境光(Ambient light) | 環(huán)境光看上去來自四面八方,場景中的一切被照亮的程度都一樣叙淌。這近似于我們從大的、平等的光源獲取的光照,比如天空 |
方向光(Directional light) | 方向光看上去似乎來自一個方向,光源好像處于極其遠的地方捉貌。這與我們從太陽或月亮獲取的光照相似 |
點光(Point light) | 點光看上去是從附近某處投射的光亮贯要,而且光的密度隨著距離而減少暖侨。這適于表示近處的光源,其把它們的光投射到四面八方崇渗,像一個燈泡或蠟燭一樣 |
聚光(Spot light) | 聚光與點光類似字逗,只是加了一個限制,只能向一個特定的方向投射宅广。這是我們從手電筒或者聚光燈所獲得的光照類型 |
把光線在物體表面反射的方式分為兩類:
反射方式 | 說明 |
---|---|
漫反射(Diffuse reflection) | 漫反射是指光線平等地向所有方向蔓延葫掉,適于表示沒有拋光表面的材質(zhì),比如地毯或外面的混凝土墻 |
鏡面反射( Specular reflection) | 鏡面反射在某個特定的方向上反射更加強烈跟狱,適于被拋光的或者閃亮的材質(zhì)俭厚,比如光滑的金屬或者剛剛打過蠟的汽車 |
朗伯體反射實現(xiàn)方向光
朗伯體反射描述了這樣一個表面,它會反射所有方向上打到它的光線驶臊,以使它在任何觀察點上看起來都是一樣的挪挤。它的外觀只依賴于它與光源所處的方位及其距離
使用一個水平表面和單個的、不隨距離而減弱的方向光源关翎,因此,唯一有影響的就是這個表面相對于該光源所處的方位
直接面對光源的表面 | 與光源成一定角度的表面 |
---|---|
image-20211223141607462.png
|
image-20211223141630129.png
|
我們可以看到表面垂直正對光源時扛门,在這個角度,它捕捉并反射盡可能多的光線纵寝;表面相對光源旋轉(zhuǎn)了45度時论寨,這個表面反射的光線與旋轉(zhuǎn)角的余弦有關(guān)
要計算出一個表面接收了多少光線,我們所需要做的就是計算出它直接面向光源時接收了多少光線,再把結(jié)果乘以那個角度的余弦值
計算高度圖的方位
在給高度圖添加朗伯體反射之前政基,需要某個方法獲知其表面的方位是什么贞铣。因為高度圖不是一個水平的表面,我們需要計算高度圖上每個點的方位沮明≡樱可以用表面法線(surface normal)表示方位,它是一個特殊類型的向量荐健,它垂直于表面酱畅,且有一個值為1的單位長度
因為表面法線是應(yīng)用于表面的而不是點,在計算每個點的法線時江场,把這個點的鄰接點合并在一起創(chuàng)建一個平面纺酸。我們將用兩個向量來表示這個平面:一個從右側(cè)的點指向左側(cè)的點,另外一個從上面的點指向下面的點址否。如果我們計算這兩個向量的叉積餐蔬,就能得到一個垂直于這個平面的向量,然后佑附,我們可以歸一化那個向量以得到中間點的表面法線樊诺,為什么使用從右向左的向量,而不是從左向右呢?因為我們想要這個表面法線指向上方音同,離開高度圖词爬,所以我們用叉積的右手規(guī)則計算出每個向量需要指向的方向
我們假定每個點占用一個單位部分,x值向右增加权均,z值向下增加顿膨。其上邊、左邊叽赊、右邊和下邊的點的高度分別是0.2恋沃、0.1、0.1和0.1必指。要計算從右向左的向量囊咏,我們用右邊的點減去左邊的點得到值為(-2,0,0)的向量,再用上邊和下邊的點做同樣的計算得到值為(0,-0.1,2)的向量取劫。一旦有了這兩個向量,我們就可以計算它們的叉積得到值為(0,4,0.2)的向量研侣,我們再把這個向量歸一化得到值為(0,0.9988,0.05) 的表面法線
給高度圖加入法線向量
public class Heightmap {
// 法線向量占的位數(shù)
private static final int NORMAL_COMPONENT_COUNT = 3;
private static final int TOTAL_COMPONENT_COUNT = NORMAL_COMPONENT_COUNT + POSITION_COMPONENT_COUNT;
private static final int STRIDE = TOTAL_COMPONENT_COUNT * BYTES_PER_FLOAT;
private int mNumOfIndex;
private VertexBuffer mVertexBuffer;
private IndexBuffer mIndexBuffer;
private int mWidth;
private int mHeight;
public Heightmap(Bitmap bitmap) {
mWidth = bitmap.getWidth();
mHeight = bitmap.getHeight();
initVertexBuffer(bitmap);
initIndexBuffer();
}
/**
* 綁定著色器中 attribute 數(shù)據(jù)谱邪,包括位置和法線向量
*
* @param heightmapProgram
*/
public void bindData(HeightmapProgram heightmapProgram) {
int offset = 0;
mVertexBuffer.setVertexAttribPointer(
offset,
heightmapProgram.getAPosition(),
POSITION_COMPONENT_COUNT,
STRIDE
);
offset += POSITION_COMPONENT_COUNT * BYTES_PER_FLOAT;
mVertexBuffer.setVertexAttribPointer(
offset,
heightmapProgram.getANormal(),
NORMAL_COMPONENT_COUNT,
STRIDE
);
}
public void draw() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer.getBufferId());
glDrawElements(GL_TRIANGLES, mNumOfIndex, GL_UNSIGNED_SHORT, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
/**
* 初始化索引Buffer
*/
private void initIndexBuffer() {
mNumOfIndex = numOfIndex();
short[] indexData = new short[mNumOfIndex];
int offset = 0;
for (short row = 0; row < mHeight - 1; row++) {
for (short col = 0; col < mWidth - 1; col++) {
short topLeft = (short) (row * mWidth + col);
short topRight = (short) (topLeft + 1);
short bottomLeft = (short) ((row + 1) * mWidth + col);
short bottomRight = (short) (bottomLeft + 1);
indexData[offset++] = topLeft;
indexData[offset++] = bottomLeft;
indexData[offset++] = topRight;
indexData[offset++] = topRight;
indexData[offset++] = bottomLeft;
indexData[offset++] = bottomRight;
}
}
mIndexBuffer = new IndexBuffer(indexData);
}
/**
* 初始化頂點Buffer,加上法向向量
*
* @param bitmap
*/
private void initVertexBuffer(Bitmap bitmap) {
float[] vertexData = new float[mWidth * mHeight * TOTAL_COMPONENT_COUNT];
int offset = 0;
int[] pixels = new int[mWidth * mHeight];
bitmap.getPixels(pixels, 0, mWidth, 0, 0, mWidth, mHeight);
for (int row = 0; row < mHeight; row++) {
for (int col = 0; col < mWidth; col++) {
// 點的位置
Point point = getPoint(pixels, row, col);
vertexData[offset++] = point.getX();
vertexData[offset++] = point.getY();
vertexData[offset++] = point.getZ();
//點的上下左右
Point top = getPoint(pixels, row - 1, col);
Point left = getPoint(pixels, row, col - 1);
Point right = getPoint(pixels, row, col + 1);
Point bottom = getPoint(pixels, row + 1, col);
// 得到法向向量
Vector rightToLeft = Vector.vectorBetween(right, left);
Vector topToBottom = Vector.vectorBetween(top, bottom);
Vector normal = rightToLeft.crossProduct(topToBottom).normalize();
// 將法向向量寫入頂點數(shù)據(jù)數(shù)組中
vertexData[offset++] = normal.getX();
vertexData[offset++] = normal.getY();
vertexData[offset++] = normal.getZ();
}
}
mVertexBuffer = new VertexBuffer(vertexData);
}
/**
* 獲取pixels像素中的某個像素的三維空間位置
*
* @param pixels
* @param row
* @param col
* @return
*/
private Point getPoint(int[] pixels, int row, int col) {
float x = (col / (float) (mWidth - 1)) - 0.5f;
float z = (row / (float) (mHeight - 1)) - 0.5f;
row = clamp(row, 0, mHeight - 1);
col = clamp(col, 0, mWidth - 1);
int pixel = pixels[row * mWidth + col];
float y = Color.red(pixel) / 255f;
return new Point(x, y, z);
}
private int clamp(int value, int min, int max) {
return Math.min(max, Math.max(value, min));
}
/**
* 返回高度圖的索引數(shù)目
* 相鄰四個像素點形成1個正方形即2個三角形庶诡,即6個頂點惦银,整個bitmap形成(mWidth - 1) * (mHeight - 1) 個正方形
*
* @return
*/
private int numOfIndex() {
return (mWidth - 1) * (mHeight - 1) * 2 * 3;
}
}
給著色器加入方向光
頂點著色器
uniform mat4 u_Matrix;
uniform mat4 u_MVMatrix;
uniform mat4 u_IT_MVMatrix;
uniform vec4 u_PointLightPositions[3];
uniform vec3 u_PointLightColors[3];
vec3 materialColor;
vec4 eyeSpacePosition;
vec3 eyeSpaceNormal;
attribute vec4 a_Position;
varying vec3 v_Color;
uniform vec3 u_VectorToLight;
attribute vec3 a_Normal;
vec3 getAmbientLighting();
vec3 getDirectionalLighting();
vec3 getPointLighting();
void main()
{
materialColor = mix(vec3(0.180, 0.467, 0.153),
vec3(0.660, 0.670, 0.680),
a_Position.y);
eyeSpacePosition=u_MVMatrix*a_Position;
eyeSpaceNormal=normalize(vec3(u_IT_MVMatrix*vec4(a_Normal, 0.0)));
v_Color=getAmbientLighting();
v_Color+=getDirectionalLighting();
v_Color+=getPointLighting();
gl_Position = u_Matrix * a_Position;
}
vec3 getAmbientLighting(){
return materialColor*0.1;
}
vec3 getDirectionalLighting(){
return materialColor*0.3*max(dot(eyeSpaceNormal, u_VectorToLight), 0.0);
}
vec3 getPointLighting(){
vec3 lightingSum=vec3(0.0);
for (int i=0;i<3;i++){
vec3 toPointLight=vec3(u_PointLightPositions[i])-vec3(eyeSpacePosition);
float diatance=length(toPointLight);
toPointLight=normalize(toPointLight);
float cos=max(dot(toPointLight, eyeSpaceNormal), 0.0);
lightingSum+=materialColor*u_PointLightColors[i]*5.0*cos/diatance;
}
return lightingSum;
}
變量說明
變量 | 說明 |
---|---|
u_Matrix | 模型視圖投影矩陣 |
u_MVMatrix | 表示模型視圖矩陣,位置與其相乘,就會將位置信息裝換到眼空間中 |
u_IT_MVMatrix | 表示模型視圖矩陣倒置矩陣的轉(zhuǎn)置矩陣扯俱,平面法線與之相乘书蚪,在進行歸一化,可以取消縮放的影響 |
u_PointLightPositions | 點光源的位置迅栅,在眼空間中 |
u_PointLightColors | 點光源顏色 |
u_VectorToLight | 存儲方向光源的歸一化向量殊校,在眼空間中 |
a_Position | 頂點位置信息 |
a_Normal | 高度圖法線 |
v_Color | 最終片段的顏色信息,因為片段著色器未做任何改動读存,直接將該值賦值給了最終片段的顏色信息 |
materialColor | 山脈顏色为流,由mix函數(shù)根據(jù)山脈高度計算得到 |
eyeSpacePosition | 頂點在眼空間中的位置,由a_Position和u_MVMatrix 進行轉(zhuǎn)換得到 |
eyeSpaceNormal | 在眼空間中的高度圖法線让簿,由a_Normal 和u_IT_MVMatrix 進行轉(zhuǎn)換并歸一化得到 |
方法說明
方法 | 說明 |
---|---|
getAmbientLighting() | 獲取環(huán)境光敬察。其值設(shè)為山脈顏色的0.1,將全局都提亮一些 |
getDirectionalLighting() | 獲取方向光尔当。相當(dāng)于太陽莲祸,其光源值定為materialColor*0.3,通過計算指向光源的向量與表面法線的點積椭迎,來計算表面與光線之間夾角的余弦值锐帜。它的工作原理是,當(dāng)兩個向量都是歸一化的向量時侠碧,那兩個向量的點積就是它們之間夾角的余弦抹估,為了避免出現(xiàn)負(fù)的結(jié)果,用max()把最小余弦值限制為0弄兜,然后药蜻,應(yīng)用這個光線,把當(dāng)前頂點的顏色與余弦值相乘替饿。余弦值在0和1之間语泽,因此,最終的顏色將是處于黑色和原色之間的某個顏色 |
getPointLighting() | 獲取點光视卢。對于當(dāng)前頂點踱卵,循環(huán)計算每個點光,得到當(dāng)前頂點到點光的向量并歸一化据过,然后計算夾角余弦惋砂,再除以距離,并把其結(jié)果加人lightingSum绳锅,就是所有點光對當(dāng)前頂點的光照值了西饵,乘以5是為了放到效果,使其更明亮 |
更新著色器封裝代碼
public class HeightmapProgram extends BaseProgram {
private static final String U_MV_MATRIX = "u_MVMatrix";
private static final String U_IT_MV_MATRIX = "u_IT_MVMatrix";
private static final String U_VECTOR_TO_LIGHT = "u_VectorToLight";
private static final String U_POINT_LIGHT_POSITIONS = "u_PointLightPositions";
private static final String U_POINT_LIGHT_COLORS = "u_PointLightColors";
private static final String A_NORMAL = "a_Normal";
private final int mUMatrix;
private final int mUVectorToLight;
private final int mUMVMatrix;
private final int mUITMVMatrix;
private final int mUPointLightPositions;
private final int mUPointLightColors;
private final int mAPosition;
private final int mANormal;
public HeightmapProgram(Context context) {
super(context, R.raw.light9_heightmap_vertex, R.raw.particles8_heightmap_fragment);
mUMatrix = glGetUniformLocation(mProgram, U_MATRIX);
mUMVMatrix = glGetUniformLocation(mProgram, U_MV_MATRIX);
mUITMVMatrix = glGetUniformLocation(mProgram, U_IT_MV_MATRIX);
mUVectorToLight = glGetUniformLocation(mProgram, U_VECTOR_TO_LIGHT);
mUPointLightPositions = glGetUniformLocation(mProgram, U_POINT_LIGHT_POSITIONS);
mUPointLightColors = glGetUniformLocation(mProgram, U_POINT_LIGHT_COLORS);
mAPosition = glGetAttribLocation(mProgram, A_POSITION);
mANormal = glGetAttribLocation(mProgram, A_NORMAL);
}
public void setUniforms(float[] mvMatrix, float[] it_MVMatrix, float[] matrix,
float[] vectorToLight, float[] pointLightPositions, float[] pointLightColors) {
glUniformMatrix4fv(mUMVMatrix, 1, false, mvMatrix, 0);
glUniformMatrix4fv(mUITMVMatrix, 1, false, it_MVMatrix, 0);
glUniformMatrix4fv(mUMatrix, 1, false, matrix, 0);
glUniform3fv(mUVectorToLight, 1, vectorToLight, 0);
glUniform4fv(mUPointLightPositions, 3, pointLightPositions, 0);
glUniform3fv(mUPointLightColors, 3, pointLightColors, 0);
}
public int getAPosition() {
return mAPosition;
}
public int getANormal() {
return mANormal;
}
}
更新渲染器代碼
public class MyRenderer implements GLSurfaceView.Renderer, ITouchRenderer {
private static final String TAG = "MyRenderer";
/*private static final int[] SKY_ID = new int[]{
R.drawable.left, R.drawable.right,
R.drawable.bottom, R.drawable.top,
R.drawable.front, R.drawable.back,
};*/
private static final int[] SKY_ID = new int[]{
R.drawable.night_left, R.drawable.night_right,
R.drawable.night_bottom, R.drawable.night_top,
R.drawable.night_front, R.drawable.night_back,
};
private Context mContext;
private float[] modelMatrix = new float[16];
private float[] viewMatrix = new float[16];
private float[] viewMatrixForSkybox = new float[16];
private float[] projectionMatrix = new float[16];
private float[] tempMatrix = new float[16];
private float[] modelViewProjectionMatrix = new float[16];
private float[] modelViewMatrix = new float[16];
private float[] it_modelViewMatrix = new float[16];
private HeightmapProgram mHeightmapProgram;
private Heightmap mHeightmap;
private ParticlesProgram mParticlesProgram;
private ParticleSystem mParticleSystem;
private ParticleShooter mRedParticleShooter;
private ParticleShooter mGreenParticleShooter;
private ParticleShooter mBlueParticleShooter;
// 控制粒子的角度
private float mAngleVarianceInDegree = 30f;
// 控制粒子的速度
private float mSpeedVariance = 1f;
private long mGlobalStartTime;
private SkyBox mSkyBox;
private SkyProgram mSkyProgram;
private int mTextureId;
private int mCubeTextureId;
private float xRotate;
private float yRotate;
// 方向光源鳞芙,指向太陽
private final float[] vectorToLight = {0.3f, 0.35f, -0.89f, 0f};
// 點光源位置
private final float[] pointLightPositions = new float[]{
-1f, 1f, 0f, 1f,
0f, 1f, 0f, 1f,
1f, 1f, 0f, 1f
};
// 點光源顏色
private final float[] pointLightColors = new float[]{
1f, 0.2f, 0.02f,
0.02f, 0.25f, 0.02f,
0.02f, 0.2f, 1f
};
public MyRenderer(Context context) {
mContext = context;
}
@Override
public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
glClearColor(0f, 0f, 0f, 0f);
glEnable(GLES20.GL_DEPTH_TEST);
glEnable(GLES20.GL_CULL_FACE);
// 初始化高度圖
mHeightmapProgram = new HeightmapProgram(mContext);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.heightmap, options);
mHeightmap = new Heightmap(bitmap);
// 粒子著色器程序
mParticlesProgram = new ParticlesProgram(mContext);
// 粒子系統(tǒng)眷柔,maxParticleCount如果太小的話期虾,可能只能看到比較新的粒子
mParticleSystem = new ParticleSystem(10000);
// 粒子方向
com.test.opengl.light9.geometry.bean.Vector particleDirection = new Vector(0f, 0.5f, 0f);
// 粒子發(fā)射器
mRedParticleShooter = new ParticleShooter(new Point(-1f, 0f, 0f), particleDirection, Color.RED, mAngleVarianceInDegree, mSpeedVariance);
mGreenParticleShooter = new ParticleShooter(new com.test.opengl.light9.geometry.bean.Point(0f, 0f, 0f), particleDirection, Color.GREEN, mAngleVarianceInDegree, mSpeedVariance);
mBlueParticleShooter = new ParticleShooter(new Point(1f, 0f, 0f), particleDirection, Color.BLUE, mAngleVarianceInDegree, mSpeedVariance);
// 粒子系統(tǒng)啟動的時間
mGlobalStartTime = System.nanoTime();
// 使用圖片的樣式繪制粒子
mTextureId = com.test.opengl.light9.util.TextureHelper.loadTexture(mContext, R.drawable.particle_texture);
mSkyProgram = new SkyProgram(mContext);
mSkyBox = new SkyBox();
mCubeTextureId = TextureHelper.loadCubeTexture(mContext, SKY_ID);
}
@Override
public void onSurfaceChanged(GL10 gl10, int width, int height) {
glViewport(0, 0, width, height);
MatrixHelper.perspectiveM(projectionMatrix, 45, (float) width / height, 1, 10);
// 更新視圖矩陣
updateViewMatrix();
}
@Override
public void onDrawFrame(GL10 gl10) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawSky();
drawHeightmap();
drawParticles();
}
private void drawHeightmap() {
// 更新矩陣
setIdentityM(modelMatrix, 0);
// 用模型矩陣使高度圖在x和z方向上變寬100倍,而在y方向上只變高10倍
// 著色器中的顏色插值依賴于頂點所在位置的y值驯嘱,這不會擾亂镶苞,因為在頂點著色器中,設(shè)置v_Color的時間是在我們把它與矩陣相乘之前
Matrix.scaleM(modelMatrix, 0, 80f, 30f, 80f);
updateMvpMatrix();
mHeightmapProgram.useProgram();
final float[] vectorToLightInEyeSpace = new float[4];
final float[] pointPositionsInEyeSpace = new float[12];
Matrix.multiplyMV(vectorToLightInEyeSpace, 0, viewMatrix, 0, vectorToLight, 0);
Matrix.multiplyMV(pointPositionsInEyeSpace, 0, viewMatrix, 0, pointLightPositions, 0);
Matrix.multiplyMV(pointPositionsInEyeSpace, 4, viewMatrix, 0, pointLightPositions, 4);
Matrix.multiplyMV(pointPositionsInEyeSpace, 8, viewMatrix, 0, pointLightPositions, 8);
mHeightmapProgram.setUniforms(modelViewMatrix, it_modelViewMatrix, modelViewProjectionMatrix,
vectorToLightInEyeSpace, pointPositionsInEyeSpace, pointLightColors);
mHeightmap.bindData(mHeightmapProgram);
mHeightmap.draw();
}
private void drawParticles() {
// 關(guān)閉深度測試的寫操作
glDepthMask(false);
// 創(chuàng)建并添加粒子
float currentTime = (System.nanoTime() - mGlobalStartTime) / 1000000000f;
mRedParticleShooter.addParticle(mParticleSystem, currentTime, 5);
mGreenParticleShooter.addParticle(mParticleSystem, currentTime, 5);
mBlueParticleShooter.addParticle(mParticleSystem, currentTime, 5);
// 更新矩陣
setIdentityM(modelMatrix, 0);
updateMvpMatrix();
// 累計混合技術(shù)鞠评,粒子越多茂蚓,就越亮
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
mParticlesProgram.useProgram();
// 設(shè)置uniform的值
mParticlesProgram.setUniforms(modelViewProjectionMatrix, currentTime, mTextureId);
// to do ,注釋掉mParticleShooter.bindData(mParticlesProgram);模擬器就不會掛
// 綁定粒子系統(tǒng)數(shù)據(jù)
mParticleSystem.bindData(mParticlesProgram);
// 繪制粒子系統(tǒng)的所有粒子
mParticleSystem.draw();
// 一次繪制完成后,關(guān)閉累計混合技術(shù)
glDisable(GL_BLEND);
glDepthMask(true);
}
private void drawSky() {
// 深度測試算法改為小于等于谢澈,讓天空盒被繪制出來
glDepthFunc(GL_LEQUAL);
// 更新矩陣
setIdentityM(modelMatrix, 0);
updateMvpMatrixForSky();
mSkyProgram.useProgram();
mSkyProgram.setUniforms(modelViewProjectionMatrix, mCubeTextureId);
mSkyBox.bindData(mSkyProgram);
mSkyBox.draw();
// 深度測試算法改回去煌贴,以免影響其他物體的繪制
glDepthFunc(GL_LESS);
}
/**
* 更新高度圖和粒子的模型視圖投影矩陣
*/
private void updateMvpMatrix() {
// 得到視圖模型矩陣
Matrix.multiplyMM(modelViewMatrix, 0, viewMatrix, 0, modelMatrix, 0);
// 視圖模型矩陣的反轉(zhuǎn)矩陣
Matrix.invertM(tempMatrix, 0, modelViewMatrix, 0);
// 視圖模型矩陣的反轉(zhuǎn)矩陣的轉(zhuǎn)置矩陣
Matrix.transposeM(it_modelViewMatrix, 0, tempMatrix, 0);
Matrix.multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, modelViewMatrix, 0);
}
/**
* 更新天空盒的模型視圖投影矩陣
*/
private void updateMvpMatrixForSky() {
Matrix.multiplyMM(tempMatrix, 0, viewMatrixForSkybox, 0, modelMatrix, 0);
multiplyMM(modelViewProjectionMatrix, 0, projectionMatrix, 0, tempMatrix, 0);
}
/**
* 處理拖拽事件
*
* @param deltaX
* @param deltaY
*/
public void handleDrag(float deltaX, float deltaY) {
Log.d(TAG, "handleDrag: deltaX=" + deltaX + " deltaY=" + deltaY);
xRotate += deltaX / 16f;
yRotate += deltaY / 16f;
if (yRotate > 90) {
yRotate = 90;
}
if (yRotate < -90) {
yRotate = -90;
}
// 更新視圖矩陣
updateViewMatrix();
}
@Override
public void handlePress(float normalizedX, float normalizedY) {
}
/**
* 更新視圖矩陣,包括viewMatrix和viewMatrixForSkybox
* 高度圖和粒子的視圖矩陣viewMatrix锥忿,代表相機牛郑,它應(yīng)用于所有的物體
* 天空盒視圖矩陣viewMatrixForSkybox,只表示旋轉(zhuǎn)
*/
private void updateViewMatrix() {
setIdentityM(viewMatrix, 0);
Matrix.rotateM(viewMatrix, 0, -yRotate, 1f, 0f, 0f);
Matrix.rotateM(viewMatrix, 0, -xRotate, 0f, 1f, 0f);
// 使用 viewMatrixForSkybox 旋轉(zhuǎn)天空盒
System.arraycopy(viewMatrix, 0, viewMatrixForSkybox, 0, viewMatrix.length);
// 使用 viewMatrix 一起旋轉(zhuǎn)和平移高度圖和粒子
translateM(viewMatrix, 0, 0, -1.5f, -5f);
}
}