-
Notifications
You must be signed in to change notification settings - Fork 25
How to use Xflow
First we will describe how data is declared and connected to the scene graph.
Several elements inside the scene graph, including <mesh>
, <shader>
and <lightshader>
use generic data content, e.g. like this:
<mesh type="triangles">
<int name="index">0 1 2 2 3 0 4 ... </int>
<float3 name="position">-1.0 -1.0 -1.0 ... </float3>
<float3 name="normal">0.0 0.0 -1.0 0.0 0.0 ... </float3>
<float2 name="texcoord">1.0 0.0 ... </float2>
</mesh>
Generic data is declared with a list of typed ValueElements, e.g. <float>
, <float3>
, <int>
and so on. Each ValueElement is assigned with a name to define a named DataField.
In XML3D, it is also possible to declare generic DataContainers that are not directly linked to any semantic. For this, we use the <data>
element:
<data id="cubeMeshData" >
<int name="index">0 1 2 2 3 0 4 ... </int>
<float3 name="position">-1.0 -1.0 -1.0 ... </float3>
<float3 name="normal">0.0 0.0 -1.0 0.0 0.0 ... </float3>
<float2 name="texcoord">1.0 0.0 ... </float2>
</data>
...
<group style="transform: translateX(-5px)" >
<mesh type="triangle" src="#cubeMeshData" />
</group>
<group style="transform: translateX(5px)" >
<mesh type="triangle" src="#cubeMeshData" />
</group>
Here, we declared the generic data inside a <data>
element and reused it for two meshes by referring the <data>
node via its document id inside the src attribute of <mesh>
.
It is possible to combine multiple DataContainers and ValueElements by declaring them as children of another <data>
element.
<data id="meshBaseData">
<int name="index">0 1 2 2 3 0 4 ... </int>
<float3 name="position">-1.0 -1.0 -1.0 ... </float3>
<float3 name="normal">0.0 0.0 -1.0 0.0 0.0 ... </float3>
</data>
<data id="meshData1" >
<data src="#meshBaseData" />
<float3 name="color" >1 0 0 ...</float3>
</data>
<data id="meshData2" >
<data src="#meshBaseData" />
<float3 name="color" >0 0 1 ...</float3>
</data>
Here we combined #meshBaseData with two different color ValueElements.
It is also possible to combine multiple DataContainers:
<data id="meshBaseData">
<int name="index">0 1 2 2 3 0 4 ... </int>
<float3 name="position">-1.0 -1.0 -1.0 ... </float3>
<float3 name="normal">0.0 0.0 -1.0 0.0 0.0 ... </float3>
</data>
<data id="meshOptionalData">
<float3 name="texcoord" >1 0 0 ...</float3>
<float3 name="color" >1 0 0 ...</float3>
</data>
<data id="meshFullData" >
<data src="#meshBaseData" />
<data src="#meshOptionalData" />
</data>
Note: A <data>
node using the src attribute never contains any children. This is because those nodes ignore all children and only reuse the data of the referred node.
When combining DataContainers and ValueElements, it is possible that we get multiple DataFields with the same name. However, a DataContainer only contains one DataField per name. Multiple DataFields with the same name are reduced to one via the following replacement rules:
- A DataField of a ValueElement always replaces a DataField of a sibling DataContainer
- If two child nodes are both DataCotainers or ValueElements, the DataField of the later child replaces the DataField of the former.
<data>
<float name="A" >2</float><!-- <<<< will be replaced -->
<float name="A" >3</float>
</data>
<data>
<data>
<float name="A" >0</float>
<float name="B" >1</float><!-- <<<< will be replaced -->
</data>
<data>
<float name="B" >2</float>
<float name="C" >3</float>
</data>
</data>
<data>
<data>
<float name="A" >0</float><!-- <<<< will be replaced -->
<float name="B" >1</float>
</data>
<int name="A">42<int>
</data>
<data>
<int name="A">23<int>
<data>
<float name="A" >0</float><!-- <<<< will be replaced -->
<float name="B" >1</float>
</data>
</data>
The DataFields inside a DataContainer can be renamed and filtered with the filter attribute. The filter attribute provides 3 modi:
- remove: provide a list of names of DataFields that should be removed from the DataContainer
- keep: provide a list of names of DataFields that should stay in the DataContainer. Remove all other DataFields
- rename: rename DataFields as specified. The syntax for the name mapping is similar to the JavaScript object notation:
{ [destination name 1] : [source name 1], [destination name 2] : [source name 2], ...}
Examples:
<data filter="keep(A,D)">
<float name="A" >0</float>
<float name="B" >1</float><!-- <<< will be removed -->
<float name="C" >1</float><!-- <<< will be removed -->
<float name="D" >1</float>
</data>
<data filter="remove(D)">
<float name="A" >0</float>
<float name="B" >1</float>
<float name="C" >1</float>
<float name="D" >1</float><!-- <<< will be removed -->
</data>
<data filter="rename( {A2 : A, B2 : B} )">
<float name="A" >0</float><!-- <<< will be renamed into A2 -->
<float name="B" >1</float><!-- <<< will be renamed into B2 -->
<float name="C" >1</float>
<float name="D" >1</float>
</data>
<data filter="keep( {A2 : A, B2 : B} )">
<float name="A" >0</float><!-- <<< will be renamed into A2 -->
<float name="B" >1</float><!-- <<< will be renamed into B2 -->
<float name="C" >1</float><!-- <<< will be removed -->
<float name="D" >1</float><!-- <<< will be removed -->
</data>
<data filter="rename( {A1 : A, A2 : A, A3: A} )">
<float name="A" >0</float><!-- <<< will be provided under the names A1, A2 and A3 -->
</data>
In certain cases we need arbitrary long sequences of data, e.g. key frame data for mesh animations. In that case it is possible to declare multiple values under the same name, using the key attribute of ValueElements:
<data id="keyFrameData">
<float3 name="position" key="0" >-5 0 5 ... </float3>
<float3 name="normal" key="0" >0 -1 0 ... </float3>
<float3 name="position" key="1" >-2.886751 2.113249 2.886751 ... </float3>
<float3 name="normal" key="1">-0.554395 -0.620718 0.554395 ... </float3>
<float3 name="position" key="2">-1.341089 4.649148 1.341089 ... </float3>
<float3 name="normal" key="2">-0.696886 0.169412 0.696886 ... </float3>
<float3 name="position" key="3" >-6.158403 1.408833 6.158403 ... </float3>
<float3 name="normal" key="3">-0.141341 -0.979819 0.141341 ... </float3>
...
</data>
The replacement rules of DataFields always apply to sequence entries with the same name and key. If two DataFields have the same name and type, but different key values, they are always combined into a sequence. If no key is provided, the value 0 is assumed.