Skip to content

Commit

Permalink
VOXELFORMAT: VOX: failed attempt to support model references
Browse files Browse the repository at this point in the history
the transformation matrices are wrong
  • Loading branch information
mgerhardy committed Jun 12, 2023
1 parent dfd9af5 commit 745c85b
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 79 deletions.
132 changes: 55 additions & 77 deletions src/modules/voxelformat/VoxFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ struct ogt_SceneContext {
core::Array<ogt_vox_keyframe_transform, 4096> keyframeTransforms;
core::Buffer<ogt_vox_cam> cameras;
bool paletteErrorPrinted = false;
core::Map<int, int> nodeToModel;
};

static void *_ogt_alloc(size_t size) {
Expand All @@ -56,37 +57,29 @@ static void _ogt_free(void *mem) {
static const ogt_vox_transform ogt_identity_transform{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};

/**
* @brief Calculate the scene graph object transformation. Used for the voxel and the AABB of the volume.
*
* @param mat The world space model matrix (rotation and translation) for the chunk
* @param pos The position inside the untransformed chunk (local position)
* @param pivot The pivot to do the rotation around. This is the @code chunk_size - 1 + 0.5 @endcode. Please
* note that the @c w component must be @c 0.0
* @return glm::vec4 The transformed world position
*/
static inline glm::vec4 calcTransform(const glm::mat4x4 &mat, const glm::ivec3 &pos, const glm::vec4 &pivot) {
return glm::floor(mat * (glm::vec4((float)pos.x + 0.5f, (float)pos.y + 0.5f, (float)pos.z + 0.5f, 1.0f) - pivot));
}

static glm::mat4 ogtTransformToMat(const ogt_vox_transform &t) {
const glm::vec4 col0(t.m00, t.m01, t.m02, t.m03);
const glm::vec4 col1(t.m10, t.m11, t.m12, t.m13);
const glm::vec4 col2(t.m20, t.m21, t.m22, t.m23);
const glm::vec4 col3(t.m30, t.m31, t.m32, t.m33);
const glm::vec4 col0(t.m00, t.m02, t.m01, t.m03);
const glm::vec4 col1(t.m20, t.m22, t.m21, t.m23);
const glm::vec4 col2(t.m10, t.m12, t.m11, t.m13);
const glm::vec4 col3(t.m30, t.m32, t.m31, t.m33);
return glm::mat4{col0, col1, col2, col3};
}

/** snapping to int to match magicavoxel */
static glm::mat4 ogtSnapToIntTranslate(const ogt_vox_model *m) {
const glm::vec3 t((float)(int)(m->size_x / 2), (float)(int)(m->size_y / 2), (float)(int)(m->size_z / 2));
return glm::translate(-t);
}

static bool loadKeyFrames(scenegraph::SceneGraph &sceneGraph, scenegraph::SceneGraphNode &node,
const ogt_vox_keyframe_transform *transformKeyframes, uint32_t numKeyframes) {
const ogt_vox_keyframe_transform *transformKeyframes, uint32_t numKeyframes, const ogt_vox_model *ogtModel) {
scenegraph::SceneGraphKeyFrames kf;
Log::debug("Load %d keyframes", numKeyframes);
kf.reserve(numKeyframes);
for (uint32_t keyFrameIdx = 0; keyFrameIdx < numKeyframes; ++keyFrameIdx) {
const ogt_vox_keyframe_transform &transform_keyframe = transformKeyframes[keyFrameIdx];
const glm::mat4 worldMatrix = ogtTransformToMat(transform_keyframe.transform);
const glm::mat4 worldMatrix = ogtTransformToMat(transform_keyframe.transform) * ogtSnapToIntTranslate(ogtModel);
scenegraph::SceneGraphKeyFrame sceneGraphKeyFrame;
// TODO: zUpMat?
sceneGraphKeyFrame.frameIdx = (scenegraph::FrameIndex)transform_keyframe.frame_index;
sceneGraphKeyFrame.interpolation = scenegraph::InterpolationType::Linear;
sceneGraphKeyFrame.longRotation = false;
Expand Down Expand Up @@ -134,66 +127,47 @@ size_t VoxFormat::loadPalette(const core::String &filename, io::SeekableReadStre
}

bool VoxFormat::loadInstance(const ogt_vox_scene *scene, uint32_t ogt_instanceIdx, scenegraph::SceneGraph &sceneGraph,
int parent, core::DynamicArray<ModelToNode> &models, const voxel::Palette &palette, bool groupHidden) {
int parent, core::DynamicArray<ModelToNode> &models, const voxel::Palette &palette,
bool groupHidden) {
const ogt_vox_instance &ogtInstance = scene->instances[ogt_instanceIdx];
const glm::mat4 ogtMat = ogtTransformToMat(ogtInstance.transform);
const ogt_vox_model *ogtModel = scene->models[ogtInstance.model_index];
const uint8_t *ogtVoxels = ogtModel->voxel_data;
const uint8_t *ogtVoxel = ogtVoxels;
const glm::ivec3 maxs(ogtModel->size_x - 1, ogtModel->size_y - 1, ogtModel->size_z - 1);
const glm::vec4 pivot((float)(int)(ogtModel->size_x / 2), (float)(int)(ogtModel->size_y / 2),
(float)(int)(ogtModel->size_z / 2), 0.0f);
const glm::ivec3 &transformedMins = calcTransform(ogtMat, glm::ivec3(0), pivot);
const glm::ivec3 &transformedMaxs = calcTransform(ogtMat, maxs, pivot);
const glm::mat4 zUpMat = transformMatrix();
const glm::ivec3 &zUpMins = calcTransform(zUpMat, transformedMins, glm::ivec4(0));
const glm::ivec3 &zUpMaxs = calcTransform(zUpMat, transformedMaxs, glm::ivec4(0));
voxel::Region region(glm::min(zUpMins, zUpMaxs), glm::max(zUpMins, zUpMaxs));
const glm::ivec3 shift = region.getLowerCorner();
region.shift(-shift);
voxel::RawVolume *v = new voxel::RawVolume(region);
scenegraph::SceneGraphTransform transform;
transform.setWorldTranslation(shift);

for (uint32_t k = 0; k < ogtModel->size_z; ++k) {
for (uint32_t j = 0; j < ogtModel->size_y; ++j) {
for (uint32_t i = 0; i < ogtModel->size_x; ++i, ++ogtVoxel) {
if (ogtVoxel[0] == 0) {
continue;
}
const voxel::Voxel voxel = voxel::createVoxel(palette, ogtVoxel[0] - 1);
const glm::ivec3 &pos = calcTransform(ogtMat, glm::ivec3(i, j, k), pivot);
const glm::ivec3 &poszUp = calcTransform(zUpMat, pos, glm::ivec4(0));
const glm::ivec3 &regionPos = poszUp - shift;
v->setVoxel(regionPos, voxel);
}
}
scenegraph::SceneGraphNodeType type = scenegraph::SceneGraphNodeType::Model;
if (models[ogtInstance.model_index].nodeId != InvalidNodeId) {
type = scenegraph::SceneGraphNodeType::ModelReference;
}

scenegraph::SceneGraphNode node(scenegraph::SceneGraphNodeType::Model);
const char *name = ogtInstance.name;
const ogt_vox_layer &layer = scene->layers[ogtInstance.layer_index];
const core::RGBA col(layer.color.r, layer.color.g, layer.color.b, layer.color.a);
const char *name = ogtInstance.name == nullptr ? layer.name : ogtInstance.name;
if (name == nullptr) {
const ogt_vox_layer &layer = scene->layers[ogtInstance.layer_index];
name = layer.name;
core::RGBA col;
col.r = layer.color.r;
col.g = layer.color.g;
col.b = layer.color.b;
col.a = layer.color.a;
node.setColor(col);
if (name == nullptr) {
name = "";
}
name = "";
}
loadKeyFrames(sceneGraph, node, ogtInstance.transform_anim.keyframes, ogtInstance.transform_anim.num_keyframes);
// TODO: we are overriding the keyframe data here
const scenegraph::KeyFrameIndex keyFrameIdx = 0;
node.setTransform(keyFrameIdx, transform);

scenegraph::SceneGraphNode node(type);
const glm::vec3 pivot(0.0f);
node.setPivot(pivot);
node.setName(name);
node.setColor(col);
node.setVisible(!ogtInstance.hidden && !groupHidden);
node.setVolume(v, true);
node.setPalette(palette);
return sceneGraph.emplace(core::move(node), parent) != -1;
if (type == scenegraph::SceneGraphNodeType::ModelReference) {
node.setReference(models[ogtInstance.model_index].nodeId);
} else {
node.setVolume(models[ogtInstance.model_index].volume, true);
models[ogtInstance.model_index].volume = nullptr;
node.setPalette(palette);
}
const ogt_vox_model *ogtModel = scene->models[ogtInstance.model_index];
if (!loadKeyFrames(sceneGraph, node, ogtInstance.transform_anim.keyframes, ogtInstance.transform_anim.num_keyframes, ogtModel)) {
scenegraph::SceneGraphTransform transform;
const glm::mat4 worldMatrix = ogtTransformToMat(ogtInstance.transform) * ogtSnapToIntTranslate(ogtModel);
transform.setWorldMatrix(worldMatrix);
const scenegraph::KeyFrameIndex keyFrameIdx = 0;
node.setTransform(keyFrameIdx, transform);
}
const int nodeId = sceneGraph.emplace(core::move(node), parent);
if (nodeId != InvalidNodeId) {
models[ogtInstance.model_index].nodeId = nodeId;
return true;
}
return false;
}

bool VoxFormat::loadGroup(const ogt_vox_scene *scene, uint32_t ogt_groupIdx, scenegraph::SceneGraph &sceneGraph,
Expand All @@ -213,7 +187,6 @@ bool VoxFormat::loadGroup(const ogt_vox_scene *scene, uint32_t ogt_groupIdx, sce
const core::RGBA color(layer.color.r, layer.color.g, layer.color.b, layer.color.a);
node.setColor(color);
}
loadKeyFrames(sceneGraph, node, ogt_group.transform_anim.keyframes, ogt_group.transform_anim.num_keyframes);
node.setName(name);
node.setVisible(!hidden);
const int groupId = parent == -1 ? sceneGraph.root().id() : sceneGraph.emplace(core::move(node), parent);
Expand Down Expand Up @@ -276,8 +249,8 @@ bool VoxFormat::loadGroupsPalette(const core::String &filename, io::SeekableRead
core_free(buffer);
return false;
}
const uint32_t ogt_vox_flags = k_read_scene_flags_keyframes | k_read_scene_flags_keep_empty_models_instances |
k_read_scene_flags_groups | k_read_scene_flags_keep_duplicate_models;
const uint32_t ogt_vox_flags =
k_read_scene_flags_keyframes | k_read_scene_flags_keep_empty_models_instances | k_read_scene_flags_groups;
const ogt_vox_scene *scene = ogt_vox_read_scene_with_flags(buffer, size, ogt_vox_flags);
core_free(buffer);
if (scene == nullptr) {
Expand Down Expand Up @@ -586,6 +559,7 @@ void VoxFormat::saveNode(const scenegraph::SceneGraph &sceneGraph, scenegraph::S
voxelutil::VisitAll(), voxelutil::VisitorOrder::YZmX);

ctx.models.push_back(ogt_model);
ctx.nodeToModel.put(node.id(), (int)ctx.models.size() - 1);
}
addInstance(sceneGraph, node, ctx, parentGroupIdx, layerIdx);
for (int childId : node.children()) {
Expand Down Expand Up @@ -618,6 +592,10 @@ bool VoxFormat::saveGroups(const scenegraph::SceneGraph &sceneGraph, const core:
ogt_SceneContext ctx;
const scenegraph::SceneGraphNode &root = sceneGraph.root();
saveNode(sceneGraph, sceneGraph.node(root.id()), ctx, k_invalid_group_index, 0, palette, palReplacement);
for (auto iter = sceneGraph.begin(scenegraph::SceneGraphNodeType::ModelReference); iter != sceneGraph.end();
++iter) {
addInstance(sceneGraph, *iter, ctx, 0, 0);
}

core::Buffer<const ogt_vox_model *> modelPtr;
modelPtr.reserve(ctx.models.size());
Expand Down
3 changes: 2 additions & 1 deletion src/modules/voxelformat/VoxFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class VoxFormat : public PaletteFormat {
bool loadScene(const ogt_vox_scene *scene, scenegraph::SceneGraph &sceneGraph, const voxel::Palette &palette);
int findClosestPaletteIndex(const voxel::Palette &palette);
bool loadInstance(const ogt_vox_scene *scene, uint32_t ogt_instanceIdx, scenegraph::SceneGraph &sceneGraph,
int parent, core::DynamicArray<ModelToNode> &models, const voxel::Palette &palette, bool groupHidden = false);
int parent, core::DynamicArray<ModelToNode> &models, const voxel::Palette &palette,
bool groupHidden = false);
bool loadGroup(const ogt_vox_scene *scene, uint32_t ogt_parentGroupIdx, scenegraph::SceneGraph &sceneGraph,
int parent, core::DynamicArray<ModelToNode> &models, core::Set<uint32_t> &addedInstances,
const voxel::Palette &palette);
Expand Down
2 changes: 1 addition & 1 deletion src/modules/voxelformat/tests/TestHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ void volumeComparator(const voxel::RawVolume& volume1, const voxel::Palette &pal
}

void sceneGraphComparator(const scenegraph::SceneGraph &graph1, const scenegraph::SceneGraph &graph2, ValidateFlags flags, float maxDelta) {
ASSERT_EQ(graph1.size(), graph2.size());
ASSERT_EQ(graph1.size(scenegraph::SceneGraphNodeType::AllModels), graph2.size(scenegraph::SceneGraphNodeType::AllModels));
auto iter1 = graph1.beginModel();
auto iter2 = graph2.beginModel();
for (; iter1 != graph1.end() && iter2 != graph2.end(); ++iter1, ++iter2) {
Expand Down

0 comments on commit 745c85b

Please sign in to comment.