透正确的纹理的映射;z距离计算可能是错的
-
20-09-2019 - |
题
我在做一个软件的光栅器,并且我已经到位的一个障碍:我似乎无法得到透正确的纹理映工作。
我的算法是以排序第一的坐标的阴谋 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;
然后我们呈现从 order[0]->y
要 order[2]->y
, 增加 x_start
和 x_end
通过三角洲。当呈现的顶端部分,三角洲的 x_delta[0]
和 x_delta[1]
.当呈现的底部的一部分,delta的是 x_delta[0]
和 x_delta[2]
.然后我们呈线性插值之间的x_start和x_end在我们的扫描线.紫外线的坐标是插在相同的方式,下令通过的y开始,开始和结束,三角洲的应用的每一个步骤。
这种工作除了当我试着做正确的角度紫外线图。基本的算法是采取 UV/z
和 1/z
每个顶点,并插入他们之间。对于每一像素,紫外线的坐标变 UV_current * z_current
.然而,这是结果:
这部分反转告诉你在哪里delta的是翻转。正如你可以看到,这两个三角形,两者似乎是走向不同点在地平线上。
这里什么我使用计算的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;
}
我是正确的,它是一个z缓冲区的问题?
解决方案
ZBuffer有什么做它。
该ZBuffer只是有用的,当三角形是重叠的,你要确保他们制定正确的(如:正确命令在Z)。该ZBuffer会,每一像素的三角形,确定如果一个先前放置的像素是近的摄像头,并且如果是这样,不画像素的三角形。
因为你们的绘图2的三角形,不重叠,这可能不是问题。
我做了一个软件的光栅器在固定点的一次(对于移动电话),但我没有来源,在我的笔记本电脑。因此,让我看看今晚,我是如何做的。在本质上你有什么不是坏的!一个像这样的事情可能引起的一个非常小的错误
一般技巧在调试,这是有几个测试的三角形(斜坡左侧,斜率右侧,90度角度,等等)和步骤,通过它的调试器,看看你的逻辑处理的案件。
编辑:
peudocode我的光栅器(仅U,V and Z是考虑到...如果你还想做高氏你也有要做的一切R克和B类似的为什么你这样做是为U和V and Z:
这个想法是一个三角形可以分2份。顶部和底部的一部分。顶部是从y[0]y[1]和底部分是从y[1]y[2].对于这两组需要计算步骤变量与你插.下面的示例说明如何做到顶部的一部分。如果需要的话我可以提供的底部。
请注意,我已经计算出需要的插值偏移的底部在下面的'伪'片段
- 第一顺序的coords(x、y、z,u,v)的顺序,以便coord[0].y < coord[1].y < coord[2].y
- 下一步检查,如果任何2台的坐标是相同(只能检查,x和y)。如果是这样不要画
- 例外:没有三角有一个平顶?如果是这样,第一坡将是无限的
- exception2:没有三角有一个平底部(是三角形可以有这些也;^)),然后最后一个斜坡也将是无限的
- 计算2坡(左边和右边)
leftDeltaX=(x[1]-x[0])/(y[1]-y[0])和rightDeltaX=(x[2]-x[0])/(y[2]-y[0]) - 第二部分,三角形的计算取决于:如果左边三角形,是现在真的,位于道路左边(或者需交换)
代码段:
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
}
- 设置currentLeftX和currentRightX上x[0]
- 设置currentLeftU在leftDeltaU,currentLeftV在leftDeltaV和currentLeftZ在leftDeltaZ
- 计算的起始和终结点,第Y范围:startY=ceil(y[0]);恩迪=ceil(y[1])
- prestep x,u,v and z的小数部分y素的精确度(我猜这也是需要花车) 我fixedpoint算法,这是需要做的线和纹理得的假象的运动中更精细的步骤,那么该决议的显示)
- 计算其中x应该在y[1]:halfwayX=(x[2]-x[0])*(y[1]-y[0])/(y[2]-y[0])+x[0] 和相同的对U和V and z:halfwayU=(u[2]-u[0])*(y[1]-y[0])/(y[2]-y[0])+u[0]
- 和使用的halfwayX计算步进对U和V and z:如果(halfwayX-x[1]==0){slopeU=0,slopeV=0,slopeZ=0}else{slopeU=(halfwayU-U[1])/(halfwayX-x[1])}//(和同样对v and z)
- 做的剪切的Y上面(因此计算,在这里我们要开始绘制的情况下顶上的三角关闭幕(或关闭的剪裁矩形))
- 为y=startY;y < 恩迪;y++)
{
- 是Y的过去的?停止渲染!
- 计算startX和endX的第一个水平线 leftCurX=ceil(startx);leftCurY=ceil(恩迪);
- 剪辑的线路被吸引到左边界水平的屏幕(或剪切的区域)
- 准备一个指向目的地的缓冲区(这样做,通过列的索引的每次太慢) unsigned int buf=destbuf+(y距)+startX;(unsigned int的情况下,你正在做的24位还是32位的渲染) 还准备好你的ZBuffer指针在这里(如果使用这一)
- 对于(x=startX;x < endX;x++)
{
- 现在斜纹理映(使用没有bilineair插你这样做以下):
代码段:
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
- 虚线
- 虚线
- 虚线
- 可选:检查zbuffer如果先前绘制的图像素在这种协调是较高或较低的然后我们的。
- 图像素
- startZ+=slopeZ;startU+=slopeU;startV+=slopeV;//更新所有内插器
- }端x循环
- leftCurX+=leftDeltaX;rightCurX+=rightDeltaX;leftCurU+=rightDeltaU;leftCurV+=rightDeltaV;leftCurZ+=rightDeltaZ;//更新Y内插器
- 虚线
}端y循环
这是结束第一部分。我们现在有一半的三角形。从顶部,中间Y坐标。//我们现在基本做同样的事情但现在底部有一半的三角(中使用的其他设置的插值器)
对不起关于'虚拟线'..他们需要得到降价码在同步。(花了我一段时间才能得到一切形式看作意)
让我知道如果这可以帮助你解决这个问题,你正面临着!
其他提示
我不知道,我可以用你的问题的帮助,但我当时已经阅读软件渲染的最好的书之一是在网上提供的图形编程黑书由迈克尔·亚伯拉什的。
如果您是插值1/z
,你需要UV/z
乘z
,不1/z
。假设你有这样的:
UV = UV_current * z_current
和z_current
被插1/z
,则应该将其更改为:
UV = UV_current / z_current
然后你可能要z_current
重命名为类似one_over_z_current
。