diff --git a/OpenWindow/OpenWindow.vcxproj b/OpenWindow/OpenWindow.vcxproj index f617bbd..d97a814 100644 --- a/OpenWindow/OpenWindow.vcxproj +++ b/OpenWindow/OpenWindow.vcxproj @@ -121,6 +121,7 @@ + @@ -129,6 +130,7 @@ + diff --git a/OpenWindow/OpenWindow.vcxproj.filters b/OpenWindow/OpenWindow.vcxproj.filters index 89db46c..a9845d1 100644 --- a/OpenWindow/OpenWindow.vcxproj.filters +++ b/OpenWindow/OpenWindow.vcxproj.filters @@ -36,6 +36,9 @@ Source Files + + Source Files + @@ -56,5 +59,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/OpenWindow/african_head_spec.tga b/OpenWindow/african_head_spec.tga new file mode 100644 index 0000000..12e02ce Binary files /dev/null and b/OpenWindow/african_head_spec.tga differ diff --git a/OpenWindow/camera.cpp b/OpenWindow/camera.cpp index 91c8729..b434b70 100644 --- a/OpenWindow/camera.cpp +++ b/OpenWindow/camera.cpp @@ -79,27 +79,31 @@ void Camera::move_camera_forward() { void Camera::move_camera_backward() { position = position - forward * movement_speed; } +void Camera::rise() { + position = position + Vec3f(0, movement_speed, 0); +} +void Camera::fall() { + position = position - Vec3f(0, movement_speed, 0); +} void Camera::SetMovementSpeed(float speed) { movement_speed = speed; } void Camera::ApplyChanges() { - forward = Vec3f(sin(rotation.y * DEG2RAD), -sin(rotation.x * DEG2RAD), -cosf(rotation.y*DEG2RAD) * cosf(rotation.x*DEG2RAD)); - right = Vec3f(cos(rotation.y*DEG2RAD), 0, sin(rotation.y * DEG2RAD)); - up = cross(right, forward); + forward = Vec3f(sin(rotation.y * DEG2RAD), -sin(rotation.x * DEG2RAD), -cosf(rotation.y*DEG2RAD) * cosf(rotation.x*DEG2RAD)).normalize(); + right = Vec3f(cos(rotation.y*DEG2RAD), 0, sin(rotation.y * DEG2RAD)).normalize(); + up = cross(right, forward).normalize(); } Matrix Camera::GetModelViewMatrix() { Vec3f center = position + forward; - Vec3f z = (position - center).normalize(); - Vec3f x = cross(up, z).normalize(); - Vec3f y = cross(z, x).normalize(); + Vec3f z = forward * -1; Matrix Minv = Matrix::identity(); Matrix Tr = Matrix::identity(); for (int i = 0; i < 3; i++) { - Minv[0][i] = x[i]; - Minv[1][i] = y[i]; + Minv[0][i] = right[i]; + Minv[1][i] = up[i]; Minv[2][i] = z[i]; Tr[i][3] = -center[i]; } diff --git a/OpenWindow/camera.h b/OpenWindow/camera.h index c3c3746..b1c4e14 100644 --- a/OpenWindow/camera.h +++ b/OpenWindow/camera.h @@ -40,6 +40,8 @@ public: void move_camera_right(); void move_camera_forward(); void move_camera_backward(); + void rise(); + void fall(); void ApplyChanges(); Matrix GetModelViewMatrix(); diff --git a/OpenWindow/main.cpp b/OpenWindow/main.cpp index da1378c..5d5e7dc 100644 --- a/OpenWindow/main.cpp +++ b/OpenWindow/main.cpp @@ -11,6 +11,8 @@ const int screen_height = 1000; int prev_mouse_x = screen_width/2; int prev_mouse_y = screen_height/2; +float TIME = 0; + int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { HWND hwnd; @@ -52,11 +54,16 @@ bool HandleButtonPressed() { camera.move_camera_right(); if (GetAsyncKeyState(VK_LEFT) & 0x8000) camera.move_camera_left(); + if (GetAsyncKeyState(VK_SPACE) & 0x8000) + camera.rise(); + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + camera.fall(); return true; } void CALLBACK FixedUpdate(HWND hwnd, UINT message, UINT uInt, DWORD dWord) { + TIME += 0.167; HandleButtonPressed(); camera.ApplyChanges(); render(); diff --git a/OpenWindow/model.cpp b/OpenWindow/model.cpp index d712c83..8ddf0cc 100644 --- a/OpenWindow/model.cpp +++ b/OpenWindow/model.cpp @@ -48,7 +48,7 @@ Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_(), diffus std::cerr << "# v# " << verts_.size() << " f# " << faces_.size() << " vt# " << uv_.size() << " vn# " << norms_.size() << std::endl; load_texture(filename, "_diffuse.tga", diffusemap_); load_texture(filename, "_nm_tangent.tga", normalmap_); - //load_texture(filename, "_spec.tga", specularmap_); + load_texture(filename, "_spec.tga", specularmap_); } Model::~Model() {} diff --git a/OpenWindow/renderer.cpp b/OpenWindow/renderer.cpp index f6bfc10..e7e87e3 100644 --- a/OpenWindow/renderer.cpp +++ b/OpenWindow/renderer.cpp @@ -8,192 +8,33 @@ #include "util_window.h" #include #include "camera.h" +#include "util_renderer.h" -#define HORIZONTAL_CAMERA_SPEED 0.1 -#define VERTICAL_CAMERA_SPEED 0.1 +#define HORIZONTAL_CAMERA_SPEED 0.1 +#define VERTICAL_CAMERA_SPEED 0.1 #define VERTICAL_CAMERA_CLAMP_UP 90 #define VERTICAL_CAMERA_CLAMP_DOWN -90 #define NEAR_CLIP_PLANE 0 -#define FAR_CLIP_PLANE 15 +#define FAR_CLIP_PLANE 10 #define FOV 30 -#define DEFAULT_CAMERA_POS Vec3f(0, 0, 5) -#define DEFAULT_CAMERA_ROT Vec3f(0, 0, 0) -#define CAMERA_MOVEMENT_SPEED 1.f +#define CAMERA_MOVEMENT_SPEED 0.05f +#define DEFAULT_CAMERA_POS Vec3f(0, 0, 5) +#define DEFAULT_CAMERA_ROT Vec3f(0, 0, 0) +#define LIGHT_INTENSITY 1 const TGAColor white = TGAColor(255, 255, 255, 255); const TGAColor red = TGAColor(255, 0, 0, 255); const TGAColor green = TGAColor(0, 255, 0, 255); const TGAColor blue = TGAColor(0, 0, 255, 255); -bool wireframe = false; - +Matrix ViewPort = Matrix::identity(); +Matrix ModelView = Matrix::identity(); +Matrix Projection = Matrix::identity(); Model* model = new Model("african_head.obj"); Camera camera; -float* z_buffer = new float[screen_width * screen_height]; -Vec3f light_dir = Vec3f(0, 0, 1).normalize(); - -Matrix viewport(int x, int y, int w, int h) { - Matrix m = Matrix::identity(); - m[0][3] = x + w / 2.f; - m[1][3] = y + h / 2.f; - m[2][3] = (FAR_CLIP_PLANE-NEAR_CLIP_PLANE) / 2.f; - - m[0][0] = w / 2.f; - m[1][1] = h / 2.f; - m[2][2] = (FAR_CLIP_PLANE+NEAR_CLIP_PLANE) / 2.f; - return m; -} - -void line(Vec3f p0, Vec3f p1, TGAColor color) -{ - bool steep = false; - - if (std::abs(p0[0] - p1[0]) < std::abs(p0[1] - p1[1])) { - std::swap(p0[0], p0[1]); - std::swap(p1[0], p1[1]); - steep = true; - - } - - if (p0[0] > p1[0]) { - std::swap(p0[0], p1[0]); - std::swap(p0[1], p1[1]); - } - - int dx = p1[0] - p0[0]; - int dy = p1[1] - p0[1]; - int derror2 = std::abs(dy) * 2; - int error2 = 0; - int y = p0[1]; - int y_step = p1[1] > p0[1] ? 1 : -1; - int dx_2 = 2 * dx; - - for (int x = p0[0]; x <= p1[0]; x++) { - if (steep) { - set_pixel(y, x, color_to_int(color)); - } - else { - set_pixel(x, y, color_to_int(color)); - } - error2 += derror2; - if (error2 > dx) { - y += (y_step); - error2 -= dx_2; - } - } -} - -Vec3f barycentric(Vec3f* pts, Vec3f P) -{ - Vec3f u = cross( - Vec3f(pts[2][0] - pts[0][0], pts[1][0] - pts[0][0], pts[0][0] - P[0]), // AC_x, AB_x, distance_x - Vec3f(pts[2][1] - pts[0][1], pts[1][1] - pts[0][1], pts[0][1] - P[1]) // AC_y, AB_y, distance_y - ); - - if (std::abs(u[2]) < 1) return Vec3f(-1, 1, 1); - return Vec3f(1.f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z); -} - - -void triangle( - Vec3f* pts, // Needed - Vec2f* diff_pts, // Should be removed - Model* model, - float* intensities) -{ - - if (pts[0].y == pts[1].y && pts[0].y == pts[2].y) return; // i dont care about degenerate triangles - if (pts[0].y > pts[1].y) { - std::swap(pts[0], pts[1]); - if(diff_pts) - std::swap(diff_pts[0], diff_pts[1]); - if(intensities) - std::swap(intensities[0], intensities[1]); - } - if (pts[0].y > pts[2].y) { - std::swap(pts[0], pts[2]); - if(diff_pts) - std::swap(diff_pts[0], diff_pts[2]); - if(intensities) - std::swap(intensities[0], intensities[2]); - } - if (pts[1].y > pts[2].y) { - std::swap(pts[1], pts[2]); - if(diff_pts) - std::swap(diff_pts[1], diff_pts[2]); - if(intensities) - std::swap(intensities[1], intensities[2]); - } - - if (wireframe) - { - line(pts[0], pts[1], white); - line(pts[1], pts[2], white); - line(pts[2], pts[0], white); - return; - } - - Vec2i bounding_box_min(screen_width - 1, screen_height - 1); - Vec2i bounding_box_max(0, 0); - Vec2i clamp(screen_width - 1, screen_height - 1); - TGAColor color = white; - - #pragma omp parallel for - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - bounding_box_min[j] = std::fmax(0, std::fmin(bounding_box_min[j], (int)pts[i][j])); - bounding_box_max[j] = std::fmin(clamp[j], std::fmax(bounding_box_max[j], (int)pts[i][j])); - } - } - - Vec3f P; - #pragma omp parallel for - for (P.x = bounding_box_min.x; P.x <= bounding_box_max.x; P.x++) { - for (P.y = bounding_box_min.y; P.y <= bounding_box_max.y; P.y++) { - Vec3f bc_coord = barycentric(pts, P); - if (bc_coord.x < 0 || bc_coord.y < 0 || bc_coord.z < 0) continue; - - - float intensity = - intensities[0] - + (intensities[1] - intensities[0]) * bc_coord[1] - + (intensities[2] - intensities[0]) * bc_coord[2]; - - - // Interpolating Z using the barycentric coordinates - P.z = 0; - for (int i = 0; i < 3; i++) P.z += pts[i][2] * bc_coord[i]; - - // Coloring according to the Z-Buffer - if (P.z > z_buffer[(int)(P.x + P.y * screen_width)] && P.z > 0) - { - z_buffer[(int)(P.x + P.y * screen_width)] = P.z; - - // If diff_pts (Diffusemap Points) were passed, then find the - // color of the current pixel - if (diff_pts) { - Vec2f diff_pt = - diff_pts[0] - + (diff_pts[1] - diff_pts[0]) * bc_coord[1] - + (diff_pts[2] - diff_pts[0]) * bc_coord[2]; - - color = model->diffuse(diff_pt); - } - color = color * intensity; - set_pixel(P.x, P.y, color_to_int(color)); - //char debugStr[200]; - //sprintf_s(debugStr, "%f\n", P.z); - //OutputDebugString(debugStr); - } - } - } -} - -int color_to_int(TGAColor col) { - return (col[2] << 16) | (col[1] << 8) | col[0]; -} +Vec3f light_dir = Vec3f(1, 1, 1).normalize(); void init_camera() { camera.SetPosition(DEFAULT_CAMERA_POS); @@ -215,49 +56,62 @@ void clear_zbuffer() z_buffer[i] = INT_MIN; } -Matrix ViewPort = Matrix::identity(); -Matrix Projection = Matrix::identity(); -Matrix ModelView = Matrix::identity(); + +struct TextureShader : public IShader { + mat<2, 3, float> varying_uv_coords; + Matrix uniform_mit; + Matrix uniform_m; + + virtual Vec4f vertex(int iface, int nthvert) { + varying_uv_coords.set_col(nthvert, model->uv(iface, nthvert)); + Vec4f gl_Vertex = embed<4>(model->vert(iface, nthvert)); // read the vertex from .obj file + return ViewPort * Projection * ModelView * gl_Vertex; // transform it to screen coordinates + } + + virtual bool fragment(Vec3f bar, TGAColor &color) { + Vec2f uv = varying_uv_coords * bar; + Vec3f normal = Vec3f(uniform_mit * Vec4f(model->normal(uv))).normalize(); + Vec3f light = Vec3f(uniform_m * Vec4f(light_dir)).normalize(); + float intensity = std::fmax(0.f, (normal*light*LIGHT_INTENSITY)); + color = model->diffuse(uv) * intensity * (cos(TIME * 10 * uv.x) + sin(TIME * 10 * uv.y)); + return false; + } +}; + void render() { - light_dir = camera.GetForward() * -1; - ViewPort = viewport(0, 0, screen_width, screen_height); - Projection = camera.GetProjectionMatrix(); - ModelView = camera.GetModelViewMatrix(); + { + light_dir = camera.GetForward().normalize() * -1; + } - Matrix z = ViewPort * Projection * ModelView * model->Transform; + { + viewport(0, 0, screen_width, screen_height, FAR_CLIP_PLANE, NEAR_CLIP_PLANE); + Projection = camera.GetProjectionMatrix(); + ModelView = camera.GetModelViewMatrix(); + } + + + //Matrix z = ViewPort * Projection * ModelView * model->Transform; clear_zbuffer(); + TextureShader shader; + shader.uniform_m = (Projection); + shader.uniform_mit = (Projection).invert_transpose(); + #pragma omp parallel for - 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 i = 0; i < model->nfaces(); i++) { + Vec4f screen_coords[3]; bool out = true; + #pragma omp parallel for + for (int j = 0; j < 3; j++) { + screen_coords[j] = shader.vertex(i, j); + Vec3f screen3(screen_coords[j]); - for (int j = 0; j < 3; j++) - { - Vec3f v = model->vert(face[j]); - Vec4f v4(v); - Vec3f coord(z * v4); - - if (coord.x > 0 && coord.x < screen_width - && coord.y > 0 && coord.y < screen_height) - out = false; - - screen_coords[j] = coord; - world_coords[j] = v; - diffuse_coords[j] = model->uv(i, j); - intensities[j] = model->normal(i, j) * light_dir; + if (screen3.x > 0 && screen3.x < screen_width && screen3.y > 0 && screen3.y < screen_height) out = false; } - - if (out) continue; - - triangle(screen_coords, diffuse_coords, model, intensities); + if(!out) + triangle(screen_coords, shader); } } diff --git a/OpenWindow/renderer.h b/OpenWindow/renderer.h index 9aef4a6..ae4152d 100644 --- a/OpenWindow/renderer.h +++ b/OpenWindow/renderer.h @@ -6,6 +6,7 @@ extern float* z_buffer; extern Camera camera; +extern float TIME; void init_camera(); void render(); diff --git a/OpenWindow/util_renderer.cpp b/OpenWindow/util_renderer.cpp new file mode 100644 index 0000000..669799b --- /dev/null +++ b/OpenWindow/util_renderer.cpp @@ -0,0 +1,73 @@ +#include "util_renderer.h" +#include "util_window.h" + +IShader::~IShader() {} + +float* z_buffer = new float[screen_width * screen_height]; + +void viewport(int x, int y, int w, int h, int far_plane, int near_plane) { + ViewPort[0][3] = x + w / 2.f; + ViewPort[1][3] = y + h / 2.f; + ViewPort[2][3] = (far_plane-near_plane) / 2.f; + + ViewPort[0][0] = w / 2.f; + ViewPort[1][1] = h / 2.f; + ViewPort[2][2] = (far_plane+near_plane) / 2.f; +} + +int color_to_int(TGAColor col) { + return (col[2] << 16) | (col[1] << 8) | col[0]; +} + +Vec3f barycentric(Vec3f* pts, Vec3f P) +{ + Vec3f u = cross( + Vec3f(pts[2][0] - pts[0][0], pts[1][0] - pts[0][0], pts[0][0] - P[0]), // AC_x, AB_x, distance_x + Vec3f(pts[2][1] - pts[0][1], pts[1][1] - pts[0][1], pts[0][1] - P[1]) // AC_y, AB_y, distance_y + ); + + if (std::abs(u[2]) < 1) return Vec3f(-1, 1, 1); + return Vec3f(1.f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z); +} + +void triangle( Vec4f* pts, IShader &shader) +{ + Vec3f pts3[3]; + for (int i = 0; i < 3; i++) + pts3[i] = Vec3f(pts[i]); + + if (pts3[0].y == pts3[1].y && pts3[0].y == pts3[2].y) return; // i dont care about degenerate triangles + //if (pts3[0].y > pts3[1].y) { std::swap(pts3[0], pts3[1]); } + //if (pts3[0].y > pts3[2].y) { std::swap(pts3[0], pts3[2]); } + //if (pts3[1].y > pts3[2].y) { std::swap(pts3[1], pts3[2]); } + + Vec2i bounding_box_min(screen_width - 1, screen_height - 1); + Vec2i bounding_box_max(0, 0); + Vec2i clamp(screen_width - 1, screen_height - 1); + + #pragma omp parallel for + for (int i = 0; i < 3; i++) + for (int j = 0; j < 2; j++) { + bounding_box_min[j] = std::fmax(0, std::fmin(bounding_box_min[j], (int)pts3[i][j])); + bounding_box_max[j] = std::fmin(clamp[j], std::fmax(bounding_box_max[j], (int)pts3[i][j])); + } + + + Vec3i P; + #pragma omp parallel for + for (P.x = bounding_box_min.x; P.x <= bounding_box_max.x; P.x++) { + for (P.y = bounding_box_min.y; P.y <= bounding_box_max.y; P.y++) { + Vec3f bc_coord = barycentric(pts3, P); + float frag_depth = 0; + for (int i = 0; i < 3; i++) + frag_depth += pts3[i][2] * bc_coord[i]; + if (bc_coord.x < 0 || bc_coord.y < 0 || bc_coord.z < 0 || z_buffer[ P.x + P.y * screen_width ]>frag_depth || frag_depth < 0) continue; + TGAColor color; + bool discard = shader.fragment(bc_coord, color); + if (!discard) { + z_buffer[P.x + P.y * screen_width] = frag_depth; + set_pixel(P.x, P.y, color_to_int(color)); + } + } + } +} \ No newline at end of file diff --git a/OpenWindow/util_renderer.h b/OpenWindow/util_renderer.h new file mode 100644 index 0000000..ff846fc --- /dev/null +++ b/OpenWindow/util_renderer.h @@ -0,0 +1,22 @@ +#pragma once +#include "tgaimage.h" +#include "model.h" +#include "geometry.h" + +extern Matrix ModelView; +extern Matrix ViewPort; +extern Matrix Projection; + +void viewport(int x, int y, int w, int h, int far, int near); + +struct IShader { + virtual ~IShader(); + virtual Vec4f vertex(int iface, int nthvert) = 0; + virtual bool fragment(Vec3f bar, TGAColor &color) = 0; +}; + +//void triangle(Vec4f *pts, IShader &shader, TGAImage &image, TGAImage &zbuffer); + +//void triangle( Vec3f* pts, Vec2f* diff_pts, Model* model, float* intensities) + +void triangle(Vec4f* pts, IShader &shader);