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

    你可能感兴趣的文章
    Open WebUI 忘了登入密码怎么办?
    查看>>
    open-vm-tools-dkms : 依赖: open-vm-tools (>= 2:9.4.0-1280544-5ubuntu3) 但是它将不会被安装
    查看>>
    open3d-Dll缺失,未找到指定模块解决
    查看>>
    Openbox-桌面图标设置
    查看>>
    opencart出现no such file or dictionary
    查看>>
    opencv Mat push_back
    查看>>
    opencv videocapture读取视频cap.isOpened 输出总是false
    查看>>
    opencv waitKey() 函数理解及应用
    查看>>
    OpenCV 中的图像转换
    查看>>
    OpenCV 在 Linux 上的 python 与 anaconda 无法正常工作.收到未实现 cv2.imshow() 的错误
    查看>>
    Opencv 完美配置攻略 2014 (Win8.1 + Opencv 2.4.8 + VS 2013)上
    查看>>
    opencv 模板匹配, 已解决模板过大程序不工作的bug
    查看>>
    OpenCV 错误:(-215)size.width>0 &&函数imshow中的size.height>0
    查看>>
    opencv&Python——多种边缘检测
    查看>>
    opencv&python——高通滤波器和低通滤波器
    查看>>
    OpenCV-Python接口、cv和cv2的性能比较
    查看>>
    opencv1-加载、修改、保存图像
    查看>>
    opencv10-形态学操作
    查看>>
    opencv11-提取水平直线和垂直直线
    查看>>
    opencv12-图像金字塔
    查看>>