计算机图形学头歌实训平台简单光照效果答案

第1关:纹理映射

main.cpp

#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include "model.h"
#include "geometry.h"
#include "pngimage.h"

using namespace std;
const double PI = acos(-1.0);

Vec3f barycentric(Vec3i *pts, Vec3f P)
{
	Vec3f u = Vec3f(pts[2].x - pts[0].x, pts[1].x - pts[0].x, pts[0].x - P.x) ^
		Vec3f(pts[2].y - pts[0].y, pts[1].y - pts[0].y, pts[0].y - P.y);
	/* `pts` and `P` has integer value as coordinates
	   so `abs(u[2])` < 1 means `u[2]` is 0, that means
	   triangle is degenerate, in this case return something with negative coordinates */
	if (std::abs(u.z) < 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(Model *model, Vec3i *pts, Vec2i *uv, PNGImage &image, float intensity, float *zbuffer)
{
	int minX = min({ pts[0].x, pts[1].x, pts[2].x });
	int maxX = max({ pts[0].x, pts[1].x, pts[2].x });
	int minY = min({ pts[0].y, pts[1].y, pts[2].y });
	int maxY = max({ pts[0].y, pts[1].y, pts[2].y });

	int width = image.get_width();
	int height = image.get_height();
	if (maxX >= width)
		maxX = width - 1;
	if (maxY >= height)
		maxY = height - 1;

	Vec3f P;
	for (P.x = minX; P.x <= maxX; P.x++) {
		for (P.y = minY; P.y <= maxY; P.y++) {
			Vec3f bc_screen = barycentric(pts, P);
			if (bc_screen.x < 0 || bc_screen.y < 0 || bc_screen.z < 0) continue;
			P.z = 0;
			Vec2i uvP;
			for (int i = 0; i < 3; i++)
			{
				P.z += pts[i].z * bc_screen[i];

				//4.由重心坐标和三角形顶点uv坐标计算三角形内部任意一点对应的uv坐标
				uvP.x += uv[i].x * bc_screen[i];
				uvP.y += uv[i].y * bc_screen[i];
				/********** Begin ********/

				/********** End *********/

			}
				
			if (zbuffer[int(P.x + P.y*width)] < P.z) {
				zbuffer[int(P.x + P.y*width)] = P.z;

				//5.由uv坐标获得三角形内部任意一点对应的纹理颜色值
				PNGColor color = model->diffuse(uvP);
				/********** Begin ********/

				/********** End *********/
				
				image.set(P.x, P.y, PNGColor(color.r*intensity, color.g*intensity, color.b*intensity, 255));
			}
		}
	}
}

Matrix projection(Vec3f eye, Vec3f center)
{
	Matrix m = Matrix::identity(4);
	m[3][2] = -1.f / (eye - center).norm();
	return m;
}

Matrix viewport(int x, int y, int w, int h, int depth) {
	Matrix m = Matrix::identity(4);
	m[0][3] = x + w / 2.f;
	m[1][3] = y + h / 2.f;
	m[2][3] = depth / 2.f;

	m[0][0] = w / 2.f;
	m[1][1] = h / 2.f;
	m[2][2] = depth / 2.f;
	return m;
}

Matrix lookat(Vec3f eye, Vec3f center, Vec3f up) {
	Vec3f z = (eye - center).normalize();
	Vec3f x = (up^z).normalize();
	Vec3f y = (z^x).normalize();
	Matrix res = Matrix::identity(4);
	for (int i = 0; i < 3; i++) {
		res[0][i] = x[i];
		res[1][i] = y[i];
		res[2][i] = z[i];
		res[i][3] = -center[i];
	}
	return res;
}

Matrix translation(Vec3f v) {
	Matrix Tr = Matrix::identity(4);
	Tr[0][3] = v.x;
	Tr[1][3] = v.y;
	Tr[2][3] = v.z;
	return Tr;
}

Matrix scale(float factorX, float factorY, float factorZ)
{
	Matrix Z = Matrix::identity(4);
	Z[0][0] = factorX;
	Z[1][1] = factorY;
	Z[2][2] = factorZ;
	return Z;
}

Matrix rotation_x(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[1][1] = R[2][2] = cosangle;
	R[1][2] = -sinangle;
	R[2][1] = sinangle;
	return R;
}

Matrix rotation_y(float angle)
{
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[2][2] = cosangle;
	R[0][2] = sinangle;
	R[2][0] = -sinangle;
	return R;
}

Matrix rotation_z(float angle) {
	angle = angle * PI / 180;
	float sinangle = sin(angle);
	float cosangle = cos(angle);

	Matrix R = Matrix::identity(4);
	R[0][0] = R[1][1] = cosangle;
	R[0][1] = -sinangle;
	R[1][0] = sinangle;
	return R;
}

int main(int argc, char** argv)
{
	const int width = 800;
	const int height = 800;
	const int depth = 255;

	//generate some image
	PNGImage image(width, height, PNGImage::RGBA); //Error when RGB because lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size() in encode
	image.init(PNGColor(0, 0, 0, 255));
	Model *model = new Model("african_head.obj");

	float *zbuffer = new float[width*height];
	for (int i = 0; i < width * height; i++)
		zbuffer[i] = -numeric_limits<float>::max();

	Vec3f eye(0, 0, 3),center(0, 0, 0), up(0, 1, 0);
	Vec3f light_dir(0, 0, -1);

	Matrix ModelView = Matrix::identity(4);;
	Matrix Projection = projection(eye, center);
	Matrix ViewPort = viewport(width / 8, height / 8, width * 3 / 4, height * 3 / 4, depth);
	Matrix VP = ViewPort * Projection;

	for (int i = 0; i < model->nfaces(); i++)
	{
		vector<int> face = model->face(i);
		{
			Vec3f world_coords[3];
			Vec3i screen_coords[3];
			for (int j = 0; j < 3; j++)
			{
				world_coords[j] = model->vert(face[j]);
				screen_coords[j] = VP * world_coords[j];
			}

			Vec3f n = (world_coords[2] - world_coords[0]) ^ (world_coords[1] - world_coords[0]);

			n.normalize();
			float intensity = n * light_dir;
			if (intensity > 0) {
				    // 2.获得三角形顶点的uv坐标
					Vec2i uv[3];
					for (int k = 0; k < 3; k++) {
					uv[k] = model->uv(i, k);
					}
					/********** Begin ********/

					/********** End *********/

				triangle(model, screen_coords, uv, image, intensity, zbuffer);
			}
		}
	}

	image.flip_vertically(); // i want to have the origin at the left bottom corner of the image
	image.write_png_file("../img_step1/test.png");
	delete model;
	delete zbuffer;
	return 0;
}

model.cpp

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <vector>
#include "model.h"

Model::Model(const char *filename) : verts_(), faces_(), norms_(), uv_() {
    std::ifstream in;
    in.open (filename, std::ifstream::in);
    if (in.fail()) return;
    std::string line;
    while (!in.eof()) {
        std::getline(in, line);
        std::istringstream iss(line.c_str());
        char trash;
        if (!line.compare(0, 2, "v ")) {
            iss >> trash;
            Vec3f v;
            for (int i=0;i<3;i++) iss >> v[i];
            verts_.push_back(v);
        } else if (!line.compare(0, 3, "vn ")) {
            iss >> trash >> trash;
            Vec3f n;
            for (int i=0;i<3;i++) iss >> n[i];
            norms_.push_back(n);
        } else if (!line.compare(0, 3, "vt ")) {
            iss >> trash >> trash;
            Vec2f uv;
            for (int i=0;i<2;i++) iss >> uv[i];
            uv_.push_back(uv);
        }  else if (!line.compare(0, 2, "f ")) {
            std::vector<Vec3i> f;
            Vec3i tmp;
            iss >> trash;
            while (iss >> tmp[0] >> trash >> tmp[1] >> trash >> tmp[2]) {
                for (int i=0; i<3; i++) tmp[i]--; // in wavefront obj all indices start at 1, not zero
                f.push_back(tmp);
            }
            faces_.push_back(f);
        }
    }

    // 1.加载纹理文件
    load_texture(filename, "_diffuse.png", diffusemap_);
    /********** Begin ********/

    /********** End *********/	
}

Model::~Model() {
}

int Model::nverts() {
    return (int)verts_.size();
}

int Model::nfaces() {
    return (int)faces_.size();
}

std::vector<int> Model::face(int idx) {
	std::vector<int> face;
	for (int i = 0; i < (int)faces_[idx].size(); i++) face.push_back(faces_[idx][i][0]);
	return face;
}

Vec3f Model::vert(int i) {
    return verts_[i];
}

void Model::load_texture(std::string filename, const char *suffix, PNGImage &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_png_file(texfile.c_str()) ? "ok" : "failed") << std::endl;
		img.flip_vertically();
	}
}

PNGColor Model::diffuse(Vec2i uv) {
    // 6.由uv坐标获得纹理颜色值
    return diffusemap_.get(uv.x, uv.y);
    /********** Begin ********/

    /********** End *********/	
}

Vec2i Model::uv(int iface, int nvert) {
    // 3.由三角形面的索引和顶点编号获得三角形顶点的uv坐标
	int idx = faces_[iface][nvert][1];
	return Vec2i(uv_[idx].x*diffusemap_.get_width(), uv_[idx].y*diffusemap_.get_height());
    /********** Begin ********/

    /********** End *********/

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值