Commit 217a70af authored by Michael Migliore's avatar Michael Migliore
Browse files

Fix glTF camera animations

parent 1347868a
Pipeline #216882 running with stage
......@@ -65,15 +65,19 @@ vtk_add_test_cxx(vtkIOImportCxxTests tests
)
vtk_add_test_cxx(vtkIOImportCxxTests tests
TestGLTFImporter,TestGLTFImporter.cxx DATA{../Data/glTF/Avocado/Avocado.glb}
TestGLTFImporter,TestGLTFImporter.cxx DATA{../Data/glTF/Avocado/Avocado.glb} -1
)
vtk_add_test_cxx(vtkIOImportCxxTests tests
TestGLTFImporterPBR,TestGLTFImporter.cxx DATA{../Data/glTF/WaterBottle/WaterBottle.glb}
TestGLTFImporterPBR,TestGLTFImporter.cxx DATA{../Data/glTF/WaterBottle/WaterBottle.glb} -1
)
vtk_add_test_cxx(vtkIOImportCxxTests tests
TestGLTFImporterKHRLightsPunctual,TestGLTFImporter.cxx DATA{../Data/glTF/Lights/lights.gltf}
TestGLTFImporterKHRLightsPunctual,TestGLTFImporter.cxx DATA{../Data/glTF/Lights/lights.gltf} 0
)
vtk_add_test_cxx(vtkIOImportCxxTests tests
TestGLTFImporterCamera,TestGLTFImporter.cxx DATA{../Data/glTF/Cameras/Cameras.gltf} 1
)
vtk_add_test_cxx(vtkIOImportCxxTests tests
......
......@@ -22,12 +22,14 @@
int TestGLTFImporter(int argc, char* argv[])
{
if (argc <= 1)
if (argc < 3)
{
std::cout << "Usage: " << argv[0] << " <gltf file>" << std::endl;
std::cout << "Usage: " << argv[0] << " <gltf file> <camera index>" << std::endl;
return EXIT_FAILURE;
}
vtkIdType cameraIndex = atoi(argv[2]);
vtkNew<vtkGLTFImporter> importer;
importer->SetFileName(argv[1]);
......@@ -41,6 +43,7 @@ int TestGLTFImporter(int argc, char* argv[])
vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
renderWindowInteractor->SetRenderWindow(renderWindow);
importer->SetCamera(cameraIndex);
importer->Update();
renderWindow->Render();
......
72efecaa9fffbd7e1d9b5a8a77fe96f96051bf20041127397bf5f218776e2a72ebf7525b197e979eab4deb52022601656df6673e65a3050ed53d7c83ccdd19bc
642857003353040bb1f49eea4ba3227a049ac03409f53fd5d713fa8c65c5c3feaf10d8bb3d6962089e2cc80be39b040ab46cdbe2fdb2a0bb1f7ce634d65b9214
1364b58ca7c2aba31f2e3087b1055b0ad88707881401cfd61e3278646210a8815e076bf1ac7396355b31a78929e85b7894b7893204ed64df7d535b2998d1ac87
879494d41c094523cce56a10bb15baa56f54337acb1fa3d16e64fdfbbc2de34927ab80e7dc8fd5b1be9f58a98a4fb05320d311c62f5e04fecf4a756e29e1f052
......@@ -321,19 +321,21 @@ void ApplyTransformToCamera(vtkSmartPointer<vtkCamera> cam, vtkSmartPointer<vtkM
return;
}
double position[3] = { 0.0 };
double viewUp[3] = { 0.0 };
double focus[3] = { 0.0 };
// At identity, camera position is origin, +y up, -z view direction
double position[3] = { 0.0, 0.0, 0.0 };
double viewUp[3] = { 0.0, 1.0, 0.0 };
double focus[3] = { 0.0, 0.0, -1.0 };
vtkNew<vtkTransform> t;
t->SetMatrix(transform);
t->TransformPoint(cam->GetPosition(), position);
t->TransformVector(cam->GetViewUp(), viewUp);
t->TransformVector(cam->GetDirectionOfProjection(), focus);
focus[0] -= position[0];
focus[1] -= position[1];
focus[2] -= position[2];
t->TransformPoint(position, position);
t->TransformVector(viewUp, viewUp);
t->TransformVector(focus, focus);
focus[0] += position[0];
focus[1] += position[1];
focus[2] += position[2];
cam->SetPosition(position);
cam->SetFocalPoint(focus);
......@@ -501,6 +503,13 @@ void vtkGLTFImporter::ImportCameras(vtkRenderer* renderer)
nodeIdStack.push(nodeId);
}
this->Cameras.clear();
for (size_t i = 0; i < model->Cameras.size(); i++)
{
vtkGLTFDocumentLoader::Camera const& camera = model->Cameras[i];
this->Cameras[static_cast<int>(i)] = GLTFCameraToVTKCamera(camera);
}
// Iterate over tree
while (!nodeIdStack.empty())
{
......@@ -512,14 +521,7 @@ void vtkGLTFImporter::ImportCameras(vtkRenderer* renderer)
// Import node's camera
if (node.Camera >= 0 && node.Camera < static_cast<int>(model->Cameras.size()))
{
vtkGLTFDocumentLoader::Camera const& camera = model->Cameras[node.Camera];
auto vtkCam = GLTFCameraToVTKCamera(camera);
ApplyTransformToCamera(vtkCam, node.GlobalTransform);
renderer->SetActiveCamera(vtkCam);
// Since the same glTF camera object can be used by multiple nodes (so with different
// transforms), multiple vtkCameras are generated for the same glTF camera object, but with
// different transforms.
this->Cameras.push_back(vtkCam);
ApplyTransformToCamera(this->Cameras[node.Camera], node.GlobalTransform);
}
// Add node's children to stack
......@@ -528,6 +530,46 @@ void vtkGLTFImporter::ImportCameras(vtkRenderer* renderer)
nodeIdStack.push(childNodeId);
}
}
// update enabled camera
if (this->EnabledCamera >= this->GetNumberOfCameras())
{
vtkErrorMacro("Camera index " << this->EnabledCamera << "is invalid");
this->EnabledCamera = -1;
return;
}
if (this->EnabledCamera >= 0)
{
renderer->SetActiveCamera(this->Cameras[this->EnabledCamera]);
}
}
//------------------------------------------------------------------------------
vtkIdType vtkGLTFImporter::GetNumberOfCameras()
{
auto model = this->Loader->GetInternalModel();
return model->Cameras.size();
}
//------------------------------------------------------------------------------
std::string vtkGLTFImporter::GetCameraName(vtkIdType camIndex)
{
auto model = this->Loader->GetInternalModel();
if (camIndex < 0 || camIndex >= this->GetNumberOfCameras())
{
vtkErrorMacro("Camera index invalid");
return "";
}
return model->Cameras[camIndex].Name;
}
//------------------------------------------------------------------------------
void vtkGLTFImporter::SetCamera(vtkIdType camIndex)
{
// if the user sets the camera before the import, we do not know how many
// cameras there are, so do not check if the index if valid here
this->EnabledCamera = camIndex;
}
//------------------------------------------------------------------------------
......@@ -614,6 +656,8 @@ void vtkGLTFImporter::UpdateTimeStep(double timestep)
}
this->Loader->BuildGlobalTransforms();
this->ImportCameras(this->Renderer);
auto model = this->Loader->GetInternalModel();
int scene = model->DefaultScene;
......@@ -758,16 +802,11 @@ void vtkGLTFImporter::PrintSelf(ostream& os, vtkIndent indent)
//------------------------------------------------------------------------------
vtkSmartPointer<vtkCamera> vtkGLTFImporter::GetCamera(unsigned int id)
{
if (id >= this->Cameras.size())
auto it = this->Cameras.find(id);
if (it == this->Cameras.end())
{
vtkErrorMacro("Out of range camera index");
return nullptr;
}
return this->Cameras[id];
}
//------------------------------------------------------------------------------
size_t vtkGLTFImporter::GetNumberOfCameras()
{
return this->Cameras.size();
return it->second;
}
......@@ -93,11 +93,6 @@ public:
*/
vtkSmartPointer<vtkCamera> GetCamera(unsigned int id);
/**
* Get the total number of cameras
*/
size_t GetNumberOfCameras();
/**
* Get a printable string describing all outputs
*/
......@@ -127,6 +122,22 @@ public:
bool IsAnimationEnabled(vtkIdType animationIndex) override;
//@}
/**
* Get the number of available cameras.
*/
vtkIdType GetNumberOfCameras() override;
/**
* Get the name of a camera.
*/
std::string GetCameraName(vtkIdType camIndex) override;
/**
* Enable a specific camera.
* If a negative index is provided, no camera from the importer is used.
*/
void SetCamera(vtkIdType camIndex) override;
/**
* Get temporal informations for the currently enabled animations.
* frameRate is used to define the number of frames for one second of simulation.
......@@ -146,12 +157,13 @@ protected:
char* FileName = nullptr;
std::vector<vtkSmartPointer<vtkCamera>> Cameras;
std::map<int, vtkSmartPointer<vtkCamera>> Cameras;
std::map<int, vtkSmartPointer<vtkTexture>> Textures;
std::map<int, std::vector<vtkSmartPointer<vtkActor>>> Actors;
vtkSmartPointer<vtkGLTFDocumentLoader> Loader;
std::string OutputsDescription;
std::vector<bool> EnabledAnimations;
vtkIdType EnabledCamera = -1;
private:
vtkGLTFImporter(const vtkGLTFImporter&) = delete;
......
......@@ -95,7 +95,7 @@ public:
* Recover a printable string that let importer implementation
* Describe their outputs.
*/
virtual std::string GetOutputsDescription() { return ""; };
virtual std::string GetOutputsDescription() { return ""; }
/**
* Get the number of available animations.
......@@ -107,17 +107,36 @@ public:
* Get the name of an animation.
* Return an empty if not provided by implementation.
*/
virtual std::string GetAnimationName(vtkIdType vtkNotUsed(animationIndex)) { return ""; };
virtual std::string GetAnimationName(vtkIdType vtkNotUsed(animationIndex)) { return ""; }
//@{
/**
* Enable/Disable/Get the status of specific animations
*/
virtual void EnableAnimation(vtkIdType vtkNotUsed(animationIndex)){};
virtual void DisableAnimation(vtkIdType vtkNotUsed(animationIndex)){};
virtual bool IsAnimationEnabled(vtkIdType vtkNotUsed(animationIndex)) { return false; };
virtual void EnableAnimation(vtkIdType vtkNotUsed(animationIndex)) {}
virtual void DisableAnimation(vtkIdType vtkNotUsed(animationIndex)) {}
virtual bool IsAnimationEnabled(vtkIdType vtkNotUsed(animationIndex)) { return false; }
//@}
/**
* Get the number of available cameras.
* Return 0 if not provided by implementation.
*/
virtual vtkIdType GetNumberOfCameras() { return 0; }
/**
* Get the name of a camera.
* Return an empty string if not provided by implementation.
*/
virtual std::string GetCameraName(vtkIdType vtkNotUsed(camIndex)) { return ""; }
/**
* Enable a specific camera.
* If a negative index is provided, no camera from the importer is used.
* Does nothing if not provided by implementation.
*/
virtual void SetCamera(vtkIdType vtkNotUsed(camIndex)) {}
/**
* Get temporal informations for the currently enabled animations.
* the three return arguments can be defined or not.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment