Name EXT_vertex_weighting Name Strings GL_EXT_vertex_weighting Contact Mark J. Kilgard, NVIDIA Corporation (mjk 'at' nvidia.com) Notice Copyright NVIDIA Corporation, 1999, 2000. Status Discontinued. NVIDIA no longer supports this extension in driver updates after November 2002. Instead, use either ARB_vertex_program & NV_vertex_program. Version NVIDIA Date: January 3, 2003 $Date$ $Revision$ Number 188 Dependencies None Written based on the wording of the OpenGL 1.2 specification but not dependent on it. Overview The intent of this extension is to provide a means for blending geometry based on two slightly differing modelview matrices. The blending is based on a vertex weighting that can change on a per-vertex basis. This provides a primitive form of skinning. A second modelview matrix transform is introduced. When vertex weighting is enabled, the incoming vertex object coordinates are transformed by both the primary and secondary modelview matrices; likewise, the incoming normal coordinates are transformed by the inverses of both the primary and secondary modelview matrices. The resulting two position coordinates and two normal coordinates are blended based on the per-vertex vertex weight and then combined by addition. The transformed, weighted, and combined vertex position and normal are then used by OpenGL as the eye-space position and normal for lighting, texture coordinate, generation, clipping, and further vertex transformation. Issues Should the extension be written to extend to more than two vertex weights and modelview matrices? RESOLUTION: NO. Supports only one vertex weight and two modelview matrices. If more than two is useful, that can be handled with another extension. Should the weighting factor be GLclampf instead of GLfloat? RESOLUTION: GLfloat. Though the value of a weighting factors outside the range of zero to one (and even weights that do not add to one) is dubious, there is no reason to limit the implementation to values between zero and one. Should the weights and modelview matrices be labeled 1 & 2 or 0 & 1? RESOLUTION: 0 & 1. This is consistent with the way lights and texture units are named in OpenGL. Make GL_MODELVIEW0_EXT be an alias for GL_MODELVIEW. Note that the GL_MODELVIEW0_EXT+1 will not be GL_MODELVIEW1_EXT as is the case with GL_LIGHT0 and GL_LIGHT1. Should there be a way to simultaneously Rotate, Translate, Scale, LoadMatrix, MultMatrix, etc. the two modelview matrices together? RESOLUTION: NO. The application must use MatrixMode and repeated calls to keep the matrices in sync if desired. Should the secondary modelview matrix stack be as deep as the primary matrix stack or can they be different sizes? RESOLUTION: Must be the SAME size. This wastes a lot of memory that will be probably never be used (the modelview matrix stack must have at least 32 entries), but memory is cheap. The value returned by MAX_MODELVIEW_STACK_DEPTH applies to both modelview matrices. Should there be any vertex array support for vertex weights. RESOLUTION: YES. Should we have a VertexWeight2fEXT that takes has two weight values? RESOLUTION: NO. The weights are always vw and 1-vw. What is the "correct" way to blend matrices, particularly when wo is not one or the modelview matrix is projective? RESOLUTION: While it may not be 100% correct, the extension blends the vertices based on transforming the object coordinates by both M0 and M1, but the resulting w coordinate comes from simply transforming the object coordinates by M0 and extracting the w. Another option would be to simply blend the two sets of eye coordinates without any special handling of w. This is harder. Another option would be to divide by w before blending the two sets of eye coordinates. This is awkward because if the weight is 1.0 with vertex weighting enabled, the result is not the same as disabling vertex weighting since EYE_LINEAR texgen is based of of the non-perspective corrected eye coordinates. As specified, the normal weighting and combination is performed on unnormalized normals. Would the math work better if the normals were normalized before weighting and combining? RESOLUTION: Vertex weighting of normals is after the GL_RESCALE_NORMAL step and before the GL_NORMALIZE step. As specified, feedback and selection should apply vertex weighting if enabled. Yuck, that would mean that we need software code for vertex weighting. RESOLUTION: YES, it should work with feedback and selection. Sometimes it would be useful to mirror changes in both modelview matrices. For example, the viewing transforms are likely to be different, just the final modeling transforms would be different. Should there be an API support for mirroring transformations into both matrices? RESOLUTION: NO. Such support is likely to complicate the matrix management in the OpenGL. Applications can do a Get matrix from modelview0 and then a LoadMatrix into modelview1 manually if they need to mirror things. I also worry that if we had a mirrored matrix mode, it would double the transform concatenation work if used naively. Many of the changes to the two modelview matrices will be the same. For example, the initial view transform loaded into each will be the same. Should there be a way to "mirror" changes to both modelview matrices? RESOLUTION: NO. Mirroring matrix changes would complicate the driver's management of matrices. Also, I am worried that naive users would mirror all transforms and lead to lots of redundant matrix concatenations. The most efficient way to handle the slight differences between the modelview matrices is simply to GetFloat the primary matrix, LoadMatrix the values in the secondary modelview matrix, and then perform the "extra" transform to the secondary modelview matrix. Ideally, a glCopyMatrix(GLenum src, GLenum dst) type OpenGL command could make this more efficient. There are similiar cases where you want the modelview matrix mirrored in the texture matrix. This is not the extension to solve this minor problem. The post-vertex weighting normal is unlikely to be normalized. Should this extension automatically enable normalization? RESOLUTION: NO. Normalization should operate as specified. The user is responsible for enabling GL_RESCALE_NORMAL or GL_NORMALIZE as needed. You could imagine cases where the application only sent vertex weights of either zero or one and pre-normalized normals so that GL_NORMALIZE would not strictly be required. Note that the vertex weighting of transformed normals occurs BEFORE normalize and AFTER rescaling. See the issue below for why this can make a difference. How does vertex weighting interact with OpenGL 1.2's GL_RESCALE_NORMAL enable? RESOLUTION: Vertex weighting of transformed normals occurs BEFORE normalize and AFTER rescaling. OpenGL 1.2 permits normal rescaling to behave just like normalize and because normalize immediately follows rescaling, enabling rescaling can be implementied by simply always enabling normalize. Vertex weighting changes this. If one or both of the modelview matrices has a non-uniform scale, it may be useful to enable rescaling and normalize and this operates differently than simply enabling normalize. The difference is that rescaling occurs before the normal vertex weighting. An implementation that truly treated rescaling as a normalize would support both a pre-weighting normalize and a post-weighting normalize. Arguably, this is a good thing. For implementations that perform simply rescaling and not a full normalize to implement rescaling, the rescaling factor can be concatenated into each particular inverse modelview matrix. New Procedures and Functions void VertexWeightfEXT(float weight); void VertexWeightfvEXT(float *weight); void VertexWeightPointerEXT(int size, enum type, sizei stride, void *pointer); New Tokens Accepted by the parameter of Enable: VERTEX_WEIGHTING_EXT 0x8509 Accepted by the parameter of MatrixMode: MODELVIEW0_EXT 0x1700 (alias to MODELVIEW enumerant) MODELVIEW1_EXT 0x850A Accepted by the parameter of GetBooleanv, GetIntegerv, GetFloatv, and GetDoublev: VERTEX_WEIGHTING_EXT MODELVIEW0_EXT MODELVIEW1_EXT MODELVIEW0_MATRIX_EXT 0x0BA6 (alias to MODELVIEW_MATRIX) MODELVIEW1_MATRIX_EXT 0x8506 CURRENT_VERTEX_WEIGHT_EXT 0x850B VERTEX_WEIGHT_ARRAY_EXT 0x850C VERTEX_WEIGHT_ARRAY_SIZE_EXT 0x850D VERTEX_WEIGHT_ARRAY_TYPE_EXT 0x850E VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F MODELVIEW0_STACK_DEPTH_EXT 0x0BA3 (alias to MODELVIEW_STACK_DEPTH) MODELVIEW1_STACK_DEPTH_EXT 0x8502 Accepted by the parameter of GetPointerv: VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 Additions to Chapter 2 of the OpenGL 1.2.1 Specification (OpenGL Operation) -- Section 2.6. 2nd paragraph changed: "Each vertex is specified with two, three, or four coordinates. In addition, a current normal, current texture coordinates, current color, and current vertex weight may be used in processing each vertex." -- Section 2.6. New paragraph after the 3rd paragraph: "A vertex weight is associated with each vertex. When vertex weighting is enabled, this weight is used as a blending factor to blend the position and normals transformed by the primary and secondary modelview matrix transforms. The vertex weighting functionality takes place completely in the "vertex / normal transformation" stage of Figure 2.2." -- Section 2.6.3. First paragraph changed to "The only GL commands that are allowed within any Begin/End pairs are the commands for specifying vertex coordinates, vertex colors, normal coordinates, and texture coordinates (Vertex, Color, VertexWeightEXT, Index, Normal, TexCoord)..." -- Section 2.7. New paragraph after the 4th paragraph: "The current vertex weight is set using void VertexWeightfEXT(float weight); void VertexWeightfvEXT(float *weight); This weight is used when vertex weighting is enabled." -- Section 2.7. The last paragraph changes from "... and one floating-point value to store the current color index." to: "... one floating-point number to store the vertex weight, and one floating-point value to store the current color index." -- Section 2.8. Change 1st paragraph to say: "The client may specify up to seven arrays: one each to store edge flags, texture coordinates, colors, color indices, vertex weights, normals, and vertices. The commands" Add to functions listed following first paragraph: void VertexWeightPointerEXT(int size, enum type, sizei stride, void *pointer); Add to table 2.4 (p. 22): Command Sizes Types ---------------------- ----- ----- VertexWeightPointerEXT 1 float Starting with the second paragraph on p. 23, change to add VERTEX_WEIGHT_ARRAY_EXT: "An individual array is enabled or disabled by calling one of void EnableClientState(enum array) void DisableClientState(enum array) with array set to EDGE_FLAG_ARRAY, TEXTURE_COORD_ARRAY, COLOR_ARRAY, INDEX_ARRAY, VERTEX_ARRAY_WEIGHT_EXT, NORMAL_ARRAY, or VERTEX_ARRAY, for the edge flag, texture coordinate, color, secondary color, color index, normal, or vertex array, respectively. The ith element of every enabled array is transferred to the GL by calling void ArrayElement(int i) For each enabled array, it is as though the corresponding command from section 2.7 or section 2.6.2 were called with a pointer to element i. For the vertex array, the corresponding command is Vertexv, where is one of [2,3,4], and is one of [s,i,f,d], corresponding to array types short, int, float, and double respectively. The corresponding commands for the edge flag, texture coordinate, color, secondary color, color index, and normal arrays are EdgeFlagv, TexCoordv, Colorv, Indexv, VertexWeightfvEXT, and Normalv, respectively..." Change pseudocode on p. 27 to disable vertex weight array for canned interleaved array formats. After the lines DisableClientState(EDGE_FLAG_ARRAY); DisableClientState(INDEX_ARRAY); insert the line DisableClientState(VERTEX_WEIGHT_ARRAY_EXT); Substitute "seven" for every occurrence of "six" in the final paragraph on p. 27. -- Section 2.10. Change the sentence: "The model-view matrix is applied to these coordinates to yield eye coordinates." to: "The primary modelview matrix is applied to these coordinates to yield eye coordinates. When vertex weighting is enabled, a secondary modelview matrix is also applied to the vertex coordinates, the result of the two modelview transformations are weighted by its respective vertex weighting factor and combined by addition to yield the true eye coordinates. Vertex weighting is enabled or disabled using Enable and Disable (see section 2.10.3) with an argument of VERTEX_WEIGHTING_EXT." Change the 4th paragraph to: "If vertex weighting is disabled and a vertex in object coordinates is given by ( xo yo zo wo )' and the primary model-view matrix is M0, then the vertex's eye coordinates are found as (xe ye ze we)' = M0 (xo yo zo wo)' If vertex weighting is enabled, then the vertex's eye coordinates are found as (xe0 ye0 ze0 we0)' = M0 (xo yo zo wo)' (xe1 ye1 ze1 we1)' = M1 (xo yo zo wo)' (xe,ye,ze)' = vw*(xe0,ye0,ze0)' + (1-vw) * (xe1,ye1,ze1)' we = we0 where M1 is the secondary modelview matrix and vw is the current vertex weight." -- Section 2.10.2 Change the 1st paragraph to say: "The projection matrix and the primary and secondary modelview matrices are set and modified with a variety of commands. The affected matrix is determined by the current matrix mode. The current matrix mode is set with void MatrixMode(enum mode); which takes one of the four pre-defined constants TEXTURE, MODELVIEW0, MODELVIEW1, or PROJECTION (note that MODELVIEW is an alias for MODELVIEW0). TEXTURE is described later. If the current matrix is MODELVIEW0, then matrix operations apply to the primary modelview matrix; if MODELVIEW1, then matrix operations apply to the secondary modelview matrix; if PROJECTION, then they apply to the projection matrix." Change the 9th paragraph to say: "There is a stack of matrices for each of the matrix modes. For the MODELVIEW0 and MODELVIEW1 modes, the stack is at least 32 (that is, there is a stack of at least 32 modelview matrices). ..." Change the last paragraph to say: "The state required to implement transformations consists of a four-valued integer indicating the current matrix mode, a stack of at least two 4x4 matrices for each of PROJECTION and TEXTURE with associated stack pointers, and two stacks of at least 32 4x4 matrices with an associated stack pointer for MODELVIEW0 and MODELVIEW1. Initially, there is only one matrix on each stack, and all matrices are set to the identity. The initial matrix mode is MODELVIEW0." -- Section 2.10.3 Change the 2nd and 7th paragraphs to say: "For a modelview matrix M, the normal for this matrix is transformed to eye coordinates by: (nx' ny' nz' q') = (nx ny nz q) * M^-1 where, if (x y z w)' are the associated vertex coordinates, then / 0, w= 0 | q = | -(nx ny nz) (x y z)' (2.1) | --------------------, w != 0 \ w Implementations may choose instead to transform (x y z)' to eye coordinates using (nx' ny' nz') = (nx ny nz) * Mu^-1 Where Mu is the upper leftmost 3x3 matrix taken from M. Rescale multiplies the transformed normals by a scale factor ( nx" ny" nz" ) = f (nx' ny' nz') If rescaling is disabled, then f = 1. If rescaling is enabled, then f is computed as (mij denotes the matrix element in row i and column j of M^-1, numbering the topmost row of the matrix as row 1 and the leftmost column as column 1 1 f = --------------------------- sqrt(m31^2 + m32^2 + m33^2) Note that if the normals sent to GL were unit length and the model-view matrix uniformly scales space, the rescale make sthe transformed normals unit length. Alternatively, an implementation may chose f as 1 f = --------------------------- sqrt(nx'^2 + ny'^2 + nz'^2) recomputing f for each normal. This makes all non-zero length normals unit length regardless of their input length and the nature of the modelview matrix. After rescaling, the final transformed normal used in lighting, nf, depends on whether vertex weighting is enabled or not. When vertex weighting is disabled, nf is computed as nf = m * ( nx"0 ny"0 nz"0 ) where (nx"0 ny"0 nz"0) is the normal transformed as described above using the primary modelview matrix for M. If normalization is enabled m=1. Otherwise 1 m = ------------------------------ sqrt(nx"0^2 + ny"0^2 + nz"0^2) However when vertex weighting is enabled, the normal is transformed twice as described above, once by the primary modelview matrix and again by the secondary modelview matrix, weighted using the current per-vertex weight, and normalized. So nf is computed as nf = m * ( nx"w ny"w nz"w ) where nw is the weighting normal computed as nw = vw * ( nx"0 ny"0 nz"0 ) + (1-vw) * (nx"1 ny"1 nz"1) where (nx"0 ny"0 nz"0) is the normal transformed as described above using the primary modelview matrix for M, and (nx"1 ny"1 nz"1) is the normal transformed as described above using the secondary modelview matrix for M, and vw is the current pver-vertex weight." -- Section 2.12. Changes the 3rd paragraph: "The coordinates are treated as if they were specified in a Vertex command. The x, y, z, and w coordinates are transformed by the current primary modelview and perspective matrices. These coordinates, along with current values, are used to generate a color and texture coordinates just as done for a vertex, except that vertex weighting is always treated as if it is disabled." Additions to Chapter 3 of the OpenGL 1.2.1 Specification (Rasterization) None Additions to Chapter 4 of the OpenGL 1.2.1 Specification (Per-Fragment Operations and the Framebuffer) None Additions to Chapter 5 of the OpenGL 1.2.1 Specification (Special Functions) None Additions to Chapter 6 of the OpenGL 1.2.1 Specification (State and State Requests) None Additions to Appendix A of the OpenGL 1.2.1 Specification (Invariance) None Additions to the AGL/GLX/WGL Specifications None GLX Protocol A new GL rendering command is added. The following command is sent to the server as part of a glXRender request: VertexWeightfvEXT 2 8 rendering command length 2 4135 rendering command opcode 4 FLOAT32 weight0 To support vertex arrays, the DrawArrays rendering command (sent via a glXRender or glXRenderLarge request) is amended as follows: The list of arrays listed for the third element in the ARRAY_INFO structure is amended to include: 0x850c j=1 VERTEX_WEIGHT_ARRAY_EXT The VERTEX_DATA description is amended to include: If the vertex weight array is enabled: ws LISTofBYTE vertex weight array element wp unused, wp=pad(ws) with the following paragraph amended to read: "where ns, cs, is, ts, es, vs, ws is the size of the normal, color, index, texture, edge, vertex, and vertex weight array elements and np, cp, ip, tp, ep, vp, wp is the padding for the normal, color, index, texture, edge, vertex, and vertex weight array elements, respectively." Errors The current vertex weight can be updated at any time. In particular WeightVertexEXT can be called between a call to Begin and the corresponding call to End. INVALID_VALUE is generated if VertexWeightPointerEXT parameter is not 1. INVALID_ENUM is generated if VertexWeightPointerEXT parameter is not FLOAT. INVALID_VALUE is generated if VertexWeightPointerEXT parameter is negative. New State (table 6.5, p196) Get Value Type Get Command Initial Value Description Sec Attribute --------- ---- ----------- ------------- ----------- --- --------- CURRENT_VERTEX_WEIGHT_EXT F GetFloatv 1 Current 2.8 current vertex weight (table 6.6, p197) Get Value Type Get Command Initial Value Description Sec Attribute --------- ---- ----------- ------------- ----------- --- --------- VERTEX_WEIGHT_ARRAY_EXT B IsEnabled False Vertex weight enable 2.8 vertex-array VERTEX_WEIGHT_ARRAY_SIZE_EXT Z+ GetIntegerv 1 Weights per vertex 2.8 vertex-array VERTEX_WEIGHT_ARRAY_TYPE_EXT Z1 GetIntegerv FLOAT Type of weights 2.8 vertex-array VERTEX_WEIGHT_ARRAY_STRIDE_EXT Z GetIntegerv 0 Stride between weights 2.8 vertex-array VERTEX_WEIGHT_ARRAY_POINTER_EXT Y GetPointerv 0 Pointer to vertex weight array 2.8 vertex-array (table 6.7, p198) Get Value Type Get Command Initial Value Description Sec Attribute --------- ---- ----------- ------------- ----------- ------ --------- MODELVIEW0_MATRIX_EXT 32*xM4 GetFloatv Identity Primary modelview 2.10.2 - stack MODELVIEW1_MATRIX_EXT 32*xM4 GetFloatv Identity Secondary modelview 2.10.2 - stack MODELVIEW0_STACK_DEPTH_EXT Z+ GetIntegerv 1 Primary modelview 2.10.2 - stack depth MODELVIEW1_STACK_DEPTH_EXT Z+ GetIntegerv 1 Secondary modelview 2.10.2 - stack depth MATRIX_MODE Z4 GetIntegerv MODELVIEW0 Current matrix mode 2.10.2 transform VERTEX_WEIGHTING_EXT B IsEnabled False Vertex weighting 2.10.2 transform/enable on/off NOTE: MODELVIEW_MATRIX is an alias for MODELVIEW0_MATRIX_EXT MODELVIEW_STACK_DEPTH is an alias for MODELVIEW0_STACK_DEPTH_EXT New Implementation Dependent State None Revision History 12/16/2000 amended to include GLX protocol for vertex arrays 5/25/2000 added missing MODELVIEW#_MATRIX_EXT token values 1/3/2003 changed status to "discontinued"