CSV物件格式(适用于openBVE,Hmmsim仅供参考)



■ 目录

1. 概述
2. 语法
3. 可用命令
    ↷ CreateMeshBuilder
    ↷ AddVertex
    ↷ AddFace
    ↷ AddFace2
    ↷ Cube
    ↷ Cylinder
    ↷ Translate, TranslateAll
    ↷ Scale, ScaleAll
    ↷ Rotate, RotateAll
    ↷ Shear, ShearAll
    ↷ Mirror, MirrorAll
    ↷ SetColor
    ↷ SetEmissiveColor
    ↷ SetBlendMode
    ↷ LoadTexture
    ↷ SetDecalTransparentColor
    ↷ SetTextureCoordinates



■ 1. 概述

一个CSV文件允许使用纯文本命令来创造单个物件。该物件可以在线路或列车中使用。文件描述的物件可以包含任意数量的多边形。文件格式允许在CreatMeshBuilder部分中对多个多边形进行分组,并将颜色或纹理(也就是贴图)信息等属性分配给在每个部分中创建的多边形。这允许在同一个CreateMeshBuilder当中创建多个多边形,这些多边形共享公共属性。多边形在这里称为面(face)。

该文件是以任意编码编码的纯文本文件,但是,带字节顺序标记的UTF-8是更好的选择。数字的解析宽松的,尽管如此,生成严格的输出还是很有必要。文件名是任意的,但必须有扩展名.csv。该文件将从上到下按照每行进行解析。

另请参阅CSV格式的快速参考...



■ 2. 语法


文件中的每一行都分为命令名称及其参数。所有命令的语法都是相同的:
命令名称, 参数1, 参数2, 参数3,...,参数n


命令名称不区分大小写。如果有参数,则命令名称参数1用逗号(U+002C)来分隔。同样,参数也用逗号分隔。命令名称和参数周围的空格以及行的开头和结尾都会被忽略。仅忽略由空格组成的空行或空行。

将文本写在参数i处也可以省略该参数。在这种情况下通常会应用该命令特定的默认值。所有默认值都在可用命令部分中指定。(这一句不太懂,所以机翻)

您可以在一行的末尾添加注释。注释由分号(U+003B)开始。注释(如果存在)在处理之前将从所有行中删除。



■ 3. 可用命令




CreateMeshBuilder

这个命令标志着新一组面(多边形)的开始。它必须位于以下任何命令之前。在文件中可以根据需要添加任意数量的该指令。后续的所有命令将与前一个CreateMeshBuilder关联。





AddVertex, vX, vY, vZ, nX, nY, nZ
vX:顶点的x坐标,以米为单位,负值向左,正值向右,默认值为0。
vY:顶点的y坐标,以米为单位,负值向下,正值向上,默认值为0。
vZ:顶点的z坐标,以米为单位,负值向后,正值向前,默认值为0。
nX:顶点法线的x坐标,以米为单位,默认值为0。
nY:顶点法线的y坐标,以米为单位,默认值为0。
nZ:顶点法线的z坐标,以米为单位,默认值为0。

这个命令将创建一个新顶点,然后可以将此顶点用于AddFace或AddFace2命令来创建面。在CreateMeshBuilder部分中可以根据需要添加任意数量的该指令。但是,给出顶点的顺序对后续的命令很重要。给定的第一个顶点具有索引0,后续顶点具有索引1,2,3等等。

法线是在特定点垂直于面的方向。如果面里的所有顶点具有相同的法线,那么面将看起来平坦。如果使用得当,您可以通过为每个顶点指定不同的法线来造成曲面的错觉 - 跨多个面在所有顶点上使用相同法线除外。请尽量使用简单的面和复杂的法线而不是复杂的面来达成曲面或凹凸效果。这能节省性能开支。如果全部为0,法线将自动计算。





AddFace, v1, v2, v3, ..., vmax
vi:此数值为将要包含在此面中的顶点索引。允许的数值为0到n-1,n是所使用的AddVertex命令数量。
此命令将创建一个以所有给出v点为顶点的面。i的值(索引值)对应于AddVertex中创建顶点的顺序,因此该命令须紧跟AddVertex命令。面的背面不可见。顶点索引出现的顺序很重要。1.当你能看到这个面时,顶点永远以顺时针排列。2.在相邻位置出现的顶点的连线不可以是该多边形的对角线。





AddFace2, v1, v2, v3, ..., vmax
vi:此数值为将要包含在此面中的顶点索引。允许的数值为0到n-1,n是所使用的AddVertex命令数量。
此命令将创建一个以所有给出v点为顶点的面。i的值(索引值)对应于AddVertex中创建顶点的顺序,因此该命令须紧跟AddVertex命令。在相邻位置出现的顶点的连线不可以是该多边形的对角线。该指令可以创造两侧可见的面,且仅支持凸多边形。
需要注意的是,在目前的openBVE版本里使用这个指令可能造成一些光照错误。这个错误也许会在将来被纠正。





Cube, 半宽, 半高, 半深
半宽:一个表示此立方体一半宽度(X轴向,左右)的浮点数,以为单位。
半高:一个表示此立方体一半高度(Y轴向,上下)的浮点数,以为单位。
半深:一个表示此立方体一半深度(Z轴向,前后)的浮点数,以为单位。

此命令将以原点(0,0,0)为中心创建一个以两倍的半宽两倍的半高两倍的半深为尺寸的立方体。立方体总有8个顶点和6个面。如果不指定半高和半深,写出Cube,半宽的指令,则会创建一个以2×半宽为边长的正方体。如半宽半高半深中有一个为负值,则显示面将从外侧转向内侧。

Cube命令使用注意
Cube命令相当于一系列的AddVertex和AddFace命令,会影响顶点索引,所以在同一CreateMeshBuilder部分中使用其他命令时需要考虑这些命令。此处提供了Cube命令的详细信息。





Cylinder, n, 上底半径, 下底半径,
n:表示顶/底面正多边形的定点分段数,译者亲测该值最好为介于2~32768之间的整数。
上底半径:顾名思义,不解释了,以为单位。如该值为负数,则上底将省略。
下底半径:同上不解释,以为单位。如该值为负数,则下底将省略。
:一个表示该圆柱/圆锥/圆台高度的浮点数,以为单位。可以为负值,那么该圆柱/圆锥/圆台将上下倒转且显示面将朝内。

该命令将创建一个截锥体。如果上底半径下底半径 是相等的,这个物件将变成棱柱,并可用作近似的圆柱。如果下底半径上底半径 为0,这个物件将变成棱锥。创建的截椎体将以原点为中心。

当半径的值较小时,顶点数n为6或8足矣,例如创建一根电线杆。无论上底半径下底半径n 的值如何,该多面体将始终有2×n个顶点和n+2个面,除非省略任何顶点。若上底半径 下底半径 为负数,则采用绝对值,但不会有相应的上限。
由于面分割过细会严重影响性能,导致您的用户卡爆(尤其是在低配电脑和手机上),译者推荐您在视觉效果可以接受的情况下尽量使用小一些的n值,造成粗糙一些的分割。您甚至有时不应该使用此指令和圆柱,而应该使用一个大平面贴上渐变色的材质来模仿圆柱的效果,以求尽量流畅的游戏体验。

Cylinder命令使用注意
Cylinder命令相当于一系列的AddVertex和AddFace命令,在同一CreateMeshBuilder部分中使用其他命令时需要考虑这些命令。此处提供了Cylinder命令的详细信息




GenerateNormals
未给出的情况下,openBVE会自动计算法线坐标。所以该命令被openBVE忽略。




Translate, X, Y, Z
TranslateAll, X, Y, Z

X:一个表示顶点在x轴上移动距离的浮点数,以为单位。负值向左平移,正值向右平移。默认值为0。
Y:一个表示顶点在y轴上移动距离的浮点数,以为单位。负值向下平移,正值向上平移。默认值为0。
Z:一个表示顶点在z轴上移动距离的浮点数,以为单位。负值向后平移,正值向前平移。默认值为0。

Translate命令将移动从CreateMeshBuilder到Translate之间创建的所有顶点,且后续顶点不受影响。您可以在CreateMeshBuilder部分中根据需要使用尽可能多的Translate命令。TranslateAll不仅影响当前CreateMeshBuilder部分中创建的顶点,还会影响到之前所有CreateMeshBuilder部分中创建的顶点,这对于在文件末尾插入来平移整个物件很有用。





Scale, X, Y, Z
ScaleAll, X, Y, Z

X:一个非零浮点数,表示x轴上的缩放比例前项(即X:1),默认值为1。
Y:一个非零浮点数,表示y轴上的缩放比例前项(即Y:1),默认值为1。
Z:一个非零浮点数,表示z轴上的缩放比例前项(即Z:1),默认值为1。

Scale命令将缩放从CreateMeshBuilder到Scale之间创建的所有顶点,且后续顶点不受影响。您可以在CreateMeshBuilder部分中根据需要使用尽可能多的Scale命令。ScaleAll不仅影响当前CreateMeshBuilder部分中创建的顶点,还会影响到之前所有CreateMeshBuilder部分中创建的顶点,这对于在文件末尾插入来缩放整个物件很有用。





Rotate, X, Y, Z, 角度
RotateAll, X, Y, Z, 角度

X:旋转轴的x方向。负值指向左侧,正值指向右侧。默认值为0。
Y:旋转轴的x方向。负值指向左侧,正值指向右侧。默认值为0。
Z:旋转轴的x方向。负值指向左侧,正值指向右侧。默认值为0。
角度 :以度为单位的旋转角度,负值逆时针,正值顺时针,默认值为0。

Rotate命令将旋转从CreateMeshBuilder到Rotate之间创建的所有顶点,且后续顶点不受影响。旋转轴通过X Y Z 值指定。旋转将发生在垂直于该轴的平面中。该轴的零向量被视为(1,0,0),所有其他方向都将标准化。

您可以在CreateMeshBuilder部分中根据需要使用尽可能多的Rotate命令。RotateAll不仅影响当前CreateMeshBuilder部分中创建的顶点,还会影响到之前所有CreateMeshBuilder部分中创建的顶点,这对于在文件末尾插入来旋转整个物件很有用。

※由于官方的说明文档原文有些晦涩,就算翻译过来也可能会看不懂,这里译者再开一段来讲讲本人是如何使用Rotate命令的。我倾向于“一对一”式的写法,即一个Rotate命令完成物件在一个坐标轴上的旋转,上文提到的X,Y,Z被我用来标记在该坐标轴上是否做出旋转动作,0代表否,1代表是。然后再用角度 参数说明旋转的角度,正值为顺时针,负值为逆时针。例如Rotate,0,1,0,180表示将该物件以y轴为基准旋转180度。





Shear, dX, dY, dZ, sX, sY, sZ, r
ShearAll, dX, dY, dZ, sX, sY, sZ, r

dX:向量D的x坐标,默认为0。
dY:向量D的y坐标,默认为0。
dZ:向量D的z坐标,默认为0。
sX:向量S的x坐标,默认为0。
sY:向量S的y坐标,默认为0。
sZ:向量S的z坐标,默认为0。
r:表示取代载体的比例。默认为0。

该指令执行斜切。
※由于翻译团队水平不足,经过反复讨论和测试,甚至咨询开发者后也没能明白本指令的参数含义和具体用法。由于本指令在实际物件中用途较少,也无法找到实例参考学习。对各位开发者造成的不便敬请谅解。我们在下方贴上了机翻内容和openBVE主程序中对该指令处理的代码。

Shear命令为当前CreateMeshBuilder部分中到目前为止创建的所有顶点执行剪切映射(英文维基百科)ShearAll不仅影响当前CreateMeshBuilder部分中创建的顶点,还会影响到之前所有CreateMeshBuilder部分中创建的顶点,这对于在文件末尾插入来剪切整个物件很有用。



剪切映射在原点周围进行。宽松地说,将物体沿方向D切成平面,然后沿方向S移位。通常,D和S是垂直的。D和S总是标准化。如果r 为0,则不执行转换。如果D和S垂直,则r 的1值对应45度的斜率。
/* 代码语言:C# */ private static void ApplyShear(MeshBuilder Builder, double dx, double dy, double dz, double sx, double sy, double sz, double r) { for (int j = 0; j < Builder.Vertices.Length; j++) { double n = r * (dx * Builder.Vertices[j].Coordinates.X + dy * Builder.Vertices[j].Coordinates.Y + dz * Builder.Vertices[j].Coordinates.Z); Builder.Vertices[j].Coordinates.X += sx * n; Builder.Vertices[j].Coordinates.Y += sy * n; Builder.Vertices[j].Coordinates.Z += sz * n; } for (int j = 0; j < Builder.Faces.Length; j++) { for (int k = 0; k < Builder.Faces[j].Vertices.Length; k++) { if (Builder.Faces[j].Vertices[k].Normal.X != 0.0f | Builder.Faces[j].Vertices[k].Normal.Y != 0.0f | Builder.Faces[j].Vertices[k].Normal.Z != 0.0f) { double nx = (double)Builder.Faces[j].Vertices[k].Normal.X; double ny = (double)Builder.Faces[j].Vertices[k].Normal.Y; double nz = (double)Builder.Faces[j].Vertices[k].Normal.Z; double n = r * (sx * nx + sy * ny + sz * nz); nx -= dx * n; ny -= dy * n; nz -= dz * n; World.Normalize(ref nx, ref ny, ref nz); Builder.Faces[j].Vertices[k].Normal.X = (float)nx; Builder.Faces[j].Vertices[k].Normal.Y = (float)ny; Builder.Faces[j].Vertices[k].Normal.Z = (float)nz; } } } }




Mirror, X, Y, Z
MirrorAll, X, Y, Z

X:决定x轴是否被镜像。默认值为0(否)。
Y:决定y轴是否被镜像。默认值为0(否)。
Z:决定z轴是否被镜像。默认值为0(否)。

Mirror命令将镜像从CreateMeshBuilder到Mirror之间创建的所有顶点,且后续顶点不受影响。此处镜像只是沿着某坐标轴翻转,并不是对称。镜像的方向通过X Y Z 值指定。您可以在CreateMeshBuilder部分中根据需要使用尽可能多的Mirror命令。MirrorAll不仅影响当前CreateMeshBuilder部分中创建的顶点,还会影响到之前所有CreateMeshBuilder部分中创建的顶点,这对于在文件末尾插入来镜像整个物件很有用。

※敬请注意,此命令仅openBVE1.5.3.1(ObjectViewer1.5.2.0)及以上版本可用,目前openBVE1.5.3.1以下版本及Hmmsim不兼容。





SetColor, 红色分量, 绿色分量, 蓝色分量, 透明度
R:该颜色的红色分量,范围为0(黑)~255(红),默认值为0。
G:该颜色的绿色分量,范围为0(黑)~255(绿),默认值为0。
B:该颜色的蓝色分量,范围为0(黑)~255(蓝),默认值为0。
透明度:该颜色的透明度,范围为0(透明)~255(不透明),默认值为255。

该命令将设置从CreateMeshBuilder到SetColor之间创建的所有面的颜色。如果未贴上材质,则将使用上述四个值对该面进行着色。(以下是译者个人理解,会和原文有出入)
如果使用了材质,那么程序将会解析图片中每个像素的颜色,逐个与上述红、绿、蓝值进行比较,并选取两个(原RGB值和定义的RGB值)当中的较小值作为该像素的最终颜色,如红、绿、蓝值为255,255,255则不变色,如为0,0,0则全部变为黑色。在路线中使用照明时,实际颜色可能会根据照明条件而变化,但通常会变暗。





SetEmissiveColor, 红色分量, 绿色分量, 蓝色分量
R:该颜色的红色分量,范围为0(黑)~255(红),默认值为0。
G:该颜色的绿色分量,范围为0(黑)~255(绿),默认值为0。
B:该颜色的蓝色分量,范围为0(黑)~255(蓝),默认值为0。

该命令将为已在当前CreateMeshBuilder部分中创建的所有面设置自发光颜色。SetColor命令受光照影响,而SetEmissiveColor不会,因此该命令应用于自身发光的面,如信号灯的发光部分。如红、绿、蓝值为0,0,0,则该面将不做任何改变,如值为255,255,255,该面将在任何时候保持原色。





SetBlendMode, 混色模式, 半发光距离, 光衰减模式
混色模式:将要使用的混色模式,默认为正常。
半发光距离:发光强度为50%时视点和物体的距离,以米为单位。该值必须是1到4095范围内的整数,或0表示禁用此功能。默认值为0。
光衰减模式:将要使用的光衰减模式,默认为四次倒数。

混色模式 命令中的可用选项:
Normal(正常):正常渲染物体。
Additive(叠加):叠加渲染物体。

光衰减模式 命令中的可用选项:
DivideExponent2(平方倒数):光的强度通过函数 x2 / (x2 + 发光半距离2) 来决定,其中 x 是视点到物体的距离,以米为单位。
DivideExponent4(四次倒数):光的强度通过函数 x4 / (x4 + 发光半距离4) 来决定,其中 x 是视点到物体的距离,以米为单位。

此命令为当前CreateMeshBuilder部分中的所有面设置混色模式。普通模式用材质像素替换屏幕像素。叠加模式将材质像素的颜色(数值)与屏幕像素颜色(数值)相加。0为下限,255为上限。所以添加黑色(0,0,0)不会改变屏幕像素,添加白色(255,255,255)结果恒为白色。如果发光半距离不为0,当视点接近物体时,物体会逐渐淡出(变得透明)。通过设置光衰减模式 可以确定特定距离的精确光强度。平方倒数创建一个更平滑的过渡,但光汇合到最大强度的过程非常缓慢,而四次倒数创建更锐利的过渡,且光线汇合更快。

    openBVE 2的未来兼容性说明:
在openBVE的未来版本计划中,将只有叠加模式受支持(因为默认模式就是正常,不写这条指令不就好了),且有可能会不再使用光衰减模式这个参数。请避免在这条指令中使用正常模式。
 




LoadTexture, 日间材质, 夜间材质
日间材质:将要加载的日间材质的文件名,最好和CSV文件在同一目录下。
夜间材质:将要加载的夜间材质的文件名,最好和CSV文件在同一目录下。

此命令将加载一或二个材质并将其用于当前CreateMeshBuilder部分中的所有面。目前openBVE支持的格式有bmp,png,jpg,gif,tif。Hmmsim仅支持bmp。您也可以使用包含完整Alpha通道(即包含透明和半透明)的png格式,但请尽量不要使用,因为很吃性能,且叠加的透明面会造成深度排序的问题。没有Alpha通道(全不透明)的材质可以与SetDecalTransparentColor命令配合使用来达到性能更好的透明效果。

如果使用了夜间材质,它指定在夜间光照状态(.Brightness 0)下使用的材质,而日间材质指定在日间光照状态(.Brightness 255)下使用的材质。两个材质会根据光照状态互相混合(.Brightness 1~254),材质也需要以此来进行设计。如果指定了夜间材质,就必须同时指定日间材质。如果没有指定夜间材质,暗光照条件会使日间材质更黑。必须使用SetTextureCoordinates指令设定好材质与各顶点的关系,材质才能被正常显示。





SetDecalTransparentColor, 红色分量, 绿色分量, 蓝色分量
R:该颜色的红色分量,范围为0(黑)~255(红),默认值为0。
G:该颜色的绿色分量,范围为0(黑)~255(绿),默认值为0。
B:该颜色的蓝色分量,范围为0(黑)~255(蓝),默认值为0。

这条指令为已经创建的所有面指定一个蒙版式的透明色(例如屏蔽门和车窗)。刚刚加载的材质中与指定的红、绿、蓝颜色相同的像素都会变为透明的。这种蒙版式的透明色比起使用全Alpha通道(透明与半透明)的png高效多了,所以比起把材质部分填成透明,不如绘制全不透明的材质,然后将材质中要透明的部分填为固定颜色,再使用此指令将这些部分“挖空”。必须使用SetTextureCoordinates指令设定好材质与各顶点的关系,材质才能被正常显示。





SetTextureCoordinates, 顶点索引, 水平偏移量(U), 垂直偏移量(V)
顶点索引:这个材质坐标匹配的模型顶点。范围是0到AddVertex指令创建的顶点数量-1。
水平偏移量(U):这个材质坐标相对于模型左边缘的位置。一个0~1之间的数字,0代表最左边,1代表最右边。
垂直偏移量(V):这个材质坐标相对于模型上边缘的位置。一个0~1之间的数字,0代表最上边,1代表最下边。

这条指令为顶点索引指定的顶点匹配一个材质坐标。由于这个索引是要匹配一个已经创建了的顶点的,所以这条指令要放在AddVertex指令的后面。其实说实话,UV并不是严格的要位于0~1之间的,当UV的值大于0小于1时,如下图所示(应该解释得很清楚了),当指定顶点上的UV值大于1,程序将把材质横纵向无限平铺(就是无数张图片组成的一个格子状的二维平面),U值“2”对应在该平面中所有左起第二列图片的右边线,V值“5”对应在该平面中所有第五行图片的下边线,而“2,5”则对应该平面中第二列第五行的那张图片的右下角(也就是前面所述两条垂直直线的交点)。使用大于1的U和V值,您可以将材质以平铺的方式在面上重复多次地贴图。