There are many silly files in the internet which are created with a primitiv converter. This converters generate files with many face sets which contain only few faces. You can see an example in the picture (the red bounding box is a face set, correct: the hull is a big face set).
In this case the hull is devided into many parts. This is not a problem in the original ( = LOD 0 ) but in a LOD you get holes in the hull, if you have a changed countour of a face set.
The ship is broken into pieces. This effect is proportional to the LOD depth.
I check every node and compare it with his next neighbour. When the
node has the same type (Separator, Group, Binding, Material, Texture, Coord,
Normal, IndexedFaceSet and IndexedLineSet) I append the content of the
first node to the second node and delete the first. A node with a DEF string
is not joinable if the DEF is used by a USE statement! In the case the
nodes are Separator nodes, I must check the sub lists and append the contents
of the first sub list to the second. Then I delete the first Separator
node and his sub list.
The algorithm works first in the leaves of the VRML tree and then proceedes
to the root.
Join two Separator nodes with same Material sub nodes and possibly different IndexedFaceSet sub nodes:
Original:
Separator {
Material { diffuseColor 0.5 0.6 0.4 }
IndexedFaceSet { coordIndex [1,2,3,-1] }
}
Separator {
Material { diffuse 0.5 0.6 0.4 }
IndexedFaceSet { coordIndex [4,5,6,-1] }
}
Result:
Separator {
Material { diffuse 0.5 0.6 0.4 }
IndexedFaceSet { coordIndex [1,2,3,-1,4,5,6,-1] }
}
Join two Separator nodes with different Material sub nodes and possibly different IndexedFaceSet sub nodes:
Original:
Separator {
Material { diffuse 0.5 0.6 0.4 }
IndexedFaceSet { coordIndex [1,2,3,-1] }
}
Separator {
Material { diffuse 0.3 0.3 0.3 }
IndexedFaceSet { coordIndex [4,5,6,-1] }
}
Result:
Separator {
Material {
ambientColor [0.2 0.2 0.2, 0.2 0.2 0.2]
diffuseColor [0.5 0.6 0.4, 0.3 0.3 0.3]
specularColor [0 0 0, 0 0 0]
emissiveColor [0 0 0, 0 0 0]
shininess [0.2, 0.2]
transparency [0, 0]
}
MaterialBinding { value PER_FACE_INDEXED }
IndexedFaceSet {
coordIndex [1,2,3,-1,4,5,6,-1]
materialIndex [0,1]
}
}
I insert a new MaterialBinding node with value PER_FACE_INDEXED and
create a materialIndex for the IndexedFaceSet.
It is also necessary to create a complete Material node (I add ambientColor,
specularColor, emissiveColor, shininess and transparency to the diffuseColor),
to join this new created nodes with other nodes.
Information: the following LOD algorithm removes not necessary color
values (example: transparency [0,0] => transparency 0).
Join two Separator nodes with possibly different Coordinate3 sub nodes and possibly different IndexedFaceSet sub nodes:
Original:
Separator {
Coordinate3 { point [ 0.5 0.6 0.4, 1.5 0.6 0.4, 1.5 1.6 0.4] }
IndexedFaceSet { coordIndex [0,1,2,-1] }
}
Separator {
Coordinate3 { point [ 3.5 3.6 3.4, 5.5 3.6 3.4, 5.5 5.6 3.4] }
IndexedFaceSet { coordIndex [0,1,2,-1] }
}
Result:
Separator {
Coordinate3 { point [
0.5 0.6 0.4, 1.5 0.6 0.4, 1.5 1.6 0.4,
3.5 3.6 3.4, 5.5 3.6 3.4, 5.5 5.6 3.4]
}
IndexedFaceSet { coordIndex [ 0,1,2,-1,3,4,5,-1] }
}
The point list of the second Coordinate3 nodes will be appended to the
point list of the first Coordinate3 node. Then this new list will be set
as list of the second node.
The same procedure will be used with the IndexedFaceSet nodes and the
coord indices. It is also necessary to increment the indices of the second
node at the point count of the first Coordinate3 node.
This join algorithm is also useable with Normal and Texture nodes.
I remove not necessary Separator nodes (a Separator node on the end of a list is not necessary) to increase the percentage of joinable nodes.
Original:
Separator {
Separator {
IndexedFaceSet { coordIndex [0,1,2,-1] }
}
}
Result:
Separator {
IndexedFaceSet { coordIndex [0,1,2,-1] }
}