目前基本实现了导入,注意只能打开含有单个模型的obj文件

四边面模型:

全三角面模型(测试单一材质,自动分了下UV):

这里介绍下obj格式:

obj格式是waveFront推出的一种3D模型格式,可以存放静态模型以及一些诸如曲线的附加信息。

其格式以文本形式存放,所以解析起来比较方便,它的大体格式如下:

# WaveFront *.obj file (generated by CINEMA 4D)

mtllib ./test.mtl

v -100.00000000000000 -100.00000000000000 -100.00000000000000
v -100.00000000000000 100.00000000000000 -100.00000000000000
v 100.00000000000000 -100.00000000000000 -100.00000000000000
v 100.00000000000000 100.00000000000000 -100.00000000000000
v 100.00000000000000 -100.00000000000000 100.00000000000000
v 100.00000000000000 100.00000000000000 100.00000000000000
v -100.00000000000000 -100.00000000000000 100.00000000000000
v -100.00000000000000 100.00000000000000 100.00000000000000
# vertices vn 0.00000000000000 0.00000000000000 -1.00000000000000
vn 1.00000000000000 0.00000000000000 0.00000000000000
vn 0.00000000000000 0.00000000000000 1.00000000000000
vn -1.00000000000000 0.00000000000000 0.00000000000000
vn 0.00000000000000 1.00000000000000 0.00000000000000
vn 0.00000000000000 -1.00000000000000 0.00000000000000
# normals vt 0.00000000000000 -1.00000000000000 0.00000000000000
vt 0.00000000000000 -0.00000000000000 0.00000000000000
vt 1.00000000000000 -0.00000000000000 0.00000000000000
vt 1.00000000000000 -1.00000000000000 0.00000000000000
# texture coordinates o Cube
usemtl default
f // // // //
f // // // //
f // // // //
f // // // //
f // // // //
f // // // //

Cube(Obj)

常用类型:

#开头表示注释

v表示顶点

vn表示法线,可以共用法线

vt表示uv坐标

f表示一个面,比如参数1/4/1,表示顶点索引/UV索引/法线索引

下面贴一下工具类的代码:

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic; namespace Hont
{
public class ObjFormatAnalyzer
{
public struct Vector
{
public float X;
public float Y;
public float Z;
} public struct FacePoint
{
public int VertexIndex;
public int TextureIndex;
public int NormalIndex;
} public struct Face
{
public FacePoint[] Points;
public bool IsQuad;
} public Vector[] VertexArr;
public Vector[] VertexNormalArr;
public Vector[] VertexTextureArr;
public Face[] FaceArr; public void Analyze(string content)
{
content = content.Replace('\r', ' ').Replace('\t', ' '); var lines = content.Split('\n');
var vertexList = new List<Vector>();
var vertexNormalList = new List<Vector>();
var vertexTextureList = new List<Vector>();
var faceList = new List<Face>(); for (int i = ; i < lines.Length; i++)
{
var currentLine = lines[i]; if (currentLine.Contains("#") || currentLine.Length == )
{
continue;
} if (currentLine.Contains("v "))
{
var splitInfo = currentLine.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
vertexList.Add(new Vector() { X = float.Parse(splitInfo[]), Y = float.Parse(splitInfo[]), Z = float.Parse(splitInfo[]) });
}
else if (currentLine.Contains("vt "))
{
var splitInfo = currentLine.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
vertexTextureList.Add(new Vector() { X = splitInfo.Length > ? float.Parse(splitInfo[]) : , Y = splitInfo.Length > ? float.Parse(splitInfo[]) : , Z = splitInfo.Length > ? float.Parse(splitInfo[]) : });
}
else if (currentLine.Contains("vn "))
{
var splitInfo = currentLine.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
vertexNormalList.Add(new Vector() { X = float.Parse(splitInfo[]), Y = float.Parse(splitInfo[]), Z = float.Parse(splitInfo[]) });
}
else if (currentLine.Contains("f "))
{
Func<string, int> tryParse = (inArg) =>
{
var outValue = -;
return int.TryParse(inArg, out outValue) ? outValue : ;
}; var splitInfo = currentLine.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
var isQuad = splitInfo.Length > ;
var face1 = splitInfo[].Split('/');
var face2 = splitInfo[].Split('/');
var face3 = splitInfo[].Split('/');
var face4 = isQuad ? splitInfo[].Split('/') : null;
var face = new Face();
face.Points = new FacePoint[];
face.Points[] = new FacePoint() { VertexIndex = tryParse(face1[]), TextureIndex = tryParse(face1[]), NormalIndex = tryParse(face1[]) };
face.Points[] = new FacePoint() { VertexIndex = tryParse(face2[]), TextureIndex = tryParse(face2[]), NormalIndex = tryParse(face2[]) };
face.Points[] = new FacePoint() { VertexIndex = tryParse(face3[]), TextureIndex = tryParse(face3[]), NormalIndex = tryParse(face3[]) };
face.Points[] = isQuad ? new FacePoint() { VertexIndex = tryParse(face4[]), TextureIndex = tryParse(face4[]), NormalIndex = tryParse(face4[]) } : default(FacePoint);
face.IsQuad = isQuad; faceList.Add(face);
}
} VertexArr = vertexList.ToArray();
VertexNormalArr = vertexNormalList.ToArray();
VertexTextureArr = vertexTextureList.ToArray();
FaceArr = faceList.ToArray();
}
}
}

ObjFormatAnalyzer

工厂类,目前只有输出GameObject:

using UnityEngine;
using System.IO;
using System.Linq;
using System.Collections;
using System.Collections.Generic; namespace Hont
{
public static class ObjFormatAnalyzerFactory
{
public static GameObject AnalyzeToGameObject(string objFilePath)
{
if (!File.Exists(objFilePath)) return null; var objFormatAnalyzer = new ObjFormatAnalyzer(); objFormatAnalyzer.Analyze(File.ReadAllText(objFilePath)); var go = new GameObject();
var meshRenderer = go.AddComponent<MeshRenderer>();
var meshFilter = go.AddComponent<MeshFilter>(); var mesh = new Mesh(); var sourceVertexArr = objFormatAnalyzer.VertexArr;
var sourceUVArr = objFormatAnalyzer.VertexTextureArr;
var faceArr = objFormatAnalyzer.FaceArr;
var notQuadFaceArr = objFormatAnalyzer.FaceArr.Where(m => !m.IsQuad).ToArray();
var quadFaceArr = objFormatAnalyzer.FaceArr.Where(m => m.IsQuad).ToArray();
var vertexList = new List<Vector3>();
var uvList = new List<Vector2>(); var triangles = new int[notQuadFaceArr.Length * + quadFaceArr.Length * ];
for (int i = , j = ; i < faceArr.Length; i++)
{
var currentFace = faceArr[i]; triangles[j] = j;
triangles[j + ] = j + ;
triangles[j + ] = j + ; var vec = sourceVertexArr[currentFace.Points[].VertexIndex - ];
vertexList.Add(new Vector3(vec.X, vec.Y, vec.Z)); var uv = sourceUVArr[currentFace.Points[].TextureIndex - ];
uvList.Add(new Vector2(uv.X, uv.Y)); vec = sourceVertexArr[currentFace.Points[].VertexIndex - ];
vertexList.Add(new Vector3(vec.X, vec.Y, vec.Z)); uv = sourceUVArr[currentFace.Points[].TextureIndex - ];
uvList.Add(new Vector2(uv.X, uv.Y)); vec = sourceVertexArr[currentFace.Points[].VertexIndex - ];
vertexList.Add(new Vector3(vec.X, vec.Y, vec.Z)); uv = sourceUVArr[currentFace.Points[].TextureIndex - ];
uvList.Add(new Vector2(uv.X, uv.Y)); if (currentFace.IsQuad)
{
triangles[j + ] = j + ;
triangles[j + ] = j + ;
triangles[j + ] = j + ;
j += ; vec = sourceVertexArr[currentFace.Points[].VertexIndex - ];
vertexList.Add(new Vector3(vec.X, vec.Y, vec.Z)); uv = sourceUVArr[currentFace.Points[].TextureIndex - ];
uvList.Add(new Vector2(uv.X, uv.Y)); vec = sourceVertexArr[currentFace.Points[].VertexIndex - ];
vertexList.Add(new Vector3(vec.X, vec.Y, vec.Z)); uv = sourceUVArr[currentFace.Points[].TextureIndex - ];
uvList.Add(new Vector2(uv.X, uv.Y)); vec = sourceVertexArr[currentFace.Points[].VertexIndex - ];
vertexList.Add(new Vector3(vec.X, vec.Y, vec.Z)); uv = sourceUVArr[currentFace.Points[].TextureIndex - ];
uvList.Add(new Vector2(uv.X, uv.Y));
} j += ;
} mesh.vertices = vertexList.ToArray();
mesh.uv = uvList.ToArray();
mesh.triangles = triangles; meshFilter.mesh = mesh;
meshRenderer.material = new Material(Shader.Find("Standard")); return go;
}
}
}

ObjFormatAnalyzerFactory

测试使用脚本:

public class ObjFormatAnalyzerTest : MonoBehaviour
{
void Start()
{
var go = ObjFormatAnalyzerFactory.AnalyzeToGameObject(@"D:\TestObj\centaur.obj"); WWW www = new WWW("file:/D:/TestObj/texture.jpg"); while (!www.isDone) { } go.GetComponent<MeshRenderer>().material.mainTexture = www.texture;
}
}

然后挂载运行即可。

目前可能还有点小问题,因为没有实现材质的绑定,所以只能支持单一材质。

Obj格式解析以及在Unity3D下导入测试的更多相关文章

  1. flash画图API:解析obj格式

    又到了周末的时间,依旧的例牌菜.只是近期在和一些同事交流下,学习了一些新的知识.过去一直没有明确的问题,如今总算有点感觉了. 平时编程偶然会用到数学,特别是在做3d的时候.相信看过rokix的3d,那 ...

  2. DirectX11 With Windows SDK--19 模型加载:obj格式的读取及使用二进制文件提升读取效率

    前言 一个模型通常是由三个部分组成:网格.纹理.材质.在一开始的时候,我们是通过Geometry类来生成简单几何体的网格.但现在我们需要寻找合适的方式去表述一个复杂的网格,而且包含网格的文件类型多种多 ...

  3. Unity NavMesh 格式 解析 分析 对比 Recast Navigation

    工具软件 Excel Nodepad++ Sublime Unity 5.4 / 5.6 VS RecastDemo CodeBlocks 分析过程以Unity项目-Demo13为例 一. 创建测试模 ...

  4. 【腾讯Bugly干货分享】手游热更新方案xLua开源:Unity3D下Lua编程解决方案

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/2bY7A6ihK9IMcA0bOFyB-Q 导语 xL ...

  5. Unity3d 下websocket的使用

    今天介绍一下如何在Unity3D下使用WebSocket. 首先介绍一下什么是websocket,以及与socket,和http的区别与联系,然后介绍一下websocket的一些开源的项目. WebS ...

  6. 腾讯开源手游热更新方案,Unity3D下的Lua编程

    原文:http://www.sohu.com/a/123334175_355140 作者|车雄生 编辑|木环 腾讯最近在开源方面的动作不断:先是微信跨平台基础组件Mars宣布开源,腾讯手游又于近期开源 ...

  7. [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ格式分析

    [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ文件格式分析作者:yuezang - iTyran     在iOS的3D开发中常常需要导入通过3DS MAX之类 ...

  8. plist文件、NSUserDefault 对文件进行存储的类、json格式解析

    ========================== 文件操作 ========================== Δ一 .plist文件 .plist文件是一个属性字典数组的一个文件: .plis ...

  9. IE8下导入EXCEL数据传到客户端以附件下载

    IE8下导入EXCEL数据传到客户端以附件下载方式出现,而不显示数据,解决方法:以text/html格式返回. HttpResponseMessage message = new HttpRespon ...

随机推荐

  1. Mybatis-Plugin插件学习使用方法

    以下教程仅供学习使用,针对于IntelliJ Idea 15中的Mybatis Plugin插件. 作者博客中的教程:http://myoss.github.io/2016/MyBatis-Plugi ...

  2. mysql 查看是否存在某一张表

    判断表是否存在 SELECT table_name FROM information_schema.TABLES WHERE table_name ='yourname'; 或者 SHOW TABLE ...

  3. Android Support Font 安卓系统支持字体(配图)

    测试了一台安卓机器,发现所有字体显示都一样.

  4. 转:python webdriver API 之操作测试对象

    一般来说,所有有趣的操作与页面交互都将通过 WebElement 接口,包括上一节中介绍的对象定位,以及本节中需要介绍的常对象操作.webdriver 中比较常用的操作元素的方法有下面几个: cle ...

  5. for穷举

    穷举:把所有可能的情况都走一遍,使用if条件筛选出来满足的条件的情况.(把所有的可能性都列举一边) 迭代:从初始情况按照规律不断求解中间情况,最终推导出结果.f foreach  专为数组定义的一种命 ...

  6. css3:与背景的相关样式

    1. (1)background-origin : border-box | padding-box | content-box;(设置元素背景图片的原始起始位置.) //需要注意的是,如果背景不是n ...

  7. fackbook的Fresco的多种图片加载方法以及解码过程

    上篇文章中我们提到了图片加载其实是用了三条线程,如果没看过的同学可以先了解下这里. fackbook的Fresco的Image Pipeline以及自身的缓存机制 那么今天我们就来探索一下如何在代码中 ...

  8. paper 24 :matlab的cat函数

    cat:用来联结数组 用法:C = cat(dim, A, B)       按dim来联结A和B两个数组. C = cat(dim, A1, A2, A3, ...)    按dim联结所有输入的数 ...

  9. AR 应收 表

    AR 应收 应收事务处理相关表 SELECT * FROM ar.ar_batches_all;                  --事务处理批 SELECT * FROM ar.ra_custom ...

  10. 夺命雷公狗—angularjs—6—单条数据的遍历

    我们在实际的工作中常常会处理到一些数据的遍历,这些数据都是后端传到前端的,有些公司会让前端帮忙处理一点遍历的工作,废话不多说,直接上代: <!doctype html> <html ...