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

本文共 4990 字,大约阅读时间需要 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/

    你可能感兴趣的文章
    Objective-C实现double hash双哈希算法(附完整源码)
    查看>>
    Objective-C实现double linear search recursion双线性搜索递归算法(附完整源码)
    查看>>
    Objective-C实现double linear search 双线性搜索算法(附完整源码)
    查看>>
    Objective-C实现double sort双重排序算法(附完整源码)
    查看>>
    Objective-C实现DoublyLinkedList双链表的算法(附完整源码)
    查看>>
    Objective-C实现DoublyLinkedList双链表算法(附完整源码)
    查看>>
    Objective-C实现DPLL(davisb putnamb logemannb loveland)算法(附完整源码)
    查看>>
    Objective-C实现DWT离散小波变换(附完整源码)
    查看>>
    Objective-C实现Edmonds-Karp算法(附完整源码)
    查看>>
    Objective-C实现EEMD算法(附完整源码)
    查看>>
    Objective-C实现elgamal 密钥生成器算法(附完整源码)
    查看>>
    Objective-C实现EM算法(附完整源码)
    查看>>
    Objective-C实现EM算法(附完整源码)
    查看>>
    Objective-C实现entropy熵算法(附完整源码)
    查看>>
    Objective-C实现euclidean distance欧式距离算法(附完整源码)
    查看>>
    Objective-C实现Euclidean GCD欧几里得最大公约数算法(附完整源码)
    查看>>
    Objective-C实现euclideanDistance欧氏距离算法(附完整源码)
    查看>>
    Objective-C实现euler method欧拉法算法(附完整源码)
    查看>>
    Objective-C实现euler modified变形欧拉法算法(附完整源码)
    查看>>
    Objective-C实现eulerianPath欧拉路径算法(附完整源码)
    查看>>