Forum Replies Created
-
AuthorPosts
-
t、b、n分别是切线、副切线和法线,这个可能是老师上课说的局部坐标系吧(t、b、n分别是局部坐标系的三个轴,有些资料里把这个坐标系空间称为“切线空间”),是为了把用微分求出来的法线从局部坐标系转换到模型空间(因为是用的局部的du和dv在局部坐标系下求得的新的法线,所以刚求出来的法线也就是框架里的ln是在局部坐标系的,至于为什么要转换到模型空间,这个查阅的资料里是这么写的,具体我们的框架是怎么样的我还没仔细看,这个你可以看看源码哈),实际上模型空间->切线空间的转换矩阵就是[t,b,n](第一行是t.x,t.y,t.z,以此类推),所以切线空间->模型空间的转换矩阵就是[t,b,n]的逆,而它又恰恰是正交矩阵,所以求[t,b,n]就是求它的转置,因此我们的框架里才会用到[t b n](第一列分别是t.x,t.y,t.z)
参考资料:
http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-13-normal-mapping/
This post has received 2 votes up.已经完成了,使用的是612×612的小贴图,效果见附件
头疼了一天,居然出在一个我自己觉得肯定不会出问题的地方😂
总结一下吧,也算替给同学踩个坑:
主要问题出在我的lerp实现上,设需要用于双线性插值的四个纹素为A、B、C、D,分别相对位于目标位置(就是需要求颜色的那个位置)的左下角,右下角,左上角,右上角,可以简单看作它们的坐标分别为(0,0) , (1,0) , (1,0) , (1,1)
那么在双线性插值时,首先先对u方向插值,那么u方向需要求两次插值,也就是对于(0,0) , (1,0)和目标坐标(u,v)做一次插值,另外要对(1,0) , (1,1)和(u,v)做一次插值。
假设先算第一个,那么需要求出u-0(只是这里恰好时0,正常情况下减去四个点里最小的u值即可)
那么此时求出的插值颜色应该是(1-(u-0))*getColor(0,0)+(u-0)*getColor(1,0)
因为离(0,0)越近,u-0越小,但实际上它的颜色对于目标点(u,v)的影响越大,所以要反过来,前面的getColor(0,0)项前面要用1-至于坐标标准的理解我自认为应没问题,需要的可以看我上面的回帖
This post has received 1 vote up and 1 vote down.Attachments:
You must be logged in to view attached files.谢了老哥,谢谢提醒,已经好了,坐标只是标准引起的歧义,主要是你一开始说的比重的问题,我算反了,反过来就好了😂
谢谢,我自己刚才再看一遍也发现了,确实是比重算错了,所以才会毛毛糙糙的😂
我懂你的意思了,谢谢。应该是我们所选取的坐标系标准不同导致我们会有歧义,可能我的问题就是出在这里,我再找点资料自己再试一试吧
这里有个地方口胡了,把纹素说成像素了,懂意思就好😂
我说的(1,1)就是你图里的纹素2,因为每个纹素的坐标不是它的中心,是它的左下角,所以我才会取到你说的交点,如果要问为什么这样想的话,因为像素就是这样的,老师讲像素的时候就说默认是拿每个像素左下角那个点当作这个像素的坐标。因为不论是像素还是纹素,它本质都是一个正方形,所以需要有一个坐标来当作整个正方形的坐标,你的意思应该是拿每个正方形中心点的坐标来代表整个正方形的坐标了吧,但是我的想法是拿左下角代表,所以我会四舍五入到“交点”,而这个“交点”虽然看起来是这个几个纹素的交点,但实际上也是纹素2的坐标位置(因为每个纹素是拿左下角的点的坐标代表整个纹素的坐标的,所以纹素2的坐标就是(1,1),也就是“交点”)
我不知道大佬你有没有理解我的意思,我主帖可能说的不清楚,我取四舍五入取到某个整数坐标点是为了方便找四周的点,举个例子,也就是我主帖的图一,因为p离p撇最近,所p需要对p撇四周的纹素进行插值混合,这时候就找到了0、1、2、3这几个点所在的像素,而0、1、2、3分别是这四个纹素的中心,所以说四舍五入找“原点”只是为了方便找应该用于近似的四个纹素而已。
至于插值计算中,仍然是用原来的坐标值去减去找到的那个纹素的中心点的坐标从而求得应该混合的比例,从而进行混合
而为什么是取中心点的话那是因为老师的课里讲双线性插值那里是这样提到的(见附件),所以我按自己的理解照做了。。- This reply was modified 4 years, 8 months ago by 戴皓天.
Attachments:
You must be logged in to view attached files.四舍五入的话应该是最中间那个点把,离哪个点近他肯定会四舍五入到最近那个点,如果点离图里的左下角近,那他肯定是近似到左下角去了,然后以那里为原点找周围的四个点做平均
好的谢谢!
是的我就是这个意思。。。但是双线性插值不是就是这个意思吗,对于低分辨率的贴图为了避免锯齿所以要根据插值取周围的颜色模糊一下,所以按这么说的话所有结果都应该是插值后的值,也就是中间值。。不知道我的理解是否有误
顺便问一句
image_data.at<cv::Vec3b>(v,u)
这个cv::mat.at()它内部是已经做了一个四舍五入了吗,因为原getColor()函数是直接传一个float值进去的lerp写错了吧,楼上说的是对的,既然第一个参数c代表百分比,那不应该是(1-c)*a+c*b吗
不好意思之前没考虑这个问题,查了点资料,你说的是对的。对于多光源,ambient确实不应该重复叠加,谢谢提醒!
光源有两个,所以他们的光照计算结果要叠加,应该是
result_color+=ambient+diffuse+specular
,而不是用赋值,用赋值的话对第二个光源的计算结果会把第一个的覆盖掉This post has received 1 vote up.你这个应该是第一个光源出来了但第二个光源没出来,按框架light的顺序,第二个光源是从小牛侧边打过来的,第一个光源是打在脸上,你看下对最终颜色的赋值是不是搞错了
因为光源有两个,所以他们的光照计算结果要叠加,应该是
result_color+=ambient+diffuse+specular
,而不是用赋值,用赋值的话对第二个光源的计算结果会把第一个的覆盖掉- This reply was modified 4 years, 8 months ago by 戴皓天.
是u+1.0/w,而不是(u+1.0)/w,你要注意这相当于是在求微分,是让u或者v加上一个很小的值
getColor(U,V)的时候你先对u和v做一个判断,小于0的让他等于0,大于1的让他等于1,计算应该没问题,可能是对纹理进行采样的时候越界了
谢谢!
可以分享一下配置过程吗,谢谢!我觉得在之后的学习里虚拟机可能真的不够用了
1/4绿+3/4黑只可能发生在除了两三角形相交处之外的其他绿三角形边缘,或者可能发生在渲染蓝三角形之前的相交处
原本的颜色和深度缓存就是储存每个片元(Fragment,可以理解为像素)的信息,缓存的下标和坐标一一对应
你是没有用四倍的深度缓存和颜色缓存吗?只是用了一个暂时的2X2大小的缓存用来暂存颜色,然后最后通过判断经过平均再写入总的颜色缓存中?
如果是这样的话你的子采样点的颜色是怎么取的呢,我不知道你具体是怎么实现的,但就我看来如果是取自原大小的颜色缓存的话就会出现黑边,因为假设绿色三角形先被渲染,蓝色后被渲染,那么在绿色三角形被渲染时,绿色三角形的边界就被写入了(绿色+黑色)的颜色,然后渲染蓝色三角形时,在两个三角形的相交处,子采样点首先肯定要取颜色,那么此时就取了绿三角形边界的颜色,也就是前面提到的(绿色+黑色)的颜色,此时这个相交处肯定至少有一个蓝三角形的子采样点满足深度测试的,而三角形内部测试的话相交处很明显是在蓝色三角形内部,所以也会通过,所以在渲染蓝色三角形的情况下,在渲染相交处的像素时,会写入(绿色+黑色)+(蓝色)也就是(绿色+黑色+蓝色)的颜色,而不是(绿色+蓝色)如果用和最终颜色缓存独立的4倍大的子采样点颜色缓存的话,子采样点中都是没被平均过的颜色,注意,这个缓存存的是每个子采样点自己的颜色,不需要平均,也就是黑色就是黑色,绿色就是绿色,显而易见,在这个颜色缓存中,在两个三角形相交处要么是绿色(说明该子采样点在绿三角形内),要么是蓝色(说明该子采样点在蓝色三角形内)。因此在渲染蓝三角形时,相交处取到的肯定是绿色和蓝色而没有黑色,所以最终写入正真的像素的颜色缓存时用的就是(绿色+蓝色),此时不用平均(注意,平均是拿子采样点的颜色缓存中的颜色进行平均,然后直接写入最终的像素颜色缓存,不需要取出最终的像素颜色缓存里的颜色,这也就避免了先写入了黑色,后来就没法消除黑色的弊端)
像我最开始也没用四倍大的子采样点的颜色缓存,每次都是子采样点判断后直接平均颜色写入颜色缓存,这样的话黑色只要写入了颜色缓存,后面因为怎么样都是在拿它做平均,所以一直会有黑色混入,最终颜色也就显然不正确了
你这个图或许只是巧合,你可以交换两个三角形的深度,看下会不会出错。我一开始没用四倍大的子采样点颜色缓存也能得到“看似”正确的结果,但是经过大佬提醒,我交换了下深度发现出错了,然后才改正的。
因为我不知道你具体是怎么实现的,所以如果你怎么变都是对的,那就坚持你自己的做法和想法吧,因为你那样肯定是对的谢谢补充!非常感谢!我在一开始做的时候就觉得作业2的pdf里写的虽然是MSAA但下面的要求看起来却像SSAA。可能是因为SSAA实现起来比较暴力,比较适合小白实现吧,MSAA的话还得判断是不是边缘,大佬上面补充的EQAA看起来是很不错的做法,至少省了很大的显存空间。
其实随便取就行,我的做法是把原本的z传过来,你直接给z赋0也行,因为insideTriangle这个函数本来就相当于在一个平面内判断某个点是不是在三角形内部的
2020.03.08 17点35分 更新:
·这次更新完全消除了黑线,是最终方案解决方案
一开始我没搞明白所谓的维护每个子采样点的深度是什么意思,后来经过大佬们的指点,我稍微理解一点
具体做法:第一步:扩大深度缓存
因为是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是为了防爆
第二步:新建一个color buffer*****这一步是“2020.03.08 17点35分 更新”新加的******
*color_buf用于存放子采样点的颜色,对每个子采样点进行深度检测时,若通过了深度检测,则在写入深度信息的同时也要往这个color_buf里写各个子采样点的颜色信息,而不是直接写进最终的颜色缓存frame_buf中
在经过四个子采样点的深度检测之后再对四个子采样点的颜色做一个平均,然后传入frame_buf
首先在rasterizer.hpp头文件里定义color_buf(用于持久保持防止回收)std::vector<Eigen::Vector3f> frame_buf; std::vector<Eigen::Vector3f> color_buf;//***这里 std::vector<float> depth_buf;
然后在rasterizer.cpp里设置初始化:
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}); std::fill(color_buf.begin(), color_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()); std::fill(depth_buf.begin(), depth_buf.end(), std::numeric_limits<float>::infinity()*(-1.0f)); } }
接着扩大到w*h的四倍
rst::rasterizer::rasterizer(int w, int h) : width(w), height(h) { frame_buf.resize(w * h); w=w*4+100; color_buf.resize(w * h);//***这里 depth_buf.resize(w * h );//*这是上一步改的 }
第三步:对每个子采样点进行三角形内部检测
这里没什么好说的,就是给insideTriangle函数传一个大小为4的数组,分别对应每个像素的4个子采样点,分别对4个子采样点进行向量叉乘判断是否在三角形内部,然后对数组写入对应的值并返回即可第四步:对每个子采样点进行深度检测和深度写入
我在这里浪费了很多时间,因为一开始我只做了对每个子采样点进行深度检测,并没有对每个子采样点进行深度写入for(对每个子采样点) { if(如果当前子采样点在三角形内部) { if(depth_buf中当前子采样点位置的深度 < 当前三角形的深度) { depth_buf中当前子采样点位置的深度 = 当前三角形的深度; color_buf中当前子采样点位置的颜色 = 当前三角形的颜色;//也就是等于t.getColor() } } } for(对每个子采样点) { 最终颜色 += color_buf中当前子采样点位置的颜色/4.0f; }
*这里要注意的是深度检测之前要先判断这个子采样点是不是在三角形内部,如果不做这个判断就会出错。因为边缘处的子采样点,只有在三角形内部才有被深度检测的意义
至此,问题就大致解决了,
我们来看下最终效果
见附件,附件已更新,是最新的效果或许不同的情况会有不同的渲染顺序,结果可能不一样,但问题思路应该是差不多的
这个问题浪费了三天时间,但好在最后总算有了个尾声
希望能够帮到各位,谢谢This post has received 2 votes up.- This reply was modified 4 years, 8 months ago by 戴皓天.
- This reply was modified 4 years, 8 months ago by 戴皓天.
Attachments:
You must be logged in to view attached files. -
AuthorPosts