Hierarchical glTF import.

This commit is contained in:
kovacsv 2021-11-02 08:40:27 +01:00
parent 71cfe70c71
commit 3423baa2b2
6 changed files with 173 additions and 184 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 177 KiB

View File

@ -37,50 +37,6 @@ OV.GltfConstants =
BINARY_CHUNK_TYPE : 0x004E4942
};
OV.GltfNodeTree = class
{
constructor ()
{
this.nodes = [];
this.nodeToParent = {};
this.nodeMatrices = {};
}
AddMeshNode (nodeIndex)
{
this.nodes.push (nodeIndex);
return this.nodes.length - 1;
}
AddNodeParent (nodeIndex, parentIndex)
{
this.nodeToParent[nodeIndex] = parentIndex;
}
GetNodeParent (nodeIndex)
{
let parentIndex = this.nodeToParent[nodeIndex];
if (parentIndex === undefined || parentIndex === -1) {
return null;
}
return parentIndex;
}
AddNodeMatrix (nodeIndex, matrix)
{
this.nodeMatrices[nodeIndex] = matrix;
}
GetNodeMatrix (nodeIndex)
{
let matrix = this.nodeMatrices[nodeIndex];
if (matrix === undefined) {
return null;
}
return matrix;
}
};
OV.GltfBufferReader = class
{
constructor (buffer)
@ -614,26 +570,22 @@ OV.ImporterGltf = class extends OV.ImporterBase
ImportModel (gltf)
{
let defaultScene = this.GetDefaultScene (gltf);
if (defaultScene === null) {
this.SetError ('No default scene found.');
return;
}
this.ImportModelProperties (gltf);
let materials = gltf.materials;
if (materials !== undefined) {
for (let i = 0; i < materials.length; i++) {
this.ImportMaterial (gltf, i);
for (let material of materials) {
this.ImportMaterial (gltf, material);
}
}
let nodeTree = this.CollectMeshNodesForScene (gltf, defaultScene);
for (let i = 0; i < nodeTree.nodes.length; i++) {
let nodeIndex = nodeTree.nodes[i];
this.ImportMeshNode (gltf, nodeIndex, nodeTree);
let meshes = gltf.meshes;
if (meshes !== undefined) {
for (let mesh of meshes) {
this.ImportMesh (gltf, mesh);
}
}
this.ImportNodes (gltf);
this.ImportModelProperties (gltf);
}
ImportModelProperties (gltf)
@ -670,39 +622,13 @@ OV.ImporterGltf = class extends OV.ImporterBase
return gltf.scenes[defaultSceneIndex];
}
CollectMeshNodesForScene (gltf, scene)
{
function CollectMeshNodeIndices (gltf, parentIndex, nodeIndex, nodeTree)
{
let node = gltf.nodes[nodeIndex];
if (node.mesh !== undefined) {
nodeTree.AddMeshNode (nodeIndex);
}
nodeTree.AddNodeParent (nodeIndex, parentIndex);
if (node.children !== undefined) {
for (let i = 0; i < node.children.length; i++) {
let childNodeIndex = node.children[i];
CollectMeshNodeIndices (gltf, nodeIndex, childNodeIndex, nodeTree);
}
}
}
let nodeTree = new OV.GltfNodeTree ();
for (let i = 0; i < scene.nodes.length; i++) {
let nodeIndex = scene.nodes[i];
CollectMeshNodeIndices (gltf, -1, nodeIndex, nodeTree);
}
return nodeTree;
}
ImportMaterial (gltf, materialIndex)
ImportMaterial (gltf, gltfMaterial)
{
function GetMaterialComponent (component)
{
return parseInt (Math.round (OV.LinearToSRGB (component) * 255.0), 10);
}
let gltfMaterial = gltf.materials[materialIndex];
let material = new OV.Material (OV.MaterialType.Physical);
if (gltfMaterial.name !== undefined) {
material.name = gltfMaterial.name;
@ -819,76 +745,18 @@ OV.ImporterGltf = class extends OV.ImporterBase
return texture;
}
ImportMeshNode (gltf, nodeIndex, nodeTree)
ImportMesh (gltf, gltfMesh)
{
function GetNodeTransformation (gltf, nodeIndex, nodeTree)
{
let node = gltf.nodes[nodeIndex];
let matrix = nodeTree.GetNodeMatrix (nodeIndex);
if (matrix !== null) {
return matrix;
}
matrix = new OV.Matrix ().CreateIdentity ();
if (node.matrix !== undefined) {
matrix.Set (node.matrix);
} else {
let hasTransformation = false;
let translation = [0.0, 0.0, 0.0];
let rotation = [0.0, 0.0, 0.0, 1.0];
let scale = [1.0, 1.0, 1.0];
if (node.translation !== undefined) {
translation = node.translation;
hasTransformation = true;
}
if (node.rotation !== undefined) {
rotation = node.rotation;
hasTransformation = true;
}
if (node.scale !== undefined) {
scale = node.scale;
hasTransformation = true;
}
if (hasTransformation) {
matrix.ComposeTRS (
OV.ArrayToCoord3D (translation),
OV.ArrayToQuaternion (rotation),
OV.ArrayToCoord3D (scale)
);
}
}
let parentNodeIndex = nodeTree.GetNodeParent (nodeIndex);
if (parentNodeIndex !== null) {
let parentMatrix = GetNodeTransformation (gltf, parentNodeIndex, nodeTree);
matrix = matrix.MultiplyMatrix (parentMatrix);
}
nodeTree.AddNodeMatrix (nodeIndex, matrix);
return matrix;
}
let gltfNode = gltf.nodes[nodeIndex];
let gltfMeshIndex = gltfNode.mesh;
let gltfMesh = gltf.meshes[gltfMeshIndex];
let mesh = new OV.Mesh ();
this.model.AddMeshToRootNode (mesh);
this.model.AddMesh (mesh);
if (gltfMesh.name !== undefined) {
mesh.SetName (gltfMesh.name);
} else if (gltfNode.name !== undefined) {
mesh.SetName (gltfNode.name);
}
for (let i = 0; i < gltfMesh.primitives.length; i++) {
let primitive = gltfMesh.primitives[i];
this.ImportPrimitive (gltf, primitive, mesh);
}
let matrix = GetNodeTransformation (gltf, nodeIndex, nodeTree);
let transformation = new OV.Transformation (matrix);
OV.TransformMesh (mesh, transformation);
}
ImportPrimitive (gltf, primitive, mesh)
@ -1022,6 +890,71 @@ OV.ImporterGltf = class extends OV.ImporterBase
mesh.AddTriangle (triangle);
}
ImportNodes (gltf)
{
let scene = this.GetDefaultScene (gltf);
if (scene === null) {
return;
}
let rootNode = this.model.GetRootNode ();
for (let nodeIndex of scene.nodes) {
let gltfNode = gltf.nodes[nodeIndex];
this.ImportNode (gltf, gltfNode, rootNode);
}
}
ImportNode (gltf, gltfNode, parentNode)
{
function GetNodeTransformation (gltfNode)
{
let matrix = new OV.Matrix ().CreateIdentity ();
if (gltfNode.matrix !== undefined) {
matrix.Set (gltfNode.matrix);
} else {
let translation = [0.0, 0.0, 0.0];
let rotation = [0.0, 0.0, 0.0, 1.0];
let scale = [1.0, 1.0, 1.0];
if (gltfNode.translation !== undefined) {
translation = gltfNode.translation;
}
if (gltfNode.rotation !== undefined) {
rotation = gltfNode.rotation;
}
if (gltfNode.scale !== undefined) {
scale = gltfNode.scale;
}
matrix.ComposeTRS (
OV.ArrayToCoord3D (translation),
OV.ArrayToQuaternion (rotation),
OV.ArrayToCoord3D (scale)
);
}
return new OV.Transformation (matrix);
}
if (gltfNode.children === undefined && gltfNode.mesh === undefined) {
return;
}
let node = new OV.Node ();
if (gltfNode.name !== undefined) {
node.SetName (gltfNode.name);
}
node.SetTransformation (GetNodeTransformation (gltfNode));
parentNode.AddChildNode (node);
if (gltfNode.children !== undefined) {
for (let childIndex of gltfNode.children) {
let childGltfNode = gltf.nodes[childIndex];
this.ImportNode (gltf, childGltfNode, node);
}
}
if (gltfNode.mesh !== undefined) {
node.AddMeshIndex (gltfNode.mesh);
}
}
GetReaderFromBufferView (bufferView)
{
let bufferIndex = bufferView.buffer || 0;

View File

@ -18,6 +18,17 @@ describe ('Gltf Importer', function () {
let testFile = testFileList[i];
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelNodesToTree (model), {
name : '<Root>',
childNodes : [
{
name : '',
childNodes : [],
meshNames : ['']
}
],
meshNames : []
});
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
@ -57,6 +68,23 @@ describe ('Gltf Importer', function () {
let testFile = testFileList[i];
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelNodesToTree (model), {
name : '<Root>',
childNodes : [
{
name : '',
childNodes : [
{
name : '',
childNodes : [],
meshNames : ['Mesh']
}
],
meshNames : []
}
],
meshNames : []
});
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
@ -75,15 +103,15 @@ describe ('Gltf Importer', function () {
}
}
]
});
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
});
}
});
it ('BoxInterleaved', function (done) {
let testFileList = [
['BoxInterleaved/glTF', 'BoxInterleaved.gltf'],
@ -95,6 +123,23 @@ describe ('Gltf Importer', function () {
let testFile = testFileList[i];
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelNodesToTree (model), {
name : '<Root>',
childNodes : [
{
name : '',
childNodes : [
{
name : '',
childNodes : [],
meshNames : ['Mesh']
}
],
meshNames : []
}
],
meshNames : []
});
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
@ -113,12 +158,12 @@ describe ('Gltf Importer', function () {
}
}
]
});
});
processed += 1;
if (processed == testFileList.length) {
done ();
}
});
});
}
});
@ -133,6 +178,23 @@ describe ('Gltf Importer', function () {
let testFile = testFileList[i];
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelNodesToTree (model), {
name : '<Root>',
childNodes : [
{
name : '',
childNodes : [
{
name : '',
childNodes : [],
meshNames : ['Mesh']
}
],
meshNames : []
}
],
meshNames : []
});
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
@ -151,7 +213,7 @@ describe ('Gltf Importer', function () {
}
}
]
});
});
processed += 1;
if (processed == testFileList.length) {
done ();
@ -170,6 +232,22 @@ describe ('Gltf Importer', function () {
let testFile = testFileList[i];
testFiles.ImportGltfFile (testFile[0], testFile[1], function (model) {
assert (OV.CheckModel (model));
assert.deepStrictEqual (testUtils.ModelNodesToTree (model), {
name : '<Root>',
childNodes : [
{
name : '',
childNodes : [],
meshNames : ['']
},
{
name : '',
childNodes : [],
meshNames : ['']
}
],
meshNames : []
});
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
@ -199,7 +277,7 @@ describe ('Gltf Importer', function () {
}
}
]
});
});
processed += 1;
if (processed == testFileList.length) {
done ();
@ -207,7 +285,7 @@ describe ('Gltf Importer', function () {
});
}
});
it ('OrientationTest', function (done) {
let testFileList = [
['OrientationTest/glTF', 'OrientationTest.gltf'],
@ -380,7 +458,7 @@ describe ('Gltf Importer', function () {
if (processed == testFileList.length) {
done ();
}
});
});
}
});
@ -415,7 +493,7 @@ describe ('Gltf Importer', function () {
}
}
]
});
});
processed += 1;
if (processed == testFileList.length) {
done ();
@ -451,7 +529,7 @@ describe ('Gltf Importer', function () {
}
}
]
});
});
processed += 1;
if (processed == testFileList.length) {
done ();
@ -495,5 +573,5 @@ describe ('Gltf Importer', function () {
}
});
}
});
});
});

View File

@ -29,26 +29,6 @@ describe ('O3dv Importer', function () {
meshNames : ['Cube']
});
assert.deepStrictEqual (testUtils.ModelToObjectSimple (model), {
name : '',
materials : [
{ name : 'Green' }
],
meshes : [
{
name : 'Cube',
vertexCount : 8,
normalCount : 12,
uvCount : 0,
triangleCount : 12,
boundingBox : {
min : [0, 0, 0],
max : [1, 1, 1]
}
}
]
});
assert.strictEqual (model.MeshInstanceCount (), 3);
let boundingBox = OV.GetBoundingBox (model);
assert (OV.CoordIsEqual3D (boundingBox.min, new OV.Coord3D (-1.0, 0.0, 0.0)));

View File

@ -139,11 +139,9 @@ module.exports =
});
}
var mesh, meshObj, boundingBox;
for (i = 0; i < model.MeshCount (); i++) {
mesh = model.GetMesh (i);
boundingBox = OV.GetBoundingBox (mesh);
meshObj = {
model.EnumerateTransformedMeshInstances ((mesh) => {
let boundingBox = OV.GetBoundingBox (mesh);
let meshObj = {
name : mesh.GetName (),
vertexCount : mesh.VertexCount (),
normalCount : mesh.NormalCount (),
@ -155,7 +153,7 @@ module.exports =
}
};
obj.meshes.push (meshObj);
}
});
return obj;
},

View File

@ -1,4 +1,4 @@
OV.FeatureSet =
{
NavigatorTree : true
NavigatorTree : false
};