Home › Forums › GAMES在线课程(现代计算机图形学入门)讨论区 › 请教老师一个问题,关于重心坐标
- This topic has 18 replies, 7 voices, and was last updated 1 year, 7 months ago by CheapMeow.
-
AuthorPosts
-
-
我们课上讲的是,根据三角形面积比计算重心坐标。
但是一旦点在三角形外,那么三个小三角形的面积,其中一个必须是负数,否则三个数的和不再是1.所以直接用面积计算可能不太合适?是否用叉积、解方程计算更合理?另一个问题是,在作业框架中,对深度进行插值时,为什么要乘w_reciprocal = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w());
多谢老师!
This post has received 1 vote up. -
我觉得老师只是说可以用面积比的形式理解重心坐标,真正计算alpha, beta, 和gamma还是用公式吧?
This post has received 2 votes up.-
这样嘛?看了回放里面,老师好像也是说要这样算。
因为之前我看到很多资料直接就用面积定义,所以之前一直直接用海伦公式计算面积算的。
和是否为1,用来判断是否在三角形内部。现在才知道原来和为1是定义本身,用来限制四点共面。。 -
关于第二个问题,大佬有什么想法吗?
不管关于这两次看起来不太影响,因为.w()都是等于1,是否乘1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w())。没有什么区别。-
若你让v=t.toVector4()
这里v[i].W()确实是1
所以这里应该用t.v[i].w(),这个才是该i点在view space下的z值。
具体这里为什么要有这样一个公式,你可以参考这个文章中的推导,这里空太小了我写不下:
https://zhuanlan.zhihu.com/p/45757899This post has received 3 votes up and 1 vote down.-
原来是这样,感谢!
-
AtlasParticipant
可是t.v[i]只是一个Vector3f
╭(°A°`)╮-
在rasterize_triangle中,进行了v = t.toVector4();修改为了齐次坐标
-
你说的是作业3吗?作业3里面t.v是
Vector4f v[3]
是四维的-
AtlasParticipant
抱歉,是我看错了。
谢谢指正~
-
-
-
有时间吗Participant
你好,我看了你给的知乎链接的推导,有一个问题是:
float Z = 1.0/(alpha / v[0].w() + beta / v[1].w() + gamma / v[2].w()); 计算出的是在view space的z值
而float zp = alpha * v[0].z() / v[0].w() + beta * v[1].z() / v[1].w() + gamma * v[2].z() / v[2].w();计算出的是在NDC上的z值
那么zp*=Z这一步将两者乘起来的含义是什么呢?-
JasonParticipant
从推导上看,我觉得是做了投影变换之后还没有做透视除法的值,就是A*z+B。
-
-
-
-
-
还是没有搞明白,跪求老师,助教老师和各位大佬解惑,十分感谢!
-
重心坐标使用面积比计算,为什么要根据是否和为一来定义共面,而不用是否为1定义是否在三角形内?
This post has received 1 vote down.-
我明白你今天课上提的问题了!是这么回事,你可以想象一个三棱锥,有一个三角形的底面,和一个不在这个平面内的点。那么这个点所连接的三个面的面积加起来肯定要大于这个底面三角形的面积(想想面积的投影就明白了)。这就是为什么说用重心坐标的前提是OAB,OBC,OCA面积加起来等于ABC面积,因为只有这个条件满足,才能说明O在三角形所在平面上(当然也是三角形内)。
This post has received 1 vote up.-
哦哦哦,理解了,多谢老师解答!!这么说是很有道理,不过在平面内但是三角形外的面积和也是大于1的?
-
对,只有在平面内且在三角形内,面积和才是等于1的。
-
嗯嗯,好吧,多谢老师啦!
-
-
-
-
-
CheapMeowParticipant
用面积计算是合适的
比如我这里使用面积计算重心坐标,可以得到预期的效果
static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector4f* v){ Eigen::Vector2f p(x, y); Eigen::Vector2f tri_node_coords[3]; for (int i = 0; i < 3; ++i) { tri_node_coords[i] = v[i].head<2>(); } Eigen::Vector2f edge_1, edge_2; float s_sub_tri[3]; for (int i = 0; i < 3; ++i) { edge_1 = tri_node_coords[(i + 1) % 3] - p; edge_2 = tri_node_coords[(i + 2) % 3] - p; s_sub_tri[i] = edge_1.x() * edge_2.y() - edge_2.x() * edge_1.y(); } float s_sum = 0; for (int i = 0; i < 3; ++i) { s_sum += s_sub_tri[i]; } return { s_sub_tri[0] / s_sum, s_sub_tri[1] / s_sum, s_sub_tri[2] / s_sum }; }
如果担心计算出来的重心坐标为负会不会不正确,那么可以试着在 rasterize_triangle() 光栅化三角形的时候就剔除掉那些重心坐标为负的点
void rst::rasterizer::rasterize_triangle(const Triangle& t, const std::array<Eigen::Vector3f, 3>& view_pos) { int x_screen_min = width - 1; int x_screen_max = 0; int y_screen_min = height - 1; int y_screen_max = 0; for (int i = 0; i < 3; i++) { x_screen_min = std::min(x_screen_min, (int)t.v[i][0]); y_screen_min = std::min(y_screen_min, (int)t.v[i][1]); x_screen_max = std::max(x_screen_max, (int)t.v[i][0]); y_screen_max = std::max(y_screen_max, (int)t.v[i][1]); } // temp var Eigen::Vector3f interpolated_color; Eigen::Vector3f interpolated_normal; Eigen::Vector2f interpolated_texcoords; Eigen::Vector3f interpolated_shadingcoords; for (int x = x_screen_min; x <= x_screen_max; ++x) { for (int y = y_screen_min; y <= y_screen_max; ++y) { if (insideTriangle(x + 0.5f, y + 0.5f, t.v)) { auto [alpha, beta, gamma] = computeBarycentric2D(x + 0.5f, y + 0.5f, t.v); if (alpha < 0.0f || alpha > 1.0f) continue; if (beta < 0.0f || beta > 1.0f) continue; if (gamma < 0.0f || gamma > 1.0f) continue;
可见,在模型的每一个三角面的边上显示出缝隙
也就是说,重心坐标为负的点也可能位于三角形的边上
如果去掉了这些点,就相当于在三角形的边上没有颜色,那么渲染出来的就会在模型的每一个三角面的边上显示出缝隙
所以只要你的 insideTriangle() 写对了,就不需要考虑 computeBarycentric2D() 算出来的重心坐标为负还是为正
Attachments:
You must be logged in to view attached files.
-
-
AuthorPosts
- You must be logged in to reply to this topic.