android 使用OPENGL ES繪製一個圓環-三維空間
效果圖:
編寫huanCH.java
*設定圓錐曲面的控制屬性,包括紋理、環半徑、截面半徑、環角度切分單位和截面角度切分單位
*通過上述屬性可以控制圓環曲面的大小,並獲取網格頂點座標;最後設定頂點、紋理、法向量緩衝,並定義繪製方 法drawSelf()
package com.scout.eeeeeee; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.util.ArrayList; import javax.microedition.khronos.opengles.GL10; public class huanCH { private FloatBuffer ding;//頂點緩衝 private FloatBuffer wen;//紋理緩衝 private FloatBuffer myNormalBuffer;//法向量緩衝 int vcount; int textureid; float rSpan; float cSpan; float ring_Radius; float circle_Radius; public float mAngleX; public float mAngleY; public float mAngleZ; public huanCH(float rSpan,float cSpan,float ring_Radius,float circle_Radius,int textureid) { //rSpan表示環每一份多少度;cSpan表示圓截環每一份多少度;ring_Radius表示環半徑;circle_Radius圓截面半徑。 this.rSpan=rSpan; this.cSpan=cSpan; this.circle_Radius=circle_Radius; this.ring_Radius=ring_Radius; this.textureid=textureid; ArrayList<Float> val=new ArrayList<Float>(); ArrayList<Float> ial=new ArrayList<Float>();//法向量存放列表 for(float circle_Degree=50f;circle_Degree<130f;circle_Degree+=cSpan) { for(float ring_Degree=-90f;ring_Degree<0f;ring_Degree+=rSpan) { float x1=(float) ((ring_Radius+circle_Radius*Math.cos(Math.toRadians(circle_Degree)))*Math.cos(Math.toRadians(ring_Degree))); float y1=(float) (circle_Radius*Math.sin(Math.toRadians(circle_Degree))); float z1=(float) ((ring_Radius+circle_Radius*Math.cos(Math.toRadians(circle_Degree)))*Math.sin(Math.toRadians(ring_Degree))); float x2=(float) ((ring_Radius+circle_Radius*Math.cos(Math.toRadians(circle_Degree)))*Math.cos(Math.toRadians(ring_Degree+rSpan))); float y2=(float) (circle_Radius*Math.sin(Math.toRadians(circle_Degree))); float z2=(float) ((ring_Radius+circle_Radius*Math.cos(Math.toRadians(circle_Degree)))*Math.sin(Math.toRadians(ring_Degree+rSpan))); float x3=(float) ((ring_Radius+circle_Radius*Math.cos(Math.toRadians(circle_Degree+cSpan)))*Math.cos(Math.toRadians(ring_Degree+rSpan))); float y3=(float) (circle_Radius*Math.sin(Math.toRadians(circle_Degree+cSpan))); float z3=(float) ((ring_Radius+circle_Radius*Math.cos(Math.toRadians(circle_Degree+cSpan)))*Math.sin(Math.toRadians(ring_Degree+rSpan))); float x4=(float) ((ring_Radius+circle_Radius*Math.cos(Math.toRadians(circle_Degree+cSpan)))*Math.cos(Math.toRadians(ring_Degree))); float y4=(float) (circle_Radius*Math.sin(Math.toRadians(circle_Degree+cSpan))); float z4=(float) ((ring_Radius+circle_Radius*Math.cos(Math.toRadians(circle_Degree+cSpan)))*Math.sin(Math.toRadians(ring_Degree))); val.add(x1);val.add(y1);val.add(z1); val.add(x4);val.add(y4);val.add(z4); val.add(x2);val.add(y2);val.add(z2); val.add(x2);val.add(y2);val.add(z2); val.add(x4);val.add(y4);val.add(z4); val.add(x3);val.add(y3);val.add(z3); //各個頂點圓截面中心的組成的圓環上的點的座標 float a1=(float) (x1-(ring_Radius*Math.cos(Math.toRadians(ring_Degree)))); float b1=y1-0; float c1=(float) (z1-(ring_Radius*Math.sin(Math.toRadians(ring_Degree)))); float l1=getVectorLength(a1, b1, c1);//模長 a1=a1/l1;//法向量規格化 b1=b1/l1; c1=c1/l1; float a2=(float) (x2-(ring_Radius*Math.cos(Math.toRadians(ring_Degree+rSpan)))); float b2=y1-0; float c2=(float) (z2-(ring_Radius*Math.sin(Math.toRadians(ring_Degree+rSpan)))); float l2=getVectorLength(a2, b2, c2);//模長 a2=a2/l2;//法向量規格化 b2=b2/l2; c2=c2/l2; float a3=(float) (x3-(ring_Radius*Math.cos(Math.toRadians(ring_Degree+rSpan)))); float b3=y1-0; float c3=(float) (z3-(ring_Radius*Math.sin(Math.toRadians(ring_Degree+rSpan)))); float l3=getVectorLength(a3, b3, c3);//模長 a3=a3/l3;//法向量規格化 b3=b3/l3; c3=c3/l3; float a4=(float) (x4-(ring_Radius*Math.cos(Math.toRadians(ring_Degree)))); float b4=y1-0; float c4=(float) (z4-(ring_Radius*Math.sin(Math.toRadians(ring_Degree)))); float l4=getVectorLength(a4, b4, c4);//模長 a4=a4/l4;//法向量規格化 b4=b4/l4; c4=c4/l4; ial.add(a1);ial.add(b1);ial.add(c1);//頂點對應的法向量 ial.add(a2);ial.add(b2);ial.add(c2); ial.add(a4);ial.add(b4);ial.add(c4); ial.add(a2);ial.add(b2);ial.add(c2); ial.add(a3);ial.add(b3);ial.add(c3); ial.add(a4);ial.add(b4);ial.add(c4); } } vcount=val.size()/3; float[] vertexs=new float[vcount*3]; for(int i=0;i<vcount*3;i++) { vertexs[i]=val.get(i); } ByteBuffer vbb=ByteBuffer.allocateDirect(vertexs.length*4); vbb.order(ByteOrder.nativeOrder()); ding=vbb.asFloatBuffer(); ding.put(vertexs); ding.position(0); //法向量 float[] normals=new float[vcount*3]; for(int i=0;i<vcount*3;i++) { normals[i]=ial.get(i); } ByteBuffer ibb=ByteBuffer.allocateDirect(normals.length*4); ibb.order(ByteOrder.nativeOrder()); myNormalBuffer=ibb.asFloatBuffer(); myNormalBuffer.put(normals); myNormalBuffer.position(0); //紋理 int row=(int) (360.0f/cSpan); int col=(int) (360.0f/rSpan); float[] textures=generateTexCoor(row,col); ByteBuffer tbb=ByteBuffer.allocateDirect(textures.length*4); tbb.order(ByteOrder.nativeOrder()); wen=tbb.asFloatBuffer(); wen.put(textures); wen.position(0); } public void drawSelf(GL10 gl) { gl.glRotatef(mAngleX, 1, 0, 0);//旋轉 gl.glRotatef(mAngleY, 0, 1, 0); gl.glRotatef(mAngleZ, 0, 0, 1); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, ding); gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);//開啟法向量緩衝 gl.glNormalPointer(GL10.GL_FLOAT, 0, myNormalBuffer);//指定法向量緩衝 gl.glEnable(GL10.GL_TEXTURE_2D); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, wen); gl.glBindTexture(GL10.GL_TEXTURE_2D, textureid); gl.glDrawArrays(GL10.GL_TRIANGLES, 0, vcount); gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);//關閉緩衝 gl.glEnable(GL10.GL_TEXTURE_2D); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); } //自動切分紋理產生紋理陣列的方法 public float[] generateTexCoor(int bw,int bh) { float[] result=new float[bw*bh*6*2]; float sizew=1.0f/bw;//列數 float sizeh=1.0f/bh;//行數 int c=0; for(int i=0;i<bh;i++) { for(int j=0;j<bw;j++) { //每行列一個矩形,由兩個三角形構成,共六個點,12個紋理座標 float s=j*sizew; float t=i*sizeh; result[c++]=s; result[c++]=t; result[c++]=s; result[c++]=t+sizeh; result[c++]=s+sizew; result[c++]=t; result[c++]=s+sizew; result[c++]=t; result[c++]=s; result[c++]=t+sizeh; result[c++]=s+sizew; result[c++]=t+sizeh; } } return result; } //法向量規格化,求模長度 public float getVectorLength(float x,float y,float z) { float pingfang=x*x+y*y+z*z; float length=(float) Math.sqrt(pingfang); return length; } }
MyGLSurfaceView.java
package com.scout.eeeeeee; /** * Created by liuguodong on 2017/10/29. */ import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLSurfaceView; import android.opengl.GLUtils; import android.view.MotionEvent; import java.io.IOException; import java.io.InputStream; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import javax.microedition.khronos.opengles.GL11; public class MyGLSurfaceView extends GLSurfaceView { private final float TOUCH_SCALE_FACTOR = 180.0f/320;//角度縮放比例 private SceneRenderer mRenderer;//場景渲染器 private float mPreviousY;//上次的觸控位置Y座標 private float mPreviousX;//上次的觸控位置Y座標 private int lightAngle=90;//燈的當前角度 public MyGLSurfaceView(Context context) { super(context); mRenderer = new SceneRenderer(); //建立場景渲染器 setRenderer(mRenderer); //設定渲染器 setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);//設定渲染模式為主動渲染 } //觸控事件回撥方法 @Override public boolean onTouchEvent(MotionEvent e) { float y = e.getY(); float x = e.getX(); switch (e.getAction()) { case MotionEvent.ACTION_MOVE: float dy = y - mPreviousY;//計算觸控筆Y位移 float dx = x - mPreviousX;//計算觸控筆Y位移 mRenderer.cylinder.mAngleX += dy * TOUCH_SCALE_FACTOR;//設定沿x軸旋轉角度 mRenderer.cylinder.mAngleZ += dx * TOUCH_SCALE_FACTOR;//設定沿z軸旋轉角度 requestRender();//重繪畫面 } mPreviousY = y;//記錄觸控筆位置 mPreviousX = x;//記錄觸控筆位置 return true; } private class SceneRenderer implements GLSurfaceView.Renderer { int textureId;//紋理名稱ID huanCH cylinder;//建立圓環體 public SceneRenderer() { } public void onDrawFrame(GL10 gl) { //清除顏色快取 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); //設定當前矩陣為模式矩陣 gl.glMatrixMode(GL10.GL_MODELVIEW); //設定當前矩陣為單位矩陣 gl.glLoadIdentity(); gl.glPushMatrix();//保護變換矩陣現場 float lx=0; //設定光源的位置 float ly=(float)(7*Math.cos(Math.toRadians(lightAngle))); float lz=(float)(7*Math.sin(Math.toRadians(lightAngle))); float[] positionParamsRed={lx,ly,lz,0}; gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_POSITION, positionParamsRed,0); initMaterial(gl);//初始化紋理 gl.glTranslatef(0, 0, -25f);//平移 initLight(gl);//開燈 cylinder.drawSelf(gl);//繪製 closeLight(gl);//關燈 gl.glPopMatrix();//恢復變換矩陣現場 } public void onSurfaceChanged(GL10 gl, int width, int height) { //設定視窗大小及位置 gl.glViewport(0, 0, width, height); //設定當前矩陣為投影矩陣 gl.glMatrixMode(GL10.GL_PROJECTION); //設定當前矩陣為單位矩陣 gl.glLoadIdentity(); //計算透視投影的比例 float ratio = (float) width / height; //呼叫此方法計算產生透視投影矩陣 gl.glFrustumf(-ratio, ratio, -1, 1, 1, 100); } public void onSurfaceCreated(GL10 gl, EGLConfig config) { //關閉抗抖動 gl.glDisable(GL10.GL_DITHER); //設定特定Hint專案的模式,這裡為設定為使用快速模式 gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST); //設定螢幕背景色黑色RGBA gl.glClearColor(0,0,0,0); //設定著色模型為平滑著色 gl.glShadeModel(GL10.GL_SMOOTH); //啟用深度測試 gl.glEnable(GL10.GL_DEPTH_TEST); textureId=initTexture(gl,R.drawable.stone2);//紋理ID cylinder=new huanCH(12f,12f,10f,2f,textureId);//建立圓柱體 // //開啟一個執行緒自動旋轉光源 // new Thread() // { // public void run() // { // while(true) // { // lightAngle+=5;//轉動燈 // mRenderer.cylinder.mAngleY+=2*TOUCH_SCALE_FACTOR;//球沿Y軸轉動 // requestRender();//重繪畫面 // try // { // Thread.sleep(50);//休息10ms再重繪 // } // catch(Exception e) // { // e.printStackTrace(); // } // } // } // }.start(); } } //初始化白色燈 private void initLight(GL10 gl) { gl.glEnable(GL10.GL_LIGHTING);//允許光照 gl.glEnable(GL10.GL_LIGHT1);//開啟1號燈 //環境光設定 float[] ambientParams={0.2f,0.2f,0.2f,1.0f};//光引數 RGBA gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_AMBIENT, ambientParams,0); //散射光設定 float[] diffuseParams={1f,1f,1f,1.0f};//光引數 RGBA gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_DIFFUSE, diffuseParams,0); //反射光設定 float[] specularParams={1f,1f,1f,1.0f};//光引數 RGBA gl.glLightfv(GL10.GL_LIGHT1, GL10.GL_SPECULAR, specularParams,0); } //關閉燈 private void closeLight(GL10 gl) { gl.glDisable(GL10.GL_LIGHT1); gl.glDisable(GL10.GL_LIGHTING); } //初始化材質 private void initMaterial(GL10 gl) { //環境光 float ambientMaterial[] = {248f/255f, 242f/255f, 144f/255f, 1.0f}; gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, ambientMaterial,0); //散射光 float diffuseMaterial[] = {248f/255f, 242f/255f, 144f/255f, 1.0f}; gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, diffuseMaterial,0); //高光材質 float specularMaterial[] = {248f/255f, 242f/255f, 144f/255f, 1.0f}; gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, specularMaterial,0); gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, 100.0f); } //初始化紋理 public int initTexture(GL10 gl,int drawableId)//textureId { //生成紋理ID int[] textures = new int[1]; gl.glGenTextures(1, textures, 0); int currTextureId=textures[0]; gl.glBindTexture(GL10.GL_TEXTURE_2D, currTextureId); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR_MIPMAP_NEAREST); gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR_MIPMAP_LINEAR); ((GL11)gl).glTexParameterf(GL10.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL10.GL_TRUE); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,GL10.GL_REPEAT); gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,GL10.GL_REPEAT); InputStream is = this.getResources().openRawResource(drawableId); Bitmap bitmapTmp; try { bitmapTmp = BitmapFactory.decodeStream(is); } finally { try { is.close(); } catch(IOException e) { e.printStackTrace(); } } GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmapTmp, 0); bitmapTmp.recycle(); return currTextureId; } }
GL_Cirque.java
package com.scout.eeeeeee; /** * Created by liuguodong on 2017/10/29. */ import android.app.Activity; import android.content.pm.ActivityInfo; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; public class GL_Cirque extends Activity { private MyGLSurfaceView mGLSurfaceView; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); mGLSurfaceView = new MyGLSurfaceView(this); setContentView(mGLSurfaceView); mGLSurfaceView.setFocusableInTouchMode(true);//設定為可觸控 mGLSurfaceView.requestFocus();//獲取焦點 } @Override protected void onResume() { super.onResume(); mGLSurfaceView.onResume(); } @Override protected void onPause() { super.onPause(); mGLSurfaceView.onPause(); } }
注意:在上述程式碼中,rSpan表示環每一份多少度,cSpan表示圓截環每一份多少度,ring_Radius表示環半徑, circle_Radius表示圓截面半徑。
相關文章
- Android OpenGL ES 系列連載:(01)繪製一個三角形Android
- Matlab三維空間座標圖繪製Matlab
- Android OpenGL ES 開發(二):繪製圖形Android
- CSS 繪製圓環CSS
- 學習OpenGL ES之繪製三角形
- OpenGL ES繪製3D圖形3D
- Android OpenGL ES 2.0 手把手教學(5)- 繪製模式Android模式
- Opengl ES 3.0 on iOS--- HelloWord(繪製彩色矩形)iOS
- canvas 繪製立體圓環Canvas
- OpenGL ES 2 0 (iOS)[03]:熟練圖元繪製,玩轉二維圖形iOS
- Android OpenGL ES 開發(二): OpenGL ES 環境搭建Android
- WebGL之繪製三維地球Web
- Anroid自定義View-繪製圓環View
- canvas繪製圓環效果程式碼例項Canvas
- OpenGL ES SDK for Android - 2Android
- OpenGL ES SDK for Android - 6Android
- android opengl es 原始碼Android原始碼
- OPENGL-ES之頂點索引繪圖索引繪圖
- Android繪製優化(一)繪製效能分析Android優化
- OpenGL/OpenGL ES 初探
- 繪製三元圖、顏色空間圖:R語言程式碼R語言
- OpenGL實現Hermite演算法繪製三次曲線MIT演算法
- 在 ECharts GL 中繪製三維地圖Echarts地圖
- Android日常學習:OpenGL 實踐之貝塞爾曲線繪製Android
- 360 Quake網路空間測繪系統重磅釋出,全面升維網路空間“全息測繪”
- 如何使用 Arduino 製作一個繪圖儀UI繪圖
- OpenGL ES 2 0 (iOS)[01]: 一步從一個小三角開始iOS
- OpenGL Android課程三:使用每片段照明Android
- 如何繪製三維動畫設計和製作場景更好動畫
- 【Android進階】RecyclerView之繪製流程(三)AndroidView
- OpenGL 學習系列---基本形狀的繪製
- OpenGL 學習系列--基礎的繪製流程
- OpenGL ES專案總結一
- DNA的三維視覺化:通過OpenGL實現一個DNA鏈視覺化
- Android音視訊(六) 使用OpenGL ES 3.0預覽CameraAndroid
- Android字型渲染器——使用OpenGL ES進行高效文字渲染Android
- 使用 Kitten 程式設計貓繪製一個魔方程式設計
- Android OpenGL ES 系列連載:(07)Transform FeedbackAndroidORM