Obj格式解析以及在Unity3D下导入测试
目前基本实现了导入,注意只能打开含有单个模型的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下导入测试的更多相关文章
- flash画图API:解析obj格式
又到了周末的时间,依旧的例牌菜.只是近期在和一些同事交流下,学习了一些新的知识.过去一直没有明确的问题,如今总算有点感觉了. 平时编程偶然会用到数学,特别是在做3d的时候.相信看过rokix的3d,那 ...
- DirectX11 With Windows SDK--19 模型加载:obj格式的读取及使用二进制文件提升读取效率
前言 一个模型通常是由三个部分组成:网格.纹理.材质.在一开始的时候,我们是通过Geometry类来生成简单几何体的网格.但现在我们需要寻找合适的方式去表述一个复杂的网格,而且包含网格的文件类型多种多 ...
- Unity NavMesh 格式 解析 分析 对比 Recast Navigation
工具软件 Excel Nodepad++ Sublime Unity 5.4 / 5.6 VS RecastDemo CodeBlocks 分析过程以Unity项目-Demo13为例 一. 创建测试模 ...
- 【腾讯Bugly干货分享】手游热更新方案xLua开源:Unity3D下Lua编程解决方案
本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/2bY7A6ihK9IMcA0bOFyB-Q 导语 xL ...
- Unity3d 下websocket的使用
今天介绍一下如何在Unity3D下使用WebSocket. 首先介绍一下什么是websocket,以及与socket,和http的区别与联系,然后介绍一下websocket的一些开源的项目. WebS ...
- 腾讯开源手游热更新方案,Unity3D下的Lua编程
原文:http://www.sohu.com/a/123334175_355140 作者|车雄生 编辑|木环 腾讯最近在开源方面的动作不断:先是微信跨平台基础组件Mars宣布开源,腾讯手游又于近期开源 ...
- [iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ格式分析
[iTyran原创]iPhone中OpenGL ES显示3DS MAX模型之一:OBJ文件格式分析作者:yuezang - iTyran 在iOS的3D开发中常常需要导入通过3DS MAX之类 ...
- plist文件、NSUserDefault 对文件进行存储的类、json格式解析
========================== 文件操作 ========================== Δ一 .plist文件 .plist文件是一个属性字典数组的一个文件: .plis ...
- IE8下导入EXCEL数据传到客户端以附件下载
IE8下导入EXCEL数据传到客户端以附件下载方式出现,而不显示数据,解决方法:以text/html格式返回. HttpResponseMessage message = new HttpRespon ...
随机推荐
- codeforces 520 Two Buttons
http://codeforces.com/problemset/problem/520/B B. Two Buttons time limit per test 2 seconds memory l ...
- ACM之Java速成(3)
ACM中Java.大数处理 先上个代码: import java.math.*; import java.util.*; class Main{ public static void main(Str ...
- 数据库 SQL基础
数据库是用来存取数据的. 数据库类型: ACESS(比较小,存储少) SQL SERVER (.net) MySQL Oracle(java) 数据库:服务.界面 服务是可以操作的后台的程序. 界面是 ...
- Spark on Mesos部署
一.Mesos的安装和部署 1.下载mesos源码和依赖包 部署环境 centOS 6.6 mesos-0.21.0 spark-1.4.1 因为mesos官方只提供源码,所以必须要自己进行编译安装使 ...
- oracle的用户
1:创建用户 create user zhaoyb identified by zhaoyb default tablespace HUAPUSALEDB create user 用户名 identi ...
- 夺命雷公狗ThinkPHP项目之----企业网站27之网站前台单页的完成(从百度编辑器里面取出文章数据)
我们的单页面里主要是为了可以取出文章分类表的栏目内容,废话先不说, 我们的实现要点: 1...获取get过来的栏目cate_id 2...然后用条件查询栏目表 <?php namespace H ...
- 夺命雷公狗---微信开发54----微信js-sdk接口开发(1)之快速入门
js-sdk基本介绍 除去服务号的九大接口外,微信提供了JS-SDK接口,所谓JS-SDK接口也就是在网页中使用javascript来更改网页设置, (比如隐藏右上角的菜单)获取用户状态(比如地理位置 ...
- Mysql 的存储引擎,myisam和innodb的区别
MyISAM 是非事务的存储引擎,innodb是支持事务的存储引擎. innodb的引擎比较适合于插入和更新操作比较多的应用,而MyISAM 则适合用于频繁查询的应用 . MyISAM --表锁,in ...
- CSS 文字阴影(text-shadow)怎么用
textShadow="1px 1px 1px #ff0000" textShadow="水平位移 垂直位移 模糊半径 阴影颜色"
- 关于mac book 的启动选项
苹果电脑是用EFI的,没有BIOS,唯一可以设置的是开机的启动选项.可以在基于 Intel 的 Mac 电脑上使用下列启动键组合启动时按住 C 键——从可启动 CD 或 DVD 光盘启动,如随机附带的 ...