Refactor codes.

Adding some Material/Shader/Texture related codes.
Add Roboto font for GUI.
This commit is contained in:
Syoyo Fujita
2020-09-05 22:45:07 +09:00
parent cc5e4fa792
commit 8db8e2c311
11 changed files with 2573 additions and 77 deletions

View File

@@ -6,6 +6,7 @@
* primvars:st : usually vec2f[] varying
* primvars:st:indices : usually int[] varying
* velocities : usually vec3f[]
* texcoord: usually `texCoord2f[]` (Texcoord bound to Mesh prim)
### Mesh property
@@ -58,6 +59,12 @@
* inputs:fallback : fallback color(Usually vec4f)
* inputs:file : @filename@
### Texcoord reader
`UsdPrimvarReader_float2`
* inputs:varname(token) : Name of UV coordinate primvar in Mesh primitive.
* outputs:<name>(float2) : Output connection name. Usually `outputs:result`
## TODO

View File

@@ -5,6 +5,11 @@
Seems USDA(ASCII) is not supported(yet?).
USDC only.
## Mesh
attribute with `texCoord2f[]` type: Can be used as explicit texture coordinate
attribute with `float2[]` type: Specify texture UV attribute from TexCoordReader(UsdPrimvarReader) with `inputs:varname` attribute.
## Material/Shader
It looks USDZ tool(e.g. ARKit) only supports UsdPreviewSurface

View File

@@ -0,0 +1,3 @@
Roboto icons : Apache 2.0 License.
Roboto : Apache 2.0 License.

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,8 @@
#include "tinyusdz.hh"
#include "trackball.h"
#include "roboto_mono_embed.inc.h"
// sdlviewer
#include "gui.hh"
@@ -53,7 +55,7 @@ struct GUIContext {
bool ctrl_pressed = false;
bool tab_pressed = false;
float yaw = 90.0f; // for Z up scene
float yaw = 90.0f; // for Z up scene
float pitch = 0.0f;
float roll = 0.0f;
@@ -361,6 +363,19 @@ int main(int argc, char** argv) {
ImGui::CreateContext();
{
ImGuiIO& io = ImGui::GetIO();
ImFontConfig roboto_config;
strcpy(roboto_config.Name, "Roboto");
float font_size = 18.0f;
io.Fonts->AddFontFromMemoryCompressedTTF(roboto_mono_compressed_data,
roboto_mono_compressed_size,
font_size, &roboto_config);
}
ImGuiSDL::Initialize(renderer, 1600, 800);
// ImGui_ImplGlfw_InitForOpenGL(window, true);
// ImGui_ImplOpenGL2_Init();
@@ -457,7 +472,7 @@ int main(int argc, char** argv) {
bool update = false;
bool update_display = false;
if (example::ImGuiComboUI("aov", aov_name, aov_list)) {
gui_ctx.aov_mode = aov_list[aov_name];
update_display = true;

View File

@@ -0,0 +1,28 @@
CXX=clang++
CXXFLAGS=-std=c++11 -I../../src -fsanitize=address -Weverything -Wall -Wno-padded -Wno-c++98-compat -Wno-c++98-compat-pedantic
LINKFLAGS=-fsanitize=address
all: serializer
serializer: tinyusdz.o serializer.o integerCoding.o lz4-compression.o lz4.o
$(CXX) $(LINKFLAGS) -o serializer $^
serializer.o: ../../src/tinyusdz.cc ../../src/tinyusdz.hh serializer.cc
$(CXX) $(CXXFLAGS) -c -o serializer.o serializer.cc
tinyusdz.o: ../../src/tinyusdz.cc ../../src/tinyusdz.hh
$(CXX) $(CXXFLAGS) -c -o tinyusdz.o ../../src/tinyusdz.cc
integerCoding.o: ../../src/integerCoding.cpp
$(CXX) $(CXXFLAGS) -c -o integerCoding.o ../../src/integerCoding.cpp
lz4-compression.o: ../../src/lz4-compression.cc
$(CXX) $(CXXFLAGS) -c -o lz4-compression.o ../../src/lz4-compression.cc
lz4.o: ../../src/pxrLZ4/lz4.cpp
$(CXX) $(CXXFLAGS) -c -o lz4.o ../../src/pxrLZ4/lz4.cpp
.PHONY: clean
clean:
rm -rf serializer lz4.o serializer.o integerCoding.o tinyusdz.o lz4-compression.o

View File

@@ -0,0 +1,6 @@
# Experimental USDC, USDZ serializer
## Status
Nothing yet

View File

@@ -0,0 +1,20 @@
#include <cstdint>
#include <cstdlib>
#include "usdc_serializer.hh"
namespace tinyusdz {
bool WriteUSDCHeader(std::vector<uint8_t> *output) {
// header = 88bytes
}
} // namespace tinyusdz
int main(int argc, char **argv)
{
return EXIT_SUCCESS;
};

View File

@@ -0,0 +1,34 @@
/*
MIT License
Copyright (c) 2020 Syoyo Fujita
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#pragma once
#include <tinyusdz.hh>
namespace tinyusdz {
bool SerializeUSDCToMemory(std::vector<uint8_t> *output);
} // namespace tinyusdz

View File

@@ -39,8 +39,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unordered_set>
#include <vector>
// local debug flag
#define TINYUSDZ_LOCAL_DEBUG_PRINT (1)
// local debug flag(now defined in tinyusdz.hh)
//#define TINYUSDZ_LOCAL_DEBUG_PRINT (1)
#include "integerCoding.h"
#include "lz4-compression.hh"
@@ -828,12 +828,32 @@ class Parser {
bool _BuildLiveFieldSets();
///
/// Parse node's attribute from FieldValuePairVector.
///
bool _ParseAttribute(const FieldValuePairVector &fvs, PrimAttrib *attr,
const std::string &prop_name);
bool _ReconstructGeomMesh(const Node &node,
const FieldValuePairVector &fields,
const std::unordered_map<uint32_t, uint32_t>
&path_index_to_spec_index_map,
GeomMesh *mesh);
bool _ReconstructMaterial(const Node &node,
const FieldValuePairVector &fields,
const std::unordered_map<uint32_t, uint32_t>
&path_index_to_spec_index_map,
Material *material);
///
/// NOTE: Currently we only support UsdPreviewSurface
///
bool _ReconstructShader(const Node &node, const FieldValuePairVector &fields,
const std::unordered_map<uint32_t, uint32_t>
&path_index_to_spec_index_map,
PreviewSurface *shader);
bool _ReconstructSceneRecursively(int parent_id, int level,
const std::unordered_map<uint32_t, uint32_t>
&path_index_to_spec_index_map,
@@ -1725,7 +1745,6 @@ bool Parser::_UnpackValueRep(const ValueRep &rep, Value *value) {
return true;
} else if (ty.id == VALUE_TYPE_FLOAT) {
assert((!rep.IsCompressed()) && (!rep.IsArray()));
float f;
@@ -2346,7 +2365,6 @@ bool Parser::_UnpackValueRep(const ValueRep &rep, Value *value) {
<< "\n";
#endif
value->SetVec3d(v);
}
return true;
@@ -2406,11 +2424,10 @@ bool Parser::_UnpackValueRep(const ValueRep &rep, Value *value) {
}
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "value.quatf = " << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3]
<< "\n";
std::cout << "value.quatf = " << v[0] << ", " << v[1] << ", " << v[2]
<< ", " << v[3] << "\n";
#endif
value->SetQuatf(v);
}
return true;
@@ -2480,7 +2497,8 @@ bool Parser::_UnpackValueRep(const ValueRep &rep, Value *value) {
} else {
// TODO(syoyo)
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cerr << "[" << __LINE__ << "] TODO: " << GetValueTypeRepr(rep.GetType()) << "\n";
std::cerr << "[" << __LINE__
<< "] TODO: " << GetValueTypeRepr(rep.GetType()) << "\n";
#endif
return false;
}
@@ -3208,14 +3226,185 @@ bool Parser::_BuildLiveFieldSets() {
return true;
}
bool Parser::_ParseAttribute(const FieldValuePairVector &fvs, PrimAttrib *attr,
const std::string &prop_name) {
bool success = false;
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "fvs.size = " << fvs.size() << "\n";
#endif
bool has_connection{false};
Variability variability{VariabilityVarying};
bool facevarying{false};
//
// Parse properties
//
for (const auto &fv : fvs) {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "=== fvs.first " << fv.first
<< ", second: " << fv.second.GetTypeName() << "\n";
#endif
if ((fv.first == "typeName") && (fv.second.GetTypeName() == "Token")) {
attr->type_name = fv.second.GetToken();
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "aaa: typeName: " << attr->type_name << "\n";
#endif
} else if (fv.first == "connectionPaths") {
// e.g. connection to texture file.
const ListOp<Path> paths = fv.second.GetPathListOp();
#if TINYUSDZ_LOCAL_DEBUG_PRINT
paths.Print();
#endif
// Currently we only support single explicit path.
if ((paths.GetExplicitItems().size() == 1)) {
const Path &path = paths.GetExplicitItems()[0];
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "full path: " << path.full_path_name() << "\n";
std::cout << "local path: " << path.local_path_name() << "\n";
#endif
attr->path = path;
attr->basic_type = "path";
has_connection = true;
} else {
return false;
}
} else if ((fv.first == "variablity") &&
(fv.second.GetTypeName() == "Variability")) {
variability = fv.second.GetVariability();
} else if ((fv.first == "interpolation") &&
(fv.second.GetTypeName() == "Token")) {
if (fv.second.GetToken() == "faceVarying") {
facevarying = true;
}
}
}
attr->facevarying = facevarying;
attr->variability = variability;
//
// Decode value(stored in "default" field)
//
for (const auto &fv : fvs) {
if (fv.first == "default") {
attr->name = prop_name;
attr->basic_type = std::string();
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "fv.second.GetTypeName = " << fv.second.GetTypeName()
<< "\n";
#endif
if (fv.second.GetTypeName() == "Float") {
attr->floatVal = fv.second.GetFloat();
attr->basic_type = "float";
success = true;
} else if (fv.second.GetTypeName() == "Bool") {
if (!fv.second.GetBool(&attr->boolVal)) {
_err += "Failed to decode Int data";
return false;
}
attr->basic_type = "bool";
success = true;
} else if (fv.second.GetTypeName() == "Int") {
if (!fv.second.GetInt(&attr->intVal)) {
_err += "Failed to decode Int data";
return false;
}
attr->basic_type = "int";
success = true;
} else if (fv.second.GetTypeName() == "Vec3f") {
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_FLOAT, 3,
/* stride */ sizeof(float), fv.second.GetData());
// attr->variability = variability;
// attr->facevarying = facevarying;
success = true;
} else if (fv.second.GetTypeName() == "FloatArray") {
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_FLOAT, 1,
/* stride */ sizeof(float), fv.second.GetData());
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
} else if (fv.second.GetTypeName() == "Vec2fArray") {
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_FLOAT, 2,
/* stride */ sizeof(float) * 2, fv.second.GetData());
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
} else if (fv.second.GetTypeName() == "Vec3fArray") {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "fv.second.data.size = " << fv.second.GetData().size()
<< "\n";
#endif
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_FLOAT, 3,
/* stride */ sizeof(float) * 3, fv.second.GetData());
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
} else if (fv.second.GetTypeName() == "Vec4fArray") {
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_FLOAT, 4,
/* stride */ sizeof(float) * 4, fv.second.GetData());
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
} else if (fv.second.GetTypeName() == "IntArray") {
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_INT, 1,
/* stride */ sizeof(int32_t), fv.second.GetData());
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "IntArray"
<< "\n";
const int32_t *ptr =
reinterpret_cast<const int32_t *>(attr->buffer.data.data());
for (size_t i = 0; i < attr->buffer.GetNumElements(); i++) {
std::cout << "[" << i << "] = " << ptr[i] << "\n";
}
#endif
} else if (fv.second.GetTypeName() == "Token") {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "bbb: token: " << fv.second.GetToken() << "\n";
#endif
attr->stringVal = fv.second.GetToken();
attr->basic_type = "string";
// attr->variability = variability;
// attr->facevarying = facevarying;
success = true;
}
}
}
if (!success && has_connection) {
// Attribute has a connection(has a path and no `default` field)
success = true;
}
return success;
}
bool Parser::_ReconstructGeomMesh(
const Node &node, const FieldValuePairVector &fields,
const std::unordered_map<uint32_t, uint32_t> &path_index_to_spec_index_map,
GeomMesh *mesh) {
(void)mesh;
bool has_position{false};
#if 0
// TODO(syoyo): Move to Parser's method.
auto ParseGeomMeshAttribute = [](const FieldValuePairVector &fvs,
PrimAttrib *attr,
const std::string &prop_name) -> bool {
@@ -3225,21 +3414,19 @@ bool Parser::_ReconstructGeomMesh(
std::cout << "fvs.size = " << fvs.size() << "\n";
#endif
std::string type_name;
Variability variability{VariabilityVarying};
bool facevarying{false};
for (const auto &fv : fvs) {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << " fvs.first " << fv.first << "\n";
std::cout << " fvs.first " << fv.first << ", second: " << fv.second.GetTypeName() << "\n";
#endif
if ((fv.first == "typeName") && (fv.second.GetTypeName() == "Token")) {
type_name = fv.second.GetToken();
attr->type_name = fv.second.GetToken();
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "aaa: typeName: " << type_name << "\n";
std::cout << "aaa: typeName: " << attr->type_name << "\n";
#endif
(void)attr;
} else if ((fv.first == "variablity") &&
(fv.second.GetTypeName() == "Variability")) {
variability = fv.second.GetVariability();
@@ -3306,7 +3493,7 @@ bool Parser::_ReconstructGeomMesh(
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "bbb: token: " << fv.second.GetToken() << "\n";
#endif
attr->tokenString = fv.second.GetToken();
attr->stringVal = fv.second.GetToken();
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
@@ -3316,6 +3503,9 @@ bool Parser::_ReconstructGeomMesh(
return success;
};
#endif
bool has_position{false};
for (const auto &fv : fields) {
if (fv.first == "properties") {
@@ -3332,10 +3522,12 @@ bool Parser::_ReconstructGeomMesh(
}
}
// Disable has_position check for a while, since Mesh may not have "points", but "position"
//if (!has_position) {
// _err += "No `position` field exist for Mesh node: " + node.GetLocalPath() +
// Disable has_position check for a while, since Mesh may not have "points",
// but "position"
// if (!has_position) {
// _err += "No `position` field exist for Mesh node: " + node.GetLocalPath()
// +
// ".\n";
// return false;
//}
@@ -3390,7 +3582,7 @@ bool Parser::_ReconstructGeomMesh(
std::string prop_name = path.GetPropPart();
PrimAttrib attr;
bool ret = ParseGeomMeshAttribute(child_fields, &attr, prop_name);
bool ret = _ParseAttribute(child_fields, &attr, prop_name);
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "prop: " << prop_name << ", ret = " << ret << "\n";
#endif
@@ -3405,20 +3597,43 @@ bool Parser::_ReconstructGeomMesh(
(attr.buffer.GetNumCoords() == 3)) {
mesh->points = std::move(attr);
}
} else if (prop_name == "doubleSided") {
if (attr.basic_type == "bool") {
mesh->doubleSided = attr.boolVal;
}
} else if (prop_name == "extent") {
// vec3f[2]
if ((attr.buffer.GetDataType() ==
BufferData::BUFFER_DATA_TYPE_FLOAT) &&
(attr.buffer.GetNumElements() == 2) &&
(attr.buffer.GetNumCoords() == 3)) {
std::vector<float> buf = attr.buffer.GetAsVec3fArray();
mesh->extent.lower[0] = buf[0];
mesh->extent.lower[1] = buf[1];
mesh->extent.lower[2] = buf[2];
mesh->extent.upper[0] = buf[3];
mesh->extent.upper[1] = buf[4];
mesh->extent.upper[2] = buf[5];
}
} else if (prop_name == "normals") {
if ((attr.buffer.GetDataType() ==
BufferData::BUFFER_DATA_TYPE_FLOAT) &&
(attr.buffer.GetNumCoords() == 3)) {
mesh->normals = std::move(attr);
}
} else if (prop_name == "primvars:UVMap") {
// TODO(syoyo): Write PrimVar parser
} else if ((prop_name == "primvars:UVMap") &&
(attr.type_name == "texCoord2f[]")) {
// Explicit UV coord attribute.
// TODO(syoyo): Write PrimVar parser
// Currently we only support vec2f for uv coords.
if ((attr.buffer.GetDataType() == BufferData::BUFFER_DATA_TYPE_FLOAT) &&
if ((attr.buffer.GetDataType() ==
BufferData::BUFFER_DATA_TYPE_FLOAT) &&
(attr.buffer.GetNumCoords() == 2)) {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "got UVCoords\n";
std::cout << "got explicit UVCoords!\n";
#endif
mesh->st.buffer = attr.buffer;
mesh->st.variability = attr.variability;
@@ -3480,22 +3695,376 @@ bool Parser::_ReconstructGeomMesh(
}
} else if (prop_name == "subdivisionScheme") {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "subdivisionScheme:" << attr.tokenString << "\n";
std::cout << "subdivisionScheme:" << attr.stringVal << "\n";
#endif
if (attr.tokenString.size()) {
if ((attr.tokenString.compare("none") == 0)) {
if (attr.stringVal.size()) {
if ((attr.stringVal.compare("none") == 0)) {
mesh->subdivisionScheme = SubdivisionSchemeNone;
} else if (attr.tokenString.compare("catmullClark") == 0) {
} else if (attr.stringVal.compare("catmullClark") == 0) {
mesh->subdivisionScheme = SubdivisionSchemeCatmullClark;
} else if (attr.tokenString.compare("bilinear") == 0) {
} else if (attr.stringVal.compare("bilinear") == 0) {
mesh->subdivisionScheme = SubdivisionSchemeBilinear;
} else if (attr.tokenString.compare("loop") == 0) {
} else if (attr.stringVal.compare("loop") == 0) {
mesh->subdivisionScheme = SubdivisionSchemeLoop;
} else {
_err += "Unknown subdivision scheme: " + attr.tokenString + "\n";
_err += "Unknown subdivision scheme: " + attr.stringVal + "\n";
return false;
}
}
} else {
// Assume Primvar.
if (mesh->attrs.count(prop_name)) {
_err += "Duplicated property name found: " + prop_name + "\n";
return false;
}
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "add [" << prop_name << "] to generic attrs\n";
#endif
mesh->attrs[prop_name] = std::move(attr);
}
}
}
}
return true;
}
bool Parser::_ReconstructMaterial(
const Node &node, const FieldValuePairVector &fields,
const std::unordered_map<uint32_t, uint32_t> &path_index_to_spec_index_map,
Material *material) {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "Parse mateiral\n";
#endif
for (const auto &fv : fields) {
if (fv.first == "properties") {
if (fv.second.GetTypeName() != "TokenArray") {
_err += "`properties` attribute must be TokenArray type\n";
return false;
}
assert(fv.second.IsArray());
for (size_t i = 0; i < fv.second.GetStringArray().size(); i++) {
}
}
}
//
// NOTE: Currently we assume one deeper node has Material's attribute
//
for (size_t i = 0; i < node.GetChildren().size(); i++) {
int child_index = int(node.GetChildren()[i]);
if ((child_index < 0) || (child_index >= int(_nodes.size()))) {
_err += "Invalid child node id: " + std::to_string(child_index) +
". Must be in range [0, " + std::to_string(_nodes.size()) + ")\n";
return false;
}
// const Node &child_node = _nodes[size_t(child_index)];
if (!path_index_to_spec_index_map.count(uint32_t(child_index))) {
// No specifier assigned to this child node.
_err += "No specifier found for node id: " + std::to_string(child_index) +
"\n";
return false;
}
uint32_t spec_index =
path_index_to_spec_index_map.at(uint32_t(child_index));
if (spec_index >= _specs.size()) {
_err += "Invalid specifier id: " + std::to_string(spec_index) +
". Must be in range [0, " + std::to_string(_specs.size()) + ")\n";
return false;
}
const Spec &spec = _specs[spec_index];
Path path = GetPath(spec.path_index);
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "Path prim part: " << path.GetPrimPart()
<< ", prop part: " << path.GetPropPart()
<< ", spec_index = " << spec_index << "\n";
#endif
if (!_live_fieldsets.count(spec.fieldset_index)) {
_err += "FieldSet id: " + std::to_string(spec.fieldset_index.value) +
" must exist in live fieldsets.\n";
return false;
}
const FieldValuePairVector &child_fields =
_live_fieldsets.at(spec.fieldset_index);
{
std::string prop_name = path.GetPropPart();
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "prop: " << prop_name << "\n";
#endif
}
}
return true;
}
bool Parser::_ReconstructShader(
const Node &node, const FieldValuePairVector &fields,
const std::unordered_map<uint32_t, uint32_t> &path_index_to_spec_index_map,
PreviewSurface *shader) {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "Parse shader\n";
#endif
for (const auto &fv : fields) {
if (fv.first == "properties") {
if (fv.second.GetTypeName() != "TokenArray") {
_err += "`properties` attribute must be TokenArray type\n";
return false;
}
assert(fv.second.IsArray());
for (size_t i = 0; i < fv.second.GetStringArray().size(); i++) {
}
}
}
#if 0
auto ParseAttribute = [](const FieldValuePairVector &fvs, PrimAttrib *attr,
const std::string &prop_name) -> bool {
bool success = false;
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "fvs.size = " << fvs.size() << "\n";
#endif
std::string type_name;
Variability variability{VariabilityVarying};
bool facevarying{false};
for (const auto &fv : fvs) {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << " fvs.first " << fv.first
<< ", second: " << fv.second.GetTypeName() << "\n";
#endif
if ((fv.first == "typeName") && (fv.second.GetTypeName() == "Token")) {
type_name = fv.second.GetToken();
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "aaa: typeName: " << type_name << "\n";
#endif
(void)attr;
} else if (fv.first == "connectionPaths") {
// e.g. connection to texture file.
const ListOp<Path> paths = fv.second.GetPathListOp();
#if TINYUSDZ_LOCAL_DEBUG_PRINT
paths.Print();
#endif
// Currently we only support single explicit path.
if ((paths.GetExplicitItems().size() == 1)) {
const Path &path = paths.GetExplicitItems()[0];
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "full path: " << path.full_path_name() << "\n";
std::cout << "local path: " << path.local_path_name() << "\n";
#endif
} else {
return false;
}
} else if ((fv.first == "variablity") &&
(fv.second.GetTypeName() == "Variability")) {
variability = fv.second.GetVariability();
} else if ((fv.first == "interpolation") &&
(fv.second.GetTypeName() == "Token")) {
if (fv.second.GetToken() == "faceVarying") {
facevarying = true;
}
}
}
// Decode value(stored in "default" field)
for (const auto &fv : fvs) {
if (fv.first == "default") {
attr->name = prop_name;
attr->basic_type = std::string();
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "fv.second.GetTypeName = " << fv.second.GetTypeName()
<< "\n";
#endif
if (fv.second.GetTypeName() == "Float") {
attr->floatVal = fv.second.GetFloat();
attr->basic_type = "float";
success = true;
} else if (fv.second.GetTypeName() == "Int") {
if (!fv.second.GetInt(&attr->intVal)) {
success = false;
break;
}
attr->basic_type = "int";
success = true;
} else if (fv.second.GetTypeName() == "Vec3f") {
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_FLOAT, 3,
/* stride */ sizeof(float), fv.second.GetData());
// attr->variability = variability;
// attr->facevarying = facevarying;
success = true;
} else if (fv.second.GetTypeName() == "FloatArray") {
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_FLOAT, 1,
/* stride */ sizeof(float), fv.second.GetData());
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
} else if (fv.second.GetTypeName() == "Vec2fArray") {
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_FLOAT, 2,
/* stride */ sizeof(float) * 2, fv.second.GetData());
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
} else if (fv.second.GetTypeName() == "Vec3fArray") {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "fv.second.data.size = " << fv.second.GetData().size()
<< "\n";
#endif
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_FLOAT, 3,
/* stride */ sizeof(float) * 3, fv.second.GetData());
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
} else if (fv.second.GetTypeName() == "Vec4fArray") {
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_FLOAT, 4,
/* stride */ sizeof(float) * 4, fv.second.GetData());
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
} else if (fv.second.GetTypeName() == "IntArray") {
attr->buffer.Set(BufferData::BUFFER_DATA_TYPE_INT, 1,
/* stride */ sizeof(int32_t), fv.second.GetData());
attr->variability = variability;
attr->facevarying = facevarying;
success = true;
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "IntArray"
<< "\n";
const int32_t *ptr =
reinterpret_cast<const int32_t *>(attr->buffer.data.data());
for (size_t i = 0; i < attr->buffer.GetNumElements(); i++) {
std::cout << "[" << i << "] = " << ptr[i] << "\n";
}
#endif
} else if (fv.second.GetTypeName() == "Token") {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "bbb: token: " << fv.second.GetToken() << "\n";
#endif
attr->stringVal = fv.second.GetToken();
attr->basic_type = "string";
// attr->variability = variability;
// attr->facevarying = facevarying;
success = true;
}
}
}
return success;
};
#endif
//
// NOTE: Currently we assume one deeper node has Material's attribute
//
for (size_t i = 0; i < node.GetChildren().size(); i++) {
int child_index = int(node.GetChildren()[i]);
if ((child_index < 0) || (child_index >= int(_nodes.size()))) {
_err += "Invalid child node id: " + std::to_string(child_index) +
". Must be in range [0, " + std::to_string(_nodes.size()) + ")\n";
return false;
}
// const Node &child_node = _nodes[size_t(child_index)];
if (!path_index_to_spec_index_map.count(uint32_t(child_index))) {
// No specifier assigned to this child node.
_err += "No specifier found for node id: " + std::to_string(child_index) +
"\n";
return false;
}
uint32_t spec_index =
path_index_to_spec_index_map.at(uint32_t(child_index));
if (spec_index >= _specs.size()) {
_err += "Invalid specifier id: " + std::to_string(spec_index) +
". Must be in range [0, " + std::to_string(_specs.size()) + ")\n";
return false;
}
const Spec &spec = _specs[spec_index];
Path path = GetPath(spec.path_index);
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "Path prim part: " << path.GetPrimPart()
<< ", prop part: " << path.GetPropPart()
<< ", spec_index = " << spec_index << "\n";
#endif
if (!_live_fieldsets.count(spec.fieldset_index)) {
_err += "FieldSet id: " + std::to_string(spec.fieldset_index.value) +
" must exist in live fieldsets.\n";
return false;
}
const FieldValuePairVector &child_fields =
_live_fieldsets.at(spec.fieldset_index);
{
std::string prop_name = path.GetPropPart();
PrimAttrib attr;
bool ret = _ParseAttribute(child_fields, &attr, prop_name);
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "prop: " << prop_name << ", ret = " << ret << "\n";
#endif
if (ret) {
// Currently we only support predefined PBR attributes.
if (prop_name.compare("outputs:surface") == 0) {
// Surface shader output available
} else if (prop_name.compare("outputs:displacement") == 0) {
// Displacement shader output available
} else if (prop_name.compare("inputs:metallic") == 0) {
// type: float
if ((attr.buffer.GetDataType() ==
BufferData::BUFFER_DATA_TYPE_FLOAT) &&
(attr.buffer.GetNumElements() == 1) &&
(attr.buffer.GetNumCoords() == 1)) {
shader->metallic.value = attr.buffer.GetAsFloat();
}
} else if (prop_name.compare("inputs:diffuseColor") == 0) {
if ((attr.buffer.GetDataType() ==
BufferData::BUFFER_DATA_TYPE_FLOAT) &&
(attr.buffer.GetNumElements() == 1) &&
(attr.buffer.GetNumCoords() == 3)) {
shader->diffuseColor.color = attr.buffer.GetAsColor3f();
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "diffuseColor: " << shader->diffuseColor.color[0]
<< ", " << shader->diffuseColor.color[1] << ", "
<< shader->diffuseColor.color[2] << "\n";
#endif
}
} else if (prop_name.compare("inputs:diffuseColor.connect") == 0) {
// Currently we assume texture is assigned to this attribute.
shader->diffuseColor.path = attr.stringVal;
}
}
}
@@ -3672,6 +4241,27 @@ bool Parser::_ReconstructSceneRecursively(
return false;
}
scene->geom_meshes.push_back(mesh);
} else if (node_type == "Material") {
Material material;
if (!_ReconstructMaterial(node, fields, path_index_to_spec_index_map,
&material)) {
_err += "Failed to reconstruct Material.\n";
return false;
}
scene->materials.push_back(material);
} else if (node_type == "Shader") {
PreviewSurface shader;
if (!_ReconstructShader(node, fields, path_index_to_spec_index_map,
&shader)) {
_err += "Failed to reconstruct PreviewSurface(Shader).\n";
return false;
}
scene->shaders.push_back(shader);
} else {
#if TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "TODO or we can ignore this node: node_type: " << node_type
<< "\n";
#endif
}
for (size_t i = 0; i < node.GetChildren().size(); i++) {
@@ -4542,7 +5132,6 @@ bool GeomMesh::GetFacevaryingNormals(std::vector<float> *v) const {
std::cout << "fvnormal numelements = " << n << ", numcoords = " << c << "\n";
#endif
memcpy(v->data(), normals.buffer.data.data(), n * c * sizeof(float));
return true;
@@ -4558,8 +5147,7 @@ bool GeomMesh::GetFacevaryingTexcoords(std::vector<float> *v) const {
return false;
}
if ((st.buffer.GetNumCoords() < 0) ||
(st.buffer.GetNumCoords() != 2)) {
if ((st.buffer.GetNumCoords() < 0) || (st.buffer.GetNumCoords() != 2)) {
return false;
}
@@ -4573,10 +5161,10 @@ bool GeomMesh::GetFacevaryingTexcoords(std::vector<float> *v) const {
v->resize(n * c);
#ifdef TINYUSDZ_LOCAL_DEBUG_PRINT
std::cout << "fvtexcoords numelements = " << n << ", numcoords = " << c << "\n";
std::cout << "fvtexcoords numelements = " << n << ", numcoords = " << c
<< "\n";
#endif
memcpy(v->data(), st.buffer.data.data(), n * c * sizeof(float));
return true;

View File

@@ -35,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <map>
#include <limits>
//#define TINYUSDZ_LOCAL_DEBUG_PRINT (1)
#define TINYUSDZ_LOCAL_DEBUG_PRINT (1)
#if TINYUSDZ_LOCAL_DEBUG_PRINT
#include <iostream> // dbg
@@ -259,6 +259,17 @@ class ListOp
ordered_items = v;
}
#if TINYUSDZ_LOCAL_DEBUG_PRINT
void Print() const {
std::cout << "is_explicit:" << is_explicit << "\n";
std::cout << "# of explicit_items" << explicit_items.size() << "\n";
std::cout << "# of added_items" << added_items.size() << "\n";
std::cout << "# of prepended_items" << prepended_items.size() << "\n";
std::cout << "# of deleted_items" << deleted_items.size() << "\n";
std::cout << "# of ordered_items" << ordered_items.size() << "\n";
}
#endif
private:
bool is_explicit{false};
@@ -386,7 +397,7 @@ class Path {
void SetLocalPath(const Path &rhs) {
//assert(rhs.valid == true);
this->local_part = rhs.local_part;
this->valid = rhs.valid;
}
@@ -1022,6 +1033,10 @@ class Value {
path_list_op = d;
}
const ListOp<Path> &GetPathListOp() const {
return path_list_op;
}
// Getter for frequently used types.
Specifier GetSpecifier() const {
if (dtype.id == VALUE_TYPE_SPECIFIER) {
@@ -1039,6 +1054,20 @@ class Value {
return NumVariabilities; // invalid
}
bool GetBool(bool *ret) const {
if (ret == nullptr) {
return false;
}
if (dtype.id == VALUE_TYPE_BOOL) {
uint8_t d = *reinterpret_cast<const uint8_t *>(data.data());
(*ret) = bool(d);
return true;
}
return false;
}
double GetDouble() const {
if (dtype.id == VALUE_TYPE_DOUBLE) {
double d = *reinterpret_cast<const double *>(data.data());
@@ -1046,7 +1075,29 @@ class Value {
} else if (dtype.id == VALUE_TYPE_FLOAT) {
float d = *reinterpret_cast<const float *>(data.data());
return static_cast<double>(d);
}
}
return std::numeric_limits<double>::quiet_NaN(); // invalid
}
bool GetInt(int *ret) const {
if (ret == nullptr) {
return false;
}
if (dtype.id == VALUE_TYPE_INT) {
float d = *reinterpret_cast<const int *>(data.data());
(*ret) = d;
return true;
}
return false;
}
float GetFloat() const {
if (dtype.id == VALUE_TYPE_FLOAT) {
float d = *reinterpret_cast<const float *>(data.data());
return d;
}
return std::numeric_limits<double>::quiet_NaN(); // invalid
}
@@ -1160,7 +1211,7 @@ struct BufferData
if (data_type == BUFFER_DATA_TYPE_INVALID) {
return false;
}
return (data.size() > 0) && (num_coords > 0);
}
@@ -1191,7 +1242,7 @@ struct BufferData
return GetDataTypeByteSize(data_type) * size_t(num_coords);
}
size_t GetNumElements() const {
size_t GetNumElements() const {
if (num_coords <= 0) {
// TODO(syoyo): Report error
return 0;
@@ -1218,8 +1269,33 @@ struct BufferData
return stride;
}
//
// Utility functions
//
float GetAsFloat() const {
if (((GetStride() == 0) || (GetStride() == sizeof(float))) &&
(GetNumCoords() == 1) &&
(GetDataType() == BUFFER_DATA_TYPE_FLOAT) &&
(GetNumElements() == 1)) {
return *(reinterpret_cast<const float *>(data.data()));
}
}
std::array<float, 3> GetAsColor3f() const {
std::array<float, 3> buf;
if (((GetStride() == 0) || (GetStride() == 3 * sizeof(float))) &&
(GetNumCoords() == 3) &&
(GetDataType() == BUFFER_DATA_TYPE_FLOAT)) {
memcpy(buf.data(), data.data(), buf.size() * sizeof(float));
}
return buf;
}
// Return empty array when required type mismatches.
//
std::vector<uint32_t> GetAsUInt32Array() const {
@@ -1301,19 +1377,49 @@ struct BufferData
return buf;
}
};
// We treat PrimVar as PrimAttrib(attributes) at the moment.
struct PrimAttrib
{
std::string name;
BufferData buffer;
std::string name; // attrib name
std::string type_name; // name of attrib type(e.g. "float', "color3f")
// For array data types(e.g. FloatArray)
BufferData buffer; // raw buffer data
Variability variability;
bool facevarying{false};
// For TokenString
std::string tokenString;
// For basic types(e.g. Bool, Float).
// "bool", "string", "float", "int", "uint", "int64", "uint64", "double" or "path"
// empty = array data type
std::string basic_type;
// TODO: Use union struct
bool boolVal;
int intVal;
uint32_t uintVal;
int64_t int64Val;
uint64_t uint64Val;
float floatVal;
double doubleVal;
std::string stringVal; // token, string
Path path;
};
// UsdPrimvarReader.
// Currently for UV texture coordinate
struct PrimvarReader
{
std::string output_type = "float2"; // currently "float2" only.
int32_t input_id{-1}; // inputs:varname. Index to PrimVar in Primitive
};
// Predefined node class
@@ -1333,15 +1439,6 @@ struct Xform
};
// Vertex attributes. e.g. UV coords, vertex colors, etc.
struct PrimVar
{
std::string name;
BufferData buffer;
Variability variability;
bool facevarying{false};
};
struct UVCoords
{
std::string name;
@@ -1354,17 +1451,17 @@ struct UVCoords
struct Extent
{
std::array<float, 3> lower = {{
Vec3f lower{
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity()
}};
};
std::array<float, 3> upper = {{
Vec3f upper{
-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity()
}};
};
};
@@ -1395,14 +1492,14 @@ struct GeomMesh
bool GetPoints(std::vector<float> *v) const;
// Get `normals` as float3 array + facevarying
// Return false if `normals` is neither float3[] type nor `varying`
// Return false if `normals` is neither float3[] type nor `varying`
bool GetFacevaryingNormals(std::vector<float> *v) const;
// Get `texcoords` as float2 array + facevarying
// Return false if `texcoords` is neither float2[] type nor `varying`
// Return false if `texcoords` is neither float2[] type nor `varying`
bool GetFacevaryingTexcoords(std::vector<float> *v) const;
// PrimVar
// PrimVar(TODO: Remove)
UVCoords st;
PrimAttrib velocitiess; // Usually float3[], varying
@@ -1420,7 +1517,6 @@ struct GeomMesh
Visibility visibility{VisibilityInherited};
Purpose purpose{PurposeDefault};
//
// SubD attribs.
//
@@ -1434,11 +1530,8 @@ struct GeomMesh
SubdivisionScheme subdivisionScheme;
// User defined attribs
std::map<std::string, PrimAttrib> custom_attrs;
// List of Primitive variables.
std::map<std::string, PrimVar> primvars;
// List of Primitive attributes(primvars)
std::map<std::string, PrimAttrib> attrs;
};
@@ -1467,6 +1560,8 @@ struct Color3OrTexture
}
std::array<float, 3> color{{0.0f, 0.0f, 0.0f}};
std::string path; // path to .connect(We only support texture file connection at the moment)
int64_t texture_id{-1};
bool HasTexture() const {
@@ -1482,6 +1577,8 @@ struct FloatOrTexture
}
float value{0.0f};
std::string path; // path to .connect(We only support texture file connection at the moment)
int64_t texture_id{-1};
bool HasTexture() const {
@@ -1510,6 +1607,7 @@ struct UsdTranform2d {
// UsdUvTexture
struct UVTexture {
std::string asset; // asset name(usually file path)
int64_t image_id{-1}; // TODO(syoyo): Consider UDIM `@textures/occlusion.<UDIM>.tex@`
std::array<float, 2> st; // texture coordinate orientation. https://graphics.pixar.com/usd/docs/UsdPreviewSurface-Proposal.html#UsdPreviewSurfaceProposal-TextureCoordinateOrientationinUSD
@@ -1521,6 +1619,13 @@ struct UVTexture {
std::array<float, 4> bias{{0.0f, 0.0f, 0.0f, 0.0f}}; // bias to be applied to output texture value
UsdTranform2d texture_transfom;
// key = connection name: e.g. "outputs:rgb"
// item = pair<type, name> : example: <"float3", "outputs:rgb">
std::map<std::string, std::pair<std::string, std::string>> outputs;
// UsdPrimvarReader_float2.
PrimvarReader texcoord_reader;
};
@@ -1612,7 +1717,7 @@ struct Scene
std::vector<Node> nodes; // Node hierarchies
// Scene global setting
std::string upAxis = "Y";
std::string upAxis = "Y";
std::string defaultPrim; // prim node name
double metersPerUnit = 1.0; // default [m]
double timeCodesPerSecond = 24.0; // default 24 fps
@@ -1628,7 +1733,7 @@ struct Scene
std::vector<Group> groups;
// TODO(syoyo): User defined custom layer data
// "customLayerData"
// "customLayerData"
};
@@ -1644,13 +1749,22 @@ struct USDLoadOptions
// This feature would be helpful if you want to load USDZ model in mobile device.
int32_t max_memory_limit_in_mb{10000}; // in [mb] Default 10GB
///
/// Loads asset data(e.g. texture image, audio). Default is true.
/// If you want to load asset data in your own way or don't need asset data to be loaded,
/// Set this false.
///
bool load_assets{true};
};
#if 0 // TODO
//struct USDWriteOptions
//{
//
//
//};
#endif
///
/// Load USDZ(zip) from a file.