<subdivision> ‐ A subdivision mesh
Name | Type | Defaults |
---|---|---|
id | ID | None (required) |
levels | INTEGER | 1 |
level0_vertices | INTEGER | 0 |
level0_texturecoords | INTEGER | 0 |
level0_colors | INTEGER | 0 |
level0_normals | INTEGER | 0 |
level0_faces | INTEGER | 0 |
max_vertices | INTEGER | 0 |
max_texturecoords | INTEGER | 0 |
max_colors | INTEGER | 0 |
max_normals | INTEGER | 0 |
max_faces | INTEGER | 0 |
max_degree | INTEGER | 30 |
subdivision_algorithm | STRING | None (required) |
coefLoop1 | FLOAT | 0.375 |
coefLoop2 | FLOAT | 0.125 |
coefMB1 | FLOAT | 0.5 |
coefMB1 | FLOAT | 0.125 |
coefMB1 | FLOAT | -(1.0/16.0) |
shadow_level | INTEGER | 0 |
autoscale | BOOLEAN | false |
autocenter | BOOLEAN | false |
flat_shading | BOOLEAN | false |
reversed_normals | BOOLEAN | false |
keypoints | INTEGER | 0 |
bones | INTEGER | 0 |
gpu_keypoint_animation | BOOLEAN | false |
This element defines a meshed surface. Figure 5-24 shows a meshed surface made of 7 vertices and 6 faces. Each vertex is associated with a 3 coordinates. Each face is made of a list of vertices that are ordered in the positive direction (counter-clockwise) in order to have a normal facing the viewer. For instance, Face1 is made of V1, V2, and V3. If the normals are predefined, each face is associated with as many normal vectors as vertices. If the normal vectors are not provided, each vertex has only one normal vector. It is computed as the average of the vectors normal to the connected faces. For instance, the default normal vector associated with Vertex1 is the average of the vector cross products V1V2×V1V3, V1V3×V1V4, ... V1V7×V1V2. If the mesh is textured, each face vertex is associated with texture coordinates. A single vertex can have as many different texture coordinates as connected faces. If the mesh is colored, each face vertex is associated with colors. A single vertex can have as many different colors as connected faces. Except for border vertices, colors or texture coordinates of a given vertex are generally the same whatever the face.
The integer value of the level0_vertices, level0_normals, and level0_faces attributes are the number of vertices, normal vectors, and faces that define the mesh. If the mesh is textured, the integer value of the level0_texturecoords attribute is the number of texture coordinates that are used to define the texture mapping on the mesh. If the mesh is colored, the integer value of the level0_colors attribute is the number of colors that are used to define the color mapping on the mesh.
Whatever its topology, the mesh can be smoothed through a recursive subdivision scheme that increases the number of vertices and faces. Two algorithm are implemented, the Loop's subdivision scheme [1] and the modified butterfly scheme. [2]
The integer value of the levels attribute controls the number of recursive steps of the subdivision algorithm. If it is lower than or equal to 1, no smoothing is made and the mesh display is based solely on the initial geometrical data (vertex coordinates, faces, and possibly normals and texture coordinates). If levels if greater than or equal to 2, the smoothing algorithm is defined by the value of the attribute subdivision_algorithm (Loop or Modified-Butterfly), and is applied levels-1 times. The integer value of the max_vertices, max_normals, max_faces, max_texturecoords, and max_colors attributes define the maximal number of vertices, normals, faces, and texture coordinates that will be used by the subdivision algorithm for all its steps. Notice that even though normals may not be provided in the subdivision definition, they are automatically defined during subdivision parsing. The max_normals value should therefore not be set to 0 so that the initialization algorithm can allocate initial normals. The integer value of the max_degree attribute is the maximal number of edges radiating from any vertex in the mesh. If the boolean value of the autoscale attribute is set to true, the mesh is automatically scaled so that the largest dimension of its bounding box is 1.0. If the boolean value of the autocenter attribute is set to true, the mesh is automatically centered at the origin.
If the boolean value of the flat_shading attribute is set to true, only one normal is used for each face. If the normals are explicitely defined in the mesh, the first normal is selected as unique normal, otherwise it is computed as through a vector product. If the value is false, an average normal is computed separately for each vertex. If the boolean value of the reversed_normals attribute is set to true, the normals are multiplied by -1 in order to inverse their orientation.
The coefficients used for the subdivision scheme are stored in the coefLoop1, coefLoop2, coefMB1, coefMB2, and coefMB3 attributes. They are defaulted to the values that perform the expected smoothing.
The integer value of the shadow_level attribute indicates the smoothing level used for computing the shadow of the mesh in the shadowing mode. This value must be lower than or equal to the value of the levels attribute.
The integer value keypoints of the keypoints attribute is the number of keypoints that are used to control the mesh. The keypoints are defined by the fdp table of keypoints. Each keypoint is bound to a vertex (this relationship is not used in vertex displacement computation) and to an external transformation node that is used to control directly the displacement of keypoints, and indirectly the displacement of vertices. The tabvertexfdp table of vertices define, for each vertex, the weights of the associated keypoints. These values are used to weight the keypoint transformations when computing the vertex transformations.
If the boolean value of the gpu_keypoint_animation attribute is true, the keypoint controlled vertex displacements are computed in the GPU by the vertex shader instead of the CPU. In this case, instead of passing the whole displaced mesh to the GPU through the graphic bus, only the keypoint displacements are sent to the vertex shader that computes the corresponding displacements of the vertices.
The GPU-based keypoint animation relies on visemes: keyframes described by tables that contain keypoint x, y, z translations (the size of each table is three times the number of keypoints). An interpolation coefficient α (a value between 0 and 1) is used to compute the current translation of the keypoints by interpolating the previous and next visemes. The animation can be divided into two channels that both use the same keypoints but different visemes and different α values. Typically one channel can be dedicated to visual speech and the other one to expression of emotions. The visemes are passed to the GPU through the visemes_to_gpu script action that provides the vertex shader with the values of the displacement tables for the preceding and next visemes each time a new interpolation is started.
In order to avoid passing too large data sets to the vertex shader, only a subset of the keypoints can be used for a channel: for example, only keypoints in the mouth area can be used to define visual speech. For this purpose, two mask tables can be associated with the subdivision node: tables of booleans of the same size as the number of keypoints. Only keypoints associated with a 1 value in the table are active keypoints for this channel. These tables must be referenced by the keypoint_mask_channel1 and keypoint_mask_channel2 attributes of the tabvertexfdp sub-element.
The vertex shader for GPU-based keypoint animation must have the following input parameters:
uniform float3 KPtranslationsIni_1[]: the keypoint translations of the preceding viseme keyframe for channel 1. The size of this table variable is the number of active keypoints for this channel (or the total number of keypoints if no mask is provided).
uniform float3 KPtranslationsEnd_1[]: the keypoint translations of the next viseme keyframe for channel 1. Similarly, the tables uniform float3 KPtranslationsIni_2[] and uniform float3 KPtranslationsEnd_2[] provide the translations of the preceding and next visemes for channel 2. These four parameters are mofied through the visemes_to_gpu script action that passes the values of the viseme displacement tables for the preceding and next visemes each time a new interpolation is started.
float4 indices_1: is used by the application to store the indices of the keypoints on which this vertex depends for the computation of its displacement for channel 1. Similarly float4 indices_2, provides the indices for channel 2. Because of masking, the indices can differ for the two channels since these indices provide indirect references to the keypoints.
float4 weights: the four weights of the four keypoints on which this vertex depends. If the vertex depends on less than four keypoints, some of the weights are equal to 0.
Two user-chosen variable names sucha as uniform float cg_vp_alpha: for the interpolation coeficient α1 between the preceding viseme and the next one for channel 1, and uniform float cg_vp_alpha_expr for the coeficient α2 for channel 2. These values must be dynamically modified by a set_material_attribute_value actions (applied to the shader of the subdivision) in a script that is executed at each frame to ensure a fluid animation.
The integer value bones of the bones attribute is the number of bones that are used to control the mesh. The bones are defined by the tabboneref table of bone references. The tabvertexbone table of bone weighted vertices define, for each vertex, the weights of the associated bones. These values are used to weight the local bone transformations when computing the vertex transformations.
This element can have elements in its scope that define the properties of the subdivision: color, material, materialRaytrace, shader, texture, or video. In addition to these optional elements, the geometry of the subdivision is defined by the following child elements: one tabvertex table of level0_vertices vertices, one tabnormal table of level0_normals normals, one tabtextureCoord table of level0_texturecoords texture coordinates or one tabcolor table of level0_colors colors, , and one tabface table of level0_faces faces (and possibly texture coordinates and/or color values and/or normal indices). If the value of the keypoints attribute is strictly positive, the subdivision has one fdp table of keypoints, , and possibly one tabvertexfdp table of vertices. If the value of the bones attribute is strictly positive, the subdivision has one tabboneref table of bone references, , and possibly one tabvertexbone table of bone weighted vertices.
The following elements must occur in subdivision: one tabvertex, one tabtextureCoord or one tabcolor, one tabnormal, and one tabface. If the value of the keypoints attribute is strictly positive, the subdivision must have one fdp table. If the value of the bones attribute is strictly positive, the subdivision must have one tabboneref table. In addition elements that describe the properties of the mesh can also be included: color, material, materialRaytrace, shader, texture, or video.
The example below defines a subdivision mesh of 144 faces generated by 96 vertices that is associated with keypoints. It can be used to define keypoint controlled mesh such as animated faces. The mesh is textured, and 100 texture coordinates are used for texture mapping. A set of 144 normal vectors is provided. The mesh is not smoothed because levels is set to 1. 32 keypoints are used to animate the mesh, only two are detailed here. The first keypoint is vertex 95; it is controlled by the node ID "2.1" (a transformation node). The second keypoint is vertex 14 controlled by transformation ID "2.10". The weighting of the vertices on the keypoint is given for the first two vertices in the mesh. The first vertex has weight of (0,-0.559154,0) on keypoint 1, the second vertex is controlled by the first two keypoints with respective weights (0,-0.496439,0) and (0,0.26621,0). The two tables lipsync_keypoint_mask and expression_keypoint_mask are used to define the useful subsets of the keypoints: the keypoints that are actually translated to define the animation keyframes. These tables must be registered in the values of the keypoint_mask_channel1 and keypoint_mask_channel2 attributes of the tabvertexfdp element.
<node id="nurbsCylinder1_0Geo"> <table id="lipsync_keypoint_mask" type="int" size="73" value="(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)"/< <table id="expression_keypoint_mask" type="int" size="73" value="(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1)"/< <subdivision id="mesh_nurbsCylinder1_0Geo" levels="1" level0_vertices="96" level0_texturecoords="100" level0_normals="144" level0_faces="144" max_vertices="96" max_texturecoords="100" max_normals="144" max_faces="144" subdivision_algorithm="Modified-Butterfly" coefLoop1=".375" coefLoop2=".125" coefMB1=".5" coefMB2=".125" coefMB3="-(1.0/16.0)" flat_shading="false" reversed_normals="false" autoscale="false" autocenter="false" > <texture encoding="pnga" xlink:href="A.png" id="Atexture"/> <tabvertex size="96"> <vertex index="1" x="-9.310" y="9.143" z="-2.643" /> ... </tabvertex> <tabnormal size="144"> <normal index="1" x="--0.027" y="0.966" z="-0.258" /> ... </tabnormal> <tabtextureCoord size="100"> <textureCoord index="1" u="1.00" v="0.958333" /> ... </tabtextureCoord> <tabface size="144"> <face index="1"> 95 2 96 </face> <facetexture index="1"> 1 2 3 </facetexture> <facenormal index="1"> 1 1 1 </facenormal> ... </tabface> <fdp size="32"> <keypoint index="1" vertex="95" xlink:href="#2.1" /> <keypoint index="2" vertex="14" xlink:href="#2.10" /> ... </fdp> <tabvertexfdp size="1991" keypoint_mask_channel1="lipsync_keypoint_mask" keypoint_mask_channel2="expression_keypoint_mask"> <vertex index="1" size="1">1 0 -0.559154 0 </vertex> <vertex index="2" size="2">1 0 -0.496439 0 2 0 0.26621 0 </vertex> ... </tabvertexfdp> </subdivision> </node>
The example below defines a subdivision mesh of 10 faces generated by 12 vertices. The mesh is colored, and 3 colors are used for color mapping. One single normal vector is provided. The mesh is not smoothed because levels is set to 1.
<node id="background #1 "> <subdivision id="crystal_#1" levels="1" level0_vertices="12" level0_faces="10" level0_normals="1" level0_colors="3" max_vertices="12" max_faces="10" max_normals="1" max_colors="3" subdivision_algorithm="Loop" coefLoop1=".375" coefLoop2=".125" coefMB1=".5" coefMB2=".125" coefMB3="(0.0-(1.0/16.0))" flat_shading="false" reversed_normals="false" autoscale="false" autocenter="false"> <tabvertex size="12"> <vertex index="1" x="500.0" y="-1.5" z="0.0" /> <vertex index="2" x="500.0" y="-1.5" z="-500.0" /> ... </tabvertex> <tabcolor size="3"> <color index="1" r="0" g="0" b="0" a="1.0"/> <color index="2" r="0" g="0" b="0" a="1.0"/> <color index="3" r="0" g="0" b="0" a="1.0"/> </tabcolor> <tabnormal size="1"> <normal index="1" x="0.0" y="0.0" z="-1.0" /> </tabnormal> <tabface size="10"> <face index="1"> 1 2 4 </face> <facenormal index="1"> 1 1 1 </facenormal> <facecolor index="1"> 1 1 2 </facecolor> ... </tabface> </subdivision> </node>
The example below defines a subdivision mesh of 194 faces generated by 99 vertices that is associated with bones. It can be used to define skeleton-based animation such as human avatars. 12 bones are used to animate the mesh, only two are detailed here, they refer to bone nodes "Body" and "Leg". The weighting of the vertices on the bone local transformations is given for the first two vertices in the mesh. They are both equally weighted on bones 1 and 9.
<node id="Avatar"> <subdivision id="Homme" levels="1" level0_vertices="99" level0_normals="99" level0_faces="194" max_vertices="99" max_normals="99" max_faces="194" bones="12"> <tabvertex size="99"> <vertex index="1" x="1.0" y="1.0" z="-0.5" /> ... </tabvertex> <tabnormal size="99"> <normal index="1" x="0.0" y="0.7071" z="-0.7071" /> ... </tabnormal> <tabface size="194"> <face index="1"> 41 19 20 </face> <facenormal index="1"> 41 19 20 </facenormal> ... </tabface> <tabboneref size="12"> <boneref index="1" xlink:href="#Body"/> <boneref index="2" xlink:href="#RightLeg"/> ... </tabboneref> <tabvertexbone size="99"> <vertex index="1" size="2"> 1 0.5 9 0.5 </vertex> <vertex index="2" size="2"> 1 0.5 9 0.5 </vertex> ... </tabvertexbone> </subdivision> </node>
The attribute values of the vertices that define a subdivision can be accessed through the sequence node:rank:attribute in which node is the subdivision node ID, rank is value of the rank attribute (the set of values {v1, v2...vn} for the nvertices), and attribute is the vertex attribute.
The examples below access attributes of vertex v{#n} in subdivision pyramid:
<action> <set_graph_particle_value index="1" operator="="> <particle x="({$pyramid:v{#n}:x} + {$pyramid:x_phys})" y="({$pyramid:v{#n}:y} + {$pyramid:y_phys})" z="({$pyramid:v{#n}:z} + {$pyramid:z_phys})" /> </set_graph_particle_value> <target type="single_node" value="#node_veil{#n}" /> </action>
[1] | Charles Loop. Smooth subdivision surfaces based on triangles. Master's thesis, Department of Mathematics, University of Utah, August 1987. |
[2] | D. Zorin, P. Schroder, and W. Sweldens. Interpolating subdivision for meshes with arbitrary topology. Computer Graphics (SIGGRAPH'96 Proceedings), pages 189-192, August 1996. |