渲染二维函数图
Rendering 2d function plot
我的任务是只使用线性代数和颜色实时生成二维函数图(想象一下必须根据函数定义在纯 C++ 中计算图像缓冲区,例如 f(x, y) = x^2 + y^2)。输出应该是这样的 3d plot。
到目前为止,我已经尝试了 3 种方法:
1:光线追踪:
将(x,y)平面分成三角形,求出每个顶点的z值,从而将图分成三角形。将每条射线与三角形相交。
2:球体追踪:
here描述了一种渲染隐式表面的方法。
3:光栅化:
(1) 的逆运算。将绘图分割成三角形,将它们投影到相机平面上,遍历 canvas 的像素并为每个选择 "closest" 投影像素。
所有这些都是减慢速度的方法。我的部分任务是围绕摄像机移动,因此必须在每一帧中重新渲染情节。请向我指出 information/another algorithm/any 类帮助的另一个来源。谢谢。
编辑
如前所述,这是我最基本的光栅器的伪代码。我知道这段代码可能并非完美无缺,但它应该与总体思路相似。然而,当我将我的情节分割成 200 个三角形时(我认为这不够),它已经运行得非常慢,甚至没有渲染任何东西。我什至没有使用深度缓冲区来提高可见性。我只是想通过如下设置帧缓冲区来测试速度:
注意:在我使用的JavaScript框架中,_
表示数组索引,a..b
组成一个从a到b的列表.
/*
* Raster setup.
* The raster is a pxH x pxW array.
* Raster coordinates might be negative or larger than the array dimensions.
* When rendering (i.e. filling the array) positions outside the visible raster will not be filled (i.e. colored).
*/
pxW := Width of the screen in pixels.
pxH := Height of the screen in pixels.
T := Transformation matrix of homogeneous world points to raster space.
// Buffer setup.
colBuffer = apply(1..pxW, apply(1..pxH, 0)); // pxH x pxW array of black pixels.
// Positive/0 if the point is on the right side of the line (V1,V2)/exactly on the line.
// p2D := point to test.
// V1, V2 := two vertices of the triangle.
edgeFunction(p2D, V1, V2) := (
det([p2D-V1, V2-V1]);
);
fillBuffer(V0, V1, V2) := (
// Dehomogenize.
hV0 = V0/(V0_3);
hV1 = V1/(V1_3);
hV2 = V2/(V2_3);
// Find boundaries of the triangle in raster space.
xMin = min(hV0.x, hV1.x, hV2.x);
xMax = max(hV0.x, hV1.x, hV2.x);
yMin = min(hV0.y, hV1.y, hV2.y);
yMax = max(hV0.y, hV1.y, hV2.y);
xMin = floor(if(xMin >= 0, xMin, 0));
xMax = ceil(if(xMax < pxW, xMax, pxW));
yMin = floor(if(yMin >= 0, yMin, 0));
yMax = ceil(if(yMax < pxH, yMax, pxH));
// Check for all points "close to" the triangle in raster space whether they lie inside it.
forall(xMin..xMax, x, forall(yMin..yMax, y, (
p2D = (x,y);
i = edgeFunction(p2D, hV0.xy, hV1.xy) * edgeFunction(p2D, hV1.xy, hV2.xy) * edgeFunction(p2D, hV2.xy, hV0.xy);
if (i > 0, colBuffer_y_x = 1); // Fill all points inside the triangle with some placeholder.
)));
);
mapTrianglesToScreen() := (
tvRaster = homogVerts * T; // Triangle vertices in raster space.
forall(1..(length(tvRaster)/3), i, (
actualI = i / 3 + 1;
fillBuffer(tvRaster_actualI, tvRaster_(actualI + 1), tvRaster_(actualI + 2));
));
);
// After all this, render the colBuffer.
这种方法有什么问题?为什么这么慢?
谢谢。
我会选择 #3 它真的没有那么复杂所以你应该在标准机器上使用纯 SW 光栅器(没有任何库)获得 > 20
fps 如果正确编码。我敢打赌,您正在使用一些缓慢的 API,例如 PutPixel
或 SetPixel
,或者正在做一些疯狂的事情。如果没有看到代码或更好地描述你是如何做的,就很难详细说明。您需要执行此操作的所有信息都在这里:
也请查看每个...的子链接
我的任务是只使用线性代数和颜色实时生成二维函数图(想象一下必须根据函数定义在纯 C++ 中计算图像缓冲区,例如 f(x, y) = x^2 + y^2)。输出应该是这样的 3d plot。 到目前为止,我已经尝试了 3 种方法:
1:光线追踪:
将(x,y)平面分成三角形,求出每个顶点的z值,从而将图分成三角形。将每条射线与三角形相交。
2:球体追踪:
here描述了一种渲染隐式表面的方法。
3:光栅化:
(1) 的逆运算。将绘图分割成三角形,将它们投影到相机平面上,遍历 canvas 的像素并为每个选择 "closest" 投影像素。
所有这些都是减慢速度的方法。我的部分任务是围绕摄像机移动,因此必须在每一帧中重新渲染情节。请向我指出 information/another algorithm/any 类帮助的另一个来源。谢谢。
编辑
如前所述,这是我最基本的光栅器的伪代码。我知道这段代码可能并非完美无缺,但它应该与总体思路相似。然而,当我将我的情节分割成 200 个三角形时(我认为这不够),它已经运行得非常慢,甚至没有渲染任何东西。我什至没有使用深度缓冲区来提高可见性。我只是想通过如下设置帧缓冲区来测试速度:
注意:在我使用的JavaScript框架中,_
表示数组索引,a..b
组成一个从a到b的列表.
/*
* Raster setup.
* The raster is a pxH x pxW array.
* Raster coordinates might be negative or larger than the array dimensions.
* When rendering (i.e. filling the array) positions outside the visible raster will not be filled (i.e. colored).
*/
pxW := Width of the screen in pixels.
pxH := Height of the screen in pixels.
T := Transformation matrix of homogeneous world points to raster space.
// Buffer setup.
colBuffer = apply(1..pxW, apply(1..pxH, 0)); // pxH x pxW array of black pixels.
// Positive/0 if the point is on the right side of the line (V1,V2)/exactly on the line.
// p2D := point to test.
// V1, V2 := two vertices of the triangle.
edgeFunction(p2D, V1, V2) := (
det([p2D-V1, V2-V1]);
);
fillBuffer(V0, V1, V2) := (
// Dehomogenize.
hV0 = V0/(V0_3);
hV1 = V1/(V1_3);
hV2 = V2/(V2_3);
// Find boundaries of the triangle in raster space.
xMin = min(hV0.x, hV1.x, hV2.x);
xMax = max(hV0.x, hV1.x, hV2.x);
yMin = min(hV0.y, hV1.y, hV2.y);
yMax = max(hV0.y, hV1.y, hV2.y);
xMin = floor(if(xMin >= 0, xMin, 0));
xMax = ceil(if(xMax < pxW, xMax, pxW));
yMin = floor(if(yMin >= 0, yMin, 0));
yMax = ceil(if(yMax < pxH, yMax, pxH));
// Check for all points "close to" the triangle in raster space whether they lie inside it.
forall(xMin..xMax, x, forall(yMin..yMax, y, (
p2D = (x,y);
i = edgeFunction(p2D, hV0.xy, hV1.xy) * edgeFunction(p2D, hV1.xy, hV2.xy) * edgeFunction(p2D, hV2.xy, hV0.xy);
if (i > 0, colBuffer_y_x = 1); // Fill all points inside the triangle with some placeholder.
)));
);
mapTrianglesToScreen() := (
tvRaster = homogVerts * T; // Triangle vertices in raster space.
forall(1..(length(tvRaster)/3), i, (
actualI = i / 3 + 1;
fillBuffer(tvRaster_actualI, tvRaster_(actualI + 1), tvRaster_(actualI + 2));
));
);
// After all this, render the colBuffer.
这种方法有什么问题?为什么这么慢?
谢谢。
我会选择 #3 它真的没有那么复杂所以你应该在标准机器上使用纯 SW 光栅器(没有任何库)获得 > 20
fps 如果正确编码。我敢打赌,您正在使用一些缓慢的 API,例如 PutPixel
或 SetPixel
,或者正在做一些疯狂的事情。如果没有看到代码或更好地描述你是如何做的,就很难详细说明。您需要执行此操作的所有信息都在这里:
也请查看每个...的子链接