• 公开课“3D勋章”实现方案


    公开课“3D勋章”实现方案

    ------ opengl es 2.0中加载.obj 与 .mtl

    先上一个效果图
    在这里插入图片描述

    看到这个需求,直接反应是用OpenGLES加载一个.obj(顶点数据)与.mtl(颜色材质信息)文件 就搞定了( .obj与.mtl文件由设计师用3dmax、Maya等工具导出)。
    本以为是一个简单需求,但做起来发现困难点并不少:

    • OpenGLES如何加载.obj与.mtl文件?
    • 勋章的进入和退出动画效果?
    • 勋章进入和退出过程中的实时光照效果该怎么做?

    解决这三个问题,是需求实现的关键。
    为此,我设计了以下架构实现方式,先看架构图:

    架构实现:
    在这里插入图片描述

    我们从下向上说:

    • 最下边运行在Android系统上,这个不用细说
    • .obj 3D文件解析引擎:
      自己手动解析的,并不是网上开源框架(大都泛泛而谈,只能做demo) 。如果开源,那我的这个工程应该就是第一个开源的比较完善的.obj3D文件.mtl材质文件的Java解析库
    • 光照系统:
      shader 主要用于模拟 环境光、散射光、镜面光(高光)。上线产品,为了效果,必须有光照;
    • 动画引擎:
      虽然看起来简单,但设计确是按照一个动画引擎标准设计的;
      整个动画引擎可以划分为:场景、层、动画精灵。引擎的架构借鉴了游戏引擎Cocos2d;
      这样设计的优点是:
      a、若底层不依赖Opengl ES 底层依赖的是View 或者SurfaceView 可直接移植为一个2D动画引擎;
      b、继续扩展还可以发展做成骨骼动画;

    下面我们对这个架构实现进行详细说明。

    一、OpenGLES如何加载.obj与.mtl文件?

    本来以为网上应该有兼容性较好的obj与mtl的java解析库,但在网上找了好多代码,发现其在加载obj与mtl中,基本都存在较大问题。

    网上代码主要分为了以下几个部分:

    • mind3d 2011年就已停止维护(为opengl es1.0),并且在加载多图形上存在很大的不兼容(主要解析了obj,mtl没有解析)。
    • 其他一些obj解析代码,基本都是解析了obj,不管mtl文件
      或者简单解析了mtl,却没有把对应的材质信息应用到opengl 绘制的图形上
    • 《Android 3D游戏开发技术宝典——OpenGL ES 2.0》(2012年我和几个同学写的书) 第九章 3D模型加载。 当时写这本书时,也只是简单解析了obj文件,而且对mtl文件并未做解析(网上很多的例子是把这一章的案例直接照搬了)

    mind3d官方地址与源码
    https://code.google.com/archive/p/min3d/
    https://github.com/deadmoose/min3d

    1.1 Obj 与mtl文件简单举例

    obj文件是3D模型文件格式。由Alias|Wavefront公司为3D建模和动画软件”Advanced Visualizer”开发的一种标准,适合用于3D软件模型之间的互导,也可以通过Maya读写。

    • 只支持模型三角面数据和材质信息,无动画功能支持;
    • 其中几何信息由.obj文件提供,材质信息由.mtl文件定义;
    • 文件以行为单位表示一条数据,可以根据行开头的字符判断后续的内容;
    • 其中 # 字符表示注释行

    1.1.1 obj文件中主要存放的以下几何信息

    • 三维空间中顶点坐标信息
    • 顶点的纹理坐标(贴图坐标)信息
    • 顶点的法向量信息(计算光照用)

    这里我手写了一份triangle.obj文件:

    triangle.obj

    # mtl材质文件
    # mtllib testvt.mtl
    
    # o 对象名称(Object name)
    o adfaf
    
    # 组名称
    g default
    
    # 顶点
    v 0 0.5 0
    v -0.5 -0.5 0
    v 0.5 -0.5 0
    
    # 纹理坐标
    vt 0.0 1.0
    vt 0.0 0.0
    vt 1.0 1.0
    
    # 顶点法线
    vn 0 0 1
    
    # 当前图元所用材质
    usemtl Default
    
    # s Smooth shading across polygons is enabled by smoothing groups.
    # Smooth shading can be disabled as well.
    s off
    
    # v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3(索引起始于1)
    f 1/1/1 2/2/1 3/3/1
    

    triangle.obj 增加了详细的注释;

    • triangle.obj 中规定了模型顶点、纹理、法向量等信息,确定了模型的顶点数据;

    1.1.2 mtl文件

    这里我手写了一份triangle.mtl文件:
    mtl中主要规定了几何图形的贴图信息,对环境光、散射光、镜面光的反射情况、透明度等

    triangle.mtl

    # 定义一个名为 'Default'的材质
    newmtl Default
    
    # 材质的环境光
    Ka 0 0 0
    # 散射光
    Kd 0.784314 0.784314 0.784314
    # 镜面光
    Ks 0 0 0
    
    # 透明度
    d 1
    
    # 为漫反射指定颜色纹理文件
    map_Kd test_vt.png
    

    triangle.mtl 增加了详细的注释;

    • triangle.mtl 中规定了模型材质相关的信息,包括纹理贴图、环境光、镜面光、散射光等相关配置都来自这个文件;

    1.1.3 triangle.obj与triangle.mtl加载到OpenGL后的运行效果

    这里写图片描述

    • 加载triangle.obj与triangle.mtl 模型后的运行效果图如上图所示;
    • 这里为了方便理解,所以仅仅加载的是一个最简单的普通三角形;

    这里写图片描述

    • 加载的triangle.obj与triangle.mtl 三角形,在三维空间中的位置如上图所示。
    • 三维空间中顶点的位置信息来源于triangle.obj文件中。

    关于关照与材质相关,详细信息,可参考我的另一篇文章:
    http://blog.csdn.net/xiaxl/article/details/76826812

    二、动画引擎实现

    在这里插入图片描述

    说动画实现之前,先要说一下动画引擎架构的设计。
    动画引擎实现,参考了Cocos2d游戏引擎的设计思想,整个动画引擎分为了三层:

    2.1、动画引擎架构实现

    前边说了,这个设计实际参考了Cocos2d游戏引擎的设计思想,所以实现上与Cocos2d有很多的相似之处:
    在这里插入图片描述

    • 场景:场景负责绘制其所包含的全部层;
    • 层:层负责管理、绘制其中的精灵;
      层亦可以携带精灵做出一些旋转、平移、缩放 等简单的动画效果;
    • 精灵:精灵是游戏实体,精灵是活泼的,可以做很多的动画效果;
      精灵应该是活泼的、好动的!!!
      而动画引擎中的 SpriteAnima ,则是我赋予精灵的动画实现,也是精灵活泼起来的根本。

    2.2、具体的代码实现

    在具体分层代码实现上:

    在这里插入图片描述

    • 场景:场景继承自GLSurfaceView 管理者众多的层,负责页面绘制;
    • 层: 层管理者众多的精灵,并且继承自SpriteAnima
      层亦被赋予了动画属性,可以携带众多的精灵完成动画,而不影像精灵的动画;
      同时也赋予了层活泼好动的天性
    • 精灵:当然亦继承自SpriteAnima,天然活泼好动。

    2.3、SpriteAnima 动画实现

    具体动画类的实现,则参考了Android属性动画的实现方案:

    Opengl ES中的属性动画

    在这里插入图片描述

    以上代码截图,就是我自定义实现的Opengl ES中的属性动画

    参考Android属性动画:

    • 通过反射调用,不断更改精灵的AngleY属性值来完成精灵属性的变更。
    • 这里我还加入了Android的动画差值器 OvershootInterpolator ,使得勋章动画在运行时,具备动画越过便边界后,回弹的效果。我们的勋章精灵变得更加活泼。

    让精灵活泼起来

    在这里插入图片描述
    如以上代码截图所示:只要动画尚未结束,则不断请求GLThread的场景重绘,来完成精灵的活泼运动效果

    三、3D空间对光的模拟

    当光照射到一个物体表面上时,会出现三种情形。

    • 首先,光可以通过物体表面向空间反射, 产生反射光。
    • 其次,对于透明体,光可以穿透该物体并从另一端射出,产生透射光。
    • 最后,部分光将被物体表面吸收而转换成热。

    在上述三部分光中,仅仅是透射光和反射光能够进入人眼产生视觉效果。这里只考虑被照明物体表面的反射光影响,假定物体表面光滑不透明且由理想材料构成,环境假设为由白光照明。
    一般来说,反射光可以分成三个分量,即环境反射、漫反射和镜面反射

    在这里插入图片描述

    • 镜面光:上图中,最亮部分为镜面光
    • 散射光(漫反射光):上图中,比镜面光稍暗部分为散射光
    • 环境光:上图中,最暗部分为环境光

    三维场景中,只要能模拟出以上三种光照效果,则成功模拟了虚拟世界中的光照。完成产品经理、设计是要求,成功上线则不成问题。

    3.1、环境光 模拟

    从四面八方照射向物体的光,这种光是非发光物体反射的其他光;
    因此,环境光可以选择一个较暗的颜色值进行模拟

    在这里插入图片描述

    shader代码实现

    shader 代码实现如下:选择一个较暗的颜色值模拟环境光

    在这里插入图片描述

    3.2、散射光(漫反射光) 模拟

    光源照射到物体的表面,经过物体表面的漫反射,四面八方反射出去的光。

    在这里插入图片描述

    如上图所示,一个光源照直射到一个球面,半个球面会有相应的反射光,这里要模拟的就是这样的光:
    半球面中心点最亮,一直到球面边缘逐渐变暗

    公式来计算

    我们可以用如下公式来计算散射光:

    在这里插入图片描述

    • 光照的中心点最亮
    • 入射角越大,最终的散射光强度就越小;从中心到边缘慢慢变暗

    shader代码实现

    在这里插入图片描述

    newNormal 点的法向量、vp 点到光源的向量 均为单位向量,因此,向量点乘即为入射角的cos值;

    在这里插入图片描述

    3.3、镜面光 模拟

    相比散射光,高光的亮度区域进一步缩小,是光照射到物体中最亮的一块

    在这里插入图片描述

    • V点到摄像机的向量
    • L点到光源的向量
    • H V与L的半向量

    模拟公式

    我们可以用以下公式来模拟:

    在这里插入图片描述

    shader代码实现

    在这里插入图片描述

    四、最终效果

    • OpenGLES如何加载.obj与.mtl文件?
    • 勋章的进入和退出动画效果?
    • 勋章进入和退出过程中的实时光照效果该怎么做?

    以上三个问题解决完成,我们来瞅瞅最终效果(炫耀一下):

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    五、开源

    最后,两个字:代码开源...

    文档地址:
    http://blog.csdn.net/xiaxl/article/details/77048507
    案例实现代码:
    https://github.com/xiaxveliang/GLES2_Anima_LoadFrom_Obj

    ========== THE END ==========

    wx_gzh.jpg

  • 相关阅读:
    JS获取今天的日期
    领域模型vs数据模型,应该怎么用?
    如何让技术想法更容易被理解?
    如何做好技术 Team Leader
    回归分析中常见的“门槛模型”!
    有了数据湖,距离数据仓库消失还有几年?
    数据治理 VS 公司治理、IT治理、数仓治理
    Sentence-seven basic patterns 英语句子结构
    VM的Linux CentOS系统的VMTools的手动安装
    linux下IPTABLES配置详解
  • 原文地址:https://www.cnblogs.com/xiaxveliang/p/12395702.html
Copyright © 2020-2023  润新知