google / google/draco

[Bug] Crash on special mesh with tangents.

Open
#832 2 comments 0 reactions 1 assignee Claimed by @ondys View on GitHub
bug
Dominant language
C++
Stars
7.5k
Forks
1.1k
Avg merge
47m
Merged PRs (30d)
1

Description

I integrated Draco into our game engine to compress meshes, it works fine on most of meshes except one.

I dumped the mesh data in binary and wrote a simple program to decode the data and encode in Draco, it also failed.

I tried digging into the source code, some very large number (like 2147483647 or -2147483648) was generated in the process of processing tangents attribute in `prediction_scheme_->ComputeCorrectionValues` in [sequential_integer_attribute_encoder.cc#L141](https://github.com/google/draco/blob/7d62f1f26fb176a89fc4e8f9e450456ee2ecdeb8/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc#L141).

Source code is below, and the binary data is in [mesh.zip](https://github.com/google/draco/files/8338173/mesh.zip).

```C++
#include "draco/compression/encode.h"
#include "draco/compression/decode.h"
#include
#include
#include
enum ShaderChannel {
kShaderChannelNone = -1,
kShaderChannelVertex = 0, // Vertex (vector3)
kShaderChannelNormal, // Normal (vector3)
kShaderChannelColor, // Vertex color
kShaderChannelTexCoord0, // Texcoord 0
kShaderChannelTexCoord1, // Texcoord 1
kShaderChannelTexCoord2, // Texcoord 2
kShaderChannelTexCoord3, // Texcoord 3
kShaderChannelTangent, // Tangent (vector4)
kShaderChannelCount, // Keep this last!
};

typedef std::array Vector2f;
typedef std::array Vector3f;
typedef std::array Vector4f;

int main(int argc, char** argv) {
std::ifstream ifs;
ifs.open(argv[1], std::ios_base::in | std::ios_base::binary);
ifs.seekg(0, std::ios::end);
auto size = ifs.tellg();
auto buffer = new char[size];
size_t bufferIndex = 0;
ifs.seekg(0, std::ios::beg);
ifs.read(buffer, size);

draco::Mesh mesh;

auto Read = [&](auto& x) -> void {
x = *reinterpret_cast(buffer + bufferIndex);
bufferIndex += sizeof(x);
};

int trianglesCount;
int vertexCount;
Read(trianglesCount);
Read(vertexCount);

mesh.SetNumFaces(trianglesCount);
mesh.set_num_points(vertexCount);

std::array attrIDs{};
for (auto& attrID : attrIDs) {
Read(attrID);
}
std::vector triangles(trianglesCount * 3, 0);
for (auto &it : triangles) { Read(it); }
for (draco::FaceIndex index(0); index < trianglesCount; ++index) {
draco::Mesh::Face face;
face[0] = triangles[index.value() * 3];
face[1] = triangles[index.value() * 3 + 1];
face[2] = triangles[index.value() * 3 + 2];
mesh.SetFace(index, face);
}
std::vector vertices;

if (attrIDs[kShaderChannelVertex] >= 0) {
vertices.resize(vertexCount);
draco::GeometryAttribute va;
va.Init(draco::GeometryAttribute::POSITION, nullptr, 3, draco::DT_FLOAT32,
false, sizeof(float) * 3, 0);
auto a = mesh.AddAttribute(va, true, vertexCount);
auto attr = mesh.attribute(a);
draco::AttributeValueIndex index(0);
for (auto& v : vertices) {
for (auto& it : v) {
Read(it);
}
attr->SetAttributeValue(index, &v);
++index;
}
}

std::array, 4> uvs;
for (auto i = 0; i < 4; ++i) {
if (attrIDs[kShaderChannelTexCoord0 + i] >= 0) {
uvs[i].resize(vertexCount);
draco::GeometryAttribute va;
va.Init(draco::GeometryAttribute::TEX_COORD, nullptr, 2, draco::DT_FLOAT32,
false, sizeof(float) * 2, 0);
auto a = mesh.AddAttribute(va, true, vertexCount);
auto attr = mesh.attribute(a);
draco::AttributeValueIndex index(0);
for (auto& it : uvs[i]) {
for (auto& j : it) {
Read(j);
}
attr->SetAttributeValue(index, &it);
++index;
}
}
}

std::vector normals;
if (attrIDs[kShaderChannelNormal] >= 0) {
normals.resize(vertexCount);
draco::GeometryAttribute va;
va.Init(draco::GeometryAttribute::NORMAL, nullptr, 3, draco::DT_FLOAT32,
false, sizeof(float) * 3, 0);
auto a = mesh.AddAttribute(va, true, vertexCount);
auto attr = mesh.attribute(a);
draco::AttributeValueIndex index(0);
for (auto& it : normals) {
for (auto& i : it) {
Read(i);
}
attr->SetAttributeValue(index, &it);
++index;
}
}

std::vector> colors;
if (attrIDs[kShaderChannelColor] >= 0) {
colors.resize(vertexCount);
draco::GeometryAttribute va;
va.Init(draco::GeometryAttribute::COLOR, nullptr, 4, draco::DT_UINT8,
false, sizeof(uint8_t) * 4, 0);
auto a = mesh.AddAttribute(va, true, vertexCount);
auto attr = mesh.attribute(a);
draco::AttributeValueIndex index(0);
for (auto& it : colors) {
for (auto& i : it) {
Read(i);
}
attr->SetAttributeValue(index, &it);
++index;
}
}

std::vector tangents;
if (attrIDs[kShaderChannelTangent] >= 0) {
tangents.resize(vertexCount);
draco::GeometryAttribute va;
va.Init(draco::GeometryAttribute::GENERIC, nullptr, 4, draco::DT_FLOAT32,
false, sizeof(float) * 4, 0);
auto a = mesh.AddAttribute(va, true, vertexCount);
auto attr = mesh.attribute(a);
draco::AttributeValueIndex index(0);
for (auto& it : tangents) {
for (auto& i : it) {
Read(i);
}
attr->SetAttributeValue(index, &it);
++index;
}
}

draco::Encoder encoder;
draco::EncoderBuffer encBuffer;
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, 12);
encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, 10);
encoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR, 8);
encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, 10);
encoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, 12);
encoder.SetSpeedOptions(7, 7);
auto encOk = encoder.EncodeMeshToBuffer(mesh, &encBuffer);

std::cout << encOk.ok() << " " << encOk.error_msg() << std::endl;
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.