Forum Replies Created
-
AuthorPosts
-
经大佬提醒发现这里有误,需要再设置一个4倍大的color buffer用于暂存每个子采样点的颜色信息,这样可以彻底消除黑线,具体见下面更新
步长其实就是单位1,点(x,y,z)在屏幕上的坐标就是(x,y),你求出bound box不就是拿x和y的最大最小来取的吗,这个x、y其实就是一个像素左下角的位置,单位就是单位1,1×1就是一个像素,(x+0.5,y+0.5)就是一个像素中心的位置。
这样的话你便利就直接两层循环,分别取x+i,y+j就是bound box里各个像素的左下角位置了我想了很久,之前就看到有同学也用了四倍的color buffer,但我一直觉得四倍color buffer跟我这样做本质上是一样,现在再想了想,四倍color buffer确实能够避免黑色的混入,谢谢提醒!我马上去改一下
光看你这段代码好像没什么问题。。
像素存在
auto v = t.toVector4();
里
这个v存了三个vector4f,分别对应每个三角形的三个点,举个例子(v[0])[0]就是读取存在v里的第一个点的x坐标
frame_buf[]存的是颜色
depth_buf[]存的是深度
给get_index(int x, int y)传像素坐标可以获得在frame_buf、depth_buf中对应的数组下标循环调用的话就循环v里的三个点呗,每次传来的都是三个点,顺序的话是按照main.cpp里面的
std::vector<Eigen::Vector3f> pos { ... };
的顺序,按顺序每三个点放在一个三角形里
你这么一说我发现了我之前颜色写入的一个bug,我之前是直接
frame_buffer+=color/通过深度和三角形测试的子采样点个数
所以效果才会这么好,边界处显得很白,看起来像是(蓝+绿),实际上并不是,只不过是巧合而已
如果把两个三角形深度对换一下就能发现问题了实际上应该是
frame_buffer = frame_buffer/(4-通过深度和三角形测试的子采样点个数)+color/通过深度和三角形测试的子采样点个数
这样才对不过这样的话解决了渲染顺序的问题,不论是哪个三角形在前都能有效果,但是边界处效果就不是那么好了,比如我先渲染近的绿三角形再渲染远的蓝三角形,最后边界处的颜色是(蓝+绿+黑)
这样看起来还是有“黑线”,但是不是那么黑,只是通过对比看起来感觉有一点偏黑,不知道该怎么解决了,但是我这样是基本按照老师的意思做了。。。有点头疼,这种淡淡的黑线应该是没法解决的吧ps:因为先写进颜色缓存的是近的三角形,在边界处就是(绿+黑),然后再渲染蓝色,那肯定就是(绿+黑+蓝)了,根据生活经验,交界处应该是(绿+蓝)才对,不应该混入黑色,我是不知道该怎么解决了。这个现象跟渲染顺序有关,我这里的话如果先渲染远的再渲染近的就不会有这个混合的问题,当然这个也可以用我这里的说法解释,因为先渲染远的再渲染近的的话,交界处本来就没有黑色混入,也就是渲染远处时本来就就是(蓝色),(蓝+黑)的部分都被覆盖掉了,所以不会有淡淡的“黑线”
- This reply was modified 4 years, 9 months ago by 戴皓天.
pixel_color初始化的问题?
pixel_color是不是应该在每个for(int i=0;i<4;i++) { .... }
循环外面初始化一下?
if(inside_num>0&&i==3) ......
这一段是不是应该放到
for(int i=0;i<4;i++) { .... }
的外面?
ps:既然你已经更新了,那就不是这个的问题,我再看看
- This reply was modified 4 years, 9 months ago by 戴皓天.
你矩阵运算不符合规范,比如3X3矩阵和4X4矩阵相乘了
仔细看一下吧,或者分段注释代码,看下哪段被注释掉后不会报错解决方案
一开始我没搞明白所谓的维护每个子采样点的深度是什么意思,后来经过大佬们的指点,我稍微理解一点
具体做法:第一步:扩大深度缓存
因为是2X2的MSAA,所以子采样点的个数是像素个数X4,为了能存下子采样点的深度信息,深度缓存就要扩大4倍rst::rasterizer::rasterizer(int w, int h) : width(w), height(h) { frame_buf.resize(w * h); w=w*4+100;//***这里改动*** depth_buf.resize(w * h ); }
+100是为了防爆
第二步:对每个子采样点进行三角形内部检测
这里没什么好说的,就是给insideTriangle函数传一个大小为4的数组,分别对应每个像素的4个子采样点,分别对4个子采样点进行向量叉乘判断是否在三角形内部,然后对数组写入对应的值并返回即可第三步:对每个子采样点进行深度检测和深度写入
我在这里浪费了很多时间,因为一开始我只做了对每个子采样点进行深度检测,并没有对每个子采样点进行深度写入for(对每个子采样点) { if(如果当前子采样点在三角形内部) { if(深度缓存中当前子采样点位置的深度 < 当前三角形的深度) { 深度缓存中当前子采样点位置的深度 = 当前三角形的深度; } } }
*这里要注意的是深度检测之前要先判断这个子采样点是不是在三角形内部,如果不做这个判断就会出错。因为边缘处的子采样点,只有在三角形内部才有被深度检测的意义
至此,问题就大致解决了,
我们来看下最终效果
见附件图1或许不同的情况会有不同的渲染顺序,结果可能不一样,但问题思路应该是差不多的
这个问题浪费了三天时间,但好在最后总算有了个尾声
希望能够帮到各位,谢谢This post has received 2 votes up.- This reply was modified 4 years, 9 months ago by 戴皓天.
Attachments:
You must be logged in to view attached files.因为我在这个问题上跌了很多跟头,浪费了太多太多时间,所以在这里整理一下我自己的错误以及分析一下对问题的理解,希望能够帮到还不理解的同学
先看下错误示例:
见附件第一张图
(如果图挂了,可以按顺序查看附件的图片)产生原因
“黑线”其实并不是完全的“黑色”,我们先来看几个图
见附件第二、三、四张图通过RGB值的测量,我们可以发现,所谓的“黑线”的黑色,只不过是颜色对比的产物而已
实际上,根据第三张图,经过RGB值的测量,其实A点,也就是绿色三角形的边缘颜色其实和“黑线”颜色一样
那么问题就显而易见了:
是因为在边缘处只渲染了绿色三角形,而没渲染蓝色三角形
那么产生的原因实际上是深度检测的精度不够,
假设我们渲染是从近到远渲染,且绿色三角形近,蓝色三角形远
则此时是先渲染绿色三角形再渲染蓝色三角形
因为在使用MSAA但并没有维护每一个子采样点的深度时,深度检测是以像素为单位的,而不是以子采样点为单位,所以此时即使在两三角形相交处那些来自蓝色三角形的像素的子采样点是处在三角形内部,那么由于深度检测的过滤,也会因为相交处蓝色三角形的像素深度小于相交处已经渲染完成的绿色三角形的像素而被放弃渲染,留下的就只是绿色三角形原本就渲染完成的边缘,也就是绿色和黑色的“混合”
所以看起来会是有一条“黑线”This post has received 2 votes up.Attachments:
You must be logged in to view attached files.是的,是代码实现的问题,我分析下我的错误吧,我把我从错误到正确分为三个阶段,姑且分别叫做A、B、C阶段吧
A阶段:
这是第一次实现的MSAA,没有维护每一个子采样点的深度,子采样点只用来产生颜色,深度检测的话是以像素为单位的,而不是对子采样点做深度检测。因此在先渲染前三角形再渲染后三角形的前提下,前三角形的边缘是黑色和绿色(也就是前三角形颜色)的平均,这个结果是正确的,但是紧接着渲染后三角形的时候,因为我是以像素为单位进行深度检测的,所以哪怕检测对象是前三角形的边缘,它的深度也是大于后三角形的任何像素的,所以渲染后三角形的时候,在两个三角形相交的地方,也就是前三角形的边缘处,经过深度检测,产生的结果就是后三角形在相交处不渲染,也就是只留下了前三角形的边缘颜色(绿色和黑色的平均),所以会产生“黑边”
具体看图,A点是前三角形的边缘,是黑色和绿色的混合,B点是相交处,经过测量可见它们的RGB值是一样的,也就是说后三角形本来应该在相交处和前三角形边缘进行颜色叠加的,但它根本就不渲染,直接忽略了,留下的就是带黑色的前三角形边缘,根本原因就是之前提到的深度检测的问题B阶段:
进行改进,扩大了深度缓存到四倍,但是深度写入有问题,具体不好说,但总的来说从结果上就是当这个像素的深度大于缓存里对应的深度的时候,四个子采样点的深度都被同时写入这个像素的深度。这里很明显错了,因为既然深度检测是以子采样点为单位的,那么深度写入也要以子采样点为单位,不然扩大深度缓存就没有任何意义C阶段:
把深度写入进行改进,得到正确结果This post has received 1 vote up.Attachments:
You must be logged in to view attached files.谢谢!今早起来再看了一遍你相关的回答,我发现我之前对sample_depth_buf的维护有点问题,重新实现了一下就解决了,具体方法我开个帖子,总之非常感谢你提供的思路!
非常感谢!你的说法我理解了,但是我可不可以再问一句,就是,具体来说应该怎么实现呢?我看了你的回复以后我回去改了好久,但是还是得不到正确的答案,非常头疼,希望大神能指导一下。我的做法是把深度缓存的大小扩大四倍,保存每一个子采样点的深度,但是现在想想这样好像没必要,因为和扩大之前是几乎一样的,更何况我也没得到正确的结果。至于我在更之前的做法是直接检测每个像素的深度,也就是和使用反走样之前的做法一模一样。黑线现象的话我再次仔细用ps吸了下颜色,发现确实如你所说的,黑线其实就是其中一个三角形的边缘梯度颜色(在我这里是靠摄像机近的那个三角形的边缘梯度颜色),并不是我之前所说的“颜色叠加”。总之希望能够指点一下,实在不知道所说的维护子采样点的深度是什么意思,也不知道应该对每个子采样点应该做哪些操作。麻烦你了!
我把截图放进ps里看了下,
蓝色三角形的RGB值是(185,217,238)
绿色三角形的RGB值是(217,238,185)
两者的RGB值取平均是(201,227.5,211.5)
取1/4是(100.5,113.75,105.75)
但是实际上通过吸管工具得到的“黑线”的RGB值是(54,60,46)
这样就很奇怪了,实际上这个相交的点的颜色值不应该这么小才对
现在又对“黑线”的产生感到疑惑了,
如果有大佬知道希望能跟我解释一下,谢谢
如果有解决方案的话那就更好了确实“黑边”并不是黑色,他是黄色和蓝色的混合,但是我现在很疑惑的是,就算每个像素都能维护了四个子采样点的深度,那着色时又要做什么操作呢?因为在我看来,MSAA的本质方法用的是模糊,所以在黄色三角形和蓝色三角形相交的地方必然会有蓝色和黄色互相模糊混合而产生的颜色(表现为深色),如果想要避免混合就不能使用模糊,也就不能使用抗锯齿了,哪怕只是在相交处禁用抗锯齿,我觉得这也不应该是最佳解决办法。所以请教一下,应该需要怎样的操作才能避免“颜色混合导致的变黑”。
This post has received 1 vote up.其实这个blinn-phong模型本身也是不考虑光源和物体的距离的,他的漫反射部分的公式实际上是光照颜色*漫反射系数*max(0,单位法线向量*单位入射光向量),在这个公式里漫反射系数是自定的一个材质参数,当作不变,而光照颜色也是这个公式的一个输入量,也是视作该公式的一个参数,因此直接影响公式结果(也就是漫反射颜色)的就只有法线和入射光的角。所以可以说这个光照模型本身是不对“距离”这个量进行“直接”计算的
至于光照能量随距离衰减,这个计算是放在求漫反射之前,计算光照颜色时做的。所以从结果上来说这个光照模型总体上对光线能量的衰减只处理了光源到物体的部分,而对物体到人眼的部分置之不理。
可能你觉得会不符合现实。因为,在现实生活中,不论是光源到物体的光线还是经物体反射到人眼的光线,只要是光,那就是电磁波,在传播的过程中不论如何都必然伴随着能量衰减。很显然我们的blinn-phong模型和现实相悖。
但我可以说实际上这个光照模型它就是不符合现实的,因为他只是一种“经验模型”,只是让人觉得看起来对,看起来符合常理,并不是“基于物理的渲染”,但哪怕是“经验模型”,在一定程度上也足够欺骗人的眼睛了。
很多时候我们觉得电影或者游戏有“真实感”,但实际上通过对比我们会发现它们并不一定是完全符合现实。我们之所以会产生“真实感”,就是因为我们看到的东西“符合常理”,是我们的大脑觉得它们看起来没问题而已,毕竟大脑是不会对接受到的每一个光线都做路径追踪的。
This post has received 2 votes up.在这个blinn-phong模型上是这样的
仔细看了看源码解决了,其实pdf里也讲了,是depth_buff初始化的问题,框架里是初始化成了最大值INF,我们要做的就是把初始化改回负的INF即可,然后深度检测就按部就班,按正常的来,即正常地把z看作是负数
具体改法:
1.在rasterizer.cpp的clear函数
把void rst::rasterizer::clear(rst::Buffers buff) { if ((buff & rst::Buffers::Color) == rst::Buffers::Color) { std::fill(frame_buf.begin(), frame_buf.end(), Eigen::Vector3f{0, 0, 0}); } if ((buff & rst::Buffers::Depth) == rst::Buffers::Depth) { std::fill(depth_buf.begin(), depth_buf.end(), std::numeric_limits<float>::infinity()); } }
改成
void rst::rasterizer::clear(rst::Buffers buff) { if ((buff & rst::Buffers::Color) == rst::Buffers::Color) { std::fill(frame_buf.begin(), frame_buf.end(), Eigen::Vector3f{0, 0, 0}); } if ((buff & rst::Buffers::Depth) == rst::Buffers::Depth) { std::fill(depth_buf.begin(), depth_buf.end(),,std::numeric_limits<float>::infinity()*(-1.0f));//*这里改动* } }
2.在写入z-buffer前的判断应该是:目标像素的当前深度值大于z-buffer里的对应位置的深度->写入z-buffer
(因为我们这时候是把各点的z值看作是负的来看,当然实际上也是负的,所以z越大越接近摄像机)This post has received 2 votes up.如果一个子采样点在三角形内,那么该子采样点所代表的像素的颜色值就加上这个三角形颜色的四分之一,也就是v.getColor()/4.0f,就跟楼上说的一样考虑每个子采样点对整个像素的贡献
谢谢!这样写的话就很严谨了
其实最后不用两两点乘,你直接判断它们的z值是不是同时大于0或者小于0就行了。但是你这样照理说应该是没问题的,要不你分步算,输出一些中间变量到控制台看一下
请问一下这里为什么只对y做一个取整,而不对x取整呢。
因为我自己传的实参就是由整型索引转成float而构成的vector3f向量所以就没在这里考虑取整的问题了我回帖的时候也出现了这种情况,不过也是偶尔吧,过一会儿就好了,只是某一段时间内,验证码怎么答都不对,估计是网络波动吧,或者是后端的bug?
漫反射光与观察者远近无关,不考虑ambient环境光和specular高光反射的情况下,漫反射只和光源距离的平方、入射光与法线的夹角有关,在这个光照模型里不论观察者离得多远,它的颜色都不会改变
确实是朝下的,因为projective的参数里near近截面和far远截面都是正的,手动改成负的就行了
因为(x,y,z,1)等价于(zx,zy,z^2,z),这里讲的是为了求出转换矩阵的第三行,要分别代入近截面(任意点)和远截面(这里用特殊点,也就是远截面的中心点),这张ppt用的是近截面所以带入的z是n,所以(zx,zy,z^2,z)也就成了(nx,ny,n^2,n)。因为在近截面,经过视投影->正交投影的矩阵 X (x,y,n,1)要等于(nx,ny,n^2,n),所以可以得到矩阵的第三行也就是(unknown ,unknown ,unknown ,unknown) X (x,y,n,1)要等与n^2,这时候分别设后面两个unknown为A、B,前面两个unknown为C、D,那么你乘一下,是不是等于Cx+Dy+An+B,因为这个式子要等于n^2,而n^2不带x、y,所以C=D=0,所以此时要么是A=n,要么是B=n^2,与x、y无关。具体求解A、B的值还要接下来和远截面的点代入后一起求
- This reply was modified 4 years, 9 months ago by 戴皓天.
不会上下翻转的,是不是model矩阵写错了
谢谢老师,已经把zNear和zFar改回负数了
已经成功啦,用glu的构成的话三角形是向上的,用老师的方法是向下的
-
AuthorPosts