📅  最后修改于: 2023-12-03 15:41:39.610000             🧑  作者: Mango
Gouraud底纹是计算机图形学中用于模拟光照效果的一种方法。通过在三维模型的表面上分别计算每个顶点的颜色,并根据三角形内部的线性插值来计算出每个像素的颜色,从而实现光照效果。
Gouraud底纹是通过计算每个顶点的颜色(以及表面法线向量、环境光、漫反射光、镜面反射光等信息),并根据三角形内部的线性插值来计算每个像素的颜色。因为计算是在顶点级别进行的,所以需要存储每个顶点的信息(即各种光照参数)。
具体来说,Gouraud底纹的计算过程如下:
其中,线性插值的公式如下:
$$ C_i = (1 - w - u)C_1 + uC_2 + wC_3 $$
其中,$C_1, C_2, C_3$ 为三个顶点的颜色,$w, u$ 分别代表像素距离 $C_1$ 和 $C_2$ 的距离占三角形边长的比例。
Gouraud底纹的实现主要分为两个步骤:
以下是C++代码片段,用于计算每个顶点的颜色:
struct Vertex {
Vector3f position;
Vector3f normal;
Vector3f color;
};
void compute_vertex_color(Vertex& v, const Vector3f& ambient, const Vector3f& light_pos, const Vector3f& light_color) {
// compute ambient color
Vector3f ambient_color = v.color * ambient;
// compute diffuse color
Vector3f to_light = (light_pos - v.position).normalized();
float diffuse = max(v.normal.dot(to_light), 0.0f);
Vector3f diffuse_color = v.color * light_color * diffuse;
// add ambient and diffuse color
v.color = ambient_color + diffuse_color;
}
以下是C++代码片段,用于生成底纹:
void generate_gouraud_mesh(const Mesh& mesh, const Vector3f& ambient, const Vector3f& light_pos, const Vector3f& light_color, std::vector<unsigned char>& image) {
// create a buffer for storing vertex colors
std::vector<Vector3f> vertex_colors(mesh.vertices.size());
// compute colors for all vertices
for (int i = 0; i < mesh.vertices.size(); i++) {
compute_vertex_color(mesh.vertices[i], ambient, light_pos, light_color);
vertex_colors[i] = mesh.vertices[i].color;
}
// iterate over all triangles and generate pixels
for (int i = 0; i < mesh.triangles.size(); i++) {
// get triangle vertices and colors
const Triangle& tri = mesh.triangles[i];
const Vector3f& c1 = vertex_colors[tri.i1];
const Vector3f& c2 = vertex_colors[tri.i2];
const Vector3f& c3 = vertex_colors[tri.i3];
// calculate triangle normal
Vector3f normal = (tri.v2 - tri.v1).cross(tri.v3 - tri.v1).normalized();
// calculate triangle bounding box
Vector2i min_pos, max_pos;
compute_bounding_box(tri, min_pos, max_pos, image.width(), image.height());
// iterate over pixels inside the bounding box
for (int y = min_pos.y(); y <= max_pos.y(); y++) {
for (int x = min_pos.x(); x <= max_pos.x(); x++) {
// check if pixel is inside triangle
Vector2f point(x + 0.5f, y + 0.5f);
float w = calculate_barycentric_weight(point, tri.v1, tri.v2, tri.v3);
if (w >= 0 && w <= 1) {
// calculate pixel color using Gouraud shading
float u = calculate_barycentric_weight(point, tri.v1, tri.v2, tri.v3);
Vector3f pixel_color = (1 - w - u) * c1 + u * c2 + w * c3;
// set pixel color
int index = x + y * image.width();
image[index * 3 + 0] = static_cast<unsigned char>(255 * pixel_color.x());
image[index * 3 + 1] = static_cast<unsigned char>(255 * pixel_color.y());
image[index * 3 + 2] = static_cast<unsigned char>(255 * pixel_color.z());
}
}
}
}
}
Gouraud底纹是一种简单有效的计算机图形学技术,可以用于模拟光照效果,使3D模型看起来更加真实。但它也有一些缺点,例如需要存储每个顶点的光照信息,且线性插值可能会导致细节丢失。因此,对于一些需要更精细光照效果的场景,我们可以考虑使用其他方法,例如Phong底纹、Blinn-Phong底纹等。