C# OBJ模型解析的封装(网上看到的保留一份)
/// <author>Lukas Eibensteiner</author>
/// <date>19.02.2013</date>
/// <summary>Example of a Wavefront OBJ 3D model importer</summary> using SlimDX;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq; namespace Games
{
/// <summary>
/// Class for reading a 3D mesh in the Wavefront OBJ format from a stream.
/// </summary>
public class WavefrontReader
{
/// <summary>
/// Enum for describing the semantic meaning of a line in an OBJ file.
/// </summary>
private enum DataType
{
/// <summary>
/// The line contains nothing or has no or an undefined keyword.
/// </summary>
Empty, /// <summary>
/// The line contains a comment.
/// </summary>
Comment, /// <summary>
/// The line contains a group definition.
/// </summary>
Group, /// <summary>
/// The line contains a smoothing group definitio.
/// </summary>
SmoothingGroup, /// <summary>
/// The line contains a position vector definition.
/// </summary>
Position, /// <summary>
/// The line contains a normal vector definition.
/// </summary>
Normal, /// <summary>
/// The line contains a texture coordinate definition.
/// </summary>
TexCoord, /// <summary>
/// The line contains a face definition.
/// </summary>
Face,
} // Dictionary mapping the DataType enumeration to the corresponding keyword.
private static Dictionary<DataType, string> Keywords
{
get
{
return new Dictionary<DataType, string>()
{
{ DataType.Comment, "#" },
{ DataType.Group, "g" },
{ DataType.SmoothingGroup, "s" },
{ DataType.Position, "v" },
{ DataType.TexCoord, "vt" },
{ DataType.Normal, "vn" },
{ DataType.Face, "f" },
};
}
} /// <summary>
/// Reads a WavefrontObject instance from the stream.
/// </summary>
/// <param name="stream">
/// Stream containing the OBJ file content.
/// </param>
/// <exception cref="ArgumentNullException">
/// <paramref name="stream"/> is <c>null</c>.
/// </exception>
/// <exception cref="IOException">
/// Error while reading from the stream.
/// </exception>
public WavefrontObject Read(Stream stream)
{
if (stream == null)
throw new ArgumentNullException("stream"); // Create the stream reader for the file
var reader = new StreamReader(stream); // Store the lines here
var lines = new List<string>(); // Store the current line here
var current = string.Empty; // Read the file line by line and normalize them
while ((current = reader.ReadLine()) != null)
lines.Add(NormalizeLine(current)); // Create empty mesh instance
var obj = new WavefrontObject(); // Iterate over all lines
foreach (string line in lines)
{
// Get line type and content
DataType type = GetType(line);
string content = GetContent(line, type); // Line is a position
if (type == DataType.Position)
obj.Positions.Add(ParseVector3(content)); // Line is a texture coordinate
if (type == DataType.TexCoord)
obj.Texcoords.Add(ParseVector2(content)); // Line is a normal vector
if (type == DataType.Normal)
obj.Normals.Add(ParseVector3(content)); // Line is a mesh sub group
if (type == DataType.Group)
obj.Groups.Add(new WavefrontFaceGroup() { Name = content }); // Line is a polygon
if (type == DataType.Face)
{
// Create the default group for all faces outside a group
if (obj.Groups.Count == 0)
obj.Groups.Add(new WavefrontFaceGroup()); // Add the face to the last group added
obj.Groups.Last().Faces.Add(ParseFace(content));
}
} return obj;
} // Trim beginning and end and collapse all whitespace in a string to single space.
private string NormalizeLine(string line)
{
return System.Text.RegularExpressions.Regex.Replace(line.Trim(), @"\s+", " ");
} // Get the type of data stored in the specified line.
private DataType GetType(string line)
{
// Iterate over the keywords
foreach (var item in Keywords)
{
var type = item.Key;
var keyword = item.Value; // Line starts with current keyword
if (line.ToLower().StartsWith(keyword.ToLower() + " "))
{
// Return current type
return type;
}
} // No type
return DataType.Empty;
} // Remove the keyword from the start of the line and return the result.
// Returns an empty string if the specified type was DataType.Empty.
private string GetContent(string line, DataType type)
{
// If empty return empty string,
// else remove the keyword from the start
return type == DataType.Empty
? string.Empty
: line.Substring(Keywords[type].Length).Trim();
} // Create an array of floats of arbitary length from a string representation,
// where the floats are spearated by whitespace.
private static float[] ParseFloatArray(string str, int count)
{
var floats = new float[count]; var segments = str.Split(' '); for (int i = 0; i < count; i++)
{
if (i < segments.Length)
{
try
{
floats[i] = float.Parse(segments[i], System.Globalization.CultureInfo.InvariantCulture);
}
catch
{
floats[i] = 0;
}
}
} return floats;
} // Parse a 3D vector from a string definition in the form of: 2.0 3.0 1.0
private Vector2 ParseVector2(string str)
{
var components = ParseFloatArray(str, 3); var vec = new Vector2(components[0], components[1]); return components[2] == 0
? vec
: vec / components[2];
} // Parse a 3D vector from a string definition in the form of: 1.0 2.0 3.0 1.0
private Vector3 ParseVector3(string str)
{
var components = ParseFloatArray(str, 4); var vec = new Vector3(components[0], components[1], components[2]); return components[3] == 0
? vec
: vec / components[3];
} // Parse a OBJ face from a string definition.
private WavefrontFace ParseFace(string str)
{
// Split the face definition at whitespace
var segments = str.Split(new Char[0], StringSplitOptions.RemoveEmptyEntries); var vertices = new List<WavefrontVertex>(); // Iterate over the segments
foreach (string segment in segments)
{
// Parse and add the vertex
vertices.Add(ParseVertex(segment));
} // Create and return the face
return new WavefrontFace()
{
Vertices = vertices,
};
} // Parse an OBJ vertex from a string definition in the forms of:
// 1/2/3
// 1//3
// 1/2
// 1
private WavefrontVertex ParseVertex(string str)
{
// Split the string definition at the slash separator
var segments = str.Split('/'); // Store the vertex indices here
var indices = new int[3]; // Iterate 3 times
for (int i = 0; i < 3; i++)
{
// If no segment exists at the location or the segment can not be passed to an integer
// Set the index to zero
if (segments.Length <= i || !int.TryParse(segments[i], out indices[i]))
indices[i] = 0;
} // Create the new vertex
return new WavefrontVertex()
{
Position = indices[0],
Texcoord = indices[1],
Normal = indices[2],
};
}
} /// <summary>
/// Class representing a Wavefront OBJ 3D mesh.
/// </summary>
public class WavefrontObject
{
public WavefrontObject()
{
Groups = new List<WavefrontFaceGroup>();
Positions = new List<Vector3>();
Texcoords = new List<Vector2>();
Normals = new List<Vector3>();
} // Lists containing the vertex components
public List<Vector3> Positions { get; private set; }
public List<Vector2> Texcoords { get; private set; }
public List<Vector3> Normals { get; private set; } // List of sub meshes
public List<WavefrontFaceGroup> Groups { get; private set; }
} /// <summary>
/// Struct representing an Wavefront OBJ face group.
/// </summary>
/// <remarks>
/// Groups contain faces and subdivide a geometry into smaller objects.
/// </remarks>
public class WavefrontFaceGroup
{
public WavefrontFaceGroup()
{
Faces = new List<WavefrontFace>();
} // Name of the sub mesh
public string Name { get; set; } // A list of faces
public List<WavefrontFace> Faces { get; set; } // Get the total number of triangles
public int TriangleCount
{
get
{
var count = 0; foreach (var face in Faces)
count += face.TriangleCount; return count;
}
}
} /// <summary>
/// A struct representing a Wavefront OBJ geometry face.
/// </summary>
/// <remarks>
/// A face is described through a list of OBJ vertices.
/// It can consist of three or more vertices an can therefore be split up
/// into one or more triangles.
/// </remarks>
public struct WavefrontFace
{
public List<WavefrontVertex> Vertices { get; set; } // Number of triangles the face (polygon) consists of
public int TriangleCount
{
get
{
return Vertices.Count - 2;
}
} // Number of vertices
public int VertexCount
{
get { return Vertices.Count; }
}
} /// <summary>
/// A struct representing an Wavefront OBJ vertex.
/// </summary>
/// <remarks>
/// OBJ vertices are indexed vertices so instead of vectors
/// it has an index for the position, texture coordinate and normal.
/// Each of those indices points to a location in a list of vectors.
/// </remarks>
public struct WavefrontVertex
{
public WavefrontVertex(int position, int texcoord, int normal)
: this()
{
Position = position;
Texcoord = texcoord;
Normal = normal;
} // Inidices of the vertex components
public int Position { get; set; }
public int Normal { get; set; }
public int Texcoord { get; set; }
}
}
C# OBJ模型解析的封装(网上看到的保留一份)的更多相关文章
- Obj模型功能完善(物体材质,光照,法线贴图).Cg着色语言+OpenTK+F#实现.
这篇文章给大家讲Obj模型里一些基本功能的完善,包含Cg着色语言,矩阵转换,光照,多重纹理,法线贴图的运用. 在上篇中,我们用GLSL实现了基本的phong光照,这里用Cg着色语言来实现另一钟Blin ...
- OpenGL OBJ模型加载.
在我们前面绘制一个屋,我们可以看到,需要每个立方体一个一个的自己来推并且还要处理位置信息.代码量大并且要时间.现在我们通过加载模型文件的方法来生成模型文件,比较流行的3D模型文件有OBJ,FBX,da ...
- 【Android开发精要笔记】Android组件模型解析
Android组件模型解析 Android中的Mashup 将应用切分成不同类别的组件,通过统一的定位模型和接口标准将他们整合在一起,来共同完成某项任务.在Android的Mashup模式下,每个组件 ...
- ASP.NET路由模型解析
大家好,我又来吹牛逼了 ~-_-~ 转载请注明出处:来自吹牛逼之<ASP.NET路由模型解析> 背景:很多人知道Asp.Net中路由怎么用的,却不知道路由模型内部的运行原理,今天我就给大家 ...
- opengl导入obj模型
在经过查阅各种资料以及各种bug之后,终于成功的实现了导入基本的obj模型. 首相介绍一下什么是obj模型 一.什么是OBJ模型 obj文件实际上是一个文本文档,主要有以下数据,一般可以通过blend ...
- 三维引擎导入obj模型全黑总结
最近有客户试用我们的三维平台,在导入模型的时候,会出现模型全黑和不可见的情况.本文说下全黑的情况. 经过测试,发现可能有如下几种情况. obj 模型没有法线向量 如果obj模型导出的时候没有导出法线向 ...
- 三维引擎导入obj模型不可见总结
最近有客户试用我们的三维平台,在导入模型的时候,会出现模型全黑和不可见的情况.上一篇文章说了全黑的情况.此文说下不可见的情况. 经过测试,发现可能有如下两种情况. 导入的模型不在镜头视野内 导入的模型 ...
- 由于OBJ模型的读取引起的Release无问题Debug卡死问题
有些时候会遇到Release版本正常运行,但是Debug无法运行甚至崩溃,原因有很多种,这里记录一下由于模型文件读取引起的Debug问题. 项目中需要读取一个obj模型文件,30M左右,Debug模式 ...
- Caffe学习笔记(一):Caffe架构及其模型解析
Caffe学习笔记(一):Caffe架构及其模型解析 写在前面:关于caffe平台如何快速搭建以及如何在caffe上进行训练与预测,请参见前面的文章<caffe平台快速搭建:caffe+wind ...
随机推荐
- java中如何修改事务的隔离级别
事务的特性: 原子性(Atomicity)原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生. (多条语句要么都成功,要么都失败.) 一致性(Consistency)事务前后 ...
- 2019年的代码都写完了吗?不如做个Python进度条看看还剩多少
我们都知道,进度条是用来直观展示流程所需时间的优秀工具,以免我们担心流程会突然挂掉,而且我们可以用它来预测代码运行是否正常,借助进度条,每个人都能直观地看到脚本最新的进展情况. 如果你之前没用过进度条 ...
- Spring之IOC、AOP和事务
IOC 什么是IOC?如果你回答:Spring是个IOC容器,实现原理是反射,没了.这样证明你没有真正理解IOC. IOC的意思是控制反转,还有个外号叫依赖注入(DI).为什么起这么晦涩难懂的名字呢? ...
- mabatisplus-update
/** * <p> * 根据 whereEntity 条件,更新记录 * </p> * * @param entity 实体对象 (set 条件值,不能为 null) * @p ...
- linux系统下安装两个或多个tomcat(转)
tomcat不用添加到环境变量中 直接解压两个tomcat 来到第二个tomcat的conf目录下 打开server.xml更改端口: 修改server.xml配置和第一个不同的启动.关闭监听端口 ...
- Python字符串(二)
四.类型转换 1. 基本语法: 类型名(数据) --- 将指定数据转换成指定类型 说明:类型名 -任何python支持的,或者自定的类型都可以数据 -需要转换的对象,类型不同要求可能不一样 2. 转换 ...
- 基于TF-IDF的推荐
仅作学习使用 基于TF-IDF的推荐: 将文档分词 对于每个term,计算词频TF和逆文本指数IDF,形成term的权重 计算项目文档和用户偏好文档的相似度 参考: https://blog.csdn ...
- Django:验证email或者name是否已被注册
灵感: http://blog.csdn.net/xxm524/article/details/48369623 使用表单的dajngo的clean()方法实现
- 十二、js去掉空格_比较字符长度_中英文判断_页面初始化_简体字与繁字体判断
1.去掉字符串前后所有空格 function trimBlank(str){ return str.replace(/(^\s*)|(\s*$)/g, ""); } 2.字符串长度 ...
- 一、什么是Velocity及简单示例
1.velocity简介: velocity是一个java模板引擎技术,任何人可以使用这种简单而又强有力的模板语言去获取java对象. 在使用Velocity进行web开发时,web开发人员和j ...