我正在尝试理解一个obj文件,所以我可以将其分解为导入。现在我的样本是一个简单的金字塔,用3ds max设计。教程中出现了一些小错误。
到目前为止,我理解了一下,但这些都正常加载:
v is vertex(point in space),
vn is vertex normal(don't understand why needed) but imported ok
vt is vertex texture
但文件中的下一个是f& s,像这样:
s 4
f 1/1/1 2/2/1 3/3/1
s 2
f 1/1/2 3/4/2 4/5/2
首先,我没有真正得到s
是什么以及为什么它以指数方式递增?
更重要的是,根据wikki的说法,我没有得到f
的细分:
f v1/vt1/vn1
对我而言,v1
是顶点,vt
是纹理,vn
是正常的,但为什么它们会在文件中重复?所以我认为我的猜测是错误的。
总的来说我的问题是我的加载对象能够填充除了faces之外的所有东西,除非faces与文件底部的多边形相同,然后是0,但这也没有意义!
请解决我的困惑,谢谢!
这里是代码&文件:
[代码]
public static ObjVolume LoadFromString(string obj)
{
// Seperate lines from the file
List<String> lines = new List<string>(obj.Split('\n'));
// Lists to hold model data
List<Vector3> verts = new List<Vector3>();
List<Vector3> colors = new List<Vector3>();
List<Vector2> texs = new List<Vector2>();
List<Tuple<int, int, int>> faces = new List<Tuple<int, int, int>>();
// Read file line by line
foreach (String line in lines)
{
if (line.StartsWith("v ")) // Vertex definition
{
// Cut off beginning of line
String temp = line.Substring(2);
temp.TrimStart( );
Vector3 vec = new Vector3();
if (temp.Count((char c) => c == ' ') == 3) // Check if there's enough elements for a vertex
{
String[] vertparts = temp.Split(' ');
vertparts[3].Replace("\r","");
// Attempt to parse each part of the vertice
bool success = float.TryParse(vertparts[1], out vec.X);
success |= float.TryParse(vertparts[2], out vec.Y);
success |= float.TryParse(vertparts[3], out vec.Z);
// Dummy color/texture coordinates for now
colors.Add(new Vector3((float)Math.Sin(vec.Z), (float)Math.Sin(vec.Z), (float)Math.Sin(vec.Z)));
texs.Add(new Vector2((float)Math.Sin(vec.Z), (float)Math.Sin(vec.Z)));
// If any of the parses failed, report the error
if (!success)
{
Console.WriteLine("Error parsing vertex: {0}", line);
}
}
verts.Add(vec);
}
else if (line.StartsWith("f ")) // Face definition
{
// Cut off beginning of line
String temp = line.Substring(2);
Tuple<int, int, int> face = new Tuple<int, int, int>(0, 0, 0);
if (temp.Count((char c) => c == ' ') == 3) // Check if there's enough elements for a face
{
String[] faceparts = temp.Split(' ');
int i1, i2, i3;
// Attempt to parse each part of the face
bool success = int.TryParse(faceparts[0], out i1);
success |= int.TryParse(faceparts[1], out i2);
success |= int.TryParse(faceparts[2], out i3);
// If any of the parses failed, report the error
if (!success)
{
Console.WriteLine("Error parsing face: {0}", line);
}
else
{
// Decrement to get zero-based vertex numbers
face = new Tuple<int, int, int>(i1 - 1, i2 - 1, i3 - 1);
faces.Add(face);
}
}
}
}
// Create the ObjVolume
ObjVolume vol = new ObjVolume();
vol.vertices = verts.ToArray();
vol.faces = new List<Tuple<int, int, int>>(faces);
vol.colors = colors.ToArray();
vol.texturecoords = texs.ToArray();
return vol;
}
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware
# File Created: 27.02.2016 07:40:58
mtllib test1.mtl
#
# object Pyramid001
#
v -15.7732 14.1346 5.0964
v -23.0566 0.0050 13.3650
v -8.4899 0.0050 13.3650
v -8.4899 0.0050 -3.1722
v -23.0566 0.0050 -3.1722
v -15.7732 0.0050 5.0964
# 6 vertices
vn 0.0000 0.5051 0.8631
vn 0.8889 0.4582 -0.0000
vn 0.0000 0.5051 -0.8631
vn -0.8889 0.4582 -0.0000
vn 0.0000 -1.0000 -0.0000
# 5 vertex normals
vt 0.5000 1.0000 0.0000
vt 0.0000 0.0000 0.0000
vt 1.0000 0.0000 0.0000
vt 0.0596 0.0000 0.0000
vt 1.0596 0.0000 0.0000
vt 0.0000 1.0000 0.0000
vt 0.5000 0.5000 0.0000
vt 1.0000 1.0000 0.0000
# 8 texture coords
g Pyramid001
usemtl wire_154215229
s 4
f 1/1/1 2/2/1 3/3/1
s 2
f 1/1/2 3/4/2 4/5/2
s 16
f 1/1/3 4/2/3 5/3/3
s 32
f 1/1/4 5/4/4 2/5/4
s 8
f 2/6/5 6/7/5 3/8/5
f 3/8/5 6/7/5 4/3/5
f 4/3/5 6/7/5 5/2/5
f 5/2/5 6/7/5 2/6/5
# 0 polygons - 8 triangles
[/代码]
答案 0 :(得分:2)
你对V / Vt / Vn是正确的。你需要再次知道面是如何连接每个面的纹理坐标和法线。它们不在文件中重复,f 1/4/10 2/5/6 3/7/11表示此面具有顶点v1,v2和v3,纹理坐标位于vt4,vt5和vt7,法线为坐标vn10,vn6和vn11。请注意,v,vt和vn的索引与它们在obj文件中出现的顺序相同。我建议您暂时忽略vt和vn,然后尝试使用f后面的第一个数字来显示面部。对于前面的示例,您可以连接v1,v2和v3,您应该得到正确的面孔。稍后您还可以添加法线和纹理,以获得具有纹理和正确照明的完整形状。请注意,当您拥有提供纹理的图像集时,vt才有意义。 vts实际上是指图像纹理的坐标。