Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/native/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ f3d_plugin_declare_reader(
NAME QuakeMDL
EXTENSIONS mdl
MIMETYPES application/vnd.mdl
OPTIONS skin_index
OPTIONS skin_index animation_interpolation
VTK_IMPORTER vtkF3DQuakeMDLImporter
FORMAT_DESCRIPTION "Quake 1 MDL model"
${_SUPPORTS_STREAM}
Expand Down
6 changes: 6 additions & 0 deletions plugins/native/mdl.inl
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,10 @@ void applyCustomImporter(vtkImporter* importer, const std::string& vtkNotUsed(fi
nullptr, "QuakeMDL.skin_index must be positive. Defaulting to 0.");
}
mdlImporter->SetSkinIndex(skinIndex);

std::string interpOptName = "QuakeMDL.animation_interpolation";
std::string interpOptStr = this->ReaderOptions.at(interpOptName);

bool interpolate = (F3DUtils::ParseToDouble(interpOptStr, 0, interpOptName) != 0);
mdlImporter->SetInterpolate(interpolate);
}
1 change: 1 addition & 0 deletions plugins/native/module/vtk.module
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ DEPENDS
VTK::CommonExecutionModel
f3d::vtkext
PRIVATE_DEPENDS
VTK::FiltersGeneral
VTK::IOPLY
VTK::RenderingOpenGL2
VTK::zlib
Expand Down
66 changes: 64 additions & 2 deletions plugins/native/module/vtkF3DQuakeMDLImporter.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
#include <vtkFileResourceStream.h>
#include <vtkFloatArray.h>
#include <vtkImageData.h>
#include <vtkInterpolateDataSetAttributes.h>
#include <vtkOpenGLTexture.h>
#include <vtkPointData.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkResourceStream.h>
#include <vtkMathUtilities.h>
#include <vtkPoints.h>

#include <cstdint>
#include <cstring>
Expand Down Expand Up @@ -653,6 +656,7 @@ struct vtkF3DQuakeMDLImporter::vtkInternals
vtkF3DQuakeMDLImporter* Parent;
vtkSmartPointer<vtkPolyDataMapper> Mapper;
vtkSmartPointer<vtkTexture> Texture;
vtkNew<vtkInterpolateDataSetAttributes> AttrInterp;

std::vector<std::string> AnimationNames;
std::vector<std::vector<double>> AnimationTimes;
Expand Down Expand Up @@ -734,10 +738,68 @@ bool vtkF3DQuakeMDLImporter::UpdateAtTimeValue(double timeValue)
(found == times.end() - 1) ? times.size() - 2 : std::distance(times.begin(), found);
// If time at index i > timeValue, then choose the previous frame
const size_t frameIndex = times[i] > timeValue && i > 0 ? i - 1 : i;
size_t upperFrameIndex =
std::distance(times.begin(), std::lower_bound(times.begin(), times.end() - 1, timeValue));
size_t lowerFrameIndex;
double alpha;
if (upperFrameIndex >= times.size() - 1)
{
// Last frame
upperFrameIndex = lowerFrameIndex = times.size() - 2;
alpha = 0.0;
}
else
{
lowerFrameIndex = upperFrameIndex > 0 ? upperFrameIndex - 1 : 0;
alpha = vtkMathUtilities::SafeDivision(
timeValue - times[lowerFrameIndex], times[upperFrameIndex] - times[lowerFrameIndex]);
}
if (isMeshAnimation)
{
this->Internals->Mapper->SetInputData(
this->Internals->AnimationFrames[animIndex][frameIndex]);
vtkPolyData* upperFrame = this->Internals->AnimationFrames[animIndex][upperFrameIndex];
vtkPolyData* lowerFrame = this->Internals->AnimationFrames[animIndex][lowerFrameIndex];
if (!this->Interpolate || upperFrame == lowerFrame)
{
// Interpolation disabled or no difference between frames
this->Internals->Mapper->SetInputData(lowerFrame);
}
else
{
// Interpolate every point between the two frames to get
// resulting interpolatedPoints
vtkPoints* lowerPoints = lowerFrame->GetPoints();
vtkPoints* upperPoints = upperFrame->GetPoints();

const vtkIdType numPoints = lowerPoints->GetNumberOfPoints();
vtkNew<vtkPoints> interpolatedPoints;
interpolatedPoints->SetNumberOfPoints(numPoints);
for (vtkIdType p = 0; p < numPoints; ++p)
{
// Get x, y, z coordinates from both frames
double lowerCoord[3];
double upperCoord[3];
lowerPoints->GetPoint(p, lowerCoord);
upperPoints->GetPoint(p, upperCoord);

interpolatedPoints->SetPoint(p,
lowerCoord[0] + alpha * (upperCoord[0] - lowerCoord[0]), // x
lowerCoord[1] + alpha * (upperCoord[1] - lowerCoord[1]), // y
lowerCoord[2] + alpha * (upperCoord[2] - lowerCoord[2])); // z
}

// Interpolate attributes only
vtkInterpolateDataSetAttributes* attrInterp = this->Internals->AttrInterp;
attrInterp->RemoveAllInputs();
attrInterp->AddInputData(lowerFrame);
attrInterp->AddInputData(upperFrame);
attrInterp->SetT(alpha);
attrInterp->Update();

vtkNew<vtkPolyData> interpolatedMesh;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while this approach works for interpolating points, you may be missing other data to interpolate between frames (eg tcoords, normals and such).

To get a proper interpolation, use vtkInterpolateDataSetAttributes.

interpolatedMesh->ShallowCopy(attrInterp->GetOutput());
interpolatedMesh->SetPoints(interpolatedPoints);
this->Internals->Mapper->SetInputData(interpolatedMesh);
}
}
else
{
Expand Down
9 changes: 9 additions & 0 deletions plugins/native/module/vtkF3DQuakeMDLImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,14 @@ class vtkF3DQuakeMDLImporter : public vtkF3DImporter
vtkGetMacro(SkinIndex, unsigned int);
///@}

///@{
/**
* Set/Get whether to interpolate between animation frames. Default is false.
*/
vtkSetMacro(Interpolate, bool);
vtkGetMacro(Interpolate, bool);
///@}

/**
* Return true if, after a quick check of file header, it looks like the provided stream
* can be read. Return false if it is sure it cannot be read as a strean.
Expand All @@ -92,6 +100,7 @@ class vtkF3DQuakeMDLImporter : public vtkF3DImporter

struct vtkInternals;
unsigned int SkinIndex = 0;
bool Interpolate = false;

std::unique_ptr<vtkInternals> Internals;
};
Expand Down