今天在写到osgb数据解析,用到的tinygltf是高版本的,模型类Model带有扩展属性。其中扩展数据需要相应的键值解析json,这里使用的是tinygltf2.2,该版本需要std_img_write.h v1.11的支持,目前我使用的是这个版本。这事起于,自己想解决3dtile中不需要修改前端代码,而是修改3dtile的数据格式,这样的一个想法。那么这里着重是要解决扩展数据json的拼接。而这里使用到了tinygltf的相关函数。
这里要是说明的是使用json键值解析时候原来的函数有点问题,其中源函数是这样定义的。
static bool ValueToJson(const Value &value, json *ret) {
json obj;
switch (value.Type()) {
case NUMBER_TYPE:
obj = json(value.Get());
break;
case INT_TYPE:
obj = json(value.Get());
break;
case BOOL_TYPE:
obj = json(value.Get());
break;
case STRING_TYPE:
obj = json(value.Get());
break;
case ARRAY_TYPE: {
for (unsigned int i = 0; i < value.ArrayLen(); ++i) {
Value elementValue = value.Get(int(i));
json elementJson;
if (ValueToJson(value.Get(int(i)), &elementJson))
obj.push_back(elementJson);
}
break;
}
case BINARY_TYPE:
// TODO
// obj = json(value.Get>());
return false;
break;
case OBJECT_TYPE: {
Value::Object objMap = value.Get();
for (auto &it : objMap) {
json elementJson;
if (ValueToJson(it.second, &elementJson)) obj[it.first] = elementJson;
}
break;
}
case NULL_TYPE:
default:
return false;
}
if (ret) *ret = obj;
return true;
}
但是在ValueToJson递归中出现了很大的问题,首先我们来说明一下类型为string值的键值,形如下面的形式。
tinygltf::ExtensionMap exu_modelViewMatrix;
exu_modelViewMatrix["semantic"] = tinygltf::Value("MODELVIEW");
在json应该解析为"semantic":"MODELVIES",可是事实在上面的函数中返回的是这样的结果:"semantic":true,这下惊呆了小伙伴。而如果我们使用如下的方式来赋值。干脆就不返回了"semantic"的值了。
string str = "_BATCHID";
exA_batchid["semantic"]= tinygltf::Value(str);
可能我们会去查看,tinygltf::Value是如何定义的,是的,我们来看一下该类的结构。
class Value {
public:
typedef std::vector Array;
typedef std::map Object;
Value() : type_(NULL_TYPE) {}
explicit Value(bool b) : type_(BOOL_TYPE) {
boolean_value_ = b; }
explicit Value(int i) : type_(INT_TYPE) {
int_value_ = i; }
explicit Value(double n) : type_(NUMBER_TYPE) {
number_value_ = n; }
explicit Value(const std::string &s) : type_(STRING_TYPE) {
string_value_ = s;
}
explicit Value(const unsigned char *p, size_t n) : type_(BINARY_TYPE) {
binary_value_.resize(n);
memcpy(binary_value_.data(), p, n);
}
explicit Value(const Array &a) : type_(ARRAY_TYPE) {
array_value_ = Array(a);
}
explicit Value(const Object &o) : type_(OBJECT_TYPE) {
object_value_ = Object(o);
}
char Type() const { return static_cast(type_); }
bool IsBool() const { return (type_ == BOOL_TYPE); }
bool IsInt() const { return (type_ == INT_TYPE); }
bool IsNumber() const { return (type_ == NUMBER_TYPE); }
bool IsString() const { return (type_ == STRING_TYPE); }
bool IsBinary() const { return (type_ == BINARY_TYPE); }
bool IsArray() const { return (type_ == ARRAY_TYPE); }
bool IsObject() const { return (type_ == OBJECT_TYPE); }
// Accessor
template
const T &Get() const;
template
T &Get();
// Lookup value from an array
const Value &Get(int idx) const {
static Value null_value;
assert(IsArray());
assert(idx >= 0);
return (static_cast(idx) < array_value_.size())
? array_value_[static_cast(idx)]
: null_value;
}
// Lookup value from a key-value pair
const Value &Get(const std::string &key) const {
static Value null_value;
assert(IsObject());
Object::const_iterator it = object_value_.find(key);
return (it != object_value_.end()) ? it->second : null_value;
}
size_t ArrayLen() const {
if (!IsArray()) return 0;
return array_value_.size();
}
// Valid only for object type.
bool Has(const std::string &key) const {
if (!IsObject()) return false;
Object::const_iterator it = object_value_.find(key);
return (it != object_value_.end()) ? true : false;
}
// List keys
std::vector Keys() const {
std::vector keys;
if (!IsObject()) return keys; // empty
for (Object::const_iterator it = object_value_.begin();
it != object_value_.end(); ++it) {
keys.push_back(it->first);
}
return keys;
}
size_t Size() const { return (IsArray() ? ArrayLen() : Keys().size()); }
bool operator==(const tinygltf::Value &other) const;
protected:
int type_;
int int_value_;
double number_value_;
std::string string_value_;
std::vector binary_value_;
Array array_value_;
Object object_value_;
bool boolean_value_;
};
Value类提供了几个构造函数,另外就是类型的判断,以及一个模板函数返回值,大家在使用的时候特别要注意对于类似"ok":[1,2,3]这样键值的json,使用的是形如下面这种方式来构造。
std::vector exEnble{ tinygltf::Value(2884) ,tinygltf::Value(2929)};
exEnbles["enable"] = tinygltf::Value(exEnble);
好了,回到上面的问题。解析出来的并不是预期的。这是什么原因呢。在源码中可以做相应的修改,我在这里修改了序列化函数,具体修改成下面的方式。
static bool ValueToJson(const Value &value, json *ret) {
json obj;
value.Type();
std::string t;
switch (value.Type()) {
case NUMBER_TYPE:
obj = json(value.Get());
break;
case INT_TYPE:
obj = json(value.Get());
break;
case BOOL_TYPE:
obj = json(value.Get());
break;
case STRING_TYPE:
obj = json(value.Get());
t= obj.dump();
return true;
case ARRAY_TYPE: {
for (unsigned int i = 0; i < value.ArrayLen(); ++i) {
Value elementValue = value.Get(int(i));
elementValue.getString();
json elementJson;
if (ValueToJson(value.Get(int(i)), &elementJson))
switch (elementValue.Type())
{
case NUMBER_TYPE:
obj.push_back(elementValue.getINT());
break;
case INT_TYPE:
obj.push_back(elementValue.getINT());
break;
case STRING_TYPE:
obj.push_back(elementValue.getString());
break;
default:
obj.push_back(elementJson);
break;
}
}
break;
}
case BINARY_TYPE:
// TODO
// obj = json(value.Get>());
return false;
break;
case OBJECT_TYPE: {
Value::Object objMap = value.Get();
for (auto &it : objMap) {
json elementJson;
if (it.first=="semantic")
{
int ex = 0;
}
if (ValueToJson(it.second, &elementJson)) {
switch (it.second.Type())
{
case NUMBER_TYPE:
obj[it.first] = it.second.getNumber();
break;
case INT_TYPE:
obj[it.first] = it.second.getINT();
break;
case STRING_TYPE:
obj[it.first] = it.second.getString();
break;
default:
obj[it.first] = elementJson;
break;
}
};
}
break;
}
case NULL_TYPE:
default:
return false;
}
if (ret) *ret = obj;
return true;
}
最后在visual studio中查看了json解析数据,应该是正确的,目前还没有完整的拼接为gltf数据。