Compare commits

..

23 Commits

Author SHA1 Message Date
Syoyo Fujita
f68d5e1f2a Merge pull request #182 from ux3d/textureinfo
[TextureInfo] fix default value checks for serialization
2019-07-26 01:29:23 +09:00
Benjamin Schmithüsen
1c84fc22a5 fix default value checks for serialization 2019-07-25 16:07:27 +02:00
Syoyo Fujita
150f243b1b Change the behavior of NUMBER value in Value class. NUMBER now reprents the value is either int or real(floating point). 2019-07-25 19:22:44 +09:00
Syoyo Fujita
0ee273fdfa Update README. Add note on tinygltf::Value for extensions. 2019-07-24 19:55:04 +09:00
Syoyo Fujita
046400b17f Now material is parsed as a struct with explicit parameter definitions.
Implement Material struct serialization.
2019-07-24 19:26:48 +09:00
Syoyo Fujita
89fd93f815 Introduce TextureInfo class(W.I.P.) 2019-07-23 22:37:06 +09:00
Syoyo Fujita
e940337796 Merge pull request #180 from ux3d/master
Explicitly use the correct constructor for empty object
2019-07-23 18:55:34 +09:00
Syoyo Fujita
1b5f476d95 Merge pull request #178 from rapidimages/feature/write-to-streams
Serialize to stream
2019-07-17 18:53:35 +09:00
Johan Bowald
52936a00e0 clang format 2019-07-17 09:06:45 +02:00
Benjamin Schmithüsen
f3ef880029 call json constructor explicitly 2019-07-16 17:07:45 +02:00
Johan Bowald
1af7c1d784 can write to streams 2019-07-16 15:56:18 +02:00
Benjamin Schmithüsen
c0b79afecc Merge pull request #2 from syoyo/master
update from original repository
2019-07-15 15:13:50 +02:00
Syoyo Fujita
c49461b7c2 Merge pull request #176 from ux3d/feature/update-lights
Feature: update lights
2019-07-10 21:20:12 +09:00
Benjamin Schmithüsen
051f4be2f1 serialize lights 2019-07-09 17:59:20 +02:00
Benjamin Schmithüsen
4557b6aa22 fix spot light parsingg 2019-07-09 16:55:55 +02:00
Benjamin Schmithüsen
b2d7d88dbc parse additional light properties and fix defaults 2019-07-09 16:32:42 +02:00
Benjamin Schmithüsen
b7ca7c9381 update lights to follow the KHR_lights_punctual extension 2019-07-08 18:04:24 +02:00
Benjamin Schmithüsen
0ffedcbe79 Merge pull request #1 from syoyo/master
update fork
2019-07-08 17:40:20 +02:00
Syoyo Fujita
80faac5238 Merge pull request #174 from Ybalrid/pr_material_param_tex_info
Add Parameter::TextureStrength(). Precise default values.
2019-07-05 14:11:15 +09:00
Arthur Brianville (Ybalrid)
2a9d9deb67 Applied clang-format 2019-07-05 00:30:47 +02:00
Arthur Brainville
8a98d98cd9 Add Paramter::TextureStrength(). Precise default values.
The default values on these methods as been set to what is described [here](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0?ts=4#normaltextureinfo) and [here](https://github.com/KhronosGroup/glTF/tree/master/specification/2.0?ts=4#occlusiontextureinfo).

This is to keep consistent with the API behavior from #144
2019-07-05 00:30:20 +02:00
Syoyo Fujita
689edcbef6 Merge pull request #173 from christophe-f8/master
Adding texture scale reading + asset copyright and texture names to the export
2019-07-04 15:39:22 +09:00
Christophe
820ede87db Adding texture scale reading (for normal maps) + asset copyright and texture names to the export 2019-07-04 15:21:21 +09:00
15 changed files with 1572 additions and 2803 deletions

View File

@@ -1,25 +0,0 @@
BSD 2-Clause License
Copyright (c) 2019, DeanoC
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -7,7 +7,7 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
## Status ## Status
- v2.3.0 release(Support loading KTX image through tiny_ktx) - v2.3.0 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class)
- v2.2.0 release(Support loading 16bit PNG. Sparse accessor support) - v2.2.0 release(Support loading 16bit PNG. Sparse accessor support)
- v2.1.0 release(Draco support) - v2.1.0 release(Draco support)
- v2.0.0 release(22 Aug, 2018)! - v2.0.0 release(22 Aug, 2018)!
@@ -53,8 +53,13 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
* [x] Image load * [x] Image load
* [x] Image save * [x] Image save
* Extensions * Extensions
* [x] Draco mesh decoding(`TINYGLTF_ENABLE_DRACO` required) * [x] Draco mesh decoding
* [x] KTX image support(no mipmap. `TINYGLTF_ENABLE_KTX` required)
## Note on extension property
In extension(`ExtensionMap`), JSON number value is parsed as int or float(number) and stored as `tinygltf::Value` object. If you want a floating point value from `tinygltf::Value`, use `GetNumberAsDouble()` method.
`IsNumber()` returns true if the underlying value is an int value or a floating point value.
## Examples ## Examples
@@ -78,12 +83,11 @@ If you are looking for old, C++03 version, please use `devel-picojson` branch.
* [x] Load Draco compressed mesh * [x] Load Draco compressed mesh
* [ ] Save Draco compressed mesh * [ ] Save Draco compressed mesh
* [ ] Open3DGC? * [ ] Open3DGC?
* [ ] Support `extensions` and `extras` property * [x] Support `extensions` and `extras` property
* [ ] HDR image? * [ ] HDR image?
* [ ] OpenEXR extension through TinyEXR. * [ ] OpenEXR extension through TinyEXR.
* [ ] 16bit PNG support in Serialization * [ ] 16bit PNG support in Serialization
* [ ] Write example and tests for `animation` and `skin` * [ ] Write example and tests for `animation` and `skin`
* [ ] mipmap support for KTX image.
## Licenses ## Licenses
@@ -95,15 +99,12 @@ TinyGLTF uses the following third party libraries.
* base64 : Copyright (C) 2004-2008 René Nyffenegger * base64 : Copyright (C) 2004-2008 René Nyffenegger
* stb_image.h : v2.08 - public domain image loader - [Github link](https://github.com/nothings/stb/blob/master/stb_image.h) * stb_image.h : v2.08 - public domain image loader - [Github link](https://github.com/nothings/stb/blob/master/stb_image.h)
* stb_image_write.h : v1.09 - public domain image writer - [Github link](https://github.com/nothings/stb/blob/master/stb_image_write.h) * stb_image_write.h : v1.09 - public domain image writer - [Github link](https://github.com/nothings/stb/blob/master/stb_image_write.h)
* tinyktx.h : Copyright (c) 2019, DeanoC. Licensed under 2 clause BSD license.
## Build and example ## Build and example
Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your project. Copy `stb_image.h`, `stb_image_write.h`, `json.hpp` and `tiny_gltf.h` to your project.
If you enable KTX support(`TINYGLTF_ENABLE_KTX`), Copy `tinyktx.h` to your project.
### Loading glTF 2.0 model ### Loading glTF 2.0 model
```c++ ```c++
@@ -149,8 +150,6 @@ if (!ret) {
* `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`. * `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`. * `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`. * `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
* `TINYGLTF_ENABLE_KTX` : Enable loading KTX images( https://www.khronos.org/opengles/sdk/tools/KTX/ ) using `tiny_ktx.h`. Supported MIME is `image/ktx` ( https://github.com/KhronosGroup/glTF/issues/835 ). See `models/Cube-KTX` for details. Application also defined `TINYKTX_IMPLEMENTATION` in **one** .cc file.
* `TINYGLTF_NO_INCLUDE_TINYKTX` : Disable including `tinyktx.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`.
### Saving gltTF 2.0 model ### Saving gltTF 2.0 model
@@ -189,6 +188,8 @@ $ ./tester
$ ./tester_noexcept $ ./tester_noexcept
``` ```
## Third party licenses used in unit tests ## Third party licenses
* json.hpp : Licensed under the MIT License <http://opensource.org/licenses/MIT>. Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
* stb_image : Public domain.
* catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0. * catch : Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. Distributed under the Boost Software License, Version 1.0.

View File

@@ -1,460 +1,365 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <GL/glew.h> #include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include "shaders.h" #include "shaders.h"
#include "window.h" #include "window.h"
#ifdef __clang__ #define TINYGLTF_IMPLEMENTATION
#pragma clang diagnostic push #define STB_IMAGE_IMPLEMENTATION
#pragma clang diagnostic ignored "-Weverything" #define STB_IMAGE_WRITE_IMPLEMENTATION
#endif #define TINYGLTF_NOEXCEPTION
#define JSON_NOEXCEPTION
// Inlude tinyktx.h before tiny_gltf.h #include "../../tiny_gltf.h"
// to get TKTX_*** definitions
#define TINYKTX_IMPLEMENTATION #define BUFFER_OFFSET(i) ((char *)NULL + (i))
#include "../../tinyktx.h"
bool loadModel(tinygltf::Model &model, const char *filename) {
#ifdef __clang__ tinygltf::TinyGLTF loader;
#pragma clang diagnostic pop std::string err;
#endif std::string warn;
#define TINYGLTF_IMPLEMENTATION bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
#define STB_IMAGE_IMPLEMENTATION if (!warn.empty()) {
#define STB_IMAGE_WRITE_IMPLEMENTATION std::cout << "WARN: " << warn << std::endl;
#define TINYGLTF_NOEXCEPTION }
#define JSON_NOEXCEPTION
#define TINYGLTF_ENABLE_KTX if (!err.empty()) {
// tinyktx.h is already included above, std::cout << "ERR: " << err << std::endl;
// so let tiny_gltf.h know do not include tinyktx.h anymore }
#define TINYGLTF_NO_INCLUDE_TINY_KTX
#include "../../tiny_gltf.h" if (!res)
std::cout << "Failed to load glTF: " << filename << std::endl;
//#define BUFFER_OFFSET(i) ((char *)nullptr + (i)) else
#define BUFFER_OFFSET(i) \ std::cout << "Loaded glTF: " << filename << std::endl;
(reinterpret_cast<void *>(i)) // TODO(syoyo): Is this right way?
return res;
bool loadModel(tinygltf::Model &model, const char *filename) { }
tinygltf::TinyGLTF loader;
std::string err; std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
std::string warn; tinygltf::Model &model, tinygltf::Mesh &mesh) {
for (size_t i = 0; i < model.bufferViews.size(); ++i) {
bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename); const tinygltf::BufferView &bufferView = model.bufferViews[i];
if (!warn.empty()) { if (bufferView.target == 0) { // TODO impl drawarrays
std::cout << "WARN: " << warn << std::endl; std::cout << "WARN: bufferView.target is zero" << std::endl;
} continue; // Unsupported bufferView.
/*
if (!err.empty()) { From spec2.0 readme:
std::cout << "ERR: " << err << std::endl; https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
} ... drawArrays function should be used with a count equal to
the count property of any of the accessors referenced by the
if (!res) attributes property (they are all equal for a given
std::cout << "Failed to load glTF: " << filename << std::endl; primitive).
else */
std::cout << "Loaded glTF: " << filename << std::endl; }
return res; tinygltf::Buffer buffer = model.buffers[bufferView.buffer];
} std::cout << "bufferview.target " << bufferView.target << std::endl;
static bool GetOpenGLFormatFromKTX(int ktx_fmt, GLint *internal_format, GLenum *format, GLenum *type) { GLuint vbo;
#if defined(TINYGLTF_ENABLE_KTX) glGenBuffers(1, &vbo);
bool ret = true; vbos[i] = vbo;
glBindBuffer(bufferView.target, vbo);
std::cout << "fmt = " << ktx_fmt << ", rgb8 fmt = " << TKTX_R8G8B8_UNORM << "\n";
std::cout << "buffer.data.size = " << buffer.data.size()
if (ktx_fmt == TKTX_R8G8B8_UNORM) { << ", bufferview.byteOffset = " << bufferView.byteOffset
(*internal_format) = GL_RGB; << std::endl;
(*format) = GL_RGB;
(*type) = GL_UNSIGNED_BYTE; glBufferData(bufferView.target, bufferView.byteLength,
} else { &buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
// TODO(syoyo): Support more KTX formats. }
ret = false;
} for (size_t i = 0; i < mesh.primitives.size(); ++i) {
tinygltf::Primitive primitive = mesh.primitives[i];
return ret; tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
#else
(void)fmt; for (auto &attrib : primitive.attributes) {
(void)internal_format; tinygltf::Accessor accessor = model.accessors[attrib.second];
(void)internal_format; int byteStride =
return false; accessor.ByteStride(model.bufferViews[accessor.bufferView]);
#endif glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
}
int size = 1;
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos, if (accessor.type != TINYGLTF_TYPE_SCALAR) {
tinygltf::Model &model, tinygltf::Mesh &mesh) { size = accessor.type;
for (size_t i = 0; i < model.bufferViews.size(); ++i) { }
const tinygltf::BufferView &bufferView = model.bufferViews[i];
if (bufferView.target == 0) { // TODO impl drawarrays int vaa = -1;
std::cout << "WARN: bufferView.target is zero" << std::endl; if (attrib.first.compare("POSITION") == 0) vaa = 0;
continue; // Unsupported bufferView. if (attrib.first.compare("NORMAL") == 0) vaa = 1;
/* if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2;
From spec2.0 readme: if (vaa > -1) {
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0 glEnableVertexAttribArray(vaa);
... drawArrays function should be used with a count equal to glVertexAttribPointer(vaa, size, accessor.componentType,
the count property of any of the accessors referenced by the accessor.normalized ? GL_TRUE : GL_FALSE,
attributes property (they are all equal for a byteStride, BUFFER_OFFSET(accessor.byteOffset));
given primitive). } else
*/ std::cout << "vaa missing: " << attrib.first << std::endl;
} }
tinygltf::Buffer buffer = model.buffers[bufferView.buffer]; GLuint texid;
std::cout << "bufferview.target " << bufferView.target << std::endl; glGenTextures(1, &texid);
GLuint vbo; tinygltf::Texture &tex = model.textures[0];
glGenBuffers(1, &vbo); tinygltf::Image &image = model.images[tex.source];
vbos[i] = vbo;
glBindBuffer(bufferView.target, vbo); glBindTexture(GL_TEXTURE_2D, texid);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
std::cout << "buffer.data.size = " << buffer.data.size() glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
<< ", bufferview.byteOffset = " << bufferView.byteOffset glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
<< std::endl; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBufferData(bufferView.target, bufferView.byteLength,
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW); GLenum format = GL_RGBA;
}
if (image.component == 1) {
for (size_t i = 0; i < mesh.primitives.size(); ++i) { format = GL_RED;
tinygltf::Primitive primitive = mesh.primitives[i]; } else if (image.component == 2) {
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices]; format = GL_RG;
} else if (image.component == 3) {
for (auto &attrib : primitive.attributes) { format = GL_RGB;
tinygltf::Accessor accessor = model.accessors[attrib.second]; } else {
int byteStride = // ???
accessor.ByteStride(model.bufferViews[accessor.bufferView]); }
glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
GLenum type = GL_UNSIGNED_BYTE;
int size = 1; if (image.bits == 8) {
if (accessor.type != TINYGLTF_TYPE_SCALAR) { // ok
size = accessor.type; } else if (image.bits == 16) {
} type = GL_UNSIGNED_SHORT;
} else {
int vaa = -1; // ???
if (attrib.first.compare("POSITION") == 0) vaa = 0; }
if (attrib.first.compare("NORMAL") == 0) vaa = 1;
if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2; glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
if (vaa > -1) { format, type, &image.image.at(0));
glEnableVertexAttribArray(vaa); }
glVertexAttribPointer(vaa, size, accessor.componentType,
accessor.normalized ? GL_TRUE : GL_FALSE, return vbos;
byteStride, BUFFER_OFFSET(accessor.byteOffset)); }
} else
std::cout << "Unsupported vertex attribute: " << attrib.first << std::endl; // bind models
} void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
tinygltf::Node &node) {
GLuint texid; bindMesh(vbos, model, model.meshes[node.mesh]);
glGenTextures(1, &texid); for (size_t i = 0; i < node.children.size(); i++) {
bindModelNodes(vbos, model, model.nodes[node.children[i]]);
tinygltf::Texture &tex = model.textures[0]; }
tinygltf::Image &image = model.images[tex.source]; }
GLuint bindModel(tinygltf::Model &model) {
glBindTexture(GL_TEXTURE_2D, texid); std::map<int, GLuint> vbos;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GLuint vao;
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glGenVertexArrays(1, &vao);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindVertexArray(vao);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); ++i) {
GLint internal_format = GL_RGBA; bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
GLenum format = GL_RGBA; }
GLenum type = GL_UNSIGNED_BYTE;
glBindVertexArray(0);
bool valid = false; // cleanup vbos
for (size_t i = 0; i < vbos.size(); ++i) {
// KTX extension glDeleteBuffers(1, &vbos[i]);
if (image.extras.Has("ktx_format")) { }
valid = GetOpenGLFormatFromKTX(image.extras.Get("ktx_format").Get<int>(), &internal_format, &format, &type); return vao;
}
if (valid) {
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
std::cout << "ktx_format: " << image.extras.Get("ktx_format").Get<int>() << std::endl; for (size_t i = 0; i < mesh.primitives.size(); ++i) {
std::cout << "ktx image size: " << image.width << ", " << image.height << std::endl; tinygltf::Primitive primitive = mesh.primitives[i];
} tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
} else { glDrawElements(primitive.mode, indexAccessor.count,
indexAccessor.componentType,
valid = true; BUFFER_OFFSET(indexAccessor.byteOffset));
}
if (image.component == 1) { }
format = GL_RED;
} else if (image.component == 2) { // recursively draw node and children nodes of model
format = GL_RG; void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
} else if (image.component == 3) { drawMesh(model, model.meshes[node.mesh]);
format = GL_RGB; for (size_t i = 0; i < node.children.size(); i++) {
} else if (image.component == 4) { drawModelNodes(model, model.nodes[node.children[i]]);
format = GL_RGBA; }
} else { }
valid = false; void drawModel(GLuint vao, tinygltf::Model &model) {
} glBindVertexArray(vao);
if (image.bits == 8) { const tinygltf::Scene &scene = model.scenes[model.defaultScene];
type = GL_UNSIGNED_BYTE; for (size_t i = 0; i < scene.nodes.size(); ++i) {
} else if (image.bits == 16) { drawModelNodes(model, model.nodes[scene.nodes[i]]);
type = GL_UNSIGNED_SHORT; }
} else {
valid = false; glBindVertexArray(0);
} }
} void dbgModel(tinygltf::Model &model) {
for (auto &mesh : model.meshes) {
if (valid) { std::cout << "mesh : " << mesh.name << std::endl;
for (auto &primitive : mesh.primitives) {
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, image.width, image.height, 0, const tinygltf::Accessor &indexAccessor =
format, type, &image.image.at(0)); model.accessors[primitive.indices];
}
} std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
<< indexAccessor.componentType << std::endl;
return vbos;
} tinygltf::Material &mat = model.materials[primitive.material];
for (auto &mats : mat.values) {
// bind models std::cout << "mat : " << mats.first.c_str() << std::endl;
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model, }
tinygltf::Node &node) {
bindMesh(vbos, model, model.meshes[node.mesh]); for (auto &image : model.images) {
for (size_t i = 0; i < node.children.size(); i++) { std::cout << "image name : " << image.uri << std::endl;
bindModelNodes(vbos, model, model.nodes[node.children[i]]); std::cout << " size : " << image.image.size() << std::endl;
} std::cout << " w/h : " << image.width << "/" << image.height
} << std::endl;
GLuint bindModel(tinygltf::Model &model) { }
std::map<int, GLuint> vbos;
GLuint vao; std::cout << "indices : " << primitive.indices << std::endl;
glGenVertexArrays(1, &vao); std::cout << "mode : "
glBindVertexArray(vao); << "(" << primitive.mode << ")" << std::endl;
const tinygltf::Scene &scene = model.scenes[model.defaultScene]; for (auto &attrib : primitive.attributes) {
for (size_t i = 0; i < scene.nodes.size(); ++i) { std::cout << "attribute : " << attrib.first.c_str() << std::endl;
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]); }
} }
}
glBindVertexArray(0); }
// cleanup vbos
for (size_t i = 0; i < vbos.size(); ++i) { glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
glDeleteBuffers(1, &vbos[i]); // Camera matrix
} glm::mat4 view = glm::lookAt(
pos, // Camera in World Space
return vao; lookat, // and looks at the origin
} glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
for (size_t i = 0; i < mesh.primitives.size(); ++i) { return view;
tinygltf::Primitive primitive = mesh.primitives[i]; }
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
glDrawElements(primitive.mode, indexAccessor.count, int h) {
indexAccessor.componentType, glm::mat4 Projection =
BUFFER_OFFSET(indexAccessor.byteOffset)); glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
}
} // Or, for an ortho camera :
// glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
// recursively draw node and children nodes of model // // In world coordinates
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
drawMesh(model, model.meshes[node.mesh]); glm::mat4 mvp = Projection * view_mat * model_mat;
for (size_t i = 0; i < node.children.size(); i++) {
drawModelNodes(model, model.nodes[node.children[i]]); return mvp;
} }
}
void drawModel(GLuint vao, tinygltf::Model &model) { void displayLoop(Window &window, const std::string &filename) {
glBindVertexArray(vao); Shaders shader = Shaders();
glUseProgram(shader.pid);
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
for (size_t i = 0; i < scene.nodes.size(); ++i) { // grab uniforms to modify
drawModelNodes(model, model.nodes[scene.nodes[i]]); GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
} GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position");
GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");
glBindVertexArray(0);
} tinygltf::Model model;
if (!loadModel(model, filename.c_str())) return;
void dbgModel(tinygltf::Model &model) {
for (auto &mesh : model.meshes) { GLuint vao = bindModel(model);
std::cout << "mesh : " << mesh.name << std::endl; // dbgModel(model); return;
for (auto &primitive : mesh.primitives) {
const tinygltf::Accessor &indexAccessor = // Model matrix : an identity matrix (model will be at the origin)
model.accessors[primitive.indices]; glm::mat4 model_mat = glm::mat4(1.0f);
glm::mat4 model_rot = glm::mat4(1.0f);
std::cout << "indexaccessor: count " << indexAccessor.count << ", type " glm::vec3 model_pos = glm::vec3(-3, 0, -3);
<< indexAccessor.componentType << std::endl;
// generate a camera view, based on eye-position and lookAt world-position
tinygltf::Material &mat = model.materials[primitive.material]; glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos);
for (auto &mats : mat.values) {
std::cout << "mat : " << mats.first.c_str() << std::endl; glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
} glm::vec3 sun_color = glm::vec3(1.0);
for (auto &image : model.images) { while (!window.Close()) {
std::cout << "image name : " << image.uri << std::endl; window.Resize();
std::cout << " size : " << image.image.size() << std::endl;
std::cout << " w/h : " << image.width << "/" << image.height glClearColor(0.2, 0.2, 0.2, 1.0);
<< std::endl; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
glm::mat4 trans =
std::cout << "indices : " << primitive.indices << std::endl; glm::translate(glm::mat4(1.0f), model_pos); // reposition model
std::cout << "mode : " model_rot = glm::rotate(model_rot, glm::radians(0.8f),
<< "(" << primitive.mode << ")" << std::endl; glm::vec3(0, 1, 0)); // rotate model on y axis
model_mat = trans * model_rot;
for (auto &attrib : primitive.attributes) {
std::cout << "attribute : " << attrib.first.c_str() << std::endl; // build a model-view-projection
} GLint w, h;
} glfwGetWindowSize(window.window, &w, &h);
} glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h);
} glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) { glUniform3fv(sun_position_u, 1, &sun_position[0]);
// Camera matrix glUniform3fv(sun_color_u, 1, &sun_color[0]);
glm::mat4 view = glm::lookAt(
pos, // Camera in World Space drawModel(vao, model);
lookat, // and looks at the origin glfwSwapBuffers(window.window);
glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down) glfwPollEvents();
); }
}
return view;
} static void error_callback(int error, const char *description) {
(void)error;
glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w, fprintf(stderr, "Error: %s\n", description);
int h) { }
glm::mat4 Projection =
glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f); int main(int argc, char **argv) {
std::string filename = "../../models/Cube/Cube.gltf";
// Or, for an ortho camera :
// glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f); if (argc > 1) {
// // In world coordinates filename = argv[1];
}
glm::mat4 mvp = Projection * view_mat * model_mat;
glfwSetErrorCallback(error_callback);
return mvp;
} if (!glfwInit()) return -1;
void displayLoop(Window &window, const std::string &filename) { // Force create OpenGL 3.3
Shaders shader = Shaders(); // NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
glUseProgram(shader.pid); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
// grab uniforms to modify glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP"); #ifdef __APPLE__
GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position"); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color"); #endif
#endif
tinygltf::Model model;
if (!loadModel(model, filename.c_str())) return; Window window = Window(800, 600, "TinyGLTF basic example");
glfwMakeContextCurrent(window.window);
GLuint vao = bindModel(model);
// dbgModel(model); return; #ifdef __APPLE__
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
// Model matrix : an identity matrix (model will be at the origin) glewExperimental = GL_TRUE;
glm::mat4 model_mat = glm::mat4(1.0f); #endif
glm::mat4 model_rot = glm::mat4(1.0f);
glm::vec3 model_pos = glm::vec3(-3, 0, -3); glewInit();
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
// generate a camera view, based on eye-position and lookAt world-position << std::endl;
glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos);
if (!GLEW_VERSION_3_3) {
glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0); std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
glm::vec3 sun_color = glm::vec3(1.0); return EXIT_FAILURE;
}
while (!window.Close()) {
window.Resize(); glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glClearColor(0.2, 0.2, 0.2, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glm::mat4 trans =
glm::translate(glm::mat4(1.0f), model_pos); // reposition model displayLoop(window, filename);
model_rot = glm::rotate(model_rot, glm::radians(0.8f),
glm::vec3(0, 1, 0)); // rotate model on y axis glfwTerminate();
model_mat = trans * model_rot; return 0;
}
// build a model-view-projection
GLint w, h;
glfwGetWindowSize(window.window, &w, &h);
glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h);
glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);
glUniform3fv(sun_position_u, 1, &sun_position[0]);
glUniform3fv(sun_color_u, 1, &sun_color[0]);
drawModel(vao, model);
glfwSwapBuffers(window.window);
glfwPollEvents();
}
}
static void error_callback(int error, const char *description) {
(void)error;
fprintf(stderr, "Error: %s\n", description);
}
static void drop_callback(GLFWwindow *window, int num, const char **paths) {
(void)window;
printf("dropCB %d\n", num);
for (int i = 0; i < num; i++) {
printf("%s\n", paths[i]);
}
}
int main(int argc, char **argv) {
std::string filename = "../../models/Cube/Cube.gltf";
if (argc > 1) {
filename = argv[1];
}
glfwSetErrorCallback(error_callback);
if (!glfwInit()) return -1;
// NOTE(syoyo): For some reason, Linux + NVIDIA driver + apt-installed
// glew(1.13) cannot initialize some ARB functions when CONTEXT_VERSION are
// explicitly given. Proably we need to compile app with recent glfw and
// glew(or use glad) package
#if !defined(__linux__)
// Try to create OpenGL 3.3 context on Windows and macOS
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
#endif
// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
Window window = Window(800, 600, "TinyGLTF basic example");
glfwSetDropCallback(window.window, drop_callback);
glfwMakeContextCurrent(window.window);
#ifdef __APPLE__
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
glewExperimental = GL_TRUE;
#endif
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to initialie glew." << std::endl;
return EXIT_FAILURE;
}
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
<< std::endl;
if (!GLEW_ARB_vertex_array_object) {
std::cerr << "GLEW_ARB_vertex_array_object was not available." << std::endl;
return EXIT_FAILURE;
}
if (!GLEW_VERSION_3_3) {
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
return EXIT_FAILURE;
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
displayLoop(window, filename);
glfwTerminate();
return 0;
}

View File

@@ -175,7 +175,10 @@ static std::string PrintIntArray(const std::vector<int> &arr) {
std::stringstream ss; std::stringstream ss;
ss << "[ "; ss << "[ ";
for (size_t i = 0; i < arr.size(); i++) { for (size_t i = 0; i < arr.size(); i++) {
ss << arr[i] << ((i != arr.size() - 1) ? ", " : ""); ss << arr[i];
if (i != arr.size() - 1) {
ss << ", ";
}
} }
ss << " ]"; ss << " ]";
@@ -190,7 +193,10 @@ static std::string PrintFloatArray(const std::vector<double> &arr) {
std::stringstream ss; std::stringstream ss;
ss << "[ "; ss << "[ ";
for (size_t i = 0; i < arr.size(); i++) { for (size_t i = 0; i < arr.size(); i++) {
ss << arr[i] << ((i != arr.size() - 1) ? ", " : ""); ss << arr[i];
if (i != arr.size() - 1) {
ss << ", ";
}
} }
ss << " ]"; ss << " ]";
@@ -243,35 +249,36 @@ static std::string PrintValue(const std::string &name,
if (tag) { if (tag) {
ss << Indent(indent) << name << " : " << value.Get<std::string>(); ss << Indent(indent) << name << " : " << value.Get<std::string>();
} else { } else {
ss << " " << value.Get<std::string>() << " "; ss << Indent(indent) << value.Get<std::string>() << " ";
} }
} else if (value.IsBool()) { } else if (value.IsBool()) {
if (tag) { if (tag) {
ss << Indent(indent) << name << " : " << value.Get<bool>(); ss << Indent(indent) << name << " : " << value.Get<bool>();
} else { } else {
ss << " " << value.Get<bool>() << " "; ss << Indent(indent) << value.Get<bool>() << " ";
} }
} else if (value.IsNumber()) { } else if (value.IsNumber()) {
if (tag) { if (tag) {
ss << Indent(indent) << name << " : " << value.Get<double>(); ss << Indent(indent) << name << " : " << value.Get<double>();
} else { } else {
ss << " " << value.Get<double>() << " "; ss << Indent(indent) << value.Get<double>() << " ";
} }
} else if (value.IsInt()) { } else if (value.IsInt()) {
if (tag) { if (tag) {
ss << Indent(indent) << name << " : " << value.Get<int>(); ss << Indent(indent) << name << " : " << value.Get<int>();
} else { } else {
ss << " " << value.Get<int>() << " "; ss << Indent(indent) << value.Get<int>() << " ";
} }
} else if (value.IsArray()) { } else if (value.IsArray()) {
ss << Indent(indent) << name << " [ "; // TODO(syoyo): Better pretty printing of array item
ss << Indent(indent) << name << " [ \n";
for (size_t i = 0; i < value.Size(); i++) { for (size_t i = 0; i < value.Size(); i++) {
ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false); ss << PrintValue("", value.Get(int(i)), indent + 1, /* tag */ false);
if (i != (value.ArrayLen() - 1)) { if (i != (value.ArrayLen() - 1)) {
ss << ", "; ss << ", \n";
} }
} }
ss << Indent(indent) << "] "; ss << "\n" << Indent(indent) << "] ";
} }
// @todo { binary } // @todo { binary }
@@ -339,6 +346,54 @@ static void DumpExtensions(const tinygltf::ExtensionMap &extension,
} }
} }
static void DumpTextureInfo(const tinygltf::TextureInfo &texinfo,
const int indent) {
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
<< "\n";
DumpExtensions(texinfo.extensions, indent + 1);
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
}
static void DumpNormalTextureInfo(const tinygltf::NormalTextureInfo &texinfo,
const int indent) {
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
<< "\n";
std::cout << Indent(indent) << "scale : " << texinfo.scale << "\n";
DumpExtensions(texinfo.extensions, indent + 1);
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
}
static void DumpOcclusionTextureInfo(
const tinygltf::OcclusionTextureInfo &texinfo, const int indent) {
std::cout << Indent(indent) << "index : " << texinfo.index << "\n";
std::cout << Indent(indent) << "texCoord : TEXCOORD_" << texinfo.texCoord
<< "\n";
std::cout << Indent(indent) << "strength : " << texinfo.strength << "\n";
DumpExtensions(texinfo.extensions, indent + 1);
std::cout << PrintValue("extras", texinfo.extras, indent + 1) << "\n";
}
static void DumpPbrMetallicRoughness(const tinygltf::PbrMetallicRoughness &pbr,
const int indent) {
std::cout << Indent(indent)
<< "baseColorFactor : " << PrintFloatArray(pbr.baseColorFactor)
<< "\n";
std::cout << Indent(indent) << "baseColorTexture :\n";
DumpTextureInfo(pbr.baseColorTexture, indent + 1);
std::cout << Indent(indent) << "metallicFactor : " << pbr.metallicFactor
<< "\n";
std::cout << Indent(indent) << "roughnessFactor : " << pbr.roughnessFactor
<< "\n";
std::cout << Indent(indent) << "metallicRoughnessTexture :\n";
DumpTextureInfo(pbr.metallicRoughnessTexture, indent + 1);
DumpExtensions(pbr.extensions, indent + 1);
std::cout << PrintValue("extras", pbr.extras, indent + 1) << "\n";
}
static void Dump(const tinygltf::Model &model) { static void Dump(const tinygltf::Model &model) {
std::cout << "=== Dump glTF ===" << std::endl; std::cout << "=== Dump glTF ===" << std::endl;
std::cout << "asset.copyright : " << model.asset.copyright std::cout << "asset.copyright : " << model.asset.copyright
@@ -509,16 +564,44 @@ static void Dump(const tinygltf::Model &model) {
<< std::endl; << std::endl;
for (size_t i = 0; i < model.materials.size(); i++) { for (size_t i = 0; i < model.materials.size(); i++) {
const tinygltf::Material &material = model.materials[i]; const tinygltf::Material &material = model.materials[i];
std::cout << Indent(1) << "name : " << material.name << std::endl; std::cout << Indent(1) << "name : " << material.name
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
<< std::endl; << std::endl;
std::cout << Indent(1) << "alphaMode : " << material.alphaMode
<< std::endl;
std::cout << Indent(1)
<< "alphaCutoff : " << material.alphaCutoff
<< std::endl;
std::cout << Indent(1) << "doubleSided : "
<< (material.doubleSided ? "true" : "false") << std::endl;
std::cout << Indent(1) << "emissiveFactor : "
<< PrintFloatArray(material.emissiveFactor) << std::endl;
std::cout << Indent(1) << "pbrMetallicRoughness :\n";
DumpPbrMetallicRoughness(material.pbrMetallicRoughness, 2);
std::cout << Indent(1) << "normalTexture :\n";
DumpNormalTextureInfo(material.normalTexture, 2);
std::cout << Indent(1) << "occlusionTexture :\n";
DumpOcclusionTextureInfo(material.occlusionTexture, 2);
std::cout << Indent(1) << "emissiveTexture :\n";
DumpTextureInfo(material.emissiveTexture, 2);
std::cout << Indent(1) << "---- legacy material parameter ----\n";
std::cout << Indent(1) << "values(items=" << material.values.size() << ")"
<< std::endl;
tinygltf::ParameterMap::const_iterator p(material.values.begin()); tinygltf::ParameterMap::const_iterator p(material.values.begin());
tinygltf::ParameterMap::const_iterator pEnd(material.values.end()); tinygltf::ParameterMap::const_iterator pEnd(material.values.end());
for (; p != pEnd; p++) { for (; p != pEnd; p++) {
std::cout << Indent(2) << p->first << ": " std::cout << Indent(2) << p->first << ": "
<< PrintParameterValue(p->second) << std::endl; << PrintParameterValue(p->second) << std::endl;
} }
std::cout << Indent(1) << "-------------------------------------\n";
DumpExtensions(material.extensions, 1);
std::cout << PrintValue("extras", material.extras, 2) << std::endl;
} }
} }

View File

@@ -1,193 +0,0 @@
{
"accessors" : [
{
"bufferView" : 0,
"byteOffset" : 0,
"componentType" : 5123,
"count" : 36,
"max" : [
35
],
"min" : [
0
],
"type" : "SCALAR"
},
{
"bufferView" : 1,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
1.000000,
1.000001
],
"min" : [
-1.000000,
-1.000000,
-1.000000
],
"type" : "VEC3"
},
{
"bufferView" : 2,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
1.000000,
1.000000
],
"min" : [
-1.000000,
-1.000000,
-1.000000
],
"type" : "VEC3"
},
{
"bufferView" : 3,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
-0.000000,
-0.000000,
1.000000
],
"min" : [
0.000000,
-0.000000,
-1.000000,
-1.000000
],
"type" : "VEC4"
},
{
"bufferView" : 4,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
1.000000
],
"min" : [
-1.000000,
-1.000000
],
"type" : "VEC2"
}
],
"asset" : {
"generator" : "VKTS glTF 2.0 exporter",
"version" : "2.0"
},
"bufferViews" : [
{
"buffer" : 0,
"byteLength" : 72,
"byteOffset" : 0,
"target" : 34963
},
{
"buffer" : 0,
"byteLength" : 432,
"byteOffset" : 72,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 432,
"byteOffset" : 504,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 576,
"byteOffset" : 936,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 288,
"byteOffset" : 1512,
"target" : 34962
}
],
"buffers" : [
{
"byteLength" : 1800,
"uri" : "Cube.bin"
}
],
"images" : [
{
"uri" : "Cube_BaseColor.ktx"
},
{
"uri" : "Cube_MetallicRoughness.ktx"
}
],
"materials" : [
{
"name" : "Cube",
"pbrMetallicRoughness" : {
"baseColorTexture" : {
"index" : 0
},
"metallicRoughnessTexture" : {
"index" : 1
}
}
}
],
"meshes" : [
{
"name" : "Cube",
"primitives" : [
{
"attributes" : {
"NORMAL" : 2,
"POSITION" : 1,
"TANGENT" : 3,
"TEXCOORD_0" : 4
},
"indices" : 0,
"material" : 0,
"mode" : 4
}
]
}
],
"nodes" : [
{
"mesh" : 0,
"name" : "Cube"
}
],
"samplers" : [
{}
],
"scene" : 0,
"scenes" : [
{
"nodes" : [
0
]
}
],
"textures" : [
{
"sampler" : 0,
"source" : 0
},
{
"sampler" : 0,
"source" : 1
}
]
}

Binary file not shown.

View File

@@ -1,12 +0,0 @@
License: Donated by Norbert Nopper for glTF testing.
https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Cube
----
Converted .png to .ktx image by Syoyo Fujita.
.png -> .ppm using image magic(resize with 25% to reduce file size)
.ppm -> .ktx using `toktx` in KTX-Software https://github.com/KhronosGroup/KTX-Software

View File

@@ -0,0 +1,224 @@
{
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 36,
"max": [
35
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
1,
1.000001
],
"min": [
-1,
-1,
-1
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
1,
1
],
"min": [
-1,
-1,
-1
],
"type": "VEC3"
},
{
"bufferView": 3,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
-0,
-0,
1
],
"min": [
0,
-0,
-1,
-1
],
"type": "VEC4"
},
{
"bufferView": 4,
"byteOffset": 0,
"componentType": 5126,
"count": 36,
"max": [
1,
1
],
"min": [
-1,
-1
],
"type": "VEC2"
}
],
"asset": {
"generator": "VKTS glTF 2.0 exporter",
"version": "2.0"
},
"bufferViews": [
{
"buffer": 0,
"byteLength": 72,
"byteOffset": 0,
"target": 34963
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 72,
"target": 34962
},
{
"buffer": 0,
"byteLength": 432,
"byteOffset": 504,
"target": 34962
},
{
"buffer": 0,
"byteLength": 576,
"byteOffset": 936,
"target": 34962
},
{
"buffer": 0,
"byteLength": 288,
"byteOffset": 1512,
"target": 34962
}
],
"buffers": [
{
"byteLength": 1800,
"uri": "Cube.bin"
}
],
"images": [
{
"0comment": "Use Cube_MetallicRoughness.png to reduce scene filesize",
"uri": "Cube_MetallicRoughness.png"
},
{
"uri": "Cube_MetallicRoughness.png"
}
],
"materials": [
{
"emissiveTexture": {
"index": 0,
"extensions": {
"KHR_texture_transform": {
"offset": [
0,
1
],
"scale": [
1,
-1
]
}
}
}
},
{
"name": "Cube",
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicRoughnessTexture": {
"index": 1,
"extensions": {
"KHR_texture_transform": {
"offset": [
0,
1
],
"rotation": 1.57079632679,
"scale": [
0.5,
0.5
]
}
}
}
}
}
],
"meshes": [
{
"name": "Cube",
"primitives": [
{
"attributes": {
"NORMAL": 2,
"POSITION": 1,
"TANGENT": 3,
"TEXCOORD_0": 4
},
"indices": 0,
"material": 0,
"mode": 4
}
]
}
],
"nodes": [
{
"mesh": 0,
"name": "Cube"
}
],
"samplers": [
{}
],
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"textures": [
{
"sampler": 0,
"source": 0
},
{
"sampler": 0,
"source": 1
}
]
}

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

View File

@@ -0,0 +1,6 @@
Added KHR_texture_transform property to Cube scene.
License: Donated by Norbert Nopper for glTF testing.
https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Cube

View File

@@ -279,3 +279,39 @@ TEST_CASE("parse-integer-array", "[bounds-checking]") {
REQUIRE_THAT(err, Catch::Contains("not an integer type")); REQUIRE_THAT(err, Catch::Contains("not an integer type"));
} }
} }
TEST_CASE("pbr-khr-texture-transform", "[material]") {
tinygltf::Model model;
tinygltf::TinyGLTF ctx;
std::string err;
std::string warn;
// Loading is expected to fail, but not crash.
bool ret = ctx.LoadASCIIFromFile(
&model, &err, &warn,
"../models/Cube-texture-ext/Cube-textransform.gltf");
REQUIRE(ret == true);
REQUIRE(model.materials.size() == 2);
REQUIRE(model.materials[0].emissiveTexture.extensions.count("KHR_texture_transform") == 1);
REQUIRE(model.materials[0].emissiveTexture.extensions["KHR_texture_transform"].IsObject());
tinygltf::Value::Object &texform = model.materials[0].emissiveTexture.extensions["KHR_texture_transform"].Get<tinygltf::Value::Object>();
REQUIRE(texform.count("scale"));
REQUIRE(texform["scale"].IsArray());
// Note: It looks json.hpp parse integer JSON number as integer, not floating point.
// IsNumber return true either value is int or floating point.
REQUIRE(texform["scale"].Get(0).IsNumber());
REQUIRE(texform["scale"].Get(1).IsNumber());
double scale[2];
scale[0] = texform["scale"].Get(0).GetNumberAsDouble();
scale[1] = texform["scale"].Get(1).GetNumberAsDouble();
REQUIRE(scale[0] == Approx(1.0));
REQUIRE(scale[1] == Approx(-1.0));
}

File diff suppressed because it is too large Load Diff

1600
tinyktx.h

File diff suppressed because it is too large Load Diff