Games101 计算机图形学入门 作业3 以及可能遇见的问题

今天做了一下午的作业3,踩过的坑真的太多了!!!

下面做个汇总 大家以后也少走些弯路。

1.框架中有错误找不到成员。 这个是C++语言版本的问题,需要更改成C++17

Games101 计算机图形学入门 作业3 以及可能遇见的问题_第1张图片

Games101 计算机图形学入门 作业3 以及可能遇见的问题_第2张图片 

点击扩展设置

Games101 计算机图形学入门 作业3 以及可能遇见的问题_第3张图片 

 在这里更改成C++17

对于作业3中的第一步 光栅化。和作业2差不多,在这一起梳理一下。

光栅化  

1.转换得到三角形的坐标 并且构建包围盒

auto v = t.toVector4();
    float min_x = std::min(t.v[0].x(), std::min(t.v[1].x(), t.v[2].x()));
    float max_x = std::max(t.v[0].x(), std::max(t.v[1].x(), t.v[2].x()));
    float min_y = std::min(t.v[0].y(), std::min(t.v[1].y(), t.v[2].y()));
    float max_y = std::max(t.v[0].y(), std::max(t.v[1].y(), t.v[2].y()));

 值得注意的是 这里涉及到一个向上向下取整的问题。

    int x_min = std::floor(min_x);
	int x_max = std::ceil(max_x);
	int y_min = std::floor(min_y);
	int y_max = std::ceil(max_y);

 接下来

1.遍历此 bounding box 内的所有像素。

2.使用像素中心的屏幕空间坐标(x + 0.5, y+0.5,t.v)来检查中心点是否在三角形内。(作业1)

3.并且对进行插值的系数计算,求出z值,进行z-buffer计算 (作业2)

4.对于需要绘制的像素点,利用上一步计算的插值系数,分别插值出颜色、法向量、UV坐标值、没有经过透视变换的真实3D坐标,初始化结构体fragment_shader_payload

for (int i = x_min; i <= x_max; i++)
	{
		for (int j = y_min; j <= y_max; j++)
		{
			if (insideTriangle(i + 0.5, j + 0.5, t.v))
			{
				//Depth interpolated
				auto[alpha, beta, gamma] = computeBarycentric2D(i + 0.5, j + 0.5, t.v);

				float Z = 1.0 / (alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
				float zp = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();
				zp *= Z;

				if (zp < depth_buf[get_index(i, j)])
				{
					// color 
					auto interpolated_color = interpolate(alpha, beta, gamma, t.color[0], t.color[1], t.color[2], 1);
					// normal
					auto interpolated_normal = interpolate(alpha, beta, gamma, t.normal[0], t.normal[1], t.normal[2], 1).normalized();
					// texture
					auto interpolated_texcoords = interpolate(alpha, beta, gamma, t.tex_coords[0], t.tex_coords[1], t.tex_coords[2], 1);
					// shadingcoords
					auto interpolated_shadingcoords = interpolate(alpha, beta, gamma, view_pos[0], view_pos[1], view_pos[2], 1);

					// 用来传递插值结果的结构体
					fragment_shader_payload payload(interpolated_color, interpolated_normal, interpolated_texcoords, texture ? &*texture : nullptr);
					payload.view_pos = interpolated_shadingcoords;
					auto pixel_color = fragment_shader(payload);
					// 设置深度
					depth_buf[get_index(i, j)] = zp;
					// 设置颜色
					set_pixel(Eigen::Vector2i(i, j), pixel_color);
				}
			}

		}
	}
}

光栅化至此完成。

2. 接下来编写 phong_fragment_shader,函数需要我们填写光照计算,而 phong 模型中光照又由环境光、漫反射和镜面反射三种构成。

漫反射

Games101 计算机图形学入门 作业3 以及可能遇见的问题_第4张图片 其他博主在这方面讲解的特别清楚了,我就不再赘述了 最好看下学习笔记再听一次课。

直接上代码

Eigen::Vector3f phong_fragment_shader(const fragment_shader_payload& payload)
{
    Eigen::Vector3f ka = Eigen::Vector3f(0.005, 0.005, 0.005);
    Eigen::Vector3f kd = payload.color;
    Eigen::Vector3f ks = Eigen::Vector3f(0.7937, 0.7937, 0.7937);

    auto l1 = light{{20, 20, 20}, {500, 500, 500}};
    auto l2 = light{{-20, 20, 0}, {500, 500, 500}};

    std::vector lights = {l1, l2};
    Eigen::Vector3f amb_light_intensity{10, 10, 10};
    Eigen::Vector3f eye_pos{0, 0, 10};

    float p = 150;

    Eigen::Vector3f color = payload.color;
    Eigen::Vector3f point = payload.view_pos;
    Eigen::Vector3f normal = payload.normal;

    Eigen::Vector3f result_color = {0, 0, 0};
    for (auto& light : lights)
    {
        // TODO: For each light source in the code, calculate what the *ambient*, *diffuse*, and *specular* 
        // components are. Then, accumulate that result on the *result_color* object.
        result_color += ka.cwiseProduct(amb_light_intensity);
        Eigen::Vector3f light_pos = light.position - point;
        Eigen::Vector3f now_eye = eye_pos - point;
        float r2 = light_pos.dot(light_pos);
        result_color += kd.cwiseProduct (light.intensity / r2) * std::max(0.0f, normal.normalized().dot(light_pos.normalized()));
        
        result_color += ks.cwiseProduct (light.intensity / r2) * std:: pow(std::max(0.0f, now_eye.normalized().dot(reflect(light_pos, normal).normalized())), p);
    }

    return result_color * 255.f;

你可能感兴趣的:(c++)