Add texture support for models

This commit is contained in:
Peder Bergebakken Sundt 2019-03-22 00:01:14 +01:00
parent 8f7f0313f5
commit 2ade6919d1
4 changed files with 58 additions and 21 deletions

View File

@ -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});

View File

@ -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);

View File

@ -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;
} }

View File

@ -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={});