当前位置: 首页 > news >正文

菏泽网站建设 梧桐树网站建设与应用

菏泽网站建设 梧桐树,网站建设与应用,tamed wordpress插件汉化,设计公司网站源码概述 前几天发现QQ音乐有个好玩的功能#xff0c;为用户提供了多种 播放器主题#xff0c;其中 原神 的主题让我眼前一亮#xff1a; 当然#xff0c;诸如 换肤、主题 类的功能已经屡见不鲜#xff0c;但这类沉浸式播放器的听歌体验确实不错。 见猎心喜#xff0c;正好…概述 前几天发现QQ音乐有个好玩的功能为用户提供了多种 播放器主题其中 原神 的主题让我眼前一亮 当然诸如 换肤、主题 类的功能已经屡见不鲜但这类沉浸式播放器的听歌体验确实不错。 见猎心喜正好中秋马上就到我也尝试整个 中秋主题音乐播放器 试试水。 整体思路有2点 首先是技术方面纯粹的 ImageView 图层堆砌来实现渲染效率太低OpenGL 是一个不错的技术方案QQ应该也是这么实现的顺便复习下图形学的知识。 其次是玩法上干脆在基础的功能上加一些 更好玩的比如为播放页设计多个图层通过陀螺仪图层联动实现的 裸眼3D 的视觉效果边听歌边玩。后续还可以考虑通过制定 设计规范让不同图层的UI元素达成更多新奇好玩的 联动效果。 说了这么多最后效果如下所示左侧展示录屏效果右侧是裸眼3D效果 ## 具体实现 1. 裸眼3D原理 2年前自如的 《自如客APP裸眼3D效果的实现》 一文引发了社区的热烈讨论和实践本着不重复造轮子的原则这里简单对原理介绍感兴趣的读者可参考上述链接。 裸眼 3D 效果的本质是——将整个图片结构分为 3 层上层、中层、以及底层。在手机左右上下旋转时上层和底层的图片呈相反的方向进行移动中层则不动在视觉上给人一种 3D 的感觉 本文的效果是由以下四张图由底至顶依次绘制而成的 接下来如何感应手机的旋转状态并将4层图片进行对应的移动呢当然是使用设备自身提供的 传感器 了通过传感器不断回调获取设备的旋转状态对 UI 进行对应地渲染即可。 2. 为何选择 OpenGL GPU 更适合图形、图像的处理裸眼3D效果中有大量的 旋转、缩放 和 位移 操作都可在 java 层通过一个 矩阵 对几何变换进行描述通过 shader 小程序中交给 GPU 处理 ——理论上 OpenGL 的渲染性能比原生的 ImageView 更好。 借助OpenGL的API渲染性能也符合预期打开 布局边界 和 GPU过渡绘制 选项后播放页渲染性能也依然稳定更不会增加布局层级的复杂度直接证明了该方案 具备应用到实际生产项目的可行性 3 代码实现 本文重点是描述 OpenGL 绘制时的思路描述因此下文仅展示部分核心代码对具体实现感兴趣的读者可参考文末的链接。 3.1 绘制静态图片 首先需要将4张图片图片素材来源依次进行静态绘制这里涉及大量 OpenGL API 的使用不熟悉的读可略读本小节以捋清思路为主。 首先看一下顶点和片元着色器的 shader 代码其定义了图像纹理是如何在GPU中处理渲染的 // 顶点着色器代码 // 顶点坐标 attribute vec4 av_Position; // 纹理坐标 attribute vec2 af_Position; uniform mat4 u_Matrix; varying vec2 v_texPo;void main() {v_texPo af_Position;gl_Position u_Matrix * av_Position; }// 片元着色器代码 precision mediump float; // 纹理坐标 varying vec2 v_texPo; uniform sampler2D sTexture; void main() {gl_FragColortexture2D(sTexture, v_texPo); } 定义好了 Shader 接下来在 GLSurfaceView (可以理解为 OpenGL 中的画布) 创建时初始化Shader小程序并将图像纹理依次加载到GPU中 public class ZQRenderer implements GLSurfaceView.Renderer {Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {// 1.加载shader小程序mProgram loadShaderWithResource(mContext, R.raw.projection_vertex_shader, R.raw.projection_fragment_shader);//...// 2. 依次将切图纹理传入GPUthis.texImageInner(R.drawable.icon_player_bg, mBackTextureId);this.texImageInner(R.drawable.icon_player_moon, mMidTextureId);this.texImageInner(R.drawable.icon_album_cover_nocturne, mCoverTextureId);this.texImageInner(R.drawable.icon_player_text, mFrontTextureId);} }接下来是定义视口以及投影矩阵因为切图的比例各不相同为了保证视觉效果需要针对不同层级的图片设置不同的正交投影策略。 public class ZQRenderer implements GLSurfaceView.Renderer {Overridepublic void onSurfaceChanged(GL10 gl, int width, int height) {//设置大小位置GLES20.glViewport(0, 0, width, height);Matrix.setIdentityM(mBgProjectionMatrix, 0);Matrix.setIdentityM(mMoonProjectionMatrix, 0);Matrix.setIdentityM(mCoverProjectionMatrix, 0);// 计算宽高比boolean isVertical width height;float screenRatio (float) width / (float) height;// 设置投影矩阵// 1.深色背景图的投影矩阵只需要铺全屏// 2.月亮和装饰图的投影矩阵float ratio (float) 1080 / (float) 1528;if (isVertical) {Matrix.orthoM(mMoonProjectionMatrix, 0, -1f, 1f, -1f / ratio, 1f / ratio, -1f, 1f);} else {Matrix.orthoM(mMoonProjectionMatrix, 0, -ratio, ratio, -1f, 1f, -1f, 1f);}// 3.歌曲封面图投影矩阵if (isVertical) {Matrix.orthoM(mCoverProjectionMatrix, 0, -1f, 1f, -1f / screenRatio, 1f / screenRatio, -1f, 1f);} else {Matrix.orthoM(mCoverProjectionMatrix, 0, -screenRatio, screenRatio, -1f, 1f, -1f, 1f);}} }最后就是 绘制读者需要理解对于4层图像的渲染其逻辑是基本一致的差异仅仅有2点图像本身不同 以及 图像的几何变换不同。 public class ZQRenderer implements GLSurfaceView.Renderer {Overridepublic void onDrawFrame(GL10 gl) {GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);GLES20.glUseProgram(mProgram);this.updateMatrix();this.drawLayerInner(mBackTextureId, mTextureBuffer, mBackMatrix); // 画背景this.drawLayerInner(mMidTextureId, mTextureBuffer, mMoonMatrix); // 画月亮this.drawLayerInner(mCoverTextureId, mTextureBuffer, mCoverMatrix); // 画封面this.drawLayerInner(mFrontTextureId, mTextureBuffer, mFrontMatrix); // 画前景装饰}private void texImageInner(DrawableRes int drawableRes, int textureId) {//绑定纹理GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);//环绕方式GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);//过滤方式GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);GLES20.glEnable(GLES20.GL_BLEND);GLES20.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);Bitmap bitmap BitmapFactory.decodeResource(mContext.getResources(), drawableRes);GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);bitmap.recycle();} }现在我们完成了图像的 静态绘制接下来我们需要接入 传感器并引入不同层级图片各自的几何变换 让图片动起来。 3.2 让图片动起来 首先我们需要对 Android 平台上的传感器进行注册监听手机的旋转状态并拿到手机 xy 轴的旋转角度。 // 2.1 注册传感器 mSensorManager (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); mAcceleSensor mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mMagneticSensor mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); mSensorManager.registerListener(mSensorEventListener, mAcceleSensor, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(mSensorEventListener, mMagneticSensor, SensorManager.SENSOR_DELAY_GAME);// 2.2 不断接受旋转状态 private final SensorEventListener mSensorEventListener new SensorEventListener() {Overridepublic void onSensorChanged(SensorEvent event) {// ... 省略具体代码float[] values new float[3];float[] R new float[9];SensorManager.getRotationMatrix(R, null, mAcceleValues, mMageneticValues);SensorManager.getOrientation(R, values);// x轴的偏转角度float degreeX (float) Math.toDegrees(values[1]);// y轴的偏转角度float degreeY (float) Math.toDegrees(values[2]);// z轴的偏转角度float degreeZ (float) Math.toDegrees(values[0]);// 拿到 xy 轴的旋转角度进行矩阵变换updateMatrix(degreeX, degreeY);} };注意因为我们只需控制图像的左右和上下移动因此我们只需关注设备本身 x 轴和 y 轴的偏转角度。但如果将图片直接进行位移操作将会因为位移后图像的另一侧没有纹理数据导致渲染结果有黑边现象为了避免这个问题我们需要将图像默认从中心点进行放大保证图像移动的过程中不会超出自身的边界。 也就是说我们一开始进入时看到的肯定只是图片的部分区域。给每一个图层设置 scale将图片进行放大。显示窗口是固定的那么一开始只能看到图片的正中位置。中层可以不用因为中层本身是不移动的所以也不必放大) 这里的处理参考自 Nayuta 的 这篇文章内部已经将思路阐述的非常清晰强烈建议读者进行阅读。 明白了这一点我们就能理解裸眼 3D 的效果实际上就是对 不同层级的图像 进行 缩放 和 位移 的变换下面是分别获取几何变换的代码 public class ZQRenderer implements GLSurfaceView.Renderer {private float[] mBgProjectionMatrix new float[16];private float[] mMoonProjectionMatrix new float[16];private float[] mCoverProjectionMatrix new float[16];private float[] mBackMatrix new float[16];private float[] mMoonMatrix new float[16];private float[] mCoverMatrix new float[16];private float[] mFrontMatrix new float[16];// 封面图旋转一圈的时间单位秒.private static final long ROTATE_TIME 20L;public static final long DELAY_INTERVAL 1000 / (360 / ROTATE_TIME);/*** 陀螺仪数据回调更新各个层级的变换矩阵.** param degreeX x轴旋转角度图片应该上下移动* param degreeY y轴旋转角度图片应该左右移动*/private void updateMatrix() {// ---------- 背景-蓝色底图 ----------Matrix.setIdentityM(mBackMatrix, 0);// 1.最大位移量float maxTransXY MAX_VISIBLE_SIDE_BACKGROUND - 1f;// 2.本次的位移量float transX ((maxTransXY) / MAX_TRANS_DEGREE_Y) * -mCurDegreeY;float transY ((maxTransXY) / MAX_TRANS_DEGREE_X) * -mCurDegreeX;float[] backMatrix new float[16];// 蓝色底图的投影矩阵需要铺展全屏.Matrix.setIdentityM(mBgProjectionMatrix, 0);Matrix.setIdentityM(backMatrix, 0);Matrix.translateM(backMatrix, 0, transX, transY, 0f); // 2.平移Matrix.scaleM(backMatrix, 0, SCALE_BACK_GROUND, SCALE_BACK_GROUND, 1f); // 1.缩放Matrix.multiplyMM(mBackMatrix, 0, mBgProjectionMatrix, 0, backMatrix, 0); // 3.正交投影// ---------- 背景 -月亮 ----------Matrix.setIdentityM(mMoonMatrix, 0);float[] midMatrix new float[16];Matrix.setIdentityM(midMatrix, 0); // Matrix.translateM(midMatrix, 0, transX, transY, 0f); // 2.平移这行注释解开后手机摇一摇封面图和月亮也会有位移偏差.Matrix.scaleM(midMatrix, 0, SCALE_MOON_GROUND, SCALE_MOON_GROUND, 1.0f); // 1.缩放Matrix.multiplyMM(mMoonMatrix, 0, mMoonProjectionMatrix, 0, midMatrix, 0); // 3.正交投影// --------- 中景-歌曲封面 ----------Matrix.setIdentityM(mCoverMatrix, 0);float[] rotateMatrix new float[16];float[] tranAndScale new float[16];float[] coverMatrix new float[16];Matrix.setIdentityM(rotateMatrix, 0);Matrix.setIdentityM(tranAndScale, 0);Matrix.setIdentityM(coverMatrix, 0);Matrix.scaleM(tranAndScale, 0, 0.565f, 0.58f, 1.0f); // 3.缩放,这里的缩放参数是开发时即时调整的保证歌曲封面和月亮的大小一致Matrix.translateM(tranAndScale, 0, 0.05f, 1.41f, 0f); // 2.平移,这里的位移参数是开发时即时调整的保证歌曲封面和月亮的center位置在一起Matrix.setRotateM(rotateMatrix, 0, 360 - mCoverDegree, 0.0f, 0.0f, 1.0f); // 1.旋转顺时针Matrix.multiplyMM(coverMatrix, 0, tranAndScale, 0, rotateMatrix, 0);Matrix.multiplyMM(mCoverMatrix, 0, mCoverProjectionMatrix, 0, coverMatrix, 0); // 4.正交投影// ---------- 前景-装饰 ----------Matrix.setIdentityM(mFrontMatrix, 0);// 1.最大位移量maxTransXY MAX_VISIBLE_SIDE_FOREGROUND - 1f;// 2.本次的位移量transX ((maxTransXY) / MAX_TRANS_DEGREE_Y) * -mCurDegreeY;transY ((maxTransXY) / MAX_TRANS_DEGREE_X) * -mCurDegreeX;float[] frontMatrix new float[16];Matrix.setIdentityM(frontMatrix, 0);Matrix.translateM(frontMatrix, 0, -transX, -transY, 0f); // 2.平移Matrix.scaleM(frontMatrix, 0, SCALE_FORE_GROUND, SCALE_FORE_GROUND, 1f); // 1.缩放Matrix.multiplyMM(mFrontMatrix, 0, mMoonProjectionMatrix, 0, frontMatrix, 0); // 3.正交投影} }背景、月亮、前景都很简单只有 中景的歌曲封面 麻烦一些首先歌曲封面要伴着歌曲进度做 旋转动画其次由于图片素材尺寸的原因中心点要 位移 到和月亮相同的位置最后 缩放 到和月亮一样的大小完成重合。 小结 现在我们完成了图示效果的开发。 限于篇幅文中代码以捋清思路为主部分细节(如 Handler 不断发消息实现旋转动画、添加 低通滤波器 防止抖动等)没展示出来感兴趣的小伙伴可以点击 这里 查看源码。 关于我 Hello我是 却把清梅嗅 如果您觉得文章对您有价值欢迎 ❤️也欢迎关注我的 博客 或者 GitHub。 我的Android学习体系关于文章纠错关于知识付费关于《反思》系列
http://www.hkea.cn/news/14427861/

相关文章:

  • 专注网站基础优化今天刚刚长沙
  • 网站建设推荐书籍广西医科大学网站建设
  • 网站的导入流量怎么做梅河口信息网
  • 网络安全企业十大seo公司
  • 公司网站建设合规吗为什么我的网站无法访问
  • 瀑布流分享网站源代码下载专业建设主考学校是什么意思
  • 上海学习网站建设天津网站制作建设
  • 中国最大的免费素材网站番号网站怎么做
  • 网站功能建设上海门户网站制
  • 网站开发和优化关系六安短视频优化费用
  • 昆明hph网站建设中国新闻社副社长
  • 静安西安网站建设网上做室内设计好的网站
  • 中国建设教育协会培训中心网站百度ocpc如何优化
  • 有主体新增网站海南省两学一做网站
  • 深圳网站建设及优化阿里云认证网站建设题库
  • 网站建设 软件 开源台州网站建设哪家便宜
  • 做展示网站要恋用什么程序软件工程最好的出路
  • 制作网站软件网站上海市建设干部学校网站
  • 甜品网站建设策划书wordpress jiathis
  • 电子购物网站开发公司莱芜做网站的商家有哪些
  • 58网站建设的目的php网站跟随导航
  • 建设信用卡商城网站深圳市建工集团
  • 你认为公司在建立网站时应满足哪些目标经典软文案例100例
  • 智趣游戏型网站开发网页制作教材素材
  • 怎样选择 网站建设常州做网站软件
  • 如何做话费卡回收网站雨颜色网站建设
  • 深圳网站建设服务合同健身网站建设
  • 网站备案号省份深圳高端做网站公司
  • 商场网站建设模板网站开发的程序平台
  • 深圳有实力的seo公司南京广告宣传公司seo