kni*_*666 6 c++ zbuffer rasterizing
我正在制作一个软件光栅化器,我遇到了一些障碍:我似乎无法使透视校正纹理映射工作.
我的算法是首先对坐标进行排序y.这将返回最高,最低和中心点.然后我使用三角洲走过扫描线:
// ordering by y is put here
order[0] = &a_Triangle.p[v_order[0]];
order[1] = &a_Triangle.p[v_order[1]];
order[2] = &a_Triangle.p[v_order[2]];
float height1, height2, height3;
height1 = (float)((int)(order[2]->y + 1) - (int)(order[0]->y));
height2 = (float)((int)(order[1]->y + 1) - (int)(order[0]->y));
height3 = (float)((int)(order[2]->y + 1) - (int)(order[1]->y));
// x
float x_start, x_end;
float x[3];
float x_delta[3];
x_delta[0] = (order[2]->x - order[0]->x) / height1;
x_delta[1] = (order[1]->x - order[0]->x) / height2;
x_delta[2] = (order[2]->x - order[1]->x) / height3;
x[0] = order[0]->x;
x[1] = order[0]->x;
x[2] = order[1]->x;
Run Code Online (Sandbox Code Playgroud)
然后我们从渲染order[0]->y到order[2]->y,增加x_start和x_end由增量.渲染顶部时,delta是x_delta[0]和x_delta[1].渲染底部时,delta是x_delta[0]和x_delta[2].然后我们在扫描线上的x_start和x_end之间进行线性插值.UV坐标以相同的方式进行插值,以y开始排序,从开始和结束开始,每一步都应用delta.
这工作正常,除非我尝试透视正确的UV映射.基本算法是采取UV/z和1/z每个顶点和它们之间的插值.对于每个像素,UV坐标变为UV_current * z_current.但是,这是结果:

反转部分告诉您三角形的翻转位置.如您所见,这两个三角形似乎都朝向地平线中的不同点.
这是我用来计算空间中某点的Z:
float GetZToPoint(Vec3 a_Point)
{
Vec3 projected = m_Rotation * (a_Point - m_Position);
// #define FOV_ANGLE 60.f
// static const float FOCAL_LENGTH = 1 / tanf(_RadToDeg(FOV_ANGLE) / 2);
// static const float DEPTH = HALFHEIGHT * FOCAL_LENGTH;
float zcamera = DEPTH / projected.z;
return zcamera;
}
Run Code Online (Sandbox Code Playgroud)
我是对的,是az缓冲区问题吗?
ZBuffer 与此无关。
ZBuffer 仅在三角形重叠并且您希望确保它们正确绘制(例如,Z 中的顺序正确)时才有用。ZBuffer 将针对三角形的每个像素确定先前放置的像素是否更靠近相机,如果是,则不绘制三角形的像素。
由于您正在绘制两个不重叠的三角形,因此这不是问题。
我已经制作了一次定点软件光栅器(用于手机),但我的笔记本电脑上没有源代码。那么今晚让我检查一下我是如何做到的。从本质上讲,你所拥有的还不错!像这样的事情可能是由一个很小的错误引起的
调试的一般技巧是使用一些测试三角形(左侧倾斜、右侧倾斜、90 度角等),然后使用调试器逐步执行它,看看您的逻辑如何处理这些情况。
编辑:
我的光栅化器的伪代码(仅考虑 U、V 和 Z...如果您也想做 gouraud,您还必须对 RG 和 B 执行所有操作,类似于对 U、V 和 Z 执行的操作:
这个想法是三角形可以分成两部分。顶部部分和底部部分。顶部是从 y[0] 到 y[1],底部是从 y[1] 到 y[2]。对于这两个集合,您需要计算要插值的步骤变量。下面的示例向您展示了如何完成顶部部分。如果需要的话我也可以提供底部部分。
请注意,我已经计算了下面“伪代码”片段中底部所需的插值偏移量
代码片段:
if (leftDeltaX < rightDeltaX)
{
leftDeltaX2 = (x[2]-x[1]) / (y[2]-y[1])
rightDeltaX2 = rightDeltaX
leftDeltaU = (u[1]-u[0]) / (y[1]-y[0]) //for texture mapping
leftDeltaU2 = (u[2]-u[1]) / (y[2]-y[1])
leftDeltaV = (v[1]-v[0]) / (y[1]-y[0]) //for texture mapping
leftDeltaV2 = (v[2]-v[1]) / (y[2]-y[1])
leftDeltaZ = (z[1]-z[0]) / (y[1]-y[0]) //for texture mapping
leftDeltaZ2 = (z[2]-z[1]) / (y[2]-y[1])
}
else
{
swap(leftDeltaX, rightDeltaX);
leftDeltaX2 = leftDeltaX;
rightDeltaX2 = (x[2]-x[1]) / (y[2]-y[1])
leftDeltaU = (u[2]-u[0]) / (y[2]-y[0]) //for texture mapping
leftDeltaU2 = leftDeltaU
leftDeltaV = (v[2]-v[0]) / (y[2]-y[0]) //for texture mapping
leftDeltaV2 = leftDeltaV
leftDeltaZ = (z[2]-z[0]) / (y[2]-y[0]) //for texture mapping
leftDeltaZ2 = leftDeltaZ
}
Run Code Online (Sandbox Code Playgroud)
代码片段:
float tv = startV / startZ
float tu = startU / startZ;
tv %= texturePitch; //make sure the texture coordinates stay on the texture if they are too wide/high
tu %= texturePitch; //I'm assuming square textures here. With fixed point you could have used &=
unsigned int *textPtr = textureBuf+tu + (tv*texturePitch); //in case of fixedpoints one could have shifted the tv. Now we have to multiply everytime.
int destColTm = *(textPtr); //this is the color (if we only use texture mapping) we'll be needing for the pixel
Run Code Online (Sandbox Code Playgroud)
y 循环结束
//第一部分到此结束。现在我们已经画出了一半的三角形。从顶部到中间的 Y 坐标。// 我们现在基本上做完全相同的事情,但现在对于三角形的下半部分(使用另一组插值器)
对“虚拟行”感到抱歉……需要它们来同步降价代码。(我花了一段时间才让一切看起来都按预期进行)
让我知道这是否可以帮助您解决您面临的问题!
| 归档时间: |
|
| 查看次数: |
4554 次 |
| 最近记录: |