【问题标题】:CPU Ray CastingCPU 光线投射
【发布时间】:2011-10-21 23:37:11
【问题描述】:

我正在尝试在 CPU 上投射八叉树(我知道 GPU 更好,但我目前无法让它工作,我相信我的八叉树纹理创建不正确)。

我了解需要做什么,到目前为止,我为每个像素投射了一条射线,并检查该射线是否与八叉树中的任何节点相交。如果是这样并且该节点不是叶节点,我检查光线是否与它的子节点相交。我一直这样做,直到一个叶节点被命中。一旦一个叶节点被命中,我就会得到那个节点的颜色。

我的问题是,将其绘制到屏幕上的最佳方式是什么?目前我将颜色存储在一个数组中并使用 glDrawPixels 绘制它们,但这不会产生正确的结果,渲染中的间隙以及投影错误(我使用的是 glRasterPos3fv)。

编辑:这里有一些代码,需要清理,抱歉。我省略了八叉树射线投射代码,因为我不确定它是否需要,但如果有帮助我会发布:)

void Draw(Vector cameraPosition, Vector cameraLookAt)
{
// Calculate the right Vector
Vector rightVector = Cross(cameraLookAt, Vector(0, 1, 0));

// Set up the screen plane starting X & Y positions
float screenPlaneX, screenPlaneY;
screenPlaneX = cameraPosition.x() - ( ( WINDOWWIDTH / 2) * rightVector.x());
screenPlaneY = cameraPosition.y() + ( (float)WINDOWHEIGHT / 2);

float deltaX, deltaY;
deltaX = 1;
deltaY = 1;

int currentX, currentY, index = 0;
Vector origin, direction;

origin = cameraPosition;
vector<Vector4<int>> colours(WINDOWWIDTH * WINDOWHEIGHT);

currentY = screenPlaneY;

Vector4<int> colour;

for (int y = 0; y < WINDOWHEIGHT; y++)
{
    // Set the current pixel along x to be the left most pixel
    // on the image plane
    currentX = screenPlaneX;

    for (int x = 0; x < WINDOWWIDTH; x++)
    {
        // default colour is black
        colour = Vector4<int>(0, 0, 0, 0);

        // Cast the ray into the current pixel. Set the length of the ray to be 200
        direction = Vector(currentX, currentY, cameraPosition.z() + ( cameraLookAt.z() * 200 ) ) - origin;
        direction.normalize();

        // Cast the ray against the octree and store the resultant colour in the array
        colours[index] = RayCast(origin, direction, rootNode, colour);

        // Move to next pixel in the plane
        currentX += deltaX;
        // increase colour arry index postion
        index++;
    }

    // Move to next row in the image plane
    currentY -= deltaY;
}

// Set the colours for the array
SetFinalImage(colours);

// Load array to 0 0 0 to set the raster position to (0, 0, 0)
GLfloat *v = new GLfloat[3];
v[0] = 0.0f;
v[1] = 0.0f;
v[2] = 0.0f;

// Set the raster position and pass the array of colours to drawPixels
glRasterPos3fv(v);
glDrawPixels(WINDOWWIDTH, WINDOWHEIGHT, GL_RGBA, GL_FLOAT, finalImage);
}

void SetFinalImage(vector<Vector4<int>> colours)
{
    // The array is a 2D array, with the first dimension
    // set to the size of the window (WINDOW_WIDTH * WINDOW_HEIGHT)
    // Second dimension stores the rgba values for each pizel

    for (int i = 0; i < colours.size(); i++)
    {
        finalImage[i][0] = (float)colours[i].r;
        finalImage[i][1] = (float)colours[i].g;
        finalImage[i][2] = (float)colours[i].b;
        finalImage[i][3] = (float)colours[i].a;
    }
}

【问题讨论】:

  • 能否提供有关像素数据如何存储在数组中的代码和信息。 glDrawPixels 应该与投影无关,但这取决于glPixelStoreglPixelTransferglPixelMapglPixelZoom 的设置。
  • 嘿,我已经用一些源代码编辑了原始帖子。现在我看了一下,我认为问题可能是我在 for 循环中计算光线方向时如何设置光线的长度
  • 您是否以您的 draw() 调用所期望的相同格式(RGB、ARGB、RGBA 等)存储颜色数据?
  • 人工制品的屏幕截图将有助于确定原因。

标签: c++ opengl volume raycasting octree


【解决方案1】:

您的像素绘图代码看起来不错。但我不确定您的 RayCasting 例程是否正确。当我编写光线追踪器时,我遇到了一个导致屏幕上出现水平伪影的错误,但这与渲染代码中的舍入错误有关。

我会试试这个...创建一个vector&lt;Vector4&lt;int&gt;&gt; 的结果集,其中颜色都是红色的。现在将其渲染到屏幕上。如果它看起来正确,那么 opengl 例程是正确的。分而治之始终是一种很好的调试方法。

这里有个问题....你为什么在稍后将图像写为GL_FLOAT 时使用 Vector4?我在这里没有看到任何 int->float 转换....

【讨论】:

  • 嗯,我不知道为什么我同时使用浮点数和整数,我现在已经改变了。我做了上面的建议,颜色确实都是红色的。但是我认为我没有理解 glDrawPixels。因为,如果我向体积移动(在这种情况下只是一个红色平面),平面会变小。如果你明白我想说的话,就好像物体随着相机一起移动。
  • 所以,关于 glDrawPixels 要记住一件事,它非常愚蠢。 glDrawPixels 完全忽略任何类型的转换等。基本上你给它一个 x/y 位置,它将图像贴到屏幕上。因此,如果您想要剪辑图像,或者除了对屏幕进行直接 blit 之外的任何操作,您将需要使用纹理并将其应用于多边形。你能发一张图片吗?令人惊讶的是,有大量图形错误,只需查看输出图像即可调试。
  • 啊,好吧,是的,这可能是问题所在。我应该使用纹理代替。是的,这里有一些图像。原始体积(在 GPU 上完成)i130.photobucket.com/albums/p251/benzino07/originalVolume.png 这里是在 CPU 上用八叉树 i130.photobucket.com/albums/p251/benzino07/frame1.png 渲染的(八叉树在这里只有 2 级或 3 级,但你可以看到它类似于体积)。但是当我移向红色框时,您可以看到音量也移动到i130.photobucket.com/albums/p251/benzino07/frame2.png 我认为这可以使用纹理来解决。
【解决方案2】:

您的问题可能出在您的 3DDDA(八叉树光线投射器)中,特别是自适应终止。它是由光线量化为网格单元形式产生的,这导致某些八叉树节点略微位于前景节点后面(即具有更高的 z 深度),因此应该部分可见和部分遮挡,根本不被渲染。您的体素越小,这种情况就越不明显。

有一种非常简单的方法可以测试这是否是问题所在 - 注释掉 3DDDA 中的自适应终止线,看看您是否仍然得到相同的间隙伪影。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-09
    • 2022-10-15
    • 1970-01-01
    相关资源
    最近更新 更多