Added support for sparse accessors in blendshapes
Testing still TBD
This commit is contained in:
parent
37f992321e
commit
eda5342286
|
@ -142,6 +142,11 @@ int main(int argc, char* argv[]) {
|
|||
gltfOptions.enableUserProperties,
|
||||
"Transcribe FBX User Properties into glTF node and material 'extras'.");
|
||||
|
||||
app.add_flag(
|
||||
"--blend-shape-sparse",
|
||||
gltfOptions.enableSparseBlendShapes,
|
||||
"Use sparse accessors to store blend shapes");
|
||||
|
||||
app.add_flag(
|
||||
"--blend-shape-normals",
|
||||
gltfOptions.useBlendShapeNormals,
|
||||
|
|
|
@ -112,6 +112,8 @@ struct GltfOptions {
|
|||
/** Whether to include lights through the KHR_punctual_lights extension. */
|
||||
bool useKHRLightsPunctual{true};
|
||||
|
||||
/** Whether to use sparse accessors in blend shapes */
|
||||
bool enableSparseBlendShapes{false};
|
||||
/** Whether to include blend shape normals, if present according to the SDK. */
|
||||
bool useBlendShapeNormals{false};
|
||||
/** Whether to include blend shape tangents, if present according to the SDK. */
|
||||
|
|
|
@ -69,6 +69,14 @@ class GltfModel {
|
|||
BufferData& buffer,
|
||||
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>
|
||||
std::shared_ptr<AccessorData> AddAccessorWithView(
|
||||
BufferViewData& bufferView,
|
||||
|
@ -76,8 +84,24 @@ class GltfModel {
|
|||
const std::vector<T>& source,
|
||||
std::string name) {
|
||||
auto accessor = accessors.hold(new AccessorData(bufferView, type, name));
|
||||
accessor->appendAsBinaryArray(source, *binary);
|
||||
bufferView.byteLength = accessor->byteLength();
|
||||
bufferView.appendAsBinaryArray(source, *binary, type);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -470,6 +470,10 @@ ModelData* Raw2Gltf(
|
|||
//
|
||||
// surface vertices
|
||||
//
|
||||
// Base Accessors needed for Sparse Accessors
|
||||
std::shared_ptr<AccessorData> pAccBase;
|
||||
std::shared_ptr<AccessorData> nAccBase;
|
||||
std::shared_ptr<AccessorData> tAccBase;
|
||||
{
|
||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_POSITION) != 0) {
|
||||
const AttributeDefinition<Vec3f> ATTR_POSITION(
|
||||
|
@ -483,6 +487,8 @@ ModelData* Raw2Gltf(
|
|||
|
||||
accessor->min = toStdVec(rawSurface.bounds.min);
|
||||
accessor->max = toStdVec(rawSurface.bounds.max);
|
||||
|
||||
pAccBase = accessor;
|
||||
}
|
||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_NORMAL) != 0) {
|
||||
const AttributeDefinition<Vec3f> ATTR_NORMAL(
|
||||
|
@ -493,11 +499,13 @@ ModelData* Raw2Gltf(
|
|||
draco::DT_FLOAT32);
|
||||
const auto _ =
|
||||
gltf->AddAttributeToPrimitive<Vec3f>(buffer, surfaceModel, *primitive, ATTR_NORMAL);
|
||||
nAccBase = _;
|
||||
}
|
||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_TANGENT) != 0) {
|
||||
const AttributeDefinition<Vec4f> ATTR_TANGENT("TANGENT", &RawVertex::tangent, GLT_VEC4F);
|
||||
const auto _ = gltf->AddAttributeToPrimitive<Vec4f>(
|
||||
buffer, surfaceModel, *primitive, ATTR_TANGENT);
|
||||
tAccBase = _;
|
||||
}
|
||||
if ((surfaceModel.GetVertexAttributes() & RAW_VERTEX_ATTRIBUTE_COLOR) != 0) {
|
||||
const AttributeDefinition<Vec4f> ATTR_COLOR(
|
||||
|
@ -559,43 +567,106 @@ ModelData* Raw2Gltf(
|
|||
|
||||
std::vector<Vec3f> positions, normals;
|
||||
std::vector<Vec4f> tangents;
|
||||
|
||||
std::vector<TriangleIndex> sparseIndices;
|
||||
|
||||
for (int jj = 0; jj < surfaceModel.GetVertexCount(); jj++) {
|
||||
auto blendVertex = surfaceModel.GetVertex(jj).blends[channelIx];
|
||||
shapeBounds.AddPoint(blendVertex.position);
|
||||
positions.push_back(blendVertex.position);
|
||||
if (options.useBlendShapeTangents && channel.hasNormals) {
|
||||
normals.push_back(blendVertex.normal);
|
||||
|
||||
bool isSparseVertex = !options.enableSparseBlendShapes; // If sparse is off, add all vertices
|
||||
// Check to see whether position, normal or tangent deviates from base mesh and flag as sparse.
|
||||
if (blendVertex.position.Length()>0.00){
|
||||
isSparseVertex = true;
|
||||
}
|
||||
if (options.useBlendShapeTangents && channel.hasTangents) {
|
||||
tangents.push_back(blendVertex.tangent);
|
||||
if (options.useBlendShapeNormals && channel.hasNormals && 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,
|
||||
/*
|
||||
std::shared_ptr<AccessorData> pAccIx = gltf->AddAccessorWithView(
|
||||
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ELEMENT_ARRAY_BUFFER),
|
||||
useLongIndices ? GLT_UINT : GLT_USHORT,
|
||||
sparseIndices,
|
||||
channel.name);
|
||||
pAcc->min = toStdVec(shapeBounds.min);
|
||||
pAcc->max = toStdVec(shapeBounds.max);
|
||||
|
||||
*/
|
||||
std::shared_ptr<AccessorData> pAcc;
|
||||
std::shared_ptr<AccessorData> nAcc;
|
||||
if (!normals.empty()) {
|
||||
nAcc = gltf->AddAccessorWithView(
|
||||
std::shared_ptr<AccessorData> tAcc;
|
||||
|
||||
if(options.enableSparseBlendShapes){
|
||||
fmt::printf("\rSparse Index Count: %d \n", sparseIndices.size());
|
||||
// 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),
|
||||
GLT_VEC3F,
|
||||
normals,
|
||||
channel.name);
|
||||
}
|
||||
|
||||
std::shared_ptr<AccessorData> tAcc;
|
||||
if (!tangents.empty()) {
|
||||
nAcc = gltf->AddAccessorWithView(
|
||||
*gltf->GetAlignedBufferView(buffer, BufferViewData::GL_ARRAY_BUFFER),
|
||||
GLT_VEC4F,
|
||||
tangents,
|
||||
positions,
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,15 +15,34 @@ AccessorData::AccessorData(const BufferViewData& bufferView, GLType type, std::s
|
|||
type(std::move(type)),
|
||||
byteOffset(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)
|
||||
: Holdable(), bufferView(-1), type(std::move(type)), byteOffset(0), count(0) {}
|
||||
: Holdable(), bufferView(-1), type(std::move(type)), byteOffset(0), count(0), sparse(false){}
|
||||
|
||||
json AccessorData::serialize() const {
|
||||
json result{
|
||||
{"componentType", type.componentType.glType}, {"type", type.dataType}, {"count", count}};
|
||||
if (bufferView >= 0) {
|
||||
if (bufferView >= 0 && !sparse) {
|
||||
result["bufferView"] = bufferView;
|
||||
result["byteOffset"] = byteOffset;
|
||||
}
|
||||
|
@ -33,6 +52,17 @@ json AccessorData::serialize() const {
|
|||
if (!max.empty()) {
|
||||
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) {
|
||||
result["name"] = name;
|
||||
}
|
||||
|
|
|
@ -11,25 +11,16 @@
|
|||
#include "gltf/Raw2Gltf.hpp"
|
||||
|
||||
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);
|
||||
AccessorData(const AccessorData& baseAccessor,
|
||||
const BufferViewData& sparseIdxBufferView,
|
||||
const BufferViewData& sparseDataBufferView,
|
||||
GLType type, std::string name);
|
||||
|
||||
json serialize() const override;
|
||||
|
||||
template <class T>
|
||||
void appendAsBinaryArray(const std::vector<T>& in, std::vector<uint8_t>& out) {
|
||||
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 {
|
||||
return type.byteStride() * count;
|
||||
}
|
||||
|
@ -42,4 +33,12 @@ struct AccessorData : Holdable {
|
|||
std::vector<float> min;
|
||||
std::vector<float> max;
|
||||
std::string name;
|
||||
|
||||
const bool sparse;
|
||||
int sparseIdxCount;
|
||||
int sparseIdxBufferView;
|
||||
int sparseIdxBufferViewOffset;
|
||||
int sparseIdxBufferViewType;
|
||||
int sparseDataBufferView;
|
||||
int sparseDataBufferViewOffset;
|
||||
};
|
||||
|
|
|
@ -21,9 +21,25 @@ struct BufferViewData : Holdable {
|
|||
|
||||
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 byteOffset;
|
||||
const GL_ArrayType target;
|
||||
|
||||
unsigned int count=0;
|
||||
unsigned int byteLength = 0;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue