完成作业
描述
实现
参数差值
在上次作业的rasterize_triangle
函数的基础上对插值部分做补充
if ( insideTriangle ( row+ 0.5f , col+ 0.5f , t. v) ) {
auto [ alpha, beta, gamma] = computeBarycentric2D ( row, col, t. v) ;
float w_reciprocal = 1.0 / ( alpha / v[ 0 ] . w ( ) + beta / v[ 1 ] . w ( ) + gamma / v[ 2 ] . w ( ) ) ;
float z_interpolated = alpha * v[ 0 ] . z ( ) / v[ 0 ] . w ( ) + beta * v[ 1 ] . z ( ) / v[ 1 ] . w ( ) + gamma * v[ 2 ] . z ( ) / v[ 2 ] . w ( ) ;
z_interpolated *= w_reciprocal;
int ind = get_index ( row, col) ;
if ( z_interpolated >= depth_buf[ ind] ) continue ;
depth_buf[ ind] = z_interpolated;
auto interpolated_color = interpolate ( alpha, beta, gamma, t. color[ 0 ] , t. color[ 1 ] , t. color[ 2 ] , 1 ) ;
auto interpolated_normal = interpolate ( alpha, beta, gamma, t. normal[ 0 ] , t. normal[ 1 ] , t. normal[ 2 ] , 1 ) ;
auto interpolated_texcoords = interpolate ( alpha, beta, gamma, t. tex_coords[ 0 ] , t. tex_coords[ 1 ] , t. tex_coords[ 2 ] , 1 ) ;
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. normalized ( ) , interpolated_texcoords, texture ? & * texture : nullptr ) ;
payload. view_pos = interpolated_shadingcoords;
auto pixel_color = fragment_shader ( payload) ;
set_pixel ( Eigen :: Vector2i ( row, col) , pixel_color) ;
}
Blinn-Phong反射模型
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< light> 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 } ;
Eigen:: Vector3f view_dir = ( eye_pos - point) . normalized ( ) ;
for ( auto & light : lights)
{
Eigen:: Vector3f diffuse ( 0 , 0 , 0 ) ;
Eigen:: Vector3f specular ( 0 , 0 , 0 ) ;
Eigen:: Vector3f ambient ( 0 , 0 , 0 ) ;
float rr = ( light. position - point) . squaredNorm ( ) ;
Eigen:: Vector3f light_dir = ( light. position - point) . normalized ( ) ;
for ( size_t i = 0 ; i < 3 ; i++ ) {
float intensity = light. intensity[ i] / rr;
Eigen:: Vector3f h = ( view_dir + light_dir) . normalized ( ) ;
diffuse[ i] = kd[ i] * intensity * std:: max ( 0.0f , normal. dot ( light_dir) ) ;
specular[ i] = ks[ i] * intensity * std:: pow ( std:: max ( 0.0f , normal. dot ( h) ) , p) ;
ambient[ i] = amb_light_intensity[ i] * ka[ i] ;
}
result_color += ( diffuse + specular + ambient) ;
}
return result_color * 255.f ;
}
纹理映射
在Blinn-Phong反射模型的基础上将漫反射系数k_d
更换为对应位置的纹理空间内的颜色值
Eigen:: Vector3f texture_fragment_shader ( const fragment_shader_payload& payload)
{
Eigen:: Vector3f return_color = { 0 , 0 , 0 } ;
if ( payload. texture)
{
return_color = payload. texture-> getColor ( payload. tex_coords. x ( ) , payload. tex_coords. y ( ) ) ;
}
Eigen:: Vector3f texture_color;
texture_color << return_color. x ( ) , return_color. y ( ) , return_color. z ( ) ;
Eigen:: Vector3f ka = Eigen :: Vector3f ( 0.005 , 0.005 , 0.005 ) ;
Eigen:: Vector3f kd = texture_color / 255.f ;
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< light> lights = { l1, l2} ;
Eigen:: Vector3f amb_light_intensity{ 10 , 10 , 10 } ;
Eigen:: Vector3f eye_pos{ 0 , 0 , 10 } ;
float p = 150 ;
Eigen:: Vector3f color = texture_color;
Eigen:: Vector3f point = payload. view_pos;
Eigen:: Vector3f normal = payload. normal;
Eigen:: Vector3f result_color = { 0 , 0 , 0 } ;
Eigen:: Vector3f view_dir = ( eye_pos - point) . normalized ( ) ;
for ( auto & light : lights)
{
Eigen:: Vector3f diffuse ( 0 , 0 , 0 ) ;
Eigen:: Vector3f specular ( 0 , 0 , 0 ) ;
Eigen:: Vector3f ambient ( 0 , 0 , 0 ) ;
float rr = ( light. position - point) . squaredNorm ( ) ;
Eigen:: Vector3f light_dir = ( light. position - point) . normalized ( ) ;
for ( size_t i = 0 ; i < 3 ; i++ ) {
float intensity = light. intensity[ i] / rr;
Eigen:: Vector3f h = ( view_dir + light_dir) . normalized ( ) ;
diffuse[ i] = kd[ i] * intensity * std:: max ( 0.0f , normal. dot ( light_dir) ) ;
specular[ i] = ks[ i] * intensity * std:: pow ( std:: max ( 0.0f , normal. dot ( h) ) , p) ;
ambient[ i] = amb_light_intensity[ i] * ka[ i] ;
}
result_color += ( diffuse + specular + ambient) ;
}
return result_color * 255.f ;
}
凹凸映射
完成bump_fragment_shader
和displacement_fragment_shader
函数 按照注释来就行
Dumping
Eigen:: Vector3f bump_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< light> 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;
float kh = 0.2 , kn = 0.1 ;
float x = normal. x ( ) , y = normal. y ( ) , z = normal. z ( ) ;
Eigen:: Vector3f t ( x* y/ sqrt ( x* x+ z* z) , sqrt ( x* x+ z* z) , z* y/ sqrt ( x* x+ z* z) ) ;
Eigen:: Vector3f b = normal. cross ( t) ;
Eigen:: Matrix3f TBN;
TBN << t, b, normal;
int w = payload. texture-> width, h = payload. texture-> height;
float u = payload. tex_coords. x ( ) , v = payload. tex_coords. y ( ) ;
payload. texture-> getColor ( u, v) ;
auto huv = payload. texture-> getColor ( u, v) . norm ( ) ;
float dU = kh * kn * ( payload. texture-> getColor ( u+ 1.0f / w, v) . norm ( ) - huv) ;
float dV = kh * kn * ( payload. texture-> getColor ( u, v+ 1.0f / h) . norm ( ) - huv) ;
Eigen:: Vector3f ln ( - dU, - dV, 1 ) ;
Eigen:: Vector3f n = ( TBN * ln) . normalized ( ) ;
Eigen:: Vector3f result_color = { 0 , 0 , 0 } ;
result_color = n;
return result_color * 255.f ;
}
Displacement
结合Blinn-Phong和Bump Mapping
Eigen:: Vector3f displacement_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< light> 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;
float kh = 0.2 , kn = 0.1 ;
float x = normal. x ( ) , y = normal. y ( ) , z = normal. z ( ) ;
Eigen:: Vector3f t ( x* y/ sqrt ( x* x+ z* z) , sqrt ( x* x+ z* z) , z* y/ sqrt ( x* x+ z* z) ) ;
Eigen:: Vector3f b = normal. cross ( t) ;
Eigen:: Matrix3f TBN;
TBN << t, b, normal;
int w = payload. texture-> width, h = payload. texture-> height;
float u = payload. tex_coords. x ( ) , v = payload. tex_coords. y ( ) ;
payload. texture-> getColor ( u, v) ;
auto huv = payload. texture-> getColor ( u, v) . norm ( ) ;
float dU = kh * kn * ( payload. texture-> getColor ( u+ 1.0f / w, v) . norm ( ) - huv) ;
float dV = kh * kn * ( payload. texture-> getColor ( u, v+ 1.0f / h) . norm ( ) - huv) ;
Eigen:: Vector3f ln ( - dU, - dV, 1 ) ;
point = point + kn * normal * huv;
Vector3f n = ( TBN * ln) . normalized ( ) ;
Eigen:: Vector3f result_color = { 0 , 0 , 0 } ;
Eigen:: Vector3f view_dir = ( eye_pos - point) . normalized ( ) ;
for ( auto & light : lights)
{
Eigen:: Vector3f diffuse ( 0 , 0 , 0 ) ;
Eigen:: Vector3f specular ( 0 , 0 , 0 ) ;
Eigen:: Vector3f ambient ( 0 , 0 , 0 ) ;
float rr = ( light. position - point) . squaredNorm ( ) ;
Eigen:: Vector3f light_dir = ( light. position - point) . normalized ( ) ;
for ( size_t i = 0 ; i < 3 ; i++ ) {
float intensity = light. intensity[ i] / rr;
Eigen:: Vector3f h = ( view_dir + light_dir) . normalized ( ) ;
diffuse[ i] = kd[ i] * intensity * std:: max ( 0.0f , n. dot ( light_dir) ) ;
specular[ i] = ks[ i] * intensity * std:: pow ( std:: max ( 0.0f , n. dot ( h) ) , p) ;
ambient[ i] = amb_light_intensity[ i] * ka[ i] ;
}
result_color += ( diffuse + specular + ambient) ;
}
return result_color * 255.f ;
}
提高
实验其他模型没有做,可以在参考连接中找其他大佬的答案 双线性插值
分别在x和y两个方向上做线性插值 注意:image_data和uv map上坐标原点的不同,一个是左上角(uv map),一个是左下角(image_data)
Eigen:: Vector3f getColorBilinear ( float u, float v)
{
float u_img = u * width;
float v_img = ( 1 - v) * height;
int cx = ( u_img - ( int ) u_img) > 0.5 ? std:: ceil ( u_img) : std:: floor ( u_img) ;
int cy = ( v_img - ( int ) v_img) > 0.5 ? std:: ceil ( v_img) : std:: floor ( v_img) ;
auto u00 = image_data. at < cv:: Vec3b> ( cy+ 0.5 , cx- 0.5 ) ;
auto u01 = image_data. at < cv:: Vec3b> ( cy- 0.5 , cx- 0.5 ) ;
auto u10 = image_data. at < cv:: Vec3b> ( cy+ 0.5 , cx+ 0.5 ) ;
auto u11 = image_data. at < cv:: Vec3b> ( cy- 0.5 , cx+ 0.5 ) ;
auto s = u_img - ( cx- 0.5 ) ;
auto t = v_img - ( cy- 0.5 ) ;
auto u0 = ( 1 - s) * u00 + s* u10;
auto u1 = ( 1 - s) * u01 + s* u11;
auto color = ( 1 - t) * u1 + t* u0;
return Eigen :: Vector3f ( color[ 0 ] , color[ 1 ] , color[ 2 ] ) ;
}
参考链接