博客
关于我
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一直显示正在启动
    查看>>
    MySQL一站到底!华为首发MySQL进阶宝典,基础+优化+源码+架构+实战五飞
    查看>>
    MySQL万字总结!超详细!
    查看>>
    Mysql下载以及安装(新手入门,超详细)
    查看>>
    MySQL不会性能调优?看看这份清华架构师编写的MySQL性能优化手册吧
    查看>>
    MySQL不同字符集及排序规则详解:业务场景下的最佳选
    查看>>
    Mysql不同官方版本对比
    查看>>
    MySQL与Informix数据库中的同义表创建:深入解析与比较
    查看>>
    mysql与mem_细说 MySQL 之 MEM_ROOT
    查看>>
    MySQL与Oracle的数据迁移注意事项,另附转换工具链接
    查看>>
    mysql丢失更新问题
    查看>>
    MySQL两千万数据优化&迁移
    查看>>
    MySql中 delimiter 详解
    查看>>
    MYSQL中 find_in_set() 函数用法详解
    查看>>