网格

glTF系列教程08

Posted by WunWun on July 22, 2017

又复习了一下glTF模型,发现了一个很好的英文教程,讲解的非常详细。没有图形学知识背景的人也可以听懂。学习的时候,就顺便翻译成中文,来和大家分享 。当然,更推荐看英文教程

Meshes

mesh表示出现在场景中的几何对象。在最小glTF文件中,我们已经见过网格的第一个示例。这个示例具有附加到单个节点的单个网格,并且网格由(包含单个属性的)单个 mesh.primitive组成——顶点位置的属性。 但通常,网格图元将包含更多的属性,比如顶点法线或纹理坐标。

本节将用一个丰富的示例,更详细地解释网格,网格图元和属性的处理。下面是一个glTF资源,它包含一个具有多属性的简单网格,我们将以此为基础,解释相关概念:

{
  "scenes" : {
    "scene0" : {
      "nodes" : [ "node0", "node1" ]
    }
  },
  "nodes" : {
    "node0" : {
      "meshes" : [ "mesh0" ]
    },
    "node1" : {
      "meshes" : [ "mesh0" ],
      "translation" : [ 1.0, 0.0, 0.0 ]
    }
  },

  "meshes" : {
    "mesh0" : {
      "primitives" : [ {
        "attributes" : {
          "POSITION" : "positionsAccessor",
          "NORMAL" : "normalsAccessor",
          "TEXCOORD_0" : "texCoordsAccessor"
        },
        "indices" : "indicesAccessor"
      } ]
    }
  },

  "buffers" : {
    "buffer0" : {
      "uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/",
      "byteLength" : 108
    }
  },
  "bufferViews" : {
    "indicesBufferView" : {
      "buffer" : "buffer0",
      "byteOffset" : 0,
      "byteLength" : 6,
      "target" : 34963
    },
    "attributesBufferView" : {
      "buffer" : "buffer0",
      "byteOffset" : 6,
      "byteLength" : 96,
      "target" : 34962
    }
  },
  "accessors" : {
    "indicesAccessor" : {
      "bufferView" : "indicesBufferView",
      "byteOffset" : 0,
      "componentType" : 5123,
      "count" : 3,
      "type" : "SCALAR",
      "max" : [ 2.0 ],
      "min" : [ 0.0 ]
    },
    "positionsAccessor" : {
      "bufferView" : "attributesBufferView",
      "byteOffset" : 0,
      "componentType" : 5126,
      "count" : 3,
      "type" : "VEC3",
      "max" : [ 1.0, 1.0, 0.0 ],
      "min" : [ 0.0, 0.0, 0.0 ]
    },
    "normalsAccessor" : {
      "bufferView" : "attributesBufferView",
      "byteOffset" : 36,
      "componentType" : 5126,
      "count" : 3,
      "type" : "VEC3",
      "max" : [ 0.0, 0.0, 1.0 ],
      "min" : [ 0.0, 0.0, 1.0 ]
    },
    "texCoordsAccessor" : {
      "bufferView" : "attributesBufferView",
      "byteOffset" : 72,
      "componentType" : 5126,
      "count" : 3,
      "type" : "VEC2",
      "max" : [ 1.0, 1.0 ],
      "min" : [ 0.0, 0.0 ]
    }
  },

  "asset" : {
    "version" : "1.1"
  }
}

这个glTF模型渲染出来是这样的:

java-javascript 图 8a:附加到两个节点的网格

附加到节点的网格

在上面的例子中,场景只有一个,并且该场景包含两个节点("node0""node1")。两个节点都引用相同的网格实例("mesh0"):

  "scenes" : {
    "scene0" : {
      "nodes" : [ "node0", "node1" ]
    }
  },
  "nodes" : {
    "node0" : {
      "meshes" : [ "mesh0" ]
    },
    "node1" : {
      "meshes" : [ "mesh0" ],
      "translation" : [ 1.0, 0.0, 0.0 ]
    }
  },

  "meshes" : {
    "mesh0" : {
      ...
    }
  },

节点"node1"具有translation属性。 我们在Scenes and Nodes中讲过,这将用于计算此节点的局部变换矩阵。 在这种情况下,矩阵将导致图元沿着x轴平移1.0。 节点的所有局部变换的乘积将产生全局变换。 附加到节点的所有元素将使用此全局变换渲染。

因此,在这个例子中,网格将被渲染两次,因为它附加到两个节点:一次是使用"node0"的全局变换(这是单位矩阵变换),一次是使用节点"node1"的全局变换( 沿着x轴平移1.0)。

网格图元

mesh包含一个mesh.primitive对象的数组。 这些mesh.primitive对象是较大对象的构建块。 一个mesh.primitive总结了关于如何渲染对象相应部分的所有信息。 特别地,网格图元使用其attributes字典来定义对象的几何数据,这将在下面解释。

下面的例子包含单个mesh.primitive:

"meshes" : {
  "mesh0" : {
    "primitives" : [ {
      "attributes" : {
        "POSITION" : "positionsAccessor",
        "NORMAL" : "normalsAccessor",
        "TEXCOORD_0" : "texCoordsAccessor"
      },
      "indices" : "indicesAccessor"
    } ]
  }
},

索引几何和非索引几何

mesh.primitive的几何数据可以是索引几何也可以是无索引几何。 示例中的是索引几何,它是由引用"indicesAccessor"indices属性表示的。 对于非索引几何,将忽略此属性。

网格图元属性

mesh.primitiveattributes字典中包含有关几何数据的信息。 特别地,它包含对(含有顶点属性数据的)访问器对象的引用。 Buffers, BufferViews and Accessors部分已经解释了访问器的详细信息。

在给定的示例中,属性字典中有三个条目。它们分别引用positionsAccessornormalsAccessortexCoordsAccessor:

"meshes" : {
  "mesh0" : {
    "primitives" : [ {
      "attributes" : {
        "POSITION" : "positionsAccessor",
        "NORMAL" : "normalsAccessor",
        "TEXCOORD_0" : "texCoordsAccessor"
      },
      "indices" : "indicesAccessor"
    } ]
  }
},

如图所示,这些访问器的元素组合在一起,定义了属于单个顶点的所有属性:

java-javascript 图 8b: 包含顶点数据的网格图元访问器

网格图元模式

默认情况下,几何数据被假定为描述三角形网格。对于 索引几何的情况,这意味着索引访问器的三个连续元素被假定为包含单个三角形的索引。 对于非索引几何,顶点属性访问器的三个元素被假定为包含三角形的三个顶点的属性。

除了三角形之外,还有其他渲染模式:几何数据还可以描述点,线或三角形带。 这是由存储在网格图元中的模式指示的:其值是指示如何解释几何数据的常数。 例如,当几何形状由点组成时,模式可以是0;当由三角形组成时,模式可以是4; 有关可用模式的列表,请参阅primitive.mode 规范

网格图元材质

网格图元还可以引用材质。在给定的示例中,没有定义材质,这使得对象用默认的50%灰色来渲染。材质的详细解释和相关概念将在下一节Materials中给出。

著作权声明

作者 陈兴旺,首次发布于 WunWun Blog,转载请保留以上链接