Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
9 changes: 8 additions & 1 deletion src/draco/io/point_cloud_io.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "draco/io/obj_decoder.h"
#include "draco/io/parser_utils.h"
#include "draco/io/ply_decoder.h"
#include "draco/io/splat_decoder.cc"

namespace draco {

Expand All @@ -26,7 +27,7 @@ StatusOr<std::unique_ptr<PointCloud>> ReadPointCloudFromFile(
std::unique_ptr<PointCloud> pc(new PointCloud());
// Analyze file extension.
const std::string extension = parser::ToLower(
file_name.size() >= 4 ? file_name.substr(file_name.size() - 4)
file_name.size() >= 5 ? file_name.substr(file_name.find_last_of('.'))
: file_name);
if (extension == ".obj") {
// Wavefront OBJ file format.
Expand All @@ -43,6 +44,12 @@ StatusOr<std::unique_ptr<PointCloud>> ReadPointCloudFromFile(
DRACO_RETURN_IF_ERROR(ply_decoder.DecodeFromFile(file_name, pc.get()));
return std::move(pc);
}
if (extension == ".splat") {
// SPLAT file format.
SplatDecoder splat_decoder;
DRACO_RETURN_IF_ERROR(splat_decoder.ReadSplatFile(file_name, pc.get()));
return std::move(pc);
}

std::vector<char> buffer;
if (!ReadFileToBuffer(file_name, &buffer)) {
Expand Down
78 changes: 78 additions & 0 deletions src/draco/io/splat_decoder.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright 2025 Patrick Trollmann.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "draco/io/splat_decoder.h"

namespace draco {
SplatDecoder::SplatDecoder() {}

Status SplatDecoder::ReadSplatFile(const std::string &filename,
PointCloud *out_point_cloud) {
std::ifstream file(filename, std::ios::binary);
if (!file) {
return Status(Status::DRACO_ERROR, "Unable to open input file.");
}

struct Gaussian {
float position[3];
float scale[3];
uint8_t color[4];
uint8_t rotation[4];
};

std::vector<Gaussian> gaussians;
Gaussian gaussian;
while (file.read(reinterpret_cast<char *>(&gaussian), sizeof(Gaussian))) {
gaussians.push_back(gaussian);
}
const PointIndex::ValueType num_vertices = gaussians.size();
out_point_cloud->set_num_points(num_vertices);

GeometryAttribute vapos;
vapos.Init(GeometryAttribute::POSITION, nullptr, 6, DT_FLOAT32, false,
sizeof(float) * 6, 0);
const int att_id_position =
out_point_cloud->AddAttribute(vapos, true, num_vertices);

GeometryAttribute vacol;
vacol.Init(GeometryAttribute::COLOR, nullptr, 8, DT_UINT8, true,
sizeof(uint8_t) * 8, 0);
const int att_id_color =
out_point_cloud->AddAttribute(vacol, true, num_vertices);

for (PointIndex::ValueType i = 0; i < num_vertices; ++i) {
const auto &g = gaussians[i];
std::array<float, 6> valpos;
valpos[0] = g.position[0];
valpos[1] = g.position[1];
valpos[2] = g.position[2];
valpos[3] = g.scale[0];
valpos[4] = g.scale[1];
valpos[5] = g.scale[2];
out_point_cloud->attribute(att_id_position)
->SetAttributeValue(AttributeValueIndex(i), &valpos[0]);

std::array<uint8_t, 8> valcol;
for (int j = 0; j < 4; j++) {
valcol[j] = g.color[j];
}
for (int j = 4; j < 8; j++) {
valcol[j] = g.rotation[j-4];
}
out_point_cloud->attribute(att_id_color)
->SetAttributeValue(AttributeValueIndex(i), &valcol[0]);
}
return OkStatus();
}
} // namespace draco
44 changes: 44 additions & 0 deletions src/draco/io/splat_decoder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2025 Patrick Trollmann.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef DRACO_IO_SPLAT_DECODER_H_
#define DRACO_IO_SPLAT_DECODER_H_

#include <fstream>
#include <vector>

#include "draco/point_cloud/point_cloud.h"
#include "draco/core/status.h"

namespace draco {

// Decodes a SPLAT file into draco::PointCloud.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is there any official SPLAT file specification / definition that we could link to here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I am using the definition by antimatter15: https://github.com/antimatter15/splat

// The current implementation assumes the properties: POSITION, SCALE, COLOR, ROTATION.
// POSITION and SCALE are stored together as GeometryAttribute.POSITION. COLOR and ROATION
Comment thread
patrikant marked this conversation as resolved.
Outdated
// are stored together as GeometryAttribute.COLOR. Currently, it is not possible to use
// custom GeometryAttribute types or the GENERIC type. This types cannot be decoded in
// the WebGL version of Draco.
class SplatDecoder {
public:
SplatDecoder();

// Decodes a splat file stored in the input file.
Status ReadSplatFile(const std::string &filename,
PointCloud *out_point_cloud);

};

} // namespace draco

#endif // DRACO_IO_SPLAT_DECODER_H_