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 ...
随机推荐
- Mybatis-Plugin插件学习使用方法
以下教程仅供学习使用,针对于IntelliJ Idea 15中的Mybatis Plugin插件. 作者博客中的教程:http://myoss.github.io/2016/MyBatis-Plugi ...
- mysql 查看是否存在某一张表
判断表是否存在 SELECT table_name FROM information_schema.TABLES WHERE table_name ='yourname'; 或者 SHOW TABLE ...
- Android Support Font 安卓系统支持字体(配图)
测试了一台安卓机器,发现所有字体显示都一样.
- 转:python webdriver API 之操作测试对象
一般来说,所有有趣的操作与页面交互都将通过 WebElement 接口,包括上一节中介绍的对象定位,以及本节中需要介绍的常对象操作.webdriver 中比较常用的操作元素的方法有下面几个: cle ...
- for穷举
穷举:把所有可能的情况都走一遍,使用if条件筛选出来满足的条件的情况.(把所有的可能性都列举一边) 迭代:从初始情况按照规律不断求解中间情况,最终推导出结果.f foreach 专为数组定义的一种命 ...
- css3:与背景的相关样式
1. (1)background-origin : border-box | padding-box | content-box;(设置元素背景图片的原始起始位置.) //需要注意的是,如果背景不是n ...
- fackbook的Fresco的多种图片加载方法以及解码过程
上篇文章中我们提到了图片加载其实是用了三条线程,如果没看过的同学可以先了解下这里. fackbook的Fresco的Image Pipeline以及自身的缓存机制 那么今天我们就来探索一下如何在代码中 ...
- paper 24 :matlab的cat函数
cat:用来联结数组 用法:C = cat(dim, A, B) 按dim来联结A和B两个数组. C = cat(dim, A1, A2, A3, ...) 按dim联结所有输入的数 ...
- AR 应收 表
AR 应收 应收事务处理相关表 SELECT * FROM ar.ar_batches_all; --事务处理批 SELECT * FROM ar.ra_custom ...
- 夺命雷公狗—angularjs—6—单条数据的遍历
我们在实际的工作中常常会处理到一些数据的遍历,这些数据都是后端传到前端的,有些公司会让前端帮忙处理一点遍历的工作,废话不多说,直接上代: <!doctype html> <html ...