跳转到内容

Celestia/3D 模型/CMOD 文件

来自维基教科书,开放世界中的开放书籍

Celestia 的内部模型对象由一组“材质”和一组“网格”组成。每个“网格”包含一组顶点定义,之后是一些“组”。每个“组”包含一个“组”类型规范,之后是属于该组的先前定义的顶点枚举。这种结构完全对应于 CMOD 文件中包含的项目。

CMOD 格式的 BN 描述

[编辑 | 编辑源代码]

以下描述改编自 Celestia 源代码中的注释。

这是 ASCII cmod 文件内容的近似巴克斯-诺尔范式。为简洁起见,类别 <unsigned_int> 和 <float> 这里没有定义——它们有明显的定义。

 <modelfile>           ::= <header> <model>
              
 <header>              ::= #celmodel__ascii
              
 <model>               ::= { <material_definition> } { <mesh_definition> }
              
 <material_definition> ::= material
                           { <material_attribute> }
                           end_material
 
 <material_attribute>  ::= diffuse  <color>  |
                           specular <color>  | 
                           emissive <color>  | 
                           specpower <float> | 
                           opacity   <float> |
                           texture0 <string> |
                           blend add |             (v1.5.0 and later)
                           normalmap   <string> |  (v1.5.0 and later)
                           specularmap <string> |  (v1.5.0 and later)
                           emissivemap <string>    (v1.5.0 and later)

 <color>               ::= <float> <float> <float>
              
 <string>              ::= """ { letter } """
             
 <mesh_definition>     ::= mesh
                           <vertex_description>
                           <vertex_pool>
                          { <prim_group> }
                           end_mesh
 
 <vertex_description>  ::= vertexdesc
                           { <vertex_attribute> }
                           end_vertexdesc

 <vertex_attribute>    ::= <vertex_semantic> <vertex_format>
              
 <vertex_semantic>     ::= position | normal | color0 | color1 | tangent |
                           texcoord0 | texcoord1 | texcoord2 | texcoord3
 
 <vertex_format>       ::= f1 | f2 | f3 | f4 | ub4
              
 <vertex_pool>         ::= vertices <count>
                           { <float> }
 
 <count>               ::= <unsigned_int>
              
 <prim_group>          ::= <prim_group_type> <material_index> <count>
                           { <unsigned_int> }
 
 <prim_group_type>     ::= trilist | tristrip | trifan |
                           linelist | linestrip | points | 
                           sprites    (v1.5.0 and later)
              
 <material_index>      :: <unsigned_int> | -1

一些元素的说明

[编辑 | 编辑源代码]

在 Celestia v1.5.0 或更高版本中,完整的材质定义将如下所示

material
diffuse 0.5 0.5 0.2
specular 1 1 1
specpower 30
opacity 1
texture0 "basetex.jpg"
normalmap "norm.png"
specularmap "specmask.jpg"
emissivemap "lights.jpg"
end_material

一些顶点属性是

  • position - 位置 (必需)
  • texcoord0 - 主要纹理坐标
  • texcoord1 ... texcoord3 - 附加纹理坐标 (用于多重纹理)
  • color0 ... color1 - 主要和次要颜色
  • tangent - 表面切线 (用于凹凸贴图)

顶点格式是

  • f1 - 一个浮点数
  • f2 - 两个浮点数 (通常用于纹理坐标)
  • f3 - 三个浮点数 (位置和法线)
  • f4 - 四个浮点数
  • ub4 - 四个无符号字节 (颜色通常的格式)

基本类型是

  • trilist
  • tristrip
  • trifan
  • linelist
  • linestrip
  • points
  • sprites (v1.5.0 及更高版本)

三角带和三角扇可能比三角形列表效率高得多。

示例 ASCII CMOD 文件

[编辑 | 编辑源代码]
#celmodel__ascii
# The above line is the 16-byte header; for binary files, it's
# #celmodel_binary

# material definitions follow--these must precede any meshes in the file
material       # index 0
emissive 0 1 0
opacity 0.5
end_material

# A material with a texture.  Texture filenames may use the wildcard
# character, which behaves exactly as it does within a .ssc file.
material	# index 1
emissive 1 1 1
texture0 "tropical-beach.*"
end_material

# There may be one or more meshes in a model file--this file happens
# to have just a single one
mesh

# The vertex description tells what attributes the vertices for this mesh
# have.  Each attribute in the description consists of a semantic and a
# data format.
vertexdesc
position f3
normal f3
texcoord0 f2
end_vertexdesc

# The vertex data--the number right after the keyword vertices is the
# number of vertices in the pool.
vertices 6
0 0 0 0 0 1 0 0
1 1 0 0 0 1 1 1
0 1 0 0 0 1 0 1
0 1 0 0 0 -1 0 1
1 1 0 0 0 -1 1 1
0 0 0 0 0 -1 0 0

# An arbitrary number of primitive groups follow

# The primitive group type is followed by a material index, then
# a count of the number of vertex indices in the group
trilist 0 3
0 1 2
trilist 1 3
3 4 5

# End of the mesh
end_mesh

# ---- end of cmod file ----

点精灵

[编辑 | 编辑源代码]

从 Celestia v1.5.0 开始,CMOD 格式支持点精灵。它们可用于各种不同的体积渲染效果,用于模拟星云、吸积盘、火山羽流或发动机排气等现象。

与点精灵相关的 cmod 格式的更改很小。有一个新的材质属性 (blend add),一个新的基本类型 (sprites) 和一个新的顶点属性类型 (pointsize)。精灵纹理是材质定义中的 texture0。这是一个使用三个红色精灵的非常基本的精灵 CMOD 示例

#celmodel__ascii
material
diffuse 1 0 0
texture0 "gaussian.jpg"
end_material

mesh
vertexdesc
position f3
pointsize f1
end_vertexdesc

vertices 3
1 0 0 0.25
2 0 0 0.25
3 0 0 0.25

sprites 0 3
0 1 2

end_mesh

CMOD 格式中有三个选项可用于影响几何体——三角形、线、点或精灵——如何与背景混合。它们是 normal、blend 和 premultiplied,其中 'normal' 是默认值。

对于星云网格,在材质定义中通过添加行 'blend add' 来指定加性混合可能很有用。这对于发射星云尤其适用,但绝对不应用于马头星云之类的暗星云。加性混合对象具有无需相对于彼此进行深度排序的优点。这是一个使用加性混合和每个顶点颜色以使每个精灵具有不同颜色的稍微复杂一些的精灵 cmod

#celmodel__ascii
material
diffuse 1 0 0
texture0 "gaussian.jpg"
blend add
end_material

mesh
vertexdesc
position f3
pointsize f1
color0 f3
end_vertexdesc

# row of sprites: red, green, blue
vertices 3
1 0 0 0.25  1 0 0
2 0 0 0.25  0 1 0
3 0 0 0.25  0 0 1

sprites 0 3
0 1 2

end_mesh

对于点精灵,每个精灵都具有颜色和 alpha 值,它们与精灵纹理颜色和 alpha 值相乘,以产生片段颜色/alpha (Fr Fg Fb) 和 Fa。alpha 值可以看作是不透明度,但正如您将看到的,它并不总是以完全相同的方式对待。

Add 是最简单的模式。如果背景颜色是 (Br Bg Bb),则最终颜色将是

Fa * (Fr Fg Fb) + (Br Bg Bb)

Normal 模式会导致背景被遮挡;alpha 值为 1 的片段将完全阻塞背景。

Fa * (Fr Fg Fb) + (1 - Fa) (Br Bg Bb)

最后,premultiplied 有点像 normal,只是它省略了与片段 alpha 的乘法。它假定由于透明度造成的任何颜色减少已经在创建几何体时完成,因此称为 premultiplied

(Fr Fg Fb) + (1 - Fa) (Br Bg Bb)

预乘混合的优点是它可以使用适当选择的 alpha 和颜色值模拟添加或 normal 混合模式。例如,将 alpha 设置为零将给出与加性混合相同的结果。Cham:我认为这就是你所说的你想为粒子单独启用 add 的意思。

对于星云,add 适用于发光、扩散的气体,其中吸收不是一个主要的因素。理论上,预乘可以让你混合发射和吸收粒子,但有一个问题:预乘和 normal 混合通常不可交换。为了获得正确的结果,必须从后到前对粒子进行排序并按顺序渲染它们,而 Celestia 目前不执行此操作,因为对大量粒子进行排序会导致性能大幅降低。事实上,混合的这种顺序依赖性长期以来一直是实时 3D 图形中的一个大难题,对于这个问题,仍然没有完全令人满意的解决方案。

使用三角带 (由 Toti)

[编辑 | 编辑源代码]

三角带是 OpenGL 基本类型,它以这种方式绘制一组三角形

     1-----2 

     1-----2 
     \     / 
       \ / 
        3 

     1-----2 
     \     /\ 
       \ /    \ 
        3-----4 

     1-----2 
     \     /\ 
       \ /    \ 
        3-----4 
        \     / 
          \ / 
           5 


因此,我们可以将其存储为:1,2,3,4,5 (5 个条目) 使用三角形列表,相同的三个三角形必须以这种方式存储:1,2,3 2,3,4 3,4,5 (9 个条目,空格仅用于使文本清晰) 基本上,前两个顶点定义了一个基准。对于每个添加的顶点 v,都会定义一个新的三角形。这个三角形由顶点 [v-2][v-1][v] 形成。

通常,对于由 T 个三角形组成的三角形列表,我们需要 3*T 个条目,但对于由 T 个三角形组成的三角带,T+2 个条目就足够了。因此,对于大型网格,您将节省 2/3 的资源。相同的方法可以应用于线段带

     1---2 

     1---2 
         / 
       / 
       3 

     1---2 
         / 
       /  
       3----4 

     1---2 
         / 
       /  
       3----4 
           / 
         / 
         5 


如果上面的网格被定义为线段列表:1,2 2,3 3,4 4,5 (8 个条目)。如果它被定义为线段带:1,2,3,4,5 (5 个条目) 线段列表需要 2*L 个条目来定义一组 L 条线段。线段带仅需要 L+1 个条目来定义相同的集合。对于大型网格,节省的资源约为 50%。

使用这些基本类型的常用方法是像往常一样建模对象,然后使用优化工具从原始三角形转换为三角带等。我不知道是否有任何免费程序/库可以做到这一点。当然,克里斯可以。

使用三角扇 (由 Toti)

[编辑 | 编辑源代码]
            1-------2 
             \     / 
              \   / 
                3 

            1-------2 
          /  \     / 
         /    \   / 
        4------ 3 

       5------ 1-------2 
        \    /  \     / 
         \  /    \   / 
           4------ 3 


使用三角扇,上面的网格可以描述为 1,2,3,4,5 每个三角形都有顶点 [v0][v-1][v],其中 v0 是集合的第一个顶点。

正如您所看到的,它类似于三角带,但第一个顶点始终是三角扇的中心。您需要 T+2 个条目来定义 T 个三角形,因此它的效率与三角带一样高 (但通常它可以在三角带无法使用的地方使用)

使用这些基本元素的优势在于,您可以节省磁盘、总线和内存资源,因为网格描述的体积较小。

华夏公益教科书