Add Sparse Accessor Support
This commit is contained in:
parent
1bfd930402
commit
2fe07994d1
|
@ -142,6 +142,11 @@ int main(int argc, char* argv[]) {
|
||||||
gltfOptions.enableUserProperties,
|
gltfOptions.enableUserProperties,
|
||||||
"Transcribe FBX User Properties into glTF node and material 'extras'.");
|
"Transcribe FBX User Properties into glTF node and material 'extras'.");
|
||||||
|
|
||||||
|
app.add_flag(
|
||||||
|
"--blend-shape-no-sparse",
|
||||||
|
gltfOptions.disableSparseBlendShapes,
|
||||||
|
"Don't use sparse accessors to store blend shapes");
|
||||||
|
|
||||||
app.add_flag(
|
app.add_flag(
|
||||||
"--blend-shape-normals",
|
"--blend-shape-normals",
|
||||||
gltfOptions.useBlendShapeNormals,
|
gltfOptions.useBlendShapeNormals,
|
||||||
|
@ -159,17 +164,17 @@ int main(int argc, char* argv[]) {
|
||||||
true);
|
true);
|
||||||
|
|
||||||
app.add_option(
|
app.add_option(
|
||||||
"--skinning-weights",
|
"--skinning-weights",
|
||||||
gltfOptions.maxSkinningWeights,
|
gltfOptions.maxSkinningWeights,
|
||||||
"The number of joint influences per vertex.",
|
"The number of joint influences per vertex.",
|
||||||
true)
|
true)
|
||||||
->check(CLI::Range(0, 512));
|
->check(CLI::Range(0, 512));
|
||||||
|
|
||||||
app.add_option(
|
app.add_option(
|
||||||
"-k,--keep-attribute",
|
"-k,--keep-attribute",
|
||||||
[&](std::vector<std::string> attributes) -> bool {
|
[&](std::vector<std::string> attributes) -> bool {
|
||||||
gltfOptions.keepAttribs =
|
gltfOptions.keepAttribs =
|
||||||
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
|
RAW_VERTEX_ATTRIBUTE_JOINT_INDICES | RAW_VERTEX_ATTRIBUTE_JOINT_WEIGHTS;
|
||||||
for (std::string attribute : attributes) {
|
for (std::string attribute : attributes) {
|
||||||
if (attribute == "position") {
|
if (attribute == "position") {
|
||||||
gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
gltfOptions.keepAttribs |= RAW_VERTEX_ATTRIBUTE_POSITION;
|
||||||
|
@ -250,7 +255,9 @@ int main(int argc, char* argv[]) {
|
||||||
->check(CLI::Range(1, 32))
|
->check(CLI::Range(1, 32))
|
||||||
->group("Draco");
|
->group("Draco");
|
||||||
|
|
||||||
app.add_option("--fbx-temp-dir", gltfOptions.fbxTempDir, "Temporary directory to be used by FBX SDK.")->check(CLI::ExistingDirectory);
|
app.add_option(
|
||||||
|
"--fbx-temp-dir", gltfOptions.fbxTempDir, "Temporary directory to be used by FBX SDK.")
|
||||||
|
->check(CLI::ExistingDirectory);
|
||||||
|
|
||||||
CLI11_PARSE(app, argc, argv);
|
CLI11_PARSE(app, argc, argv);
|
||||||
|
|
||||||
|
|
|
@ -112,21 +112,23 @@ struct GltfOptions {
|
||||||
/** Whether to include lights through the KHR_punctual_lights extension. */
|
/** Whether to include lights through the KHR_punctual_lights extension. */
|
||||||
bool useKHRLightsPunctual{true};
|
bool useKHRLightsPunctual{true};
|
||||||
|
|
||||||
/** Whether to include blend shape normals, if present according to the SDK. */
|
/** Whether to not use sparse accessors in blend shapes */
|
||||||
bool useBlendShapeNormals { false };
|
bool disableSparseBlendShapes{false};
|
||||||
/** Whether to include blend shape tangents, if present according to the SDK. */
|
/** Whether to include blend shape normals, if present according to the SDK. */
|
||||||
bool useBlendShapeTangents { false };
|
bool useBlendShapeNormals{false};
|
||||||
/** Whether to normalized skinning weights. */
|
/** Whether to include blend shape tangents, if present according to the SDK. */
|
||||||
bool normalizeSkinningWeights { true };
|
bool useBlendShapeTangents{false};
|
||||||
/** Maximum number of bone influences per vertex. */
|
/** Whether to normalized skinning weights. */
|
||||||
int maxSkinningWeights { 8 };
|
bool normalizeSkinningWeights{true};
|
||||||
/** When to compute vertex normals from geometry. */
|
/** Maximum number of bone influences per vertex. */
|
||||||
ComputeNormalsOption computeNormals = ComputeNormalsOption::BROKEN;
|
int maxSkinningWeights{8};
|
||||||
/** When to use 32-bit indices. */
|
/** When to compute vertex normals from geometry. */
|
||||||
UseLongIndicesOptions useLongIndices = UseLongIndicesOptions::AUTO;
|
ComputeNormalsOption computeNormals = ComputeNormalsOption::BROKEN;
|
||||||
/** Select baked animation framerate. */
|
/** When to use 32-bit indices. */
|
||||||
AnimationFramerateOptions animationFramerate = AnimationFramerateOptions::BAKE30;
|
UseLongIndicesOptions useLongIndices = UseLongIndicesOptions::AUTO;
|
||||||
|
/** Select baked animation framerate. */
|
||||||
|
AnimationFramerateOptions animationFramerate = AnimationFramerateOptions::BAKE30;
|
||||||
|
|
||||||
/** Temporary directory used by FBX SDK. */
|
/** Temporary directory used by FBX SDK. */
|
||||||
std::string fbxTempDir;
|
std::string fbxTempDir;
|
||||||
};
|
};
|
||||||
|
|
|
@ -69,6 +69,12 @@ class GltfModel {
|
||||||
BufferData& buffer,
|
BufferData& buffer,
|
||||||
const std::string& filename);
|
const std::string& filename);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void
|
||||||
|
CopyToBufferView(BufferViewData& bufferView, const std::vector<T>& source, const GLType& type) {
|
||||||
|
bufferView.appendAsBinaryArray(source, *binary, type);
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
std::shared_ptr<AccessorData> AddAccessorWithView(
|
std::shared_ptr<AccessorData> AddAccessorWithView(
|
||||||
BufferViewData& bufferView,
|
BufferViewData& bufferView,
|
||||||
|
@ -76,8 +82,42 @@ class GltfModel {
|
||||||
const std::vector<T>& source,
|
const std::vector<T>& source,
|
||||||
std::string name) {
|
std::string name) {
|
||||||
auto accessor = accessors.hold(new AccessorData(bufferView, type, name));
|
auto accessor = accessors.hold(new AccessorData(bufferView, type, name));
|
||||||
accessor->appendAsBinaryArray(source, *binary);
|
bufferView.appendAsBinaryArray(source, *binary, type);
|
||||||
bufferView.byteLength = accessor->byteLength();
|
accessor->count = bufferView.count;
|
||||||
|
return accessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
std::shared_ptr<AccessorData> AddSparseAccessorWithView(
|
||||||
|
AccessorData& baseAccessor,
|
||||||
|
BufferViewData& indexBufferView,
|
||||||
|
const GLType& indexBufferViewType,
|
||||||
|
BufferViewData& bufferView,
|
||||||
|
const GLType& type,
|
||||||
|
const std::vector<T>& source,
|
||||||
|
std::string name) {
|
||||||
|
auto accessor =
|
||||||
|
accessors.hold(new AccessorData(baseAccessor, indexBufferView, bufferView, type, name));
|
||||||
|
bufferView.appendAsBinaryArray(source, *binary, type);
|
||||||
|
accessor->count = baseAccessor.count;
|
||||||
|
accessor->sparseIdxBufferViewType = indexBufferViewType.componentType.glType;
|
||||||
|
return accessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// template <class T>
|
||||||
|
std::shared_ptr<AccessorData> AddSparseAccessor(
|
||||||
|
AccessorData& baseAccessor,
|
||||||
|
BufferViewData& indexBufferView,
|
||||||
|
const GLType& indexBufferViewType,
|
||||||
|
BufferViewData& bufferView,
|
||||||
|
const GLType& type,
|
||||||
|
// const std::vector<T>& source,
|
||||||
|
std::string name) {
|
||||||
|
auto accessor =
|
||||||
|
accessors.hold(new AccessorData(baseAccessor, indexBufferView, bufferView, type, name));
|
||||||
|
// bufferView.appendAsBinaryArray(source, *binary, type);
|
||||||
|
accessor->count = baseAccessor.count;
|
||||||
|
accessor->sparseIdxBufferViewType = indexBufferViewType.componentType.glType;
|
||||||
return accessor;
|
return accessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,10 +164,10 @@ class GltfModel {
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
std::shared_ptr<AccessorData> AddAttributeArrayToPrimitive(
|
std::shared_ptr<AccessorData> AddAttributeArrayToPrimitive(
|
||||||
BufferData& buffer,
|
BufferData& buffer,
|
||||||
const RawModel& surfaceModel,
|
const RawModel& surfaceModel,
|
||||||
PrimitiveData& primitive,
|
PrimitiveData& primitive,
|
||||||
const AttributeArrayDefinition<T>& attrDef) {
|
const AttributeArrayDefinition<T>& attrDef) {
|
||||||
// copy attribute data into vector
|
// copy attribute data into vector
|
||||||
std::vector<T> attribArr;
|
std::vector<T> attribArr;
|
||||||
surfaceModel.GetArrayAttributeArray<T>(attribArr, attrDef.rawAttributeIx, attrDef.arrayOffset);
|
surfaceModel.GetArrayAttributeArray<T>(attribArr, attrDef.rawAttributeIx, attrDef.arrayOffset);
|
||||||
|
@ -138,8 +178,7 @@ class GltfModel {
|
||||||
|
|
||||||
accessor = accessors.hold(new AccessorData(attrDef.glType));
|
accessor = accessors.hold(new AccessorData(attrDef.glType));
|
||||||
accessor->count = attribArr.size();
|
accessor->count = attribArr.size();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER);
|
auto bufferView = GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER);
|
||||||
accessor = AddAccessorWithView(*bufferView, attrDef.glType, attribArr, std::string(""));
|
accessor = AddAccessorWithView(*bufferView, attrDef.glType, attribArr, std::string(""));
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,6 +470,9 @@ ModelData* Raw2Gltf(
|
||||||
surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex);
|
surfaceModel.GetMaterial(surfaceModel.GetTriangle(0).materialIndex);
|
||||||
const MaterialData& mData = require(materialsById, rawMaterial.id);
|
const MaterialData& mData = require(materialsById, rawMaterial.id);
|
||||||
|
|
||||||
|
if (verboseOutput)
|
||||||
|
fmt::printf("\rMaterial Name: %s\n", mData.name);
|
||||||
|
|
||||||
MeshData* mesh = nullptr;
|
MeshData* mesh = nullptr;
|
||||||
auto meshIter = meshBySurfaceId.find(surfaceId);
|
auto meshIter = meshBySurfaceId.find(surfaceId);
|
||||||
if (meshIter != meshBySurfaceId.end()) {
|
if (meshIter != meshBySurfaceId.end()) {
|
||||||
|
@ -522,6 +525,16 @@ ModelData* Raw2Gltf(
|
||||||
//
|
//
|
||||||
// surface vertices
|
// surface vertices
|
||||||
//
|
//
|
||||||
|
// Base Accessors needed for Sparse Accessors
|
||||||
|
std::shared_ptr<AccessorData> pAccBase;
|
||||||
|
std::shared_ptr<AccessorData> nAccBase;
|
||||||
|
std::shared_ptr<AccessorData> tAccBase;
|
||||||
|
|
||||||
|
// Sparse accessors cannot be zero length, but morph targets can easily have
|
||||||
|
// no modified vertices in multiprim meshes. In order to utilise sparse accessors
|
||||||
|
// in this case, we need a couple of single element dummy buffer views to reference.
|
||||||
|
std::shared_ptr<BufferViewData> dummyIdxView;
|
||||||
|
std::shared_ptr<BufferViewData> dummyDataView;
|
||||||
{
|
{
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) {
|
||||||
const AttributeDefinition<Vec3f> ATTR_POSITION(
|
const AttributeDefinition<Vec3f> ATTR_POSITION(
|
||||||
|
@ -535,6 +548,8 @@ ModelData* Raw2Gltf(
|
||||||
|
|
||||||
accessor->min = toStdVec(rawSurface.bounds.min);
|
accessor->min = toStdVec(rawSurface.bounds.min);
|
||||||
accessor->max = toStdVec(rawSurface.bounds.max);
|
accessor->max = toStdVec(rawSurface.bounds.max);
|
||||||
|
|
||||||
|
pAccBase = accessor;
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_NORMAL) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_NORMAL) != 0) {
|
||||||
const AttributeDefinition<Vec3f> ATTR_NORMAL(
|
const AttributeDefinition<Vec3f> ATTR_NORMAL(
|
||||||
|
@ -545,11 +560,13 @@ ModelData* Raw2Gltf(
|
||||||
draco::DT_FLOAT32);
|
draco::DT_FLOAT32);
|
||||||
const auto _ =
|
const auto _ =
|
||||||
gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_NORMAL);
|
gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_NORMAL);
|
||||||
|
nAccBase = _;
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_TANGENT) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_TANGENT) != 0) {
|
||||||
const AttributeDefinition<Vec4f> ATTR_TANGENT("TANGENT", &RawVertex::tangent, GLT_VEC4F);
|
const AttributeDefinition<Vec4f> ATTR_TANGENT("TANGENT", &RawVertex::tangent, GLT_VEC4F);
|
||||||
const auto _ =
|
const auto _ =
|
||||||
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_TANGENT);
|
gltf->AddAttributeToPrimitive<Vec4f>(buffer, surfaceModel, *primitive, ATTR_TANGENT);
|
||||||
|
tAccBase = _;
|
||||||
}
|
}
|
||||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_COLOR) != 0) {
|
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_COLOR) != 0) {
|
||||||
const AttributeDefinition<Vec4f> ATTR_COLOR(
|
const AttributeDefinition<Vec4f> ATTR_COLOR(
|
||||||
|
@ -617,43 +634,133 @@ ModelData* Raw2Gltf(
|
||||||
|
|
||||||
std::vector<Vec3f> positions, normals;
|
std::vector<Vec3f> positions, normals;
|
||||||
std::vector<Vec4f> tangents;
|
std::vector<Vec4f> tangents;
|
||||||
|
|
||||||
|
std::vector<TriangleIndex> sparseIndices;
|
||||||
|
|
||||||
for (int jj = 0; jj < surfaceModel.GetVertexCount(); jj++) {
|
for (int jj = 0; jj < surfaceModel.GetVertexCount(); jj++) {
|
||||||
auto blendVertex = surfaceModel.GetVertex(jj).blends[channelIx];
|
auto blendVertex = surfaceModel.GetVertex(jj).blends[channelIx];
|
||||||
shapeBounds.AddPoint(blendVertex.position);
|
shapeBounds.AddPoint(blendVertex.position);
|
||||||
positions.push_back(blendVertex.position);
|
bool isSparseVertex = options.disableSparseBlendShapes; // If sparse is off, add all vertices
|
||||||
if (options.useBlendShapeTangents && channel.hasNormals) {
|
// Check to see whether position, normal or tangent deviates from base mesh and flag as
|
||||||
normals.push_back(blendVertex.normal);
|
// sparse.
|
||||||
|
if (blendVertex.position.Length() > 0.00) {
|
||||||
|
isSparseVertex = true;
|
||||||
}
|
}
|
||||||
if (options.useBlendShapeTangents && channel.hasTangents) {
|
// if (options.useBlendShapeNormals && channel.hasNormals &&
|
||||||
tangents.push_back(blendVertex.tangent);
|
// blendVertex.normal.Length() > 0.00) {
|
||||||
|
// isSparseVertex = true;
|
||||||
|
// }
|
||||||
|
// if (options.useBlendShapeTangents && channel.hasTangents &&
|
||||||
|
// blendVertex.tangent.Length() > 0.00) {
|
||||||
|
// isSparseVertex = true;
|
||||||
|
// }
|
||||||
|
if (isSparseVertex == true) {
|
||||||
|
sparseIndices.push_back(jj);
|
||||||
|
positions.push_back(blendVertex.position);
|
||||||
|
if (options.useBlendShapeNormals && channel.hasNormals) {
|
||||||
|
normals.push_back(blendVertex.normal);
|
||||||
|
}
|
||||||
|
if (options.useBlendShapeTangents && channel.hasTangents) {
|
||||||
|
tangents.push_back(blendVertex.tangent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::shared_ptr<AccessorData> pAcc = gltf->AddAccessorWithView(
|
|
||||||
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
|
||||||
GLT_VEC3F,
|
|
||||||
positions,
|
|
||||||
channel.name);
|
|
||||||
pAcc->min = toStdVec(shapeBounds.min);
|
|
||||||
pAcc->max = toStdVec(shapeBounds.max);
|
|
||||||
|
|
||||||
|
std::shared_ptr<AccessorData> pAcc;
|
||||||
std::shared_ptr<AccessorData> nAcc;
|
std::shared_ptr<AccessorData> nAcc;
|
||||||
if (!normals.empty()) {
|
std::shared_ptr<AccessorData> tAcc;
|
||||||
nAcc = gltf->AddAccessorWithView(
|
if (!options.disableSparseBlendShapes) {
|
||||||
|
if (verboseOutput)
|
||||||
|
fmt::printf(
|
||||||
|
"\rChannel Name: %-50s Sparse Count: %d\n", channel.name, sparseIndices.size());
|
||||||
|
|
||||||
|
if (sparseIndices.size() == 0) {
|
||||||
|
// Initalize dummy bufferviews if needed
|
||||||
|
if (!dummyIdxView) {
|
||||||
|
std::vector<TriangleIndex> dummyIndices;
|
||||||
|
dummyIndices.push_back(int(0));
|
||||||
|
|
||||||
|
dummyIdxView = gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
|
||||||
|
gltf->CopyToBufferView(
|
||||||
|
*dummyIdxView, dummyIndices, useLongIndices ? GLT_UINT : GLT_USHORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dummyDataView) {
|
||||||
|
std::vector<Vec3f> dummyData;
|
||||||
|
dummyData.push_back(Vec3f(0.0));
|
||||||
|
|
||||||
|
dummyDataView = gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
|
||||||
|
dummyDataView->appendAsBinaryArray(dummyData, *gltf->binary, GLT_VEC3F);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up sparse accessor with dummy buffer views
|
||||||
|
pAcc = gltf->AddSparseAccessor(
|
||||||
|
*pAccBase,
|
||||||
|
*dummyIdxView,
|
||||||
|
useLongIndices ? GLT_UINT : GLT_USHORT,
|
||||||
|
*dummyDataView,
|
||||||
|
GLT_VEC3F,
|
||||||
|
channel.name);
|
||||||
|
} else {
|
||||||
|
// Build Orphan Bufferview for Sparse Indices
|
||||||
|
std::shared_ptr<BufferViewData> indexBufferView =
|
||||||
|
gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE);
|
||||||
|
gltf->CopyToBufferView(
|
||||||
|
*indexBufferView, sparseIndices, useLongIndices ? GLT_UINT : GLT_USHORT);
|
||||||
|
|
||||||
|
pAcc = gltf->AddSparseAccessorWithView(
|
||||||
|
*pAccBase,
|
||||||
|
*indexBufferView,
|
||||||
|
useLongIndices ? GLT_UINT : GLT_USHORT,
|
||||||
|
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE),
|
||||||
|
GLT_VEC3F,
|
||||||
|
positions,
|
||||||
|
channel.name);
|
||||||
|
if (!normals.empty()) {
|
||||||
|
nAcc = gltf->AddSparseAccessorWithView(
|
||||||
|
*nAccBase,
|
||||||
|
*indexBufferView,
|
||||||
|
useLongIndices ? GLT_UINT : GLT_USHORT,
|
||||||
|
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE),
|
||||||
|
GLT_VEC3F,
|
||||||
|
normals,
|
||||||
|
channel.name);
|
||||||
|
}
|
||||||
|
if (!tangents.empty()) {
|
||||||
|
tAcc = gltf->AddSparseAccessorWithView(
|
||||||
|
*nAccBase,
|
||||||
|
*indexBufferView,
|
||||||
|
useLongIndices ? GLT_UINT : GLT_USHORT,
|
||||||
|
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_NONE),
|
||||||
|
GLT_VEC4F,
|
||||||
|
tangents,
|
||||||
|
channel.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pAcc = gltf->AddAccessorWithView(
|
||||||
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
||||||
GLT_VEC3F,
|
GLT_VEC3F,
|
||||||
normals,
|
positions,
|
||||||
channel.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<AccessorData> tAcc;
|
|
||||||
if (!tangents.empty()) {
|
|
||||||
nAcc = gltf->AddAccessorWithView(
|
|
||||||
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
|
||||||
GLT_VEC4F,
|
|
||||||
tangents,
|
|
||||||
channel.name);
|
channel.name);
|
||||||
|
if (!normals.empty()) {
|
||||||
|
nAcc = gltf->AddAccessorWithView(
|
||||||
|
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
||||||
|
GLT_VEC3F,
|
||||||
|
normals,
|
||||||
|
channel.name);
|
||||||
|
}
|
||||||
|
if (!tangents.empty()) {
|
||||||
|
nAcc = gltf->AddAccessorWithView(
|
||||||
|
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
||||||
|
GLT_VEC4F,
|
||||||
|
tangents,
|
||||||
|
channel.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pAcc->min = toStdVec(shapeBounds.min);
|
||||||
|
pAcc->max = toStdVec(shapeBounds.max);
|
||||||
primitive->AddTarget(pAcc.get(), nAcc.get(), tAcc.get());
|
primitive->AddTarget(pAcc.get(), nAcc.get(), tAcc.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,23 @@ AccessorData::AccessorData(const BufferViewData& bufferView, GLType type, std::s
|
||||||
type(std::move(type)),
|
type(std::move(type)),
|
||||||
byteOffset(0),
|
byteOffset(0),
|
||||||
count(0),
|
count(0),
|
||||||
name(name) {}
|
name(name),
|
||||||
|
sparse(false) {}
|
||||||
|
|
||||||
|
AccessorData::AccessorData(const AccessorData& baseAccessor, const BufferViewData& sparseIdxBufferView, const BufferViewData& sparseDataBufferView, GLType type, std::string name)
|
||||||
|
: Holdable(),
|
||||||
|
bufferView(baseAccessor.bufferView),
|
||||||
|
type(std::move(type)),
|
||||||
|
byteOffset(baseAccessor.byteOffset),
|
||||||
|
count(baseAccessor.count),
|
||||||
|
name(name),
|
||||||
|
sparse(true),
|
||||||
|
sparseIdxCount(sparseIdxBufferView.count),
|
||||||
|
sparseIdxBufferView(sparseIdxBufferView.ix),
|
||||||
|
sparseIdxBufferViewOffset(0),
|
||||||
|
sparseIdxBufferViewType(0),
|
||||||
|
sparseDataBufferView(sparseDataBufferView.ix),
|
||||||
|
sparseDataBufferViewOffset(0) {}
|
||||||
|
|
||||||
AccessorData::AccessorData(GLType type)
|
AccessorData::AccessorData(GLType type)
|
||||||
: Holdable(), bufferView(-1), type(std::move(type)), byteOffset(0), count(0) {}
|
: Holdable(), bufferView(-1), type(std::move(type)), byteOffset(0), count(0) {}
|
||||||
|
@ -23,7 +39,7 @@ AccessorData::AccessorData(GLType type)
|
||||||
json AccessorData::serialize() const {
|
json AccessorData::serialize() const {
|
||||||
json result{
|
json result{
|
||||||
{"componentType", type.componentType.glType}, {"type", type.dataType}, {"count", count}};
|
{"componentType", type.componentType.glType}, {"type", type.dataType}, {"count", count}};
|
||||||
if (bufferView >= 0) {
|
if (bufferView >= 0 && !sparse) {
|
||||||
result["bufferView"] = bufferView;
|
result["bufferView"] = bufferView;
|
||||||
result["byteOffset"] = byteOffset;
|
result["byteOffset"] = byteOffset;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +49,17 @@ json AccessorData::serialize() const {
|
||||||
if (!max.empty()) {
|
if (!max.empty()) {
|
||||||
result["max"] = max;
|
result["max"] = max;
|
||||||
}
|
}
|
||||||
|
if (sparse) {
|
||||||
|
json sparseData = {{"count", sparseIdxCount}};
|
||||||
|
sparseData["indices"] = { {"bufferView", sparseIdxBufferView},
|
||||||
|
{"byteOffset", sparseIdxBufferViewOffset},
|
||||||
|
{"componentType", sparseIdxBufferViewType}};
|
||||||
|
|
||||||
|
sparseData["values"] = { {"bufferView", sparseDataBufferView},
|
||||||
|
{"byteOffset", sparseDataBufferViewOffset}};
|
||||||
|
|
||||||
|
result["sparse"] = sparseData;
|
||||||
|
}
|
||||||
if (name.length() > 0) {
|
if (name.length() > 0) {
|
||||||
result["name"] = name;
|
result["name"] = name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,35 +11,30 @@
|
||||||
#include "gltf/Raw2Gltf.hpp"
|
#include "gltf/Raw2Gltf.hpp"
|
||||||
|
|
||||||
struct AccessorData : Holdable {
|
struct AccessorData : Holdable {
|
||||||
AccessorData(const BufferViewData& bufferView, GLType type, std::string name);
|
AccessorData(const BufferViewData& bufferView, GLType type, std::string name);
|
||||||
explicit AccessorData(GLType type);
|
explicit AccessorData(GLType type);
|
||||||
|
AccessorData(const AccessorData& baseAccessor, const BufferViewData& sparseIdxBufferView, const BufferViewData& sparseDataBufferView, GLType type, std::string name);
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
template <class T>
|
unsigned int byteLength() const {
|
||||||
void appendAsBinaryArray(const std::vector<T>& in, std::vector<uint8_t>& out) {
|
return type.byteStride() * count;
|
||||||
const unsigned int stride = type.byteStride();
|
|
||||||
const size_t offset = out.size();
|
|
||||||
const size_t count = in.size();
|
|
||||||
|
|
||||||
this->count = (unsigned int)count;
|
|
||||||
|
|
||||||
out.resize(offset + count * stride);
|
|
||||||
for (int ii = 0; ii < count; ii++) {
|
|
||||||
type.write(&out[offset + ii * stride], in[ii]);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int byteLength() const {
|
const int bufferView;
|
||||||
return type.byteStride() * count;
|
const GLType type;
|
||||||
}
|
|
||||||
|
|
||||||
const int bufferView;
|
unsigned int byteOffset;
|
||||||
const GLType type;
|
unsigned int count;
|
||||||
|
std::vector<float> min;
|
||||||
|
std::vector<float> max;
|
||||||
|
std::string name;
|
||||||
|
|
||||||
unsigned int byteOffset;
|
bool sparse;
|
||||||
unsigned int count;
|
int sparseIdxCount;
|
||||||
std::vector<float> min;
|
int sparseIdxBufferView;
|
||||||
std::vector<float> max;
|
int sparseIdxBufferViewOffset;
|
||||||
std::string name;
|
int sparseIdxBufferViewType;
|
||||||
|
int sparseDataBufferView;
|
||||||
|
int sparseDataBufferViewOffset;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,9 +21,25 @@ struct BufferViewData : Holdable {
|
||||||
|
|
||||||
json serialize() const override;
|
json serialize() const override;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void appendAsBinaryArray(const std::vector<T>& in, std::vector<uint8_t>& out, GLType type) {
|
||||||
|
const unsigned int stride = type.byteStride();
|
||||||
|
const size_t offset = out.size();
|
||||||
|
const size_t count = in.size();
|
||||||
|
|
||||||
|
this->byteLength = stride * count;
|
||||||
|
this->count = count;
|
||||||
|
|
||||||
|
out.resize(offset + count * stride);
|
||||||
|
for (int ii = 0; ii < count; ii++) {
|
||||||
|
type.write(&out[offset + ii * stride], in[ii]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const unsigned int buffer;
|
const unsigned int buffer;
|
||||||
const unsigned int byteOffset;
|
const unsigned int byteOffset;
|
||||||
const GL_ArrayType target;
|
const GL_ArrayType target;
|
||||||
|
|
||||||
|
unsigned int count = 0;
|
||||||
unsigned int byteLength = 0;
|
unsigned int byteLength = 0;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue