博客
关于我
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/

    你可能感兴趣的文章
    mysql5.7示例数据库_Linux MySQL5.7多实例数据库配置
    查看>>
    Mysql8 数据库安装及主从配置 | Spring Cloud 2
    查看>>
    mysql8 配置文件配置group 问题 sql语句group不能使用报错解决 mysql8.X版本的my.cnf配置文件 my.cnf文件 能够使用的my.cnf配置文件
    查看>>
    MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
    查看>>
    MYSQL8.0以上忘记root密码
    查看>>
    Mysql8.0以上重置初始密码的方法
    查看>>
    mysql8.0新特性-自增变量的持久化
    查看>>
    Mysql8.0注意url变更写法
    查看>>
    Mysql8.0的特性
    查看>>
    MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
    查看>>
    MySQL8修改密码的方法
    查看>>
    Mysql8在Centos上安装后忘记root密码如何重新设置
    查看>>
    Mysql8在Windows上离线安装时忘记root密码
    查看>>
    MySQL8找不到my.ini配置文件以及报sql_mode=only_full_group_by解决方案
    查看>>
    mysql8的安装与卸载
    查看>>
    MySQL8,体验不一样的安装方式!
    查看>>
    MySQL: Host '127.0.0.1' is not allowed to connect to this MySQL server
    查看>>
    Mysql: 对换(替换)两条记录的同一个字段值
    查看>>
    mysql:Can‘t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘解决方法
    查看>>
    MYSQL:基础——3N范式的表结构设计
    查看>>