项目中有个load obj需求,在网上看了很多的例子,也找了几个开源框架,发现其在解析obj与mtl文件上均不完善(其中包括2012年我们几个写的《Android 3D游戏开发技术宝典——OpenGL ES 2.0》)。 比如:
mind3d官方地址与源码: https://code.google.com/archive/p/min3d/ https://github.com/deadmoose/min3d
《Android 3D游戏开发技术宝典——OpenGL ES 2.0》请自行京东
我觉得,项目开发中时间紧张,不应该把时间话费在obj与mtl文件解析上。 所以,打算搞一个兼容性较强obj 3d文件加载库,便于以后项目中再次遇到时,可节省大量项目时间。
对于obj与mtl文件格式不太了解的同学,可参考: http://blog.csdn.net/xiaxl/article/details/76893165
/**
* @author xiaxl
* <p>
* create by xiaxl on 2017.08.09
* 加载材质工具类
*/
public class MtlLoaderUtil {
private static final String TAG = "MtlLoaderUtil";
/**
* 加载材质的方法
*
* @param fname assets的mtl文件路径
* @param res
* @return
*/
public static HashMap<String, MtlData> load(String fname, Resources res) throws Exception {
// 材质数组
HashMap<String, MtlData> mMTLMap = new HashMap<String, MtlData>();
//
if (res == null || TextUtils.isEmpty(fname)) {
return mMTLMap;
}
//
MtlData currMtlData = null;
try {
// 读取assets下文件
InputStream in = res.getAssets().open(fname);
InputStreamReader isr = new InputStreamReader(in);
BufferedReader buffer = new BufferedReader(isr);
// 行数据
String line;
//
while ((line = buffer.readLine()) != null) {
// Skip comments and empty lines.
if (line.length() == 0 || line.charAt(0) == '#') {
continue;
}
//
StringTokenizer parts = new StringTokenizer(line, " ");
int numTokens = parts.countTokens();
if (numTokens == 0) {
continue;
}
//
String type = parts.nextToken();
type = type.replaceAll("\\t", "");
type = type.replaceAll(" ", "");
// 定义一个名为 'xxx'的材质
if (type.equals(MtlLoaderUtil.NEWMTL)) {
String name = parts.hasMoreTokens() ? parts.nextToken() : "def";
// 将上一个对象加入到列表中
if (currMtlData != null) {
mMTLMap.put(currMtlData.name, currMtlData);
}
// 创建材质对象
currMtlData = new MtlData();
// 材质对象名称
currMtlData.name = name;
}
// 环境光
else if (type.equals(MtlLoaderUtil.KA)) {
currMtlData.Ka_Color = getColorFromParts(parts);
}
// 散射光
else if (type.equals(MtlLoaderUtil.KD)) {
currMtlData.Kd_Color = getColorFromParts(parts);
}
// 镜面光
else if (type.equals(MtlLoaderUtil.KS)) {
currMtlData.Ks_Color = getColorFromParts(parts);
}
// 高光调整参数
else if (type.equals(MtlLoaderUtil.NS)) {
String ns = parts.nextToken();
currMtlData.ns = Float.parseFloat(ns);
}
// 溶解度,为0时完全透明,1完全不透明
//else if (type.equals(MtlLoaderUtil.D) || type.equals(MtlLoaderUtil.TR)) {
else if (type.equals(MtlLoaderUtil.D)) {
currMtlData.alpha = Float.parseFloat(parts.nextToken());
}
// map_Ka,map_Kd,map_Ks:材质的环境(ambient),散射(diffuse)和镜面(specular)贴图
else if (type.equals(MtlLoaderUtil.MAP_KA)) {
currMtlData.Ka_Texture = parts.nextToken();
} else if (type.equals(MtlLoaderUtil.MAP_KD)) {
currMtlData.Kd_Texture = parts.nextToken();
} else if (type.equals(MtlLoaderUtil.MAP_KS)) {
currMtlData.Ks_ColorTexture = parts.nextToken();
} else if (type.equals(MtlLoaderUtil.MAP_NS)) {
currMtlData.Ns_Texture = parts.nextToken();
} else if (type.equals(MtlLoaderUtil.MAP_D) || type.equals(MtlLoaderUtil.MAP_TR)) {
currMtlData.alphaTexture = parts.nextToken();
} else if (type.equals(MtlLoaderUtil.MAP_BUMP)) {
currMtlData.bumpTexture = parts.nextToken();
}
}
if (currMtlData != null) {
mMTLMap.put(currMtlData.name, currMtlData);
}
buffer.close();
} catch (Exception e) {
Log.e(TAG, e.getMessage());
throw new Exception(e.getMessage(), e.getCause());
}
return mMTLMap;
}
//####################################################################################
/**
* 材质需解析字段
*/
// 定义一个名为 'xxx'的材质
private static final String NEWMTL = "newmtl";
// 材质的环境光(ambient color)
private static final String KA = "Ka";
// 散射光(diffuse color)用Kd
private static final String KD = "Kd";
// 镜面光(specular color)用Ks
private static final String KS = "Ks";
// 反射指数 定义了反射高光度。该值越高则高光越密集,一般取值范围在0~1000。
private static final String NS = "Ns";
// 渐隐指数描述 参数factor表示物体融入背景的数量,取值范围为0.0~1.0,取值为1.0表示完全不透明,取值为0.0时表示完全透明。
private static final String D = "d";
// 滤光透射率
private static final String TR = "Tr";
// map_Ka,map_Kd,map_Ks:材质的环境(ambient),散射(diffuse)和镜面(specular)贴图
private static final String MAP_KA = "map_Ka";
private static final String MAP_KD = "map_Kd";
private static final String MAP_KS = "map_Ks";
private static final String MAP_NS = "map_Ns";
private static final String MAP_D = "map_d";
private static final String MAP_TR = "map_Tr";
private static final String MAP_BUMP = "map_Bump";
public static class MtlData {
// 材质对象名称
public String name;
// 环境光
public int Ka_Color;
// 散射光
public int Kd_Color;
// 镜面光
public int Ks_Color;
// 高光调整参数
public float ns;
// 溶解度,为0时完全透明,1完全不透明
public float alpha = 1f;
// map_Ka,map_Kd,map_Ks:材质的环境(ambient),散射(diffuse)和镜面(specular)贴图
public String Ka_Texture;
public String Kd_Texture;
public String Ks_ColorTexture;
public String Ns_Texture;
public String alphaTexture;
public String bumpTexture;
}
//####################################################################################
/**
* 返回一个oxffffffff格式的颜色值
*
* @param parts
* @return
*/
private static int getColorFromParts(StringTokenizer parts) {
int r = (int) (Float.parseFloat(parts.nextToken()) * 255f);
int g = (int) (Float.parseFloat(parts.nextToken()) * 255f);
int b = (int) (Float.parseFloat(parts.nextToken()) * 255f);
return Color.rgb(r, g, b);
}
}
相关阅读:
opengl es 2.0中加载.obj 与 .mtl(下篇)
本文来自网易实践者社区,经作者夏学良授权发布。