我的编程空间,编程开发者的网络收藏夹
学习永远不晚

轻松实现Android3D效果通俗易懂

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

轻松实现Android3D效果通俗易懂

文章最后将会贴出源码(照顾新手附加注释)

一、先看看聊天(需求)

请添加图片描述

二、实现效果

请添加图片描述

三、实现

前五步传感器内容。

1.通过getSystemService获得SensorManager实例对象


mSensorManager = (SensorManager)context.getSystemService(SENSOR_SERVICE);

2.通过SensorManager实例对象获得想要的传感器对象:参数决定获取哪个传感器


 mRotationVectorSensor = mSensorManager.getDefaultSensor(
                Sensor.TYPE_ROTATION_VECTOR);

3.在获得焦点时注册传感器并让本类实现SensorEventListener接口


 mSensorManager.registerListener(this, mRotationVectorSensor, 10000);
  • 第一个参数:SensorEventListener接口的实例对象
  • 第二个参数:需要注册的传感器实例
  • 第三个参数:传感器获取传感器事件event值频率:

SensorManager.SENSOR_DELAY_FASTEST = 0:对应0微秒的更新间隔,最快,1微秒 = 1 % 1000000秒
SensorManager.SENSOR_DELAY_GAME = 1:对应20000微秒的更新间隔,游戏中常用
SensorManager.SENSOR_DELAY_UI = 2:对应60000微秒的更新间隔
SensorManager.SENSOR_DELAY_NORMAL = 3:对应200000微秒的更新间隔
键入自定义的int值x时:对应x微秒的更新间隔

4.必须重写的两个方法

onAccuracyChanged和onSensorChanged

onSensorChanged: 传感器事件值改变时的回调接口:执行此方法的频率与注册传感器时的频率有关.

onAccuracyChanged:传感器精度发生改变的回调接口

5.在失去焦点时注销传感器(为Activity提供调用)


    public void stop() {
        mSensorManager.unregisterListener(this);
    }

6.draw方法中的方发详解

本案例(opengl坐标系中采用的是3维坐标)

  • glEnable:启用服务器端GL功能。
  • glFrontFace:定义多边形的正面和背面。多边形正面的方向。GL_CW和GL_CCW被允许,初始值为GL_CCW。
  • glShadeModel:选择恒定或光滑着色模式。GL图元可以采用恒定或者光滑着色模式,默认值为光滑着色模式。当图元进行光栅化的时候,将引起插入顶点颜色计算,不同颜色将被均匀分布到各个像素片段。允许的值有GL_FLAT 和GL_SMOOTH,初始值为GL_SMOOTH。
  • glVertexPointer:定义一个顶点坐标矩阵。(后续源码中会贴上各个参数以及需要注意的地方)。
  • glColorPointer:定义一个颜色矩阵。size指明每个颜色的元素数量,必须为4。type指明每个颜色元素的数据类型,stride指明从一个颜色到下一个允许的顶点的字节增幅,并且属性值被挤入简单矩阵或存储在单独的矩阵中(简单矩阵存储可能在一些版本中更有效率)。
  • glDrawElements:由矩阵数据渲染图元

更多建议参考Android官方文档。

四、需求中的青黄色参数


            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,
            };

五、源码

TdRenderer.java


public class TdRenderer implements GLSurfaceView.Renderer, SensorEventListener {
    //传感器
    private SensorManager mSensorManager;
    private Sensor mRotationVectorSensor;
    private Cube mCube;

    private final float[] mRotationMatrix = new float[16];

    public TdRenderer(Context context) {
        //第一步:通过getSystemService获得SensorManager实例对象
        mSensorManager = (SensorManager)context.getSystemService(SENSOR_SERVICE);
        //第二步:通过SensorManager实例对象获得想要的传感器对象:参数决定获取哪个传感器
        mRotationVectorSensor = mSensorManager.getDefaultSensor(
                Sensor.TYPE_ROTATION_VECTOR);

        mCube = new Cube();
        mRotationMatrix[ 0] = 1;
        mRotationMatrix[ 4] = 1;
        mRotationMatrix[ 8] = 1;
        mRotationMatrix[12] = 1;
    }
   // 第三步:在获得焦点时注册传感器并让本类实现SensorEventListener接口
    public void start() {
        
        mSensorManager.registerListener(this, mRotationVectorSensor, 10000);
    }
    //第四步:必须重写的两个方法:onAccuracyChanged,onSensorChanged
    //第五步:在失去焦点时注销传感器(为Activity提供调用)
    public void stop() {
        mSensorManager.unregisterListener(this);
    }
    //传感器事件值改变时的回调接口:执行此方法的频率与注册传感器时的频率有关
    public void onSensorChanged(SensorEvent event) {
        // 大部分传感器会返回三个轴方向x,y,x的event值
        //float x = event.values[0];
        //float y = event.values[1];
        //float z = event.values[2];
        if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
            SensorManager.getRotationMatrixFromVector(
                    mRotationMatrix , event.values);
        }
    }

    public void onDrawFrame(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
        gl.glTranslatef(0, 0, -3.0f);
        gl.glMultMatrixf(mRotationMatrix, 0);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);

        mCube.draw(gl);
    }

    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 void onSurfaceCreated(GL10 gl, EGLConfig config) {
        gl.glDisable(GL10.GL_DITHER);
        //指定颜色缓冲区的清理值
        gl.glClearColor(1,1,1,1);
    }

    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);
        }
    }
    //传感器精度发生改变的回调接口
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        //在传感器精度发生改变时做些操作,accuracy为当前传感器精度
    }
}

ThreeDimensionsRotation,java(Activity记得注册)


public class ThreeDimensionsRotation extends Activity {
    private GLSurfaceView mGLSurfaceView;
    private TdRenderer tdRenderer;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        tdRenderer=new TdRenderer(this);
        // 创建预览视图,并将其设置为Activity的内容
        mGLSurfaceView = new GLSurfaceView(this);
        mGLSurfaceView.setRenderer(tdRenderer);
        setContentView(mGLSurfaceView);
    }

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

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

}

到此这篇关于轻松实现Android3D效果通俗易懂的文章就介绍到这了,更多相关Android 3D效果内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

轻松实现Android3D效果通俗易懂

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android 轻松实现图片倒影效果实例代码

主Activity 代码如下:package com.mj.myweather;import android.app.Activity;import android.graphics.Bitmap;import android.graphi
2022-06-06

轻松实现功能强大的Android刮奖效果控件(ScratchView)

前言 我身边有一部分开发的小伙伴,存在着这样一种习惯。某一天,突然看到某一款 App 上有个很漂亮的自定义控件(动画)效果,就会绞尽脑子想办法去自己实现一发。当然,我自己也是属于这类型的骚年,看到某种效果就会手痒难耐琢磨着实现套路。个人觉得
2022-06-06

HTML5 画布标签的绘制技巧大揭秘:轻松实现图形效果

HTML5 画布标签 (canvas) 提供了强大的图形绘制功能,可用于创建各种图形效果。本文将深入探讨画布标签的绘制技巧,从基本形状绘制到高级图形效果,帮助您轻松实现创意设计。
HTML5 画布标签的绘制技巧大揭秘:轻松实现图形效果
2024-02-25

HTML无序列表实战演练:手把手教你,轻松实现各种列表效果

HTML 无序列表实战演练:手把手教您轻松显示列表效果
HTML无序列表实战演练:手把手教你,轻松实现各种列表效果
2024-02-14

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录