Add texture support for models
This commit is contained in:
parent
8f7f0313f5
commit
2ade6919d1
|
@ -2,19 +2,24 @@
|
||||||
#include <glm/vec2.hpp>
|
#include <glm/vec2.hpp>
|
||||||
#include <glm/gtc/noise.hpp>
|
#include <glm/gtc/noise.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
using glm::vec2;
|
using glm::vec2;
|
||||||
|
using std::string;
|
||||||
|
using std::map;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
typedef unsigned int uint;
|
typedef unsigned int uint;
|
||||||
|
|
||||||
// Original source: https://raw.githubusercontent.com/lvandeve/lodepng/master/examples/example_decode.cpp
|
// Original source: https://raw.githubusercontent.com/lvandeve/lodepng/master/examples/example_decode.cpp
|
||||||
PNGImage loadPNGFile(std::string fileName, bool flip_handedness) {
|
PNGImage loadPNGFile(string filename, bool flip_handedness) {
|
||||||
vector<unsigned char> png;
|
vector<unsigned char> png;
|
||||||
vector<unsigned char> pixels; //the raw pixels
|
vector<unsigned char> pixels; //the raw pixels
|
||||||
uint width, height;
|
uint width, height;
|
||||||
|
|
||||||
//load and decode
|
//load and decode
|
||||||
uint error = lodepng::load_file(png, fileName);
|
uint error = lodepng::load_file(png, filename);
|
||||||
if(!error) error = lodepng::decode(pixels, width, height, png);
|
if(!error) error = lodepng::decode(pixels, width, height, png);
|
||||||
|
|
||||||
//if there's an error, display it
|
//if there's an error, display it
|
||||||
|
@ -57,6 +62,17 @@ PNGImage loadPNGFile(std::string fileName, bool flip_handedness) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PNGImage* loadPNGFileDynamic(string filename, bool flip_handedness) {
|
||||||
|
static map<string, PNGImage*> cache{};
|
||||||
|
if (cache.find(filename) == cache.end())
|
||||||
|
cache[filename] = loadPNGFileDynamicNoCaching(filename, flip_handedness);
|
||||||
|
return cache[filename];
|
||||||
|
}
|
||||||
|
PNGImage* loadPNGFileDynamicNoCaching(string filename, bool flip_handedness) {
|
||||||
|
PNGImage* out = new PNGImage;
|
||||||
|
*out = loadPNGFile(filename, flip_handedness);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
PNGImage makePerlinNoisePNG(uint w, uint h, float scale) {
|
PNGImage makePerlinNoisePNG(uint w, uint h, float scale) {
|
||||||
return makePerlinNoisePNG(w, h, vector<float>{scale});
|
return makePerlinNoisePNG(w, h, vector<float>{scale});
|
||||||
|
|
|
@ -12,7 +12,10 @@ struct PNGImage {
|
||||||
std::vector<unsigned char> pixels; // RGBA
|
std::vector<unsigned char> pixels; // RGBA
|
||||||
};
|
};
|
||||||
|
|
||||||
PNGImage loadPNGFile(std::string fileName, bool flip_handedness=false);
|
PNGImage loadPNGFile(std::string filename, bool flip_handedness=false);
|
||||||
|
|
||||||
|
PNGImage* loadPNGFileDynamic(std::string filename, bool flip_handedness=false);
|
||||||
|
PNGImage* loadPNGFileDynamicNoCaching(std::string filename, bool flip_handedness=false);
|
||||||
|
|
||||||
PNGImage makePerlinNoisePNG(uint w, uint h, float scale=0.1);
|
PNGImage makePerlinNoisePNG(uint w, uint h, float scale=0.1);
|
||||||
|
|
||||||
|
|
|
@ -25,15 +25,14 @@ using std::endl;
|
||||||
SceneNode* buildSceneNodes(
|
SceneNode* buildSceneNodes(
|
||||||
const aiNode* node,
|
const aiNode* node,
|
||||||
const vector<Mesh>& meshes,
|
const vector<Mesh>& meshes,
|
||||||
const vector<PNGImage>& textures,
|
|
||||||
const vector<Material*>& mat_lookup) {
|
const vector<Material*>& mat_lookup) {
|
||||||
if (DEBUG) cout << "Building node from " << node->mName.C_Str() << "..." << endl;
|
if (DEBUG) cout << "Building node from " << node->mName.data << "..." << endl;
|
||||||
|
|
||||||
// filter semantic-only nodes
|
// filter semantic-only nodes
|
||||||
if (node->mTransformation.IsIdentity()
|
if (node->mTransformation.IsIdentity()
|
||||||
&& node->mNumMeshes == 0
|
&& node->mNumMeshes == 0
|
||||||
&& node->mNumChildren == 1)
|
&& node->mNumChildren == 1)
|
||||||
return buildSceneNodes(node->mChildren[0], meshes, textures, mat_lookup);
|
return buildSceneNodes(node->mChildren[0], meshes, mat_lookup);
|
||||||
|
|
||||||
SceneNode* out = createSceneNode();
|
SceneNode* out = createSceneNode();
|
||||||
|
|
||||||
|
@ -58,15 +57,15 @@ SceneNode* buildSceneNodes(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint i=0; i<node->mNumChildren; i++)
|
for (uint i=0; i<node->mNumChildren; i++)
|
||||||
out->children.push_back(buildSceneNodes(node->mChildren[i], meshes, textures, mat_lookup));
|
out->children.push_back(buildSceneNodes(node->mChildren[i], meshes, mat_lookup));
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneNode* loadModelScene(const std::string& filename, const map<int, Material>& overrides) {
|
SceneNode* loadModelScene(const std::string& dirname, const std::string& filename, const map<int, Material>& overrides) {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
|
|
||||||
const aiScene* scene = importer.ReadFile(filename,
|
const aiScene* scene = importer.ReadFile(dirname + "/" + filename,
|
||||||
aiProcess_CalcTangentSpace
|
aiProcess_CalcTangentSpace
|
||||||
//| aiProcess_FlipWindingOrder
|
//| aiProcess_FlipWindingOrder
|
||||||
| aiProcess_Triangulate
|
| aiProcess_Triangulate
|
||||||
|
@ -82,7 +81,7 @@ SceneNode* loadModelScene(const std::string& filename, const map<int, Material>&
|
||||||
|
|
||||||
// read materials
|
// read materials
|
||||||
uint j=0;
|
uint j=0;
|
||||||
Material default_material = Material().diffuse({1, 1, 1});
|
Material default_material;
|
||||||
vector<Material> materials(scene->mNumMaterials);
|
vector<Material> materials(scene->mNumMaterials);
|
||||||
for (Material& material : materials) {
|
for (Material& material : materials) {
|
||||||
const aiMaterial* aimat = scene->mMaterials[j++];
|
const aiMaterial* aimat = scene->mMaterials[j++];
|
||||||
|
@ -90,9 +89,9 @@ SceneNode* loadModelScene(const std::string& filename, const map<int, Material>&
|
||||||
// print material
|
// print material
|
||||||
aiString name; aimat->Get(AI_MATKEY_NAME, name);
|
aiString name; aimat->Get(AI_MATKEY_NAME, name);
|
||||||
if (DEBUG){
|
if (DEBUG){
|
||||||
cout << "Read material #" << j-1 << " '" << name.C_Str() << "':" << endl;
|
cout << "Read material #" << j-1 << " '" << name.data << "':" << endl;
|
||||||
for (uint i=0; i < aimat->mNumProperties; i++)
|
for (uint i=0; i < aimat->mNumProperties; i++)
|
||||||
cout << " " << aimat->mProperties[i]->mKey.C_Str() << endl;
|
cout << " " << aimat->mProperties[i]->mKey.data << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
aiColor3D color (1,1,1);
|
aiColor3D color (1,1,1);
|
||||||
|
@ -111,8 +110,32 @@ SceneNode* loadModelScene(const std::string& filename, const map<int, Material>&
|
||||||
// material.specular_color = {color4.r, color4.g, color4.b};
|
// material.specular_color = {color4.r, color4.g, color4.b};
|
||||||
|
|
||||||
aimat->Get(AI_MATKEY_SHININESS, material.shininess);
|
aimat->Get(AI_MATKEY_SHININESS, material.shininess);
|
||||||
|
//todo: opacity?
|
||||||
|
|
||||||
|
if (aimat->GetTextureCount(aiTextureType_DIFFUSE)) {
|
||||||
|
aiString path; aimat->GetTexture(aiTextureType_DIFFUSE, 0, &path);
|
||||||
|
if (DEBUG) cout << " diffuse texture path: " << dirname << "/" << path.data << endl;
|
||||||
|
material.diffuse_texture = loadPNGFileDynamic(dirname + "/" + path.data);
|
||||||
|
}
|
||||||
|
if (aimat->GetTextureCount(aiTextureType_NORMALS)) {
|
||||||
|
aiString path; aimat->GetTexture(aiTextureType_NORMALS, 0, &path);
|
||||||
|
if (DEBUG) cout << " normal texture path: " << dirname << "/" << path.data << endl;
|
||||||
|
material.normal_texture = loadPNGFileDynamic(dirname + "/" + path.data);
|
||||||
|
}
|
||||||
|
if (aimat->GetTextureCount(aiTextureType_DISPLACEMENT)) {
|
||||||
|
aiString path; aimat->GetTexture(aiTextureType_DISPLACEMENT, 0, &path);
|
||||||
|
if (DEBUG) cout << " displacement texture path: " << dirname << "/" << path.data << endl;
|
||||||
|
material.displacement_texture = loadPNGFileDynamic(dirname + "/" + path.data);
|
||||||
|
}
|
||||||
|
if (aimat->GetTextureCount(aiTextureType_REFLECTION)) {
|
||||||
|
aiString path; aimat->GetTexture(aiTextureType_REFLECTION, 0, &path);
|
||||||
|
if (DEBUG) cout << " displacement texture path: " << dirname << "/" << path.data << endl;
|
||||||
|
material.reflection_texture = loadPNGFileDynamic(dirname + "/" + path.data);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply material overriders to material list
|
||||||
for (auto override : overrides) {
|
for (auto override : overrides) {
|
||||||
Material& mat = (override.first>=0)
|
Material& mat = (override.first>=0)
|
||||||
? materials[override.first]
|
? materials[override.first]
|
||||||
|
@ -121,7 +144,6 @@ SceneNode* loadModelScene(const std::string& filename, const map<int, Material>&
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<Mesh> meshes( scene->mNumMeshes);
|
vector<Mesh> meshes( scene->mNumMeshes);
|
||||||
vector<PNGImage> textures(scene->mNumTextures);
|
|
||||||
vector<Material*> mat_lookup(scene->mNumMeshes); // to be passed to buildSceneNodes
|
vector<Material*> mat_lookup(scene->mNumMeshes); // to be passed to buildSceneNodes
|
||||||
|
|
||||||
// read meshes
|
// read meshes
|
||||||
|
@ -174,13 +196,8 @@ SceneNode* loadModelScene(const std::string& filename, const map<int, Material>&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// read textures
|
// build scene node tree:
|
||||||
j=0;
|
SceneNode* out = buildSceneNodes(scene->mRootNode, meshes, mat_lookup);
|
||||||
for (PNGImage& texture : textures) {
|
|
||||||
const aiTexture* aitex = scene->mTextures[j++];
|
|
||||||
// todo
|
|
||||||
}
|
|
||||||
SceneNode* out = buildSceneNodes(scene->mRootNode, meshes, textures, mat_lookup);
|
|
||||||
out->rotation.x += M_PI/2; // account for my weird coordinates. Z is upward damnit!
|
out->rotation.x += M_PI/2; // account for my weird coordinates. Z is upward damnit!
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,5 +8,6 @@
|
||||||
#define DEBUG false
|
#define DEBUG false
|
||||||
|
|
||||||
SceneNode* loadModelScene(
|
SceneNode* loadModelScene(
|
||||||
const std::string& filename,
|
const std::string& dirname,
|
||||||
|
const std::string& filename, //basename
|
||||||
const std::map<int, Material>& overrides={});
|
const std::map<int, Material>& overrides={});
|
||||||
|
|
Loading…
Reference in New Issue