|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "rasterize.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool is_point_in_tri(Point p, Point p0, Point p1, Point p2) { |
|
|
|
Point v0, v1, v2; |
|
v0 = p2 - p0; |
|
v1 = p1 - p0; |
|
v2 = p - p0; |
|
|
|
|
|
float dot00 = v0.dot(v0); |
|
float dot01 = v0.dot(v1); |
|
float dot02 = v0.dot(v2); |
|
float dot11 = v1.dot(v1); |
|
float dot12 = v1.dot(v2); |
|
|
|
|
|
float inverDeno; |
|
if (dot00 * dot11 - dot01 * dot01 == 0) |
|
inverDeno = 0; |
|
else |
|
inverDeno = 1 / (dot00 * dot11 - dot01 * dot01); |
|
|
|
float u = (dot11 * dot02 - dot01 * dot12) * inverDeno; |
|
float v = (dot00 * dot12 - dot01 * dot02) * inverDeno; |
|
|
|
|
|
return (u >= 0) && (v >= 0) && (u + v < 1); |
|
} |
|
|
|
void get_point_weight(float *weight, Point p, Point p0, Point p1, Point p2) { |
|
|
|
Point v0, v1, v2; |
|
v0 = p2 - p0; |
|
v1 = p1 - p0; |
|
v2 = p - p0; |
|
|
|
|
|
float dot00 = v0.dot(v0); |
|
float dot01 = v0.dot(v1); |
|
float dot02 = v0.dot(v2); |
|
float dot11 = v1.dot(v1); |
|
float dot12 = v1.dot(v2); |
|
|
|
|
|
float inverDeno; |
|
if (dot00 * dot11 - dot01 * dot01 == 0) |
|
inverDeno = 0; |
|
else |
|
inverDeno = 1 / (dot00 * dot11 - dot01 * dot01); |
|
|
|
float u = (dot11 * dot02 - dot01 * dot12) * inverDeno; |
|
float v = (dot00 * dot12 - dot01 * dot02) * inverDeno; |
|
|
|
|
|
weight[0] = 1 - u - v; |
|
weight[1] = v; |
|
weight[2] = u; |
|
} |
|
|
|
|
|
|
|
|
|
void _get_tri_normal(float *tri_normal, float *vertices, int *triangles, int ntri, bool norm_flg) { |
|
int tri_p0_ind, tri_p1_ind, tri_p2_ind; |
|
float v1x, v1y, v1z, v2x, v2y, v2z; |
|
|
|
for (int i = 0; i < ntri; i++) { |
|
tri_p0_ind = triangles[3 * i]; |
|
tri_p1_ind = triangles[3 * i + 1]; |
|
tri_p2_ind = triangles[3 * i + 2]; |
|
|
|
|
|
v1x = vertices[3 * tri_p1_ind] - vertices[3 * tri_p0_ind]; |
|
v1y = vertices[3 * tri_p1_ind + 1] - vertices[3 * tri_p0_ind + 1]; |
|
v1z = vertices[3 * tri_p1_ind + 2] - vertices[3 * tri_p0_ind + 2]; |
|
|
|
v2x = vertices[3 * tri_p2_ind] - vertices[3 * tri_p0_ind]; |
|
v2y = vertices[3 * tri_p2_ind + 1] - vertices[3 * tri_p0_ind + 1]; |
|
v2z = vertices[3 * tri_p2_ind + 2] - vertices[3 * tri_p0_ind + 2]; |
|
|
|
if (norm_flg) { |
|
float c1 = v1y * v2z - v1z * v2y; |
|
float c2 = v1z * v2x - v1x * v2z; |
|
float c3 = v1x * v2y - v1y * v2x; |
|
float det = sqrt(c1 * c1 + c2 * c2 + c3 * c3); |
|
if (det <= 0) det = 1e-6; |
|
tri_normal[3 * i] = c1 / det; |
|
tri_normal[3 * i + 1] = c2 / det; |
|
tri_normal[3 * i + 2] = c3 / det; |
|
} else { |
|
tri_normal[3 * i] = v1y * v2z - v1z * v2y; |
|
tri_normal[3 * i + 1] = v1z * v2x - v1x * v2z; |
|
tri_normal[3 * i + 2] = v1x * v2y - v1y * v2x; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
void _get_ver_normal(float *ver_normal, float *tri_normal, int *triangles, int nver, int ntri) { |
|
int tri_p0_ind, tri_p1_ind, tri_p2_ind; |
|
|
|
for (int i = 0; i < ntri; i++) { |
|
tri_p0_ind = triangles[3 * i]; |
|
tri_p1_ind = triangles[3 * i + 1]; |
|
tri_p2_ind = triangles[3 * i + 2]; |
|
|
|
for (int j = 0; j < 3; j++) { |
|
ver_normal[3 * tri_p0_ind + j] += tri_normal[3 * i + j]; |
|
ver_normal[3 * tri_p1_ind + j] += tri_normal[3 * i + j]; |
|
ver_normal[3 * tri_p2_ind + j] += tri_normal[3 * i + j]; |
|
} |
|
} |
|
|
|
|
|
float nx, ny, nz, det; |
|
for (int i = 0; i < nver; ++i) { |
|
nx = ver_normal[3 * i]; |
|
ny = ver_normal[3 * i + 1]; |
|
nz = ver_normal[3 * i + 2]; |
|
|
|
det = sqrt(nx * nx + ny * ny + nz * nz); |
|
if (det <= 0) det = 1e-6; |
|
ver_normal[3 * i] = nx / det; |
|
ver_normal[3 * i + 1] = ny / det; |
|
ver_normal[3 * i + 2] = nz / det; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
void _get_normal(float *ver_normal, float *vertices, int *triangles, int nver, int ntri) { |
|
int tri_p0_ind, tri_p1_ind, tri_p2_ind; |
|
float v1x, v1y, v1z, v2x, v2y, v2z; |
|
|
|
|
|
|
|
float *tri_normal; |
|
tri_normal = new float[3 * ntri]; |
|
for (int i = 0; i < ntri; i++) { |
|
tri_p0_ind = triangles[3 * i]; |
|
tri_p1_ind = triangles[3 * i + 1]; |
|
tri_p2_ind = triangles[3 * i + 2]; |
|
|
|
|
|
v1x = vertices[3 * tri_p1_ind] - vertices[3 * tri_p0_ind]; |
|
v1y = vertices[3 * tri_p1_ind + 1] - vertices[3 * tri_p0_ind + 1]; |
|
v1z = vertices[3 * tri_p1_ind + 2] - vertices[3 * tri_p0_ind + 2]; |
|
|
|
v2x = vertices[3 * tri_p2_ind] - vertices[3 * tri_p0_ind]; |
|
v2y = vertices[3 * tri_p2_ind + 1] - vertices[3 * tri_p0_ind + 1]; |
|
v2z = vertices[3 * tri_p2_ind + 2] - vertices[3 * tri_p0_ind + 2]; |
|
|
|
|
|
tri_normal[3 * i] = v1y * v2z - v1z * v2y; |
|
tri_normal[3 * i + 1] = v1z * v2x - v1x * v2z; |
|
tri_normal[3 * i + 2] = v1x * v2y - v1y * v2x; |
|
|
|
} |
|
|
|
|
|
for (int i = 0; i < ntri; i++) { |
|
tri_p0_ind = triangles[3 * i]; |
|
tri_p1_ind = triangles[3 * i + 1]; |
|
tri_p2_ind = triangles[3 * i + 2]; |
|
|
|
for (int j = 0; j < 3; j++) { |
|
ver_normal[3 * tri_p0_ind + j] += tri_normal[3 * i + j]; |
|
ver_normal[3 * tri_p1_ind + j] += tri_normal[3 * i + j]; |
|
ver_normal[3 * tri_p2_ind + j] += tri_normal[3 * i + j]; |
|
} |
|
} |
|
|
|
|
|
float nx, ny, nz, det; |
|
for (int i = 0; i < nver; ++i) { |
|
nx = ver_normal[3 * i]; |
|
ny = ver_normal[3 * i + 1]; |
|
nz = ver_normal[3 * i + 2]; |
|
|
|
det = sqrt(nx * nx + ny * ny + nz * nz); |
|
if (det <= 0) det = 1e-6; |
|
ver_normal[3 * i] = nx / det; |
|
ver_normal[3 * i + 1] = ny / det; |
|
ver_normal[3 * i + 2] = nz / det; |
|
} |
|
|
|
delete[] tri_normal; |
|
} |
|
|
|
|
|
|
|
void _rasterize( |
|
unsigned char *image, float *vertices, int *triangles, float *colors, float *depth_buffer, |
|
int ntri, int h, int w, int c, float alpha, bool reverse) { |
|
int x, y, k; |
|
int tri_p0_ind, tri_p1_ind, tri_p2_ind; |
|
Point p0, p1, p2, p; |
|
int x_min, x_max, y_min, y_max; |
|
float p_depth, p0_depth, p1_depth, p2_depth; |
|
float p_color, p0_color, p1_color, p2_color; |
|
float weight[3]; |
|
|
|
for (int i = 0; i < ntri; i++) { |
|
tri_p0_ind = triangles[3 * i]; |
|
tri_p1_ind = triangles[3 * i + 1]; |
|
tri_p2_ind = triangles[3 * i + 2]; |
|
|
|
p0.x = vertices[3 * tri_p0_ind]; |
|
p0.y = vertices[3 * tri_p0_ind + 1]; |
|
p0_depth = vertices[3 * tri_p0_ind + 2]; |
|
p1.x = vertices[3 * tri_p1_ind]; |
|
p1.y = vertices[3 * tri_p1_ind + 1]; |
|
p1_depth = vertices[3 * tri_p1_ind + 2]; |
|
p2.x = vertices[3 * tri_p2_ind]; |
|
p2.y = vertices[3 * tri_p2_ind + 1]; |
|
p2_depth = vertices[3 * tri_p2_ind + 2]; |
|
|
|
x_min = max((int) ceil(min(p0.x, min(p1.x, p2.x))), 0); |
|
x_max = min((int) floor(max(p0.x, max(p1.x, p2.x))), w - 1); |
|
|
|
y_min = max((int) ceil(min(p0.y, min(p1.y, p2.y))), 0); |
|
y_max = min((int) floor(max(p0.y, max(p1.y, p2.y))), h - 1); |
|
|
|
if (x_max < x_min || y_max < y_min) { |
|
continue; |
|
} |
|
|
|
for (y = y_min; y <= y_max; y++) { |
|
for (x = x_min; x <= x_max; x++) { |
|
p.x = float(x); |
|
p.y = float(y); |
|
|
|
|
|
get_point_weight(weight, p, p0, p1, p2); |
|
|
|
|
|
if (weight[2] > 0 && weight[1] > 0 && weight[0] > 0) { |
|
get_point_weight(weight, p, p0, p1, p2); |
|
p_depth = weight[0] * p0_depth + weight[1] * p1_depth + weight[2] * p2_depth; |
|
|
|
if ((p_depth > depth_buffer[y * w + x])) { |
|
for (k = 0; k < c; k++) { |
|
p0_color = colors[c * tri_p0_ind + k]; |
|
p1_color = colors[c * tri_p1_ind + k]; |
|
p2_color = colors[c * tri_p2_ind + k]; |
|
|
|
p_color = weight[0] * p0_color + weight[1] * p1_color + weight[2] * p2_color; |
|
if (reverse) { |
|
image[(h - 1 - y) * w * c + x * c + k] = (unsigned char) ( |
|
(1 - alpha) * image[(h - 1 - y) * w * c + x * c + k] + alpha * 255 * p_color); |
|
|
|
} else { |
|
image[y * w * c + x * c + k] = (unsigned char) ( |
|
(1 - alpha) * image[y * w * c + x * c + k] + alpha * 255 * p_color); |
|
|
|
} |
|
} |
|
|
|
depth_buffer[y * w + x] = p_depth; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
void _rasterize_triangles( |
|
float *vertices, int *triangles, float *depth_buffer, int *triangle_buffer, float *barycentric_weight, |
|
int ntri, int h, int w) { |
|
int i; |
|
int x, y, k; |
|
int tri_p0_ind, tri_p1_ind, tri_p2_ind; |
|
Point p0, p1, p2, p; |
|
int x_min, x_max, y_min, y_max; |
|
float p_depth, p0_depth, p1_depth, p2_depth; |
|
float weight[3]; |
|
|
|
for (i = 0; i < ntri; i++) { |
|
tri_p0_ind = triangles[3 * i]; |
|
tri_p1_ind = triangles[3 * i + 1]; |
|
tri_p2_ind = triangles[3 * i + 2]; |
|
|
|
p0.x = vertices[3 * tri_p0_ind]; |
|
p0.y = vertices[3 * tri_p0_ind + 1]; |
|
p0_depth = vertices[3 * tri_p0_ind + 2]; |
|
p1.x = vertices[3 * tri_p1_ind]; |
|
p1.y = vertices[3 * tri_p1_ind + 1]; |
|
p1_depth = vertices[3 * tri_p1_ind + 2]; |
|
p2.x = vertices[3 * tri_p2_ind]; |
|
p2.y = vertices[3 * tri_p2_ind + 1]; |
|
p2_depth = vertices[3 * tri_p2_ind + 2]; |
|
|
|
x_min = max((int) ceil(min(p0.x, min(p1.x, p2.x))), 0); |
|
x_max = min((int) floor(max(p0.x, max(p1.x, p2.x))), w - 1); |
|
|
|
y_min = max((int) ceil(min(p0.y, min(p1.y, p2.y))), 0); |
|
y_max = min((int) floor(max(p0.y, max(p1.y, p2.y))), h - 1); |
|
|
|
if (x_max < x_min || y_max < y_min) { |
|
continue; |
|
} |
|
|
|
for (y = y_min; y <= y_max; y++) |
|
{ |
|
for (x = x_min; x <= x_max; x++) |
|
{ |
|
p.x = x; |
|
p.y = y; |
|
|
|
if (is_point_in_tri(p, p0, p1, p2)) { |
|
get_point_weight(weight, p, p0, p1, p2); |
|
p_depth = weight[0] * p0_depth + weight[1] * p1_depth + weight[2] * p2_depth; |
|
|
|
if ((p_depth > depth_buffer[y * w + x])) { |
|
depth_buffer[y * w + x] = p_depth; |
|
triangle_buffer[y * w + x] = i; |
|
for (k = 0; k < 3; k++) { |
|
barycentric_weight[y * w * 3 + x * 3 + k] = weight[k]; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
void _render_texture_core( |
|
float *image, float *vertices, int *triangles, |
|
float *texture, float *tex_coords, int *tex_triangles, |
|
float *depth_buffer, |
|
int nver, int tex_nver, int ntri, |
|
int h, int w, int c, |
|
int tex_h, int tex_w, int tex_c, |
|
int mapping_type) { |
|
int i; |
|
int x, y, k; |
|
int tri_p0_ind, tri_p1_ind, tri_p2_ind; |
|
int tex_tri_p0_ind, tex_tri_p1_ind, tex_tri_p2_ind; |
|
Point p0, p1, p2, p; |
|
Point tex_p0, tex_p1, tex_p2, tex_p; |
|
int x_min, x_max, y_min, y_max; |
|
float weight[3]; |
|
float p_depth, p0_depth, p1_depth, p2_depth; |
|
float xd, yd; |
|
float ul, ur, dl, dr; |
|
for (i = 0; i < ntri; i++) { |
|
|
|
tri_p0_ind = triangles[3 * i]; |
|
tri_p1_ind = triangles[3 * i + 1]; |
|
tri_p2_ind = triangles[3 * i + 2]; |
|
|
|
p0.x = vertices[3 * tri_p0_ind]; |
|
p0.y = vertices[3 * tri_p0_ind + 1]; |
|
p0_depth = vertices[3 * tri_p0_ind + 2]; |
|
p1.x = vertices[3 * tri_p1_ind]; |
|
p1.y = vertices[3 * tri_p1_ind + 1]; |
|
p1_depth = vertices[3 * tri_p1_ind + 2]; |
|
p2.x = vertices[3 * tri_p2_ind]; |
|
p2.y = vertices[3 * tri_p2_ind + 1]; |
|
p2_depth = vertices[3 * tri_p2_ind + 2]; |
|
|
|
|
|
tex_tri_p0_ind = tex_triangles[3 * i]; |
|
tex_tri_p1_ind = tex_triangles[3 * i + 1]; |
|
tex_tri_p2_ind = tex_triangles[3 * i + 2]; |
|
|
|
tex_p0.x = tex_coords[3 * tex_tri_p0_ind]; |
|
tex_p0.y = tex_coords[3 * tri_p0_ind + 1]; |
|
tex_p1.x = tex_coords[3 * tex_tri_p1_ind]; |
|
tex_p1.y = tex_coords[3 * tri_p1_ind + 1]; |
|
tex_p2.x = tex_coords[3 * tex_tri_p2_ind]; |
|
tex_p2.y = tex_coords[3 * tri_p2_ind + 1]; |
|
|
|
|
|
x_min = max((int) ceil(min(p0.x, min(p1.x, p2.x))), 0); |
|
x_max = min((int) floor(max(p0.x, max(p1.x, p2.x))), w - 1); |
|
|
|
y_min = max((int) ceil(min(p0.y, min(p1.y, p2.y))), 0); |
|
y_max = min((int) floor(max(p0.y, max(p1.y, p2.y))), h - 1); |
|
|
|
|
|
if (x_max < x_min || y_max < y_min) { |
|
continue; |
|
} |
|
|
|
for (y = y_min; y <= y_max; y++) |
|
{ |
|
for (x = x_min; x <= x_max; x++) |
|
{ |
|
p.x = x; |
|
p.y = y; |
|
if (p.x < 2 || p.x > w - 3 || p.y < 2 || p.y > h - 3 || is_point_in_tri(p, p0, p1, p2)) { |
|
get_point_weight(weight, p, p0, p1, p2); |
|
p_depth = weight[0] * p0_depth + weight[1] * p1_depth + weight[2] * p2_depth; |
|
|
|
if ((p_depth > depth_buffer[y * w + x])) { |
|
|
|
|
|
get_point_weight(weight, p, p0, p1, p2); |
|
|
|
tex_p = tex_p0 * weight[0] + tex_p1 * weight[1] + tex_p2 * weight[2]; |
|
tex_p.x = max(min(tex_p.x, float(tex_w - 1)), float(0)); |
|
tex_p.y = max(min(tex_p.y, float(tex_h - 1)), float(0)); |
|
|
|
yd = tex_p.y - floor(tex_p.y); |
|
xd = tex_p.x - floor(tex_p.x); |
|
for (k = 0; k < c; k++) { |
|
if (mapping_type == 0) |
|
{ |
|
image[y * w * c + x * c + k] = texture[int(round(tex_p.y)) * tex_w * tex_c + |
|
int(round(tex_p.x)) * tex_c + k]; |
|
} else |
|
{ |
|
ul = texture[(int) floor(tex_p.y) * tex_w * tex_c + (int) floor(tex_p.x) * tex_c + k]; |
|
ur = texture[(int) floor(tex_p.y) * tex_w * tex_c + (int) ceil(tex_p.x) * tex_c + k]; |
|
dl = texture[(int) ceil(tex_p.y) * tex_w * tex_c + (int) floor(tex_p.x) * tex_c + k]; |
|
dr = texture[(int) ceil(tex_p.y) * tex_w * tex_c + (int) ceil(tex_p.x) * tex_c + k]; |
|
|
|
image[y * w * c + x * c + k] = |
|
ul * (1 - xd) * (1 - yd) + ur * xd * (1 - yd) + dl * (1 - xd) * yd + |
|
dr * xd * yd; |
|
} |
|
|
|
} |
|
|
|
depth_buffer[y * w + x] = p_depth; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _write_obj_with_colors_texture(string filename, string mtl_name, |
|
float *vertices, int *triangles, float *colors, float *uv_coords, |
|
int nver, int ntri, int ntexver) { |
|
int i; |
|
|
|
ofstream obj_file(filename); |
|
|
|
|
|
obj_file << "mtllib " << mtl_name << endl; |
|
|
|
|
|
for (i = 0; i < nver; ++i) { |
|
obj_file << "v " << vertices[3 * i] << " " << vertices[3 * i + 1] << " " << vertices[3 * i + 2] << colors[3 * i] |
|
<< " " << colors[3 * i + 1] << " " << colors[3 * i + 2] << endl; |
|
} |
|
|
|
|
|
for (i = 0; i < ntexver; ++i) { |
|
|
|
obj_file << "vt " << uv_coords[2 * i] << " " << uv_coords[2 * i + 1] << endl; |
|
} |
|
|
|
obj_file << "usemtl FaceTexture" << endl; |
|
|
|
for (i = 0; i < ntri; ++i) { |
|
|
|
obj_file << "f " << triangles[3 * i + 2] << "/" << triangles[3 * i + 2] << " " << triangles[3 * i + 1] << "/" |
|
<< triangles[3 * i + 1] << " " << triangles[3 * i] << "/" << triangles[3 * i] << endl; |
|
} |
|
|
|
} |