Compare commits

..

4 Commits

Author SHA1 Message Date
Syoyo Fujita
98eef6ee75 Fix non-KTX texture was not handled correctly.
Experience file drop API of glfw(not working yet).
2019-07-06 15:13:13 +09:00
Syoyo Fujita
c7bf800075 Support KTX texture of R8G8B8 format in basic example. 2019-07-05 16:20:53 +09:00
Syoyo Fujita
006ab90c67 Initial support of KTX texture load using TinyKTX. 2019-07-04 14:30:28 +09:00
Syoyo Fujita
6f7518255f Add tinyktx.
Add workaround for OpenGL3 context creation in `basic` example.
2019-07-03 16:41:11 +09:00
15 changed files with 2802 additions and 1571 deletions

25
LICENSE.tinyktx Normal file
View File

@@ -0,0 +1,25 @@
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 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class) - v2.3.0 release(Support loading KTX image through tiny_ktx)
- 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,13 +53,8 @@ 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 * [x] Draco mesh decoding(`TINYGLTF_ENABLE_DRACO` required)
* [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
@@ -83,11 +78,12 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number
* [x] Load Draco compressed mesh * [x] Load Draco compressed mesh
* [ ] Save Draco compressed mesh * [ ] Save Draco compressed mesh
* [ ] Open3DGC? * [ ] Open3DGC?
* [x] Support `extensions` and `extras` property * [ ] 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
@@ -99,12 +95,15 @@ 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++
@@ -150,6 +149,8 @@ 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
@@ -188,8 +189,6 @@ $ ./tester
$ ./tester_noexcept $ ./tester_noexcept
``` ```
## Third party licenses ## Third party licenses used in unit tests
* 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,365 +1,460 @@
#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"
#define TINYGLTF_IMPLEMENTATION #ifdef __clang__
#define STB_IMAGE_IMPLEMENTATION #pragma clang diagnostic push
#define STB_IMAGE_WRITE_IMPLEMENTATION #pragma clang diagnostic ignored "-Weverything"
#define TINYGLTF_NOEXCEPTION #endif
#define JSON_NOEXCEPTION
#include "../../tiny_gltf.h" // Inlude tinyktx.h before tiny_gltf.h
// to get TKTX_*** definitions
#define BUFFER_OFFSET(i) ((char *)NULL + (i)) #define TINYKTX_IMPLEMENTATION
#include "../../tinyktx.h"
bool loadModel(tinygltf::Model &model, const char *filename) {
tinygltf::TinyGLTF loader; #ifdef __clang__
std::string err; #pragma clang diagnostic pop
std::string warn; #endif
bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename); #define TINYGLTF_IMPLEMENTATION
if (!warn.empty()) { #define STB_IMAGE_IMPLEMENTATION
std::cout << "WARN: " << warn << std::endl; #define STB_IMAGE_WRITE_IMPLEMENTATION
} #define TINYGLTF_NOEXCEPTION
#define JSON_NOEXCEPTION
if (!err.empty()) { #define TINYGLTF_ENABLE_KTX
std::cout << "ERR: " << err << std::endl; // tinyktx.h is already included above,
} // so let tiny_gltf.h know do not include tinyktx.h anymore
#define TINYGLTF_NO_INCLUDE_TINY_KTX
if (!res) #include "../../tiny_gltf.h"
std::cout << "Failed to load glTF: " << filename << std::endl;
else //#define BUFFER_OFFSET(i) ((char *)nullptr + (i))
std::cout << "Loaded glTF: " << filename << std::endl; #define BUFFER_OFFSET(i) \
(reinterpret_cast<void *>(i)) // TODO(syoyo): Is this right way?
return res;
} bool loadModel(tinygltf::Model &model, const char *filename) {
tinygltf::TinyGLTF loader;
std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos, std::string err;
tinygltf::Model &model, tinygltf::Mesh &mesh) { std::string warn;
for (size_t i = 0; i < model.bufferViews.size(); ++i) {
const tinygltf::BufferView &bufferView = model.bufferViews[i]; bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
if (bufferView.target == 0) { // TODO impl drawarrays if (!warn.empty()) {
std::cout << "WARN: bufferView.target is zero" << std::endl; std::cout << "WARN: " << warn << std::endl;
continue; // Unsupported bufferView. }
/*
From spec2.0 readme: if (!err.empty()) {
https://github.com/KhronosGroup/glTF/tree/master/specification/2.0 std::cout << "ERR: " << err << std::endl;
... drawArrays function should be used with a count equal to }
the count property of any of the accessors referenced by the
attributes property (they are all equal for a given if (!res)
primitive). std::cout << "Failed to load glTF: " << filename << std::endl;
*/ else
} std::cout << "Loaded glTF: " << filename << std::endl;
tinygltf::Buffer buffer = model.buffers[bufferView.buffer]; return res;
std::cout << "bufferview.target " << bufferView.target << std::endl; }
GLuint vbo; static bool GetOpenGLFormatFromKTX(int ktx_fmt, GLint *internal_format, GLenum *format, GLenum *type) {
glGenBuffers(1, &vbo); #if defined(TINYGLTF_ENABLE_KTX)
vbos[i] = vbo; bool ret = true;
glBindBuffer(bufferView.target, vbo);
std::cout << "fmt = " << ktx_fmt << ", rgb8 fmt = " << TKTX_R8G8B8_UNORM << "\n";
std::cout << "buffer.data.size = " << buffer.data.size()
<< ", bufferview.byteOffset = " << bufferView.byteOffset if (ktx_fmt == TKTX_R8G8B8_UNORM) {
<< std::endl; (*internal_format) = GL_RGB;
(*format) = GL_RGB;
glBufferData(bufferView.target, bufferView.byteLength, (*type) = GL_UNSIGNED_BYTE;
&buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW); } else {
} // TODO(syoyo): Support more KTX formats.
ret = false;
for (size_t i = 0; i < mesh.primitives.size(); ++i) { }
tinygltf::Primitive primitive = mesh.primitives[i];
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices]; return ret;
#else
for (auto &attrib : primitive.attributes) { (void)fmt;
tinygltf::Accessor accessor = model.accessors[attrib.second]; (void)internal_format;
int byteStride = (void)internal_format;
accessor.ByteStride(model.bufferViews[accessor.bufferView]); return false;
glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]); #endif
}
int size = 1;
if (accessor.type != TINYGLTF_TYPE_SCALAR) { std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
size = accessor.type; tinygltf::Model &model, tinygltf::Mesh &mesh) {
} for (size_t i = 0; i < model.bufferViews.size(); ++i) {
const tinygltf::BufferView &bufferView = model.bufferViews[i];
int vaa = -1; if (bufferView.target == 0) { // TODO impl drawarrays
if (attrib.first.compare("POSITION") == 0) vaa = 0; std::cout << "WARN: bufferView.target is zero" << std::endl;
if (attrib.first.compare("NORMAL") == 0) vaa = 1; continue; // Unsupported bufferView.
if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2; /*
if (vaa > -1) { From spec2.0 readme:
glEnableVertexAttribArray(vaa); https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
glVertexAttribPointer(vaa, size, accessor.componentType, ... drawArrays function should be used with a count equal to
accessor.normalized ? GL_TRUE : GL_FALSE, the count property of any of the accessors referenced by the
byteStride, BUFFER_OFFSET(accessor.byteOffset)); attributes property (they are all equal for a
} else given primitive).
std::cout << "vaa missing: " << attrib.first << std::endl; */
} }
GLuint texid; tinygltf::Buffer buffer = model.buffers[bufferView.buffer];
glGenTextures(1, &texid); std::cout << "bufferview.target " << bufferView.target << std::endl;
tinygltf::Texture &tex = model.textures[0]; GLuint vbo;
tinygltf::Image &image = model.images[tex.source]; glGenBuffers(1, &vbo);
vbos[i] = vbo;
glBindTexture(GL_TEXTURE_2D, texid); glBindBuffer(bufferView.target, vbo);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); std::cout << "buffer.data.size = " << buffer.data.size()
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); << ", bufferview.byteOffset = " << bufferView.byteOffset
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); << std::endl;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glBufferData(bufferView.target, bufferView.byteLength,
GLenum format = GL_RGBA; &buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
}
if (image.component == 1) {
format = GL_RED; for (size_t i = 0; i < mesh.primitives.size(); ++i) {
} else if (image.component == 2) { tinygltf::Primitive primitive = mesh.primitives[i];
format = GL_RG; tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];
} else if (image.component == 3) {
format = GL_RGB; for (auto &attrib : primitive.attributes) {
} else { tinygltf::Accessor accessor = model.accessors[attrib.second];
// ??? int byteStride =
} accessor.ByteStride(model.bufferViews[accessor.bufferView]);
glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);
GLenum type = GL_UNSIGNED_BYTE;
if (image.bits == 8) { int size = 1;
// ok if (accessor.type != TINYGLTF_TYPE_SCALAR) {
} else if (image.bits == 16) { size = accessor.type;
type = GL_UNSIGNED_SHORT; }
} else {
// ??? int vaa = -1;
} if (attrib.first.compare("POSITION") == 0) vaa = 0;
if (attrib.first.compare("NORMAL") == 0) vaa = 1;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2;
format, type, &image.image.at(0)); if (vaa > -1) {
} glEnableVertexAttribArray(vaa);
glVertexAttribPointer(vaa, size, accessor.componentType,
return vbos; accessor.normalized ? GL_TRUE : GL_FALSE,
} byteStride, BUFFER_OFFSET(accessor.byteOffset));
} else
// bind models std::cout << "Unsupported vertex attribute: " << attrib.first << std::endl;
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model, }
tinygltf::Node &node) {
bindMesh(vbos, model, model.meshes[node.mesh]); GLuint texid;
for (size_t i = 0; i < node.children.size(); i++) { glGenTextures(1, &texid);
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) {
std::map<int, GLuint> vbos; glBindTexture(GL_TEXTURE_2D, texid);
GLuint vao; glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenVertexArrays(1, &vao); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindVertexArray(vao); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
const tinygltf::Scene &scene = model.scenes[model.defaultScene]; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
for (size_t i = 0; i < scene.nodes.size(); ++i) {
bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]); GLint internal_format = GL_RGBA;
} GLenum format = GL_RGBA;
GLenum type = GL_UNSIGNED_BYTE;
glBindVertexArray(0);
// cleanup vbos bool valid = false;
for (size_t i = 0; i < vbos.size(); ++i) {
glDeleteBuffers(1, &vbos[i]); // KTX extension
} if (image.extras.Has("ktx_format")) {
return vao; valid = GetOpenGLFormatFromKTX(image.extras.Get("ktx_format").Get<int>(), &internal_format, &format, &type);
}
if (valid) {
void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
for (size_t i = 0; i < mesh.primitives.size(); ++i) { std::cout << "ktx_format: " << image.extras.Get("ktx_format").Get<int>() << std::endl;
tinygltf::Primitive primitive = mesh.primitives[i]; std::cout << "ktx image size: " << image.width << ", " << image.height << std::endl;
tinygltf::Accessor indexAccessor = model.accessors[primitive.indices]; }
glDrawElements(primitive.mode, indexAccessor.count, } else {
indexAccessor.componentType,
BUFFER_OFFSET(indexAccessor.byteOffset)); valid = true;
}
} if (image.component == 1) {
format = GL_RED;
// recursively draw node and children nodes of model } else if (image.component == 2) {
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) { format = GL_RG;
drawMesh(model, model.meshes[node.mesh]); } else if (image.component == 3) {
for (size_t i = 0; i < node.children.size(); i++) { format = GL_RGB;
drawModelNodes(model, model.nodes[node.children[i]]); } else if (image.component == 4) {
} format = GL_RGBA;
} } else {
void drawModel(GLuint vao, tinygltf::Model &model) { valid = false;
glBindVertexArray(vao); }
const tinygltf::Scene &scene = model.scenes[model.defaultScene]; if (image.bits == 8) {
for (size_t i = 0; i < scene.nodes.size(); ++i) { type = GL_UNSIGNED_BYTE;
drawModelNodes(model, model.nodes[scene.nodes[i]]); } else if (image.bits == 16) {
} type = GL_UNSIGNED_SHORT;
} else {
glBindVertexArray(0); valid = false;
} }
void dbgModel(tinygltf::Model &model) { }
for (auto &mesh : model.meshes) {
std::cout << "mesh : " << mesh.name << std::endl; if (valid) {
for (auto &primitive : mesh.primitives) {
const tinygltf::Accessor &indexAccessor = glTexImage2D(GL_TEXTURE_2D, 0, internal_format, image.width, image.height, 0,
model.accessors[primitive.indices]; format, type, &image.image.at(0));
}
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) {
std::cout << "mat : " << mats.first.c_str() << std::endl; // bind models
} void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
tinygltf::Node &node) {
for (auto &image : model.images) { bindMesh(vbos, model, model.meshes[node.mesh]);
std::cout << "image name : " << image.uri << std::endl; for (size_t i = 0; i < node.children.size(); i++) {
std::cout << " size : " << image.image.size() << std::endl; bindModelNodes(vbos, model, model.nodes[node.children[i]]);
std::cout << " w/h : " << image.width << "/" << image.height }
<< std::endl; }
} GLuint bindModel(tinygltf::Model &model) {
std::map<int, GLuint> vbos;
std::cout << "indices : " << primitive.indices << std::endl; GLuint vao;
std::cout << "mode : " glGenVertexArrays(1, &vao);
<< "(" << primitive.mode << ")" << std::endl; glBindVertexArray(vao);
for (auto &attrib : primitive.attributes) { const tinygltf::Scene &scene = model.scenes[model.defaultScene];
std::cout << "attribute : " << attrib.first.c_str() << std::endl; for (size_t i = 0; i < scene.nodes.size(); ++i) {
} bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
} }
}
} glBindVertexArray(0);
// cleanup vbos
glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) { for (size_t i = 0; i < vbos.size(); ++i) {
// Camera matrix glDeleteBuffers(1, &vbos[i]);
glm::mat4 view = glm::lookAt( }
pos, // Camera in World Space
lookat, // and looks at the origin return vao;
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) {
return view; for (size_t i = 0; i < mesh.primitives.size(); ++i) {
} 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,
int h) { glDrawElements(primitive.mode, indexAccessor.count,
glm::mat4 Projection = indexAccessor.componentType,
glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f); BUFFER_OFFSET(indexAccessor.byteOffset));
}
// Or, for an ortho camera : }
// glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
// // In world coordinates // recursively draw node and children nodes of model
void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
glm::mat4 mvp = Projection * view_mat * model_mat; drawMesh(model, model.meshes[node.mesh]);
for (size_t i = 0; i < node.children.size(); i++) {
return mvp; drawModelNodes(model, model.nodes[node.children[i]]);
} }
}
void displayLoop(Window &window, const std::string &filename) { void drawModel(GLuint vao, tinygltf::Model &model) {
Shaders shader = Shaders(); glBindVertexArray(vao);
glUseProgram(shader.pid);
const tinygltf::Scene &scene = model.scenes[model.defaultScene];
// grab uniforms to modify for (size_t i = 0; i < scene.nodes.size(); ++i) {
GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP"); drawModelNodes(model, model.nodes[scene.nodes[i]]);
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) {
GLuint vao = bindModel(model); for (auto &mesh : model.meshes) {
// dbgModel(model); return; std::cout << "mesh : " << mesh.name << std::endl;
for (auto &primitive : mesh.primitives) {
// Model matrix : an identity matrix (model will be at the origin) const tinygltf::Accessor &indexAccessor =
glm::mat4 model_mat = glm::mat4(1.0f); model.accessors[primitive.indices];
glm::mat4 model_rot = glm::mat4(1.0f);
glm::vec3 model_pos = glm::vec3(-3, 0, -3); std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
<< indexAccessor.componentType << std::endl;
// generate a camera view, based on eye-position and lookAt world-position
glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos); tinygltf::Material &mat = model.materials[primitive.material];
for (auto &mats : mat.values) {
glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0); std::cout << "mat : " << mats.first.c_str() << std::endl;
glm::vec3 sun_color = glm::vec3(1.0); }
while (!window.Close()) { for (auto &image : model.images) {
window.Resize(); std::cout << "image name : " << image.uri << std::endl;
std::cout << " size : " << image.image.size() << std::endl;
glClearColor(0.2, 0.2, 0.2, 1.0); std::cout << " w/h : " << image.width << "/" << image.height
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); << std::endl;
}
glm::mat4 trans =
glm::translate(glm::mat4(1.0f), model_pos); // reposition model std::cout << "indices : " << primitive.indices << std::endl;
model_rot = glm::rotate(model_rot, glm::radians(0.8f), std::cout << "mode : "
glm::vec3(0, 1, 0)); // rotate model on y axis << "(" << primitive.mode << ")" << std::endl;
model_mat = trans * model_rot;
for (auto &attrib : primitive.attributes) {
// build a model-view-projection std::cout << "attribute : " << attrib.first.c_str() << std::endl;
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]); glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
glUniform3fv(sun_color_u, 1, &sun_color[0]); // Camera matrix
glm::mat4 view = glm::lookAt(
drawModel(vao, model); pos, // Camera in World Space
glfwSwapBuffers(window.window); lookat, // and looks at the origin
glfwPollEvents(); glm::vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
} );
}
return view;
static void error_callback(int error, const char *description) { }
(void)error;
fprintf(stderr, "Error: %s\n", description); glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
} int h) {
glm::mat4 Projection =
int main(int argc, char **argv) { glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);
std::string filename = "../../models/Cube/Cube.gltf";
// Or, for an ortho camera :
if (argc > 1) { // glm::mat4 Projection = glm::ortho(-10.0f,10.0f,-10.0f,10.0f,0.0f,100.0f);
filename = argv[1]; // // In world coordinates
}
glm::mat4 mvp = Projection * view_mat * model_mat;
glfwSetErrorCallback(error_callback);
return mvp;
if (!glfwInit()) return -1; }
// Force create OpenGL 3.3 void displayLoop(Window &window, const std::string &filename) {
// NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work. Shaders shader = Shaders();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glUseProgram(shader.pid);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // grab uniforms to modify
#ifdef __APPLE__ GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position");
#endif GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");
#endif
tinygltf::Model model;
Window window = Window(800, 600, "TinyGLTF basic example"); if (!loadModel(model, filename.c_str())) return;
glfwMakeContextCurrent(window.window);
GLuint vao = bindModel(model);
#ifdef __APPLE__ // dbgModel(model); return;
// https://stackoverflow.com/questions/50192625/openggl-segmentation-fault
glewExperimental = GL_TRUE; // Model matrix : an identity matrix (model will be at the origin)
#endif glm::mat4 model_mat = glm::mat4(1.0f);
glm::mat4 model_rot = glm::mat4(1.0f);
glewInit(); glm::vec3 model_pos = glm::vec3(-3, 0, -3);
std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
<< std::endl; // generate a camera view, based on eye-position and lookAt world-position
glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos);
if (!GLEW_VERSION_3_3) {
std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl; glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
return EXIT_FAILURE; glm::vec3 sun_color = glm::vec3(1.0);
}
while (!window.Close()) {
glEnable(GL_DEPTH_TEST); window.Resize();
glDepthFunc(GL_LESS);
glClearColor(0.2, 0.2, 0.2, 1.0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glm::mat4 trans =
displayLoop(window, filename); glm::translate(glm::mat4(1.0f), model_pos); // reposition model
model_rot = glm::rotate(model_rot, glm::radians(0.8f),
glfwTerminate(); glm::vec3(0, 1, 0)); // rotate model on y axis
return 0; model_mat = trans * model_rot;
}
// 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,10 +175,7 @@ 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]; ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
if (i != arr.size() - 1) {
ss << ", ";
}
} }
ss << " ]"; ss << " ]";
@@ -193,10 +190,7 @@ 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]; ss << arr[i] << ((i != arr.size() - 1) ? ", " : "");
if (i != arr.size() - 1) {
ss << ", ";
}
} }
ss << " ]"; ss << " ]";
@@ -249,36 +243,35 @@ 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 << Indent(indent) << value.Get<std::string>() << " "; ss << " " << 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 << Indent(indent) << value.Get<bool>() << " "; ss << " " << 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 << Indent(indent) << value.Get<double>() << " "; ss << " " << 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 << Indent(indent) << value.Get<int>() << " "; ss << " " << value.Get<int>() << " ";
} }
} else if (value.IsArray()) { } else if (value.IsArray()) {
// TODO(syoyo): Better pretty printing of array item ss << Indent(indent) << name << " [ ";
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 << ", \n"; ss << ", ";
} }
} }
ss << "\n" << Indent(indent) << "] "; ss << Indent(indent) << "] ";
} }
// @todo { binary } // @todo { binary }
@@ -346,54 +339,6 @@ 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
@@ -564,44 +509,16 @@ 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::cout << Indent(1) << "name : " << material.name << 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::cout << Indent(1) << "values(items=" << material.values.size() << ")"
<< std::endl; << 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

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

193
models/Cube-KTX/Cube.gltf Normal file
View File

@@ -0,0 +1,193 @@
{
"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.

Binary file not shown.

12
models/Cube-KTX/README.md Normal file
View File

@@ -0,0 +1,12 @@
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

@@ -1,224 +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,
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
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 319 B

View File

@@ -1,6 +0,0 @@
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,39 +279,3 @@ 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 Normal file

File diff suppressed because it is too large Load Diff