博客
关于我
Android OpenGLES2.0(十六)——3D模型贴图及光照处理(obj+mtl)
阅读量:208 次
发布时间:2019-02-28

本文共 4870 字,大约阅读时间需要 16 分钟。

在Android OpenGLES2.0(十四)中,我们成功实现了Obj格式3D模型的加载。具体来说,我们加载了一个没有贴图和光照处理的帽子模型,通过手动添加光照来呈现立体效果。对于具有贴图和光照处理的模型,如何实现加载呢?让我们深入探讨一下。

模型及贴图加载

模型加载与之前的实现类似,但这次我们需要同时加载顶点法线和贴图坐标,并将它们传递给着色器。此外,还需要提取并解析mtl文件中的材质信息。解析流程如下:

  • 解析Obj文件:以Obj文件为入口,提取mtllib文件的相对路径,并解析mtl文件。
  • 解析mtl文件:将mtl文件拆分为多个单一材质。
  • 解析3D模型:根据使用的材质不同,将Obj对象拆分为多个3D模型。
  • 技术实现细节

    为了实现上述功能,我们设计了以下类:

    public class MtlInfo {    public String newmtl;    public float[] Ka = new float[3]; // 阴影色    public float[] Kd = new float[3]; // 固有色    public float[] Ks = new float[3]; // 高光色    public float[] Ke = new float[3]; // Ke    public float Ns; // shininess    public String map_Kd; // 固有纹理贴图    public String map_Ks; // 高光纹理贴图    public String map_Ka; // 阴影纹理贴图    public int illum; // 光照模型}
    public class Obj3D {    public FloatBuffer vert;    public int vertCount;    public FloatBuffer vertNorl;    public FloatBuffer vertTexture;    public MtlInfo mtl;    private ArrayList
    tempVert; private ArrayList
    tempVertNorl; private ArrayList
    tempVertTexture; public int textureSMode; public int textureTMode; public void addVert(float d) { if (tempVert == null) { tempVert = new ArrayList<>(); } tempVert.add(d); } public void addVertTexture(float d) { if (tempVertTexture == null) { tempVertTexture = new ArrayList<>(); } tempVertTexture.add(d); } public void addVertNorl(float d) { if (tempVertNorl == null) { tempVertNorl = new ArrayList<>(); } tempVertNorl.add(d); } public void dataLock() { if (tempVert != null) { setVert(tempVert); tempVert.clear(); tempVert = null; } if (tempVertTexture != null) { setVertTexture(tempVertTexture); tempVertTexture.clear(); tempVertTexture = null; } if (tempVertNorl != null) { setVertNorl(tempVertNorl); tempVertNorl.clear(); tempVertNorl = null; } } public void setVert(ArrayList
    data) { int size = data.size(); ByteBuffer buffer = ByteBuffer.allocateDirect(size * 4); buffer.order(ByteOrder.nativeOrder()); vert = buffer.asFloatBuffer(); for (int i = 0; i < size; i++) { vert.put(data.get(i)); } vert.position(0); vertCount = size / 3; } public void setVertNorl(ArrayList
    data) { int size = data.size(); ByteBuffer buffer = ByteBuffer.allocateDirect(size * 4); buffer.order(ByteOrder.nativeOrder()); vertNorl = buffer.asFloatBuffer(); for (int i = 0; i < size; i++) { vertNorl.put(data.get(i)); } vertNorl.position(0); } public void setVertTexture(ArrayList
    data) { int size = data.size(); ByteBuffer buffer = ByteBuffer.allocateDirect(size * 4); buffer.order(ByteOrder.nativeOrder()); vertTexture = buffer.asFloatBuffer(); for (int i = 0; i < size; i++) { vertTexture.put(data.get(i)); } vertTexture.position(0); }}

    光照与纹理处理

    在顶点着色器中,我们需要传递以下参数到片元着色器:

    attribute vec3 vPosition;attribute vec2 vCoord;uniform mat4 vMatrix;uniform vec3 vKa;uniform vec3 vKd;uniform vec3 vKs;varying vec2 textureCoordinate;attribute vec3 vNormal;varying vec4 vDiffuse;varying vec4 vAmbient;varying vec4 vSpecular;void main() {    gl_Position = vMatrix * vec4(vPosition, 1);    textureCoordinate = vCoord;    vec3 lightLocation = vec3(0.0, -200.0, -500.0);    vec3 camera = vec3(0, 200.0, 0);    float shininess = 10.0;    vec3 newNormal = normalize((vMatrix * vec4(vNormal + vPosition, 1)).xyz - (vMatrix * vec4(vPosition, 1)).xyz);    vec3 vp = normalize(lightLocation - (vMatrix * vec4(vPosition, 1)).xyz);    vDiffuse = vec4(vKd, 1.0) * max(0.0, dot(newNormal, vp));    vec3 eye = normalize(camera - (vMatrix * vec4(vPosition, 1)).xyz);    vec3 halfVector = normalize(vp + eye);    float nDotViewHalfVector = dot(newNormal, halfVector);    float powerFactor = max(0.0, pow(nDotViewHalfVector, shininess));    vSpecular = vec4(vKs, 1.0) * powerFactor;    vAmbient = vec4(vKa, 1.0);}
    precision mediump float;varying vec2 textureCoordinate;uniform sampler2D vTexture;varying vec4 vDiffuse;varying vec4 vAmbient;varying vec4 vSpecular;void main() {    vec4 finalColor = texture2D(vTexture, textureCoordinate);    gl_FragColor = finalColor * vAmbient + finalColor * vSpecular + finalColor * vDiffuse;}

    渲染实现

    在应用程序中,我们可以按照以下步骤进行渲染:

    List
    model = ObjReader.readMultiObj(this, "assets/3dres/pikachu.obj");List
    filters = new ArrayList<>();for (int i = 0; i < model.size(); i++) { Obj3D obj = model.get(i); obj.dataLock(); // 添加渲染相关逻辑}

    总结

    通过以上实现,我们成功地将带有贴图和光照处理的Obj格式3D模型加载到Android OpenGLES2.0环境中。整个过程包括Obj文件解析、mtl文件解析、顶点、法线和贴图数据的提取与处理,以及顶点着色器和片元着色器的实现。通过合理的数据传递和光照计算,我们能够实现高质量的3D渲染效果。

    转载地址:http://yngs.baihongyu.com/

    你可能感兴趣的文章
    mysql加强(1)~用户权限介绍、分别使用客户端工具和命令来创建用户和分配权限
    查看>>
    mysql加强(3)~分组(统计)查询
    查看>>
    mysql加强(4)~多表查询:笛卡尔积、消除笛卡尔积操作(等值、非等值连接),内连接(隐式连接、显示连接)、外连接、自连接
    查看>>
    mysql加强(5)~DML 增删改操作和 DQL 查询操作
    查看>>
    mysql加强(6)~子查询简单介绍、子查询分类
    查看>>
    mysql加强(7)~事务、事务并发、解决事务并发的方法
    查看>>
    MySQL千万级多表关联SQL语句调优
    查看>>
    mysql千万级大数据SQL查询优化
    查看>>
    MySQL千万级大表优化策略
    查看>>
    MySQL单实例或多实例启动脚本
    查看>>
    MySQL压缩包方式安装,傻瓜式教学
    查看>>
    MySQL原理、设计与应用全面解析
    查看>>
    MySQL原理简介—1.SQL的执行流程
    查看>>
    MySQL参数调优详解
    查看>>
    mysql参考触发条件_MySQL 5.0-触发器(参考)_mysql
    查看>>
    MySQL及navicat for mysql中文乱码
    查看>>
    MySqL双机热备份(二)--MysqL主-主复制实现
    查看>>
    MySQL各个版本区别及问题总结
    查看>>
    MySql各种查询
    查看>>
    mysql同主机下 复制一个数据库所有文件到另一个数据库
    查看>>