软件编程
位置:首页>> 软件编程>> Android编程>> Android自定义view之3D正方体效果实例

Android自定义view之3D正方体效果实例

作者:计蒙不吃鱼  发布时间:2023-02-01 05:01:34 

标签:android,自定义view,3d正方体
目录
  • 前言

  • 一、小提

  • 二、将传感器改成事件分发机制

  • 三、使用

  • 四、源码

  • 总结

前言

在之前写了一篇关于3D效果的文章,借助传感器展示,有小伙伴问可不可以改成手势滑动操作(事件分发),所以出一篇文章

传感器相关文章链接:Android 3D效果的实现

一、小提

相对于常见的自定义view而言,继承的GLSurfaceView只有两个构造函数。可以理解为没有提供获取自定义属性的方法。


   public TouchSurfaceView(Context context) {
       super(context);
   }

public TouchSurfaceView(Context context, AttributeSet attrs) {
       super(context, attrs);
   }

二、将传感器改成事件分发机制


   @Override
   public boolean onTouchEvent(MotionEvent e) {
       float x = e.getX();
       float y = e.getY();
       switch (e.getAction()) {
           case MotionEvent.ACTION_MOVE:
               float dx = x - mPreviousX;
               float dy = y - mPreviousY;
               mRenderer.mAngleX += dx * TOUCH_SCALE_FACTOR;
               mRenderer.mAngleY += dy * TOUCH_SCALE_FACTOR;
               requestRender();
       }
       mPreviousX = x;
       mPreviousY = y;
       return true;
   }

要注意还有一个滚动球事件


   @Override
   public boolean onTrackballEvent(MotionEvent e) {
       mRenderer.mAngleX += e.getX() * TRACKBALL_SCALE_FACTOR;
       mRenderer.mAngleY += e.getY() * TRACKBALL_SCALE_FACTOR;
       requestRender();
       return true;
   }

三、使用


 mGLSurfaceView = new TouchSurfaceView(this);
       setContentView(mGLSurfaceView);
       mGLSurfaceView.requestFocus();
       mGLSurfaceView.setFocusableInTouchMode(true);

注意要在对应生命周期中处理


   @Override
   protected void onResume() {
       super.onResume();
       mGLSurfaceView.onResume();
   }

@Override
   protected void onPause() {
       super.onPause();
       mGLSurfaceView.onPause();
   }

四、源码

TouchSurfaceView.java

除去前面的修改部分,其他大多与链接文章相同,仅将传感器改成了事件分发。(代码中难点有注释)


public class TouchSurfaceView extends GLSurfaceView {
   private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
   private final float TRACKBALL_SCALE_FACTOR = 36.0f;
   private CubeRenderer mRenderer;
   private float mPreviousX;
   private float mPreviousY;

public TouchSurfaceView(Context context) {
       super(context);
       mRenderer = new CubeRenderer();
       setRenderer(mRenderer);
       setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
   }

public TouchSurfaceView(Context context, AttributeSet attrs) {
       super(context, attrs);
   }

@Override
   public boolean onTrackballEvent(MotionEvent e) {
       mRenderer.mAngleX += e.getX() * TRACKBALL_SCALE_FACTOR;
       mRenderer.mAngleY += e.getY() * TRACKBALL_SCALE_FACTOR;
       requestRender();
       return true;
   }

@Override
   public boolean onTouchEvent(MotionEvent e) {
       float x = e.getX();
       float y = e.getY();
       switch (e.getAction()) {
           case MotionEvent.ACTION_MOVE:
               float dx = x - mPreviousX;
               float dy = y - mPreviousY;
               mRenderer.mAngleX += dx * TOUCH_SCALE_FACTOR;
               mRenderer.mAngleY += dy * TOUCH_SCALE_FACTOR;
               requestRender();
       }
       mPreviousX = x;
       mPreviousY = y;
       return true;
   }

private class CubeRenderer implements GLSurfaceView.Renderer {

private Cube mCube;
       public float mAngleX;
       public float mAngleY;
       public CubeRenderer() {
           mCube =new Cube();
       }

public void onDrawFrame(GL10 gl) {
// | GL10.GL_DEPTH_BUFFER_BIT
           gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
           gl.glMatrixMode(GL10.GL_MODELVIEW);
           gl.glLoadIdentity();
           gl.glTranslatef(0, 0, -3.0f);
           gl.glRotatef(mAngleX, 0, 1, 0);
           gl.glRotatef(mAngleY, 1, 0, 0);
           gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
           gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
           mCube.draw(gl);
       }

@Override
       public void onSurfaceCreated(GL10 gl, javax.microedition.khronos.egl.EGLConfig config) {
           gl.glDisable(GL10.GL_DITHER);
           gl.glClearColor(1,1,1,1);
       }

public void onSurfaceChanged(GL10 gl, int width, int height) {
           gl.glViewport(0, 0, width, height);
           //设置投影矩阵。但并不需要在每次绘制时都做,通常情况下,当视图调整大小时,需要设置一个新的投影。
           float ratio = (float) width / height;
           gl.glMatrixMode(GL10.GL_PROJECTION);
           gl.glLoadIdentity();
           gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
       }

}

public class Cube {
       //opengl坐标系中采用的是3维坐标:
       private FloatBuffer mVertexBuffer;
       private FloatBuffer mColorBuffer;
       private ByteBuffer mIndexBuffer;

public Cube() {
           final float vertices[] = {
                   -1, -1, -1, 1, -1, -1,
                   1,  1, -1,    -1,  1, -1,
                   -1, -1,  1,      1, -1,  1,
                   1,  1,  1,     -1,  1,  1,
           };

final float colors[] = {
                   0,  1,  1,  1,  1,  1,  1,  1,
                   1,  1,  0,  1,  1,  1,  1,  1,
                   1,  1,  1,  1,  0,  1,  1,  1,
                   1,  1,  1,  1,  1,  1,  0,  1,
           };

final byte indices[] = {
                   0, 4, 5,    0, 5, 1,
                   1, 5, 6,    1, 6, 2,
                   2, 6, 7,    2, 7, 3,
                   3, 7, 4,    3, 4, 0,
                   4, 7, 6,    4, 6, 5,
                   3, 0, 1,    3, 1, 2
           };

ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length*4);
           vbb.order(ByteOrder.nativeOrder());
           mVertexBuffer = vbb.asFloatBuffer();
           mVertexBuffer.put(vertices);
           mVertexBuffer.position(0);

ByteBuffer cbb = ByteBuffer.allocateDirect(colors.length*4);
           cbb.order(ByteOrder.nativeOrder());
           mColorBuffer = cbb.asFloatBuffer();
           mColorBuffer.put(colors);
           mColorBuffer.position(0);

mIndexBuffer = ByteBuffer.allocateDirect(indices.length);
           mIndexBuffer.put(indices);
           mIndexBuffer.position(0);
       }

public void draw(GL10 gl) {
           //启用服务器端GL功能。
           gl.glEnable(GL10.GL_CULL_FACE);
           //定义多边形的正面和背面。
           //参数:
           //mode——多边形正面的方向。GL_CW和GL_CCW被允许,初始值为GL_CCW。
           gl.glFrontFace(GL10.GL_CW);
           //选择恒定或光滑着色模式。
           //GL图元可以采用恒定或者光滑着色模式,默认值为光滑着色模式。当图元进行光栅化的时候,将引起插入顶点颜色计算,不同颜色将被均匀分布到各个像素片段。
           //参数:
           //mode——指明一个符号常量来代表要使用的着色技术。允许的值有GL_FLAT 和GL_SMOOTH,初始值为GL_SMOOTH。
           gl.glShadeModel(GL10.GL_SMOOTH);
           //定义一个顶点坐标矩阵。
           //参数:
           //
           //size——每个顶点的坐标维数,必须是2, 3或者4,初始值是4。
           //
           //type——指明每个顶点坐标的数据类型,允许的符号常量有GL_BYTE, GL_SHORT, GL_FIXED和GL_FLOAT,初始值为GL_FLOAT。
           //
           //stride——指明连续顶点间的位偏移,如果为0,顶点被认为是紧密压入矩阵,初始值为0。
           //
           //pointer——指明顶点坐标的缓冲区,如果为null,则没有设置缓冲区。
           gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
           //定义一个颜色矩阵。
           //size指明每个颜色的元素数量,必须为4。type指明每个颜色元素的数据类型,stride指明从一个颜色到下一个允许的顶点的字节增幅,并且属性值被挤入简单矩阵或存储在单独的矩阵中(简单矩阵存储可能在一些版本中更有效率)。
           gl.glColorPointer(4, GL10.GL_FLOAT, 0, mColorBuffer);
           //由矩阵数据渲染图元
           //可以事先指明独立的顶点、法线、颜色和纹理坐标矩阵并且可以通过调用glDrawElements方法来使用它们创建序列图元。
           gl.glDrawElements(GL10.GL_TRIANGLES, 36, GL10.GL_UNSIGNED_BYTE, mIndexBuffer);
       }
   }
}

MainActivity.java


public class MainActivity extends AppCompatActivity {
   private GLSurfaceView mGLSurfaceView;
   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       mGLSurfaceView = new TouchSurfaceView(this);
       setContentView(mGLSurfaceView);
       mGLSurfaceView.requestFocus();
       mGLSurfaceView.setFocusableInTouchMode(true);
   }

@Override
   protected void onResume() {
       super.onResume();
       mGLSurfaceView.onResume();
   }

@Override
   protected void onPause() {
       super.onPause();
       mGLSurfaceView.onPause();
   }

}

来源:https://blog.csdn.net/qq_42761395/article/details/119830330

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com