Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define _USE_MATH_DEFINES
- #include<iostream>
- #include<cmath>
- #include<algorithm>
- #include <optional>
- #define NOMINMAX
- #include <d3d12.h>
- #include "SimpleMath.h"
- #include "tgaimage.h"
- #include "model.h"
- #include "Camera.h"
- #include "string"
- using namespace DirectX::SimpleMath;
- std::ostream& operator<< (std::ostream& a, Vector3& v) {
- return a << v.x << " " << v.y << " " << v.z << " ";
- }
- std::ostream& operator<< (std::ostream& a, Vector4& v) {
- return a << v.x << " " << v.y << " " << v.z << " " << v.w << " ";
- }
- const TGAColor white = TGAColor(255, 255, 255, 255);
- const TGAColor red = TGAColor(255, 0, 0, 255);
- Vector3 barycentric(Vector2 A, Vector2 B, Vector2 C, Vector2 P) {
- Vector3 s[2];
- s[0].x = C.x - A.x;
- s[0].y = B.x - A.x;
- s[0].z = A.x - P.x;
- s[1].x = C.y - A.y;
- s[1].y = B.y - A.y;
- s[1].z = A.y - P.y;
- Vector3 u = s[0].Cross(s[1]);
- if (std::abs(u.z) > 1e-2) return Vector3(1.f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z);
- return Vector3(-1, 1, 1);
- }
- Model* model = NULL;
- Vector3 light_dir(1, 0, 1);
- Camera camera;
- struct IShader {
- virtual ~IShader() {};
- virtual Vector3 vertex(int iface, int nthvert, Matrix world) = 0;
- virtual bool fragment(Vector3 bar, TGAColor& color) = 0;
- };
- struct Shader : public IShader {
- Vector3 varying_intensity;
- mat<2, 3, float> varying_uv;
- virtual Vector3 vertex(int iface, int nthvert, Matrix world) {
- varying_uv.set_col(nthvert, model->uv(iface, nthvert));
- float light_coeff = model->normal(iface, nthvert).Dot(light_dir);
- float val = std::max(0.f, light_coeff);
- if (nthvert == 0) varying_intensity.x = val;
- else if (nthvert == 1) varying_intensity.y = val;
- else if (nthvert == 2) varying_intensity.z = val;
- Vector3 vert = model->vert(iface, nthvert);
- Vector4 gl_Vertex(vert);
- gl_Vertex.w = 1;
- gl_Vertex = Vector4::Transform(gl_Vertex, world);
- Vector4 camera_coordinates = camera.ProjectToCamera(gl_Vertex);
- return Vector3(camera_coordinates.x / camera_coordinates.w,
- camera_coordinates.y / camera_coordinates.w,
- camera_coordinates.z / camera_coordinates.w);
- }
- virtual bool fragment(Vector3 bar, TGAColor& color) {
- auto uv = varying_uv * vec<3, float>(bar.x, bar.y, bar.z);
- float intensity = varying_intensity.Dot(bar);
- intensity = std::max(0.f, std::min(intensity, 1.f));
- color = model->diffuse(uv) * intensity;
- return false;
- }
- };
- void line(int x0, int y0, int x1, int y1, TGAImage& image, TGAColor color) {
- bool steep = false;
- if (std::abs(x0 - x1) < std::abs(y0 - y1)) {
- std::swap(x0, y0);
- std::swap(x1, y1);
- steep = true;
- }
- if (x0 > x1) {
- std::swap(x0, x1);
- std::swap(y0, y1);
- }
- int dx = x1 - x0;
- int dy = y1 - y0;
- float derror = std::abs(dy / float(dx));
- float error = 0;
- int y = y0;
- for (int x = x0; x <= x1; x++) {
- if (steep) image.set(y, x, color);
- else image.set(x, y, color);
- error += derror;
- if (error > .5) {
- y += (y1 > y0 ? 1 : -1);
- error -= 1.;
- }
- }
- }
- void triangle(Vector3* pts, IShader& shader, TGAImage& image, TGAImage& zbuffer) {
- Vector2 bboxmin(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
- Vector2 bboxmax(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max());
- for (int i = 0; i < 3; i++) {
- bboxmin.x = std::min(bboxmin.x, pts[i].x);
- bboxmax.x = std::max(bboxmax.x, pts[i].x);
- bboxmin.y = std::min(bboxmin.y, pts[i].y);
- bboxmax.y = std::max(bboxmax.y, pts[i].y);
- }
- Vec2i P;
- TGAColor color;
- for (P.x = bboxmin.x; P.x <= bboxmax.x; P.x++) {
- for (P.y = bboxmin.y; P.y <= bboxmax.y; P.y++) {
- Vector3 c = barycentric(Vector2(pts[0].x, pts[0].y),
- Vector2(pts[1].x, pts[1].y),
- Vector2(pts[2].x, pts[2].y),
- Vector2(static_cast<float>(P.x), static_cast<float>(P.y)));
- float z = pts[0].z * c.x + pts[1].z * c.y + pts[2].z * c.z;
- int frag_depth = std::max(0, std::min(255, int(z + .5)));
- if (c.x < 0 || c.y < 0 || c.z < 0) continue;
- if (zbuffer.get(P.x, P.y)[0] >= frag_depth) continue;
- bool discard = shader.fragment(c, color);
- if (!discard) {
- zbuffer.set(P.x, P.y, TGAColor(frag_depth));
- image.set(P.x, P.y, color);
- }
- }
- }
- }
- void drawImage() {
- int width = 1000;
- int height = 1000;
- for (int a = 0;a <= 10;a++)
- {
- TGAImage image(width, height, TGAImage::RGB);
- TGAImage* zbuffer = new TGAImage(width, height, TGAImage::Format::GRAYSCALE);
- light_dir.Normalize();
- Vector3 eye(0, 0, 3);
- Vector3 center(0, 0, 0);
- Vector3 up(0, 1, 0);
- camera = Camera(eye, center, up, 1, 0.5, width, height);
- Shader shader;
- Matrix world = Matrix::Identity;
- model = new Model(R"(african_head.obj)");
- for (int i = 0; i < model->nfaces(); i++) {
- if (i % 100 == 0) {
- std::cout << i << '\r' << std::flush;
- }
- std::vector<int> face = model->face(i);
- Vector3 screen_coords[3];
- Vector3 model_coords[3];
- for (int j = 0; j < 3; j++) {
- Vector3 v = model->vert(face[j]);
- model_coords[j] = v;
- screen_coords[j] = shader.vertex(i, j, world);
- }
- triangle(screen_coords, shader, image, *zbuffer);
- }
- model = new Model(R"(african_head_eye_inner.obj)");
- for (int i = 0; i < model->nfaces(); i++) {
- if (i % 100 == 0) {
- std::cout << i << '\r' << std::flush;
- }
- std::vector<int> face = model->face(i);
- Vector3 screen_coords[3];
- Vector3 model_coords[3];
- for (int j = 0; j < 3; j++) {
- Vector3 v = model->vert(face[j]);
- model_coords[j] = v;
- screen_coords[j] = shader.vertex(i, j, Matrix::CreateRotationZ(a * 6.28 / 10));
- }
- triangle(screen_coords, shader, image, *zbuffer);
- }
- std::string name = "output" + std::to_string(a) + ".tga";
- image.flip_vertically();
- image.write_tga_file(name.c_str());
- system(name.c_str());
- }
- }
- int main() {
- drawImage();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement