Difference between revisions of "Using accessors"

From COLLADA Public Wiki
Jump to navigation Jump to search
(→‎Detailed annotated examples: reduce leading spaces)
Line 240: Line 240:
 
===Introducing the elements and a simple case===
 
===Introducing the elements and a simple case===
 
This example introduces the accessor-related elements and explains how each is used in the simplest case. (Example file: Accessor_1.dae)  
 
This example introduces the accessor-related elements and explains how each is used in the simplest case. (Example file: Accessor_1.dae)  
 +
 +
''sthomas Note: Replace all the *******'s with proper XML comment tags.''
  
 
  <library_geometries>
 
  <library_geometries>

Revision as of 22:07, 18 May 2007

Tutorials
This article is one several tutorials, guides, and annotated examples available in this wiki.
Multipage tutorials:  • COLLADA DOM user guide
Shorter how-tos:  • Using accessors  • Schema validation • Using URIs
 • Various annotated examples

Instructions for adding a tutorial

[[Category: ]]


This tutorial about using accessors provides examples of COLLADA <accessor>/<param> use with

 element arrays.

==Overview==
Surveys of COLLADA users have shown that the 1.4.1 [[specification]] description of how to use <accessor>s and <param>s to read a <source> can be confusing and needs to be clarified.  Many people think this is much more complicated than it actually is, so we recommend that everyone read this, as it may save you some work.

==How accessors work==
To properly read a <source> through an <accessor>, the program has to consider:
* The data expected by a particular <input> ''semantic''
* The ''stride'' attribute value
* The ''offset'' attribute value
* The number of <param>s with nonnull names to decide which values to read and which to skip

Semantics in an <input> imply a specific data ordering in a <source>, such as X, Y, Z  for positions or R, G, B for colors.  If the ''name'' attribute in a <param> is missing or empty, the corresponding value in the <source> is skipped.  

'''''Note:''' The text in the ''name'' attribute is a user label only and does not affect how the <source> data is read.''

If you have a POSITION ''semantic'' reading a <source> with three <param>s, it doesn’t matter whether the <param>s are named X, Y, Z or ONE, TWO, THREE: the first value should always be treated as the X position, the second as Y, and the third as Z.  If there are fewer <param> elements than the ''stride'' for the source, skip the values that are missing <param>s.  For example, if you have a ''stride'' of 5 and only three <param> elements, you would read three values, skip two, read three more, skip 2, and so on.

==Example target data structure==
The following examples show how <param>, ''count'', ''stride'', and ''offset'' interact.
For all of them, assume that your application has the following vertex-map-like structure array that it’s trying to fill with geometry:

 struct
 {
    float x_pos, y_pos, z_pos, x_norm, y_norm, z_norm, text1_U, tex1_V, tex2_U tex2_V;
 } my_array[1000];

==Example 1: A simple case==
Given a COLLADA <source> and a <triangles> element with <input>s like this:

 <source id=test1>
   <float_array name="values" count="9">
     1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0
   </ float _array>
   <technique_common>
     <accessor source="#values" count="3" stride=”3”>
       <param name="A" type="float"/>
       <param name="F" type="float"/>
       <param name="X" type="float"/>
     </accessor>
   </technique_common>
<triangles count=”1”> 
  <input semantic="POSITION" source="#test1" offset=”0”/>
  <p>0 1 2</p>
</triangles>

You can read the data into my_array sequentially. Because the stride of the <accessor> is 3 and all three <param>s have names, the

 is assumed to contain 3D positions and '''my_array''' would be filled in like this:

{| border=1 cellpadding=3 cellspacing=0
|-
!X_pos || Y_pos || Z_pos || X_norm || Y_norm || Z_norm || Tex1_U || Tex1_V || Tex2_U || Tex2_v
|-
|1.0 || 2.0 || 3.0 || ||  ||  ||  ||  ||  || 
|-
|4.0 || 5.0 || 6.0 ||  ||  ||  ||  ||  ||  || 
|-
|7.0 || 8.0 || 9.0 ||  ||  ||  ||  ||  ||  || 
|}						

==Example 2: Parameter skipping==
This is an example of the advanced parameter skipping usage: 

 <source id=test1>
   <float_array name="values" count="9">
     1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0
   </ float _array>
   <technique_common>
     <accessor source="#values" count="3" stride=”3”>
       <param name="A" type="float"/>
       <param type="float"/>
       <param name="X" type="float"/>
     </accessor>
   </technique_common>
<triangles count=”1”>
  <input semantic="POSITION" source="#test1" offset=”0”/>
  <p>0 1 2</p> 
</triangles>

Because the second <param> now has no name, it is skipped. With only two named <param>s, the

 is assumed to contain 2D positions and is read like this:


{| border=1 cellpadding=3 cellspacing=0
|-
!X_pos || Y_pos || Z_pos || X_norm || Y_norm || Z_norm || Tex1_U || Tex1_V || Tex2_U || Tex2_v
|-
|1.0 || 3.0|| ||  ||  ||  ||  ||  ||  || 
|-
|4.0 || 6.0|| ||  ||  ||  ||  ||  ||  || 
|-
|7.0 || 9.0|| ||  ||  ||  ||  ||  ||  || 
|}

==Example 3: Multiple accessors with a single source array==
Usually an application creates one <source>/<float_array> for each type of data, for example, a stride-3 array for positions, another for normals, a stride-2 array for texture coordinates, and so on.  Most COLLADA documents that you download will be organized this way, so it’s easy to find an example of how this looks.

Some applications may want to pack all the information about a vertex into a single <source> array that is similar to an OpenGL vertex array. This requires creating several <source>s and <accessor>s that all reference data in the same <float_array>.  This can be done using only basic COLLADA features, so all COLLADA applications should be able to handle this data.

 <source id=positions>
   <float_array name="values" count="30">
     1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
   </ float _array>
   <technique_common>
     <accessor source="#values" count="3" stride=”10”>
       <param name="NAME" type="float"/>
       <param name="VALUES" type="float"/>
       <param name="ARE" type="float"/>
     </accessor>
   </technique_common>
   <technique_common>
     <accessor source="#values" offset=”3” count="3" stride=”10”>
       <param name="NOT" type="float"/>
       <param name="SIGNIFICANT" type="float"/>
       <param name="X" type="float"/>
     </accessor>
   </technique_common>
   <technique_common>
     <accessor source="#values" offset=”6” count="3" stride=”10”>
       <param name="A" type="float"/>
       <param name="F" type="float"/>
     </accessor>
   </technique_common>
   <technique_common>
     <accessor source="#values" offset=”8”  count="3" stride=”10”>
       <param name="Q" type="float"/>
       <param name="F" type="float"/>
     </accessor>
   </technique_common>
<triangles count=”1”>
  <input semantic="POSITION" source="#positions" offset=”0”/>
  <input semantic="NORMAL"   source="#normals" offset=”0”/>
  <input semantic="TEXCOORD" source="#texture1" offset=”0”/>
  <input semantic="TEXCOORD" source="#texture2" offset=”0”/>
  <p>1 2 3</p> 
</triangles>

The first <accessor> tells you to start with the first value in the source, read three values into the position part of your array, skip 7 values, read three more positions, and so on. The second <accessor> begins by skipping 3 values (the offset) then reads 3, skips 7, and so on. An application could also decide to read the entire COLLADA float_array into a 10-column-wide array in memory, then use the <accessor>s as a way to identify what is in each column of the array. Regardless of how you do it, my_array would end up getting filled in like this:

X_pos Y_pos Z_pos X_norm Y_norm Z_norm Tex1_U Tex1_V Tex2_U Tex2_v
1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0
11.0 12.0 13.0 14.0 15.0 16.0 17.0 18.0 19.0 20.0
21.0 22.0 23.0 24.0 25.0 26.0 27.0 28.0 29.0 30.0

Example 4: Parameters with blank names

This next example produces the same results as the preceding example, but it uses the “skipping <param>s with blank names” approach rather than an offset. This skipping behavior is supported only by advanced programs, so it may be wise to avoid using it if you can.

   <float_array name="values" count="30">
     1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
   </ float _array>
   <technique_common>
     <accessor source="#values" count="3" stride=”10”>
       <param name="A" type="float"/>
       <param name="F" type="float"/>
       <param name="X" type="float"/>
     </accessor>
   </technique_common>
   <technique_common>
     <accessor source="#values" count="3" stride=”10”>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param name="A" type="float"/>
       <param name="F" type="float"/>
       <param name="X" type="float"/>
     </accessor>
   </technique_common>
   <technique_common>
     <accessor source="#values" count="3" stride=”10”>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param name="A" type="float"/>
       <param name="F" type="float"/>
     </accessor>
   </technique_common>
   <technique_common>
     <accessor source="#values" count="3" stride=”10”>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param type="float"/>
       <param name="F" type="float"/>
       <param name="X" type="float"/>
     </accessor>
   </technique_common>
<triangles count=”1”>
  <input semantic="POSITION" source="#positions" offset=”0”/>
  <input semantic="NORMAL" source="#normals" offset=”0”/>
  <input semantic="TEXCOORD" source="#texture1" offset=”0”/>
  <input semantic="TEXCOORD" source="#texture2" offset=”0”/>
  <p>1 2 3</p>
</triangles>

After reading this example, you may realize that there are very few occasions where the “skipping <param>s with blank names” behavior would be used, at least with “technique_common” COLLADA data. The parameter skipping is mainly of use for application-defined techniques that may have application-defined semantics where skipping values in the middle of a source array is useful.

An example of how this might be useful in an advanced program might be where an application has defined its own semantic that reads a vertex array's positions and a set of texture coordinates. The <float_array> in the COLLADA document could potentially contain more than one set of texture coordinates, each designed to produce an object with a different appearance. The blank-<param>-skipping behavior could be used to select which set of texture coordinates would be used when drawing primitives for different versions of the object.

Conformance testing note

Although the COLLADA conformance test process is not yet complete, at this time (April 2007) we do not plan to require basic COLLADA programs to support skipping of <param>s with blank or missing name attributes. This behavior is rarely useful for <technique_common> semantics and COLLADA data. Because application-defined techniques and semantics are considered advanced features, skipping <param>s with blank names will also be considered an advanced feature.

Detailed annotated examples

The following examples show how to use the

, <accessor>, and <param> elements in COLLADA.

===Introducing the elements and a simple case===
This example introduces the accessor-related elements and explains how each is used in the simplest case. (Example file: Accessor_1.dae) 

''sthomas Note: Replace all the *******'s with proper XML comment tags.''

 <library_geometries>
  <geometry id="triangle-lib" name="triangle">
     <mesh>
        ******************************************************************************************
        This is a simple triangle mesh with 3 typical source inputs, positions, normal, and texcoords.
        There are 3 vertices, 3 normals, and 3 texture coords. 
        The first source consists of a  float_array of 9 floating point values (3 sets of vertices).
        We refer to the float_array as the "source array" below. 
        ******************************************************************************************    
        <source id="triangle-lib-positions" name="position">
           <float_array id="triangle-lib-positions-array" count="9">
                   -50 -50 0   
                     0  50 0   
                    50 -50 0
           </float_array>
           <technique_common>
              ******************************************************************************************
              The accessor tells the application how to read the source array data into the application. In 
              the accessor below we see that the count is 3. This means that there are 3 sets of XYZ data.
              In other words there are three sets of vertices to read. The stride is also 3, indicating that 
              the source array consists purely of positional data.
              The following chart shows the relationship between the data, the stride, and the Vertex position 
              placement within the data source.           
           
              Data:        -50, -50,   0,    0,  50,   0,   50, -50,   0    
              Stride #:      1    2    3     1    2    3     1    2    3    
              Pos          P0X, P0Y, P0Z,  P1X, P1Y, P1Z,  P2X, P2Y, P2Z, 
                         
              A useful tool to remember is that the count in the source array should always equal the 
              accessor's count * stride.
           
              In this case 3 * 3 = 9
              ******************************************************************************************  
              <accessor count="3" offset="0" source="#triangle-lib-positions-array" stride="3">
                 <param name="X" type="float"></param>
                 <param name="Y" type="float"></param>
                 <param name="Z" type="float"></param>
              </accessor>
           </technique_common>
       ******************************************************************************************
       The second source consists of a  float_array of 9 floating point values (3 sets of normals).
       ******************************************************************************************   
           <float_array id="triangle-lib-normals-array" count="9">
                      0 0 -1  
                      0 0 -1  
                      0 0 -1 
           </float_array>
   
           <technique_common>
              ******************************************************************************************
              The accessor in this source works just the same as in the Position Source. There are three sets
              of normals (one normal for each vertex), and each normal consists of 3 values (X,Y,Z). Again,
              the source array consists purely of normal data (the accessor stride is 3, the accessor count 
              is 3, and the total number of values in the source array is 9). 
              ******************************************************************************************               
              <accessor count="3" offset="0" source="#triangle-lib-normals-array" stride="3">
                 <param name="X" type="float"></param>
                 <param name="Y" type="float"></param>
                 <param name="Z" type="float"></param>
              </accessor>
           </technique_common>
       ******************************************************************************************
       The third source is a little different from the first two. It consists of a  float_array of 
       6 floating point values (3 sets of texture coords, one for each vertex), each texture coord 
       only has 2 values (U, V).
       ******************************************************************************************   
           <float_array id="triangle-lib-texcoords-array" count="6">
                        0    0  
                      0.5  1.0 
                      1.0  0.0 
           </float_array>
           ******************************************************************************************
           The accessor in this source works in just the same way as the first two except that texture
           coords only require two values per vertex. So, the stride in the source array if now only 2.
           The count is 3, the stride is 2 and the source count is 6 (3*2=6).
           ******************************************************************************************   
           <technique_common>
              <accessor count="3" offset="0" source="#triangle-lib-texcoords-array" stride="2">
                 <param name="U" type="float"></param>
                 <param name="V" type="float"></param>
              </accessor>
           </technique_common>
       <vertices id="triangle-lib-vertices">
          <input semantic="POSITION" source="#triangle-lib-positions"></input>
       </vertices>
       
       <triangles count="1" material="BlueSG">
          ******************************************************************************************
          Notice that the offset in each input is 0. This indicates that the indices in <p> array are 
          the same for each source. This means that vertex 0 has has normal 0 and has texcoord 0.
          Vertex 1 has normal 1 and texcoord 1, and so on.
          ******************************************************************************************  
          <input offset="0" semantic="VERTEX" source="#triangle-lib-vertices"></input>
          <input offset="0" semantic="NORMAL" source="#triangle-lib-normals"></input>
          <input offset="0" semantic="TEXCOORD" source="#triangle-lib-texcoords"></input>
          <p>0 1 2</p>
       </triangles>
       
    </mesh>
 </geometry>
</library_geometries>

Interleaved data and extracting source streams

This example introduces the concept of interleaved data and shows how the accessor can be used to extract individual source streams. (Example file: Accessor_2.dae)

<library_geometries>
 <geometry id="triangle-lib" name="triangle">
    <mesh>
       ******************************************************************************************
       This is a simple triangle mesh with 3 typical source inputs, positions, normal, and texcoords.
       There are 3 vertices, 3 normals, and 3 texture coords. This example introduces the concept of
       interleaving a source array with both position and normal data. The accessors are reconfigured 
       to extract the interleaved data into separate sources, see below.
       The first source consists of a  float_array of 18 floating point values that define the vertex 
       positions and normals. The order of the data is a vertex triple folowed by a normal triple, e.g.
       P0X, P0Y, P0Z, N0X, N0Y, N0Z, P1X, P1Y, P1Z, .....
       ******************************************************************************************    
           <float_array id="triangle-positions-normals-array" count="18">
                      -50 -50  0  
                        0   0 -1 
                        0  50  0  
                        0   0 -1 
                       50 -50  0
                        0   0 -1
           </float_array>
           <technique_common>
              ******************************************************************************************
              This accessor extracts the vertex position data. Notice that the stride has changed from 3 (as 
              used in the first example) to 6. The count of 3 is the same (i.e. positions still have XY and 
              Z components). Also, notice that the offset is 0. So, the stride is 6, meaning that there are 6 
              values per vertex - 3 for the position XYZs followed by 3 for the normal XYZs. The offset of 0 
              indicates that the position XYZ's are first within each stride.
              
              The following chart shows the relationship between the data, the stride, and the Position and 
              Normal placement within the data source.
              
              Data:        -50, -50,   0,    0,   0,  -1,    0,  50,   0     0,   0,  -1,
              Stride #:      1    2    3     4    4    6     1    2    3     4    5    6
              Pos/Norm     P0X, P0Y, P0Z,  N0X, N0Y, N0Z,  P1X, P1Y, P1Z,  N1X, N1Y, N1Z,
           
              A useful tool to remember is that the count in the source array should always equal the 
              accessor's count * stride.
           
              In this case 3 * 6 = 18
              ******************************************************************************************  
              <accessor count="3" offset="0" source="#triangle-positions-normals-array" stride="6">
                 <param name="X" type="float"></param>
                 <param name="Y" type="float"></param>
                 <param name="Z" type="float"></param>
              </accessor>
           </technique_common>


       ******************************************************************************************
       The second source does not have its own source data, it re-uses the same interleaved Position-Normals
       source as the Position accessor.
       ******************************************************************************************   
           <technique_common>
              ******************************************************************************************
              This accessor re-uses the Position-Normals source. Notice that the count and stride are the same
              as those used by the Positions accessor (because it is using the same data!). The offset, however,
              is different, it is 3. This means the normal data starts at position 3 within each stride. 
              
              The chart below shows a stride of 6 data values form the position source. You can see that the 
              normal data starts at an offset of 3 into the source data.
              
              Stride #:      1    2    3     4    4    6  
              Data:        -50, -50,   0,    0,   0,  -1,    
              Pos/Norm     P0X, P0Y, P0Z,  N0X, N0Y, N0Z, 
              Offset:        0    1    2    3    4    5
              
              ******************************************************************************************               
              <accessor count="3" offset="3" source="#triangle-positions-normals-array" stride="6">
                 <param name="X" type="float"></param>
                 <param name="Y" type="float"></param>
                 <param name="Z" type="float"></param>
              </accessor>
           </technique_common>
       ******************************************************************************************
       The texcoord accessor has not changed. It consists of a  float_array of 
       6 floating point values (3 sets of texture coords, one for each vertex), each texture coord 
       only has 2 values (U, V).
       ******************************************************************************************   
           <float_array id="triangle-lib-texcoords-array" count="6">
                        0    0  
                      0.5  1.0 
                      1.0  0.0 
           </float_array>
           ******************************************************************************************
           Texture coords only require two values per vertex. Therefor, the stride in the source array is 2.
           The accessor count is 3, the accessor stride is 2, and the source count is 6 (3*2=6).
           ******************************************************************************************   
           <technique_common>
              <accessor count="3" offset="0" source="#triangle-lib-texcoords-array" stride="2">
                 <param name="U" type="float"></param>
                 <param name="V" type="float"></param>
              </accessor>
           </technique_common>


       <vertices id="triangle-lib-vertices">
          <input semantic="POSITION" source="#triangle-positions-normals"></input>
       </vertices>
       
       <triangles count="1" material="BlueSG">
          ******************************************************************************************
          Notice that the offset in each input is 0. This indicates that the indices in <p> array are 
          the same for each source. This means that vertex 0 has has normal 0 and has texcoord 0.
          Vertex 1 has normal 1 and texcoord 1, and so on.  Basically, the <p> index array is used for 
          each of the sources.
          ******************************************************************************************  
          <input offset="0" semantic="VERTEX" source="#triangle-lib-vertices"></input>
          <input offset="0" semantic="NORMAL" source="#triangle-lib-normals"></input>
          <input offset="0" semantic="TEXCOORD" source="#triangle-lib-texcoords"></input>
          <p>0 1 2</p>
       </triangles>
    </mesh>
 </geometry>
</library_geometries>

Skipping parameters

This example introduces the concept of skipping params - another way to deal with an interleaved data input stream. (Example file: Accessor_3.dae)

<library_geometries>
  <geometry id="triangle-lib" name="triangle">
    <mesh>
       ******************************************************************************************
       This is a simple triangle mesh with 3 typical source inputs, positions, normal, and texcoords.
       There are 3 vertices, 3 normals, and 3 texture coords. This example introduces the concept of
       skipping params in the accessor to handle interleaved data.
       The first source consists of a  float_array of 18 floating point values that define the vertex 
       positions and normals. The order of the data is a vertex triple folowed by a normal triple, e.g.
       P0X, P0Y, P0Z, N0X, N0Y, N0Z, P1X, P1Y, P1Z, .....
       ******************************************************************************************    
           <float_array id="triangle-positions-normals-array" count="18">
                      -50 -50  0  
                        0   0 -1 
                        0  50  0  
                        0   0 -1 
                       50 -50  0
                        0   0 -1
           </float_array>
           <technique_common>
              ******************************************************************************************
              This accessor extracts the vertex position data - it is the same as in example 2.
              Notice that the stride is 6. The count of 3 is the same (i.e. positions still have XY and Z 
              components). Also, notice that the offset is 0. So, the stride is 6, meaning that there are 6 
              values per vertex - 3 for the position XYZs followed by 3 for the normal XYZs. The offset of 0 
              indicates that the position XYZ's are first within each stride.
              
              The following chart shows the relationship between the data, the stride, and the Position and 
              Normal placement within the data source.
              
              Data:        -50, -50,   0,    0,   0,  -1,    0,  50,   0     0,   0,  -1,
              Stride #:      1    2    3     4    4    6     1    2    3     4    5    6
              Pos/Norm     P0X, P0Y, P0Z,  N0X, N0Y, N0Z,  P1X, P1Y, P1Z,  N1X, N1Y, N1Z,
           
              A useful tool to remember is that the count in the source array should always equal the 
              accessor's count * stride.
           
              In this case 3 * 6 = 18
              ******************************************************************************************  
              <accessor count="3" offset="0" source="#triangle-positions-normals-array" stride="6">
                 <param name="X" type="float"></param>
                 <param name="Y" type="float"></param>
                 <param name="Z" type="float"></param>
              </accessor>
           </technique_common>


       ******************************************************************************************
       The second source does not have its own source data, it re-uses the same interleaved Position-Normals
       source as the Position accessor. 
       ******************************************************************************************   
           <technique_common>
              ******************************************************************************************
              This accessor re-uses the Position-Normals source. Notice that the count and stride are the same
              as those used by the Positions accessor (because it is using the same data!). Note, the offset is set 
              to 0. So, how do we get to the get the Normal data which starts at index 3?  We do this by adding 
              3 new params to the front and by NOT giving them a name. Only params that have a name will actually 
              get read into your application.
              
              The chart below shows a stride of 6 data values form the position source. You can see that the 
              normal data starts at an offset of 3 into the source data.
              
              Stride #:      1    2    3     4    4    6  
              Data:        -50, -50,   0,    0,   0,  -1,    
              Pos/Norm     P0X, P0Y, P0Z,  N0X, N0Y, N0Z, 
              Offset:        0    1    2    3    4    5
              
              ******************************************************************************************               
              <accessor count="3" offset="0" source="#triangle-positions-normals-array" stride="6">
                 <param type="float"></param>
                 <param type="float"></param>
                 <param type="float"></param>                 
                 <param name="nX" type="float"></param>
                 <param name="nY" type="float"></param>
                 <param name="nZ" type="float"></param>
              </accessor>
           </technique_common>
       ******************************************************************************************
       The texcoord accessor has not changed. It consists of a  float_array of 
       6 floating point values (3 sets of texture coords, one for each vertex), each texture coord 
       only has 2 values (U, V).
       ******************************************************************************************   
           <float_array id="triangle-lib-texcoords-array" count="6">
                        0    0  
                      0.5  1.0 
                      1.0  0.0 
           </float_array>
           ******************************************************************************************
           Texture coords only require two values per vertex. Therefor, the stride in the source array is 2.
           The accessor count is 3, the accessor stride is 2, and the source count is 6 (3*2=6).
           ******************************************************************************************   
           <technique_common>
              <accessor count="3" offset="0" source="#triangle-lib-texcoords-array" stride="2">
                 <param name="U" type="float"></param>
                 <param name="V" type="float"></param>
              </accessor>
           </technique_common>


       <vertices id="triangle-lib-vertices">
          <input semantic="POSITION" source="#triangle-positions-normals"></input>
       </vertices>
       
       <triangles count="1" material="BlueSG">
          ******************************************************************************************
          Notice that the offset in each input is 0. This indicates that the indices in <p> array are 
          the same for each source. This means that vertex 0 has has normal 0 and has texcoord 0.
          Vertex 1 has normal 1 and texcoord 1, and so on.  Basically, the <p> index array is used for 
          each of the sources.
          ******************************************************************************************  
          <input offset="0" semantic="VERTEX" source="#triangle-lib-vertices"></input>
          <input offset="0" semantic="NORMAL" source="#triangle-lib-normals"></input>
          <input offset="0" semantic="TEXCOORD" source="#triangle-lib-texcoords"></input>
          <p>0 1 2</p>
       </triangles>
       
    </mesh>
  </geometry>
</library_geometries>