在Android OpenGLES2.0(十四)——Obj格式3D模型加载中实现了Obj格式的3D模型的加载,加载的是一个没有贴图,没有光照处理的帽子,为了呈现出立体效果,“手动”加了光照,拥有贴图的纹理及光照又该怎么加载呢?
本篇博客例子中加载的是一个卡通形象皮卡丘,资源是在网上随便找的一个。加载出来如图所示: 
obj内容格式如下:
# Wavefront OBJ file# Exported by Misfit Model 3D 1.3.8# Thu Sep 27 20:02:52 2012mtllib pikachu.mtl# 191 Verticesv 34.493484 75.31411 -39.308891v 27.34606 45.516556 -47.155548#...省略若干行vt 0.859513 0.676464vt 0.769048 0.0597#...省略若干行vn -0.068504 -0.433852 -0.898376vn 0.422088 -0.855411 -0.30019#...省略若干行usemtl pikageno DrawCall_25g DrawCall_25f 2/1/1 1/2/2 3/3/3f 1/4/4 2/5/5 4/6/6#...省略若干行usemtl pikageno DrawCall_262g DrawCall_262f 2/58/58 3/59/59 17/60/60f 2/61/61 17/62/62 6/63/63#...省略若干行mtl文件内容格式如下:
# Material file for pikachu.objnewmtl eye Ns 0 d 1 illum 2 Kd 0.8 0.8 0.8 Ks 0.0 0.0 0.0 Ka 0.2 0.2 0.2 map_Kd eye1.pngnewmtl mouth Ns 0 d 1 illum 2 Kd 0.8 0.8 0.8 Ks 0.0 0.0 0.0 Ka 0.2 0.2 0.2 map_Kd mouth1.pngnewmtl pikagen Ns 0 d 1 illum 2 Kd 0.8 0.8 0.8 Ks 0.0 0.0 0.0 Ka 0.2 0.2 0.2 map_Kd pikagen.png关于Obj的内容格式,在上篇博客中已经做了总结,本篇博客中使用的obj,可以看到f后面的不再跟的是4个数字,而是f 2/58/58 3/59/59 17/60/60这种样子的三组数,每一组都表示为顶点坐标索引/贴图坐标点索引/顶点法线索引,三个顶点组成一个三角形。而头部的mtllib pikachu.mtl则指明使用的材质库。 而mtl格式文件中,主要数据类型为:
模型加载和之前的模型加载大同小异,不同的是,这次我们需要将模型的贴图坐标、顶点法线也一起加载,并传入到shader中。其他参数,有的自然也要取到。 模型加载以obj文件为入口,解析obj文件,从中获取到mtl文件相对路径,然后解析mtl文件。将材质库拆分为诸多的单一材质。obj对象的 加载,根据具使用材质不同来分解为多个3D模型。具体加载过程如下:
顶点着色器
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;}完成了以上准备工作,就可以调用readMultiObj方法,将obj文件读成一个或多个带有各项参数的3D模型类,然后将每一个3D模型的参数传入shader中,进而进行渲染:
OK,至此大功告成。
所有的代码全部在一个项目中,托管在Github上——Android OpenGLES 2.0系列博客的Demo
欢迎转载,转载请保留文章出处。湖广午王的博客[http://blog.csdn.net/junzia/article/details/58272305]
新闻热点
疑难解答