diff --git a/OpenWindow/ColladaModel.cpp b/OpenWindow/ColladaModel.cpp index 51db00e..9e5ede7 100644 --- a/OpenWindow/ColladaModel.cpp +++ b/OpenWindow/ColladaModel.cpp @@ -1,7 +1,18 @@ +#include +#include +#include #include "ColladaModel.h" +#define PI 3.14159265358979323846 +#define DEG2RAD PI/180 + ColladaModel::ColladaModel(const char* filename) : faces_(), vertices_(), normals_() { + Transform = Matrix::identity(); + Rotation = Matrix::identity(); + Scale = Matrix::identity(); + Translation = Matrix::identity(); + tinyxml2::XMLDocument doc; doc.LoadFile(filename); /////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -56,23 +67,112 @@ ColladaModel::ColladaModel(const char* filename) : faces_(), vertices_(), normal str_normal >> temp.z; normals_.push_back(temp); } + /////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////////////// + texcoord_count = 0; + tinyxml2::XMLElement* xml_texture = doc.FirstChildElement("COLLADA")->FirstChildElement("library_geometries")->FirstChildElement("geometry")->FirstChildElement("mesh")->FirstChildElement("source")->NextSiblingElement()->NextSiblingElement()->FirstChildElement("float_array"); + xml_texture->QueryIntAttribute("count", &texcoord_count); + std::stringstream str_texcoord(xml_texture->GetText()); + + for (int i = 0; i < texcoord_count / 2; i++) + { + Vec2f temp; + str_texcoord >> temp.x; + str_texcoord >> temp.y; + textureco_.push_back(temp); + } + + load_texture(filename, "_diffuse.tga", diffusemap_); + load_texture(filename, "_nm_tangent.tga", normalmap_); } ColladaModel::~ColladaModel() { } -std::vector ColladaModel::face(int idx) { - return faces_[idx]; +void ColladaModel::ApplyTransform() { + Transform = Translation * Scale * Rotation; } -Vec3f ColladaModel::vertex(int i) { - return vertices_[i]; +void ColladaModel::translate(Vec3f tr) { + Translation[0][3] += tr.x; + Translation[1][3] += tr.y; + Translation[2][3] += tr.z; } +void ColladaModel::rotate(Vec3f rot) { + rot = rot * DEG2RAD; -int ColladaModel::nvertices() { - return vertex_count; + Rotation[0][0] = cosf(rot.y) * cosf(rot.z); + Rotation[0][1] = -cosf(rot.y) * sinf(rot.z); + Rotation[0][2] = sinf(rot.y); + Rotation[1][0] = sinf(rot.x) * sinf(rot.y) * cosf(rot.z) + cosf(rot.x) * sinf(rot.z); + Rotation[1][1] = -sinf(rot.x) * sinf(rot.y) * sinf(rot.z) + cosf(rot.x) * cosf(rot.z); + Rotation[1][2] = -sinf(rot.x) * cosf(rot.y); + Rotation[2][0] = -cosf(rot.x) * sinf(rot.y) * cosf(rot.z) + sinf(rot.x) * sinf(rot.z); + Rotation[2][1] = cosf(rot.x) * sinf(rot.y) * sinf(rot.z) + sinf(rot.x) * cosf(rot.z); + Rotation[2][2] = cosf(rot.x) * cosf(rot.y); +} +void ColladaModel::scale(Vec3f scl) { + Scale[0][0] = scl.x; + Scale[1][1] = scl.y; + Scale[2][2] = scl.z; } int ColladaModel::nfaces() { return face_count; -} \ No newline at end of file +} +int ColladaModel::nvertices() { + return vertex_count; +} + +std::vector ColladaModel::face(int idx) { + std::vector face; + for (int i = 0; i < (int)faces_[idx].size(); i++) face.push_back(faces_[idx][i][0]); + return face; +} + +Vec3f ColladaModel::vertix(int i) { + return vertices_[i]; +} + +Vec3f ColladaModel::vertix(int iface, int nthvert) { + return vertices_[faces_[iface][nthvert][0]]; +} + +void ColladaModel::load_texture(std::string filename, const char* suffix, TGAImage& img) { + std::string texfile(filename); + size_t dot = texfile.find_last_of("."); + if (dot != std::string::npos) { + texfile = texfile.substr(0, dot) + std::string(suffix); + std::cerr << "texture file " << texfile << " loading " << (img.read_tga_file(texfile.c_str()) ? "ok" : "failed") << std::endl; + img.flip_vertically(); + } +} + +TGAColor ColladaModel::diffuse(Vec2f uvf) { + Vec2i uv(uvf[0] * diffusemap_.get_width(), uvf[1] * diffusemap_.get_height()); + return diffusemap_.get(uv[0], uv[1]); +} + +Vec3f ColladaModel::normal(Vec2f uvf) { + Vec2i uv(uvf[0] * normalmap_.get_width(), uvf[1] * normalmap_.get_height()); + TGAColor c = normalmap_.get(uv[0], uv[1]); + Vec3f res; + for (int i = 0; i < 3; i++) + res[2 - i] = (float)c[i] / 255.f * 2.f - 1.f; + return res; +} + +Vec2f ColladaModel::uv(int iface, int nthvert) { + return textureco_[faces_[iface][nthvert][2]]; +} + +float ColladaModel::specular(Vec2f uvf) { + Vec2i uv(uvf[0] * specularmap_.get_width(), uvf[1] * specularmap_.get_height()); + return specularmap_.get(uv[0], uv[1])[0] / 1.f; +} + +Vec3f ColladaModel::normal(int iface, int nthvert) { + int idx = faces_[iface][nthvert][1]; + return normals_[idx].normalize(); +} diff --git a/OpenWindow/ColladaModel.h b/OpenWindow/ColladaModel.h index 622cfa7..57bb70a 100644 --- a/OpenWindow/ColladaModel.h +++ b/OpenWindow/ColladaModel.h @@ -1,11 +1,12 @@ #ifndef __MODEL_s__ #define __MODEL_s__ - #pragma once #include "ColladaModel.h" #include "tinyxml2.h" #include "geometry.h" +#include "tgaimage.h" + #include #include #include @@ -16,31 +17,50 @@ #include #include - class ColladaModel { private: int face_count; int vertex_count; int normal_count; - int textureco_count; + int texcoord_count; - std::vector > faces_; + std::vector > faces_; //vertex/normal/uv std::vector vertices_; std::vector normals_; - std::vector textureco_; + std::vector textureco_; + + TGAImage diffusemap_; + TGAImage normalmap_; + TGAImage specularmap_; + + void load_texture(std::string filename, const char* suffix, TGAImage& img); public: ColladaModel(const char* filename); ~ColladaModel(); - std::vector face(int idx); - Vec3f vertex(int i); - Vec3f normal(int i); - Vec3f textureco(int i); - int nfaces(); int nvertices(); - int nnormals(); - int ntextureco(); -}; + Vec3f vertix(int iface, int nthvert); + Vec3f vertix(int i); + + Vec3f normal(int iface, int nthvert); + Vec3f normal(Vec2f uv); + + Vec2f uv(int iface, int nthvert); + + Matrix Transform; + Matrix Rotation; + Matrix Scale; + Matrix Translation; + + void translate(Vec3f tr); + void rotate(Vec3f rot); + void scale(Vec3f scl); + void ApplyTransform(); + + TGAColor diffuse(Vec2f uv); + float specular(Vec2f uv); + std::vector face(int idx); +}; #endif \ No newline at end of file diff --git a/OpenWindow/renderer.cpp b/OpenWindow/renderer.cpp index 4a77694..b96edd0 100644 --- a/OpenWindow/renderer.cpp +++ b/OpenWindow/renderer.cpp @@ -87,7 +87,7 @@ Vec3f barycentric(Vec3f* pts, Vec3f P) void triangle( Vec3f* pts, // Needed - Model* model, // Should be removed + ColladaModel* model, // Should be removed Vec2f* diff_pts, // Should be removed float* intensities, Vec3f camera_pos) // Not really sure yet @@ -186,77 +186,38 @@ Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) { return Minv * Tr; } -void my_triangle(Vec2i t0, Vec2i t1, Vec2i t2, TGAImage& image, TGAColor color) { - if (t0.y == t1.y && t0.y == t2.y) return; // i dont care about degenerate triangles - if (t0.y > t1.y) std::swap(t0, t1); - if (t0.y > t2.y) std::swap(t0, t2); - if (t1.y > t2.y) std::swap(t1, t2); - int total_height = t2.y - t0.y; - for (int i = 0; i < total_height; i++) { - bool second_half = i > t1.y - t0.y || t1.y == t0.y; - int segment_height = second_half ? t2.y - t1.y : t1.y - t0.y; - float alpha = (float)i / total_height; - float beta = (float)(i - (second_half ? t1.y - t0.y : 0)) / segment_height; // be careful: with above conditions no division by zero here - Vec2i A = t0 + (t2 - t0) * alpha; - Vec2i B = second_half ? t1 + (t2 - t1) * beta : t0 + (t1 - t0) * beta; - if (A.x > B.x) std::swap(A, B); - for (int j = A.x; j <= B.x; j++) { - image.set(j, t0.y + i, color); // attention, due to int casts t0.y+i != A.y - } - } -} - void render() { - //Model* model = new Model("african_head.obj"); - //Matrix ViewPort = viewport(screen_width / 8, screen_height / 8, screen_width * 3 / 4, screen_height * 3 / 4); - //Matrix Projection = Matrix::identity(); - //Matrix ModelView = lookat(eye, center, Vec3f(0, 1, 0)); - - //Projection[3][2] = -1.f / (eye - center).norm(); - - //Matrix z = ViewPort * Projection * ModelView * model->Transform; - - //init_zbuffer(); - //for (int i = 0; i < model->nfaces(); i++) - //{ - // std::vector face = model->face(i); - // Vec3f screen_coords[3]; - // Vec3f world_coords[3]; - // Vec2f diffuse_coords[3]; - // float intensities[3]; - - // for (int j = 0; j < 3; j++) - // { - // Vec3f v = model->vert(face[j]); - // Vec4f v4(v); - // Vec3f coord(z * v4); - - // screen_coords[j] = coord; - // world_coords[j] = v; - // diffuse_coords[j] = model->uv(i, j); - // intensities[j] = model->normal(i, j) * light_dir; - // } - - // triangle(screen_coords, model, diffuse_coords, intensities, Vec3f(0, 0, 5)); - //} - ColladaModel* model = new ColladaModel("african_head.dae"); - TGAImage image(800, 800, TGAImage::RGB); - Vec3f light_dir(0, 0, -1); - for (int i = 0; i < model->nfaces(); i++) { - std::vector face = model->face(i); - Vec2i screen_coords[3]; - Vec3f world_coords[3]; - for (int j = 0; j < 3; j++) { - Vec3f v = model->vertex(face[j][0]); - screen_coords[j] = Vec2i((v.x + 1.) * 800 / 2., (v.y + 1.) * 800 / 2.); - world_coords[j] = v; - } - my_triangle(screen_coords[0], screen_coords[1], screen_coords[2], image, white); - } + Matrix ViewPort = viewport(screen_width / 8, screen_height / 8, screen_width * 3 / 4, screen_height * 3 / 4); + Matrix Projection = Matrix::identity(); + Matrix ModelView = lookat(eye, center, Vec3f(0, 1, 0)); - image.flip_vertically(); // i want to have the origin at the left bottom corner of the image - image.write_tga_file("output.tga"); - delete model; + Projection[3][2] = -1.f / (eye - center).norm(); + + Matrix z = ViewPort * Projection * ModelView * model->Transform; + + init_zbuffer(); + for (int i = 0; i < model->nfaces(); i++) + { + std::vector face = model->face(i); + Vec3f screen_coords[3]; + Vec3f world_coords[3]; + Vec2f diffuse_coords[3]; + float intensities[3]; + + for (int j = 0; j < 3; j++) + { + Vec3f v = model->vertix(face[j]); + Vec4f v4(v); + Vec3f coord(z * v4); + + screen_coords[j] = coord; + world_coords[j] = v; + diffuse_coords[j] = model->uv(i, j); + intensities[j] = model->normal(i, j) * light_dir; + } + + triangle(screen_coords, model, diffuse_coords, intensities, Vec3f(0, 0, 5)); + } } \ No newline at end of file