用c++实现光栅化和深度缓冲



我正在尝试在cc+中实现光栅化方法。我正在尝试实现一个插值函数,用于处理x、y和z顶点之间的插值。这样我就可以把z的倒数保存在深度缓冲区中。在这一点上,我只得到绘制在渲染图像上的顶点。有人能看到我的代码出了什么问题吗?我已经发布了完整的代码,所以你可以看到整个程序。非常感谢。

编辑

我发现我在vertexshader中写pixel.zinv = 1 / vPrime.z而不是p.zinv = 1/ vPrime.z时出错了。现在没有任何渲染,只有一个黑屏。

编辑2我检查一个像素是否应该画错了。

if (depthBuffer[row[i].x][row[i].y] < row[i].zinv)

是正确的。现在我得到了一些彩色的小碎片。

#include <iostream>
#include <glm/glm.hpp>
#include <SDL.h>
#include "SDLauxiliary.h"
#include "TestModel.h"

using namespace std;
using glm::vec2;
using glm::vec3;
using glm::ivec2;
using glm::mat3;
using glm::max;
// ----------------------------------------------------------------------------
// GLOBAL VARIABLES
int cc = 0;
const int SCREEN_WIDTH = 500;
const int SCREEN_HEIGHT = 500;
SDL_Surface* screen;
int t;
vector<Triangle> triangles;
vec3 cameraPos(0, 0, -3.001);
float f = 500;
double yaw = 0;
vec3 c1(cos(yaw), 0, -sin(yaw));
vec3 c2(0, 1, 0);
vec3 c3(sin(yaw), 0, cos(yaw));
glm::mat3 R(c1, c2, c3);
float translation = 0.1;        // use this to set translation increment
const float PI = 3.1415927;
vec3 currentColor;
float depthBuffer[SCREEN_HEIGHT][SCREEN_WIDTH];
// ----------------------------------------------------------------------------
// STUCTURES
struct Pixel
{
    int x;
    int y;
    float zinv;
}pixel;
// ----------------------------------------------------------------------------
// FUNCTIONS
void Update();
void Draw();
void VertexShader(const vec3& v, Pixel& p);
void Interpolate(ivec2 a, ivec2 b, vector<ivec2>& result);
void DrawLineSDL(SDL_Surface* surface, ivec2 a, ivec2 b, vec3 color);
void DrawPolygonEdges(const vector<vec3>& vertices);
void ComputePolygonRows(const vector<Pixel>& vertexPixels, vector<Pixel>& leftPixels, vector<Pixel>& rightPixels);
void DrawPolygonRows(const vector<Pixel>& leftPixels, const vector<Pixel>& rightPixels);
void DrawPolygon(const vector<vec3>& vertices);
void Interpolate2(Pixel a, Pixel b, vector<Pixel>& result);

int main(int argc, char* argv[])
{
    LoadTestModel(triangles);
    screen = InitializeSDL(SCREEN_WIDTH, SCREEN_HEIGHT);
    t = SDL_GetTicks(); // Set start value for timer.
    while (NoQuitMessageSDL())
    {
        Draw();
    }
    //Draw();
    //cin.get();
    SDL_SaveBMP(screen, "screenshot.bmp");
    return 0;
}

void Draw()
{
    SDL_FillRect(screen, 0, 0);
    if (SDL_MUSTLOCK(screen))
        SDL_LockSurface(screen);
    for (int y = 0; y<SCREEN_HEIGHT; ++y)
        for (int x = 0; x<SCREEN_WIDTH; ++x)
            depthBuffer[y][x] = 0;
    for (int i = 0; i<triangles.size(); ++i)
    {
        currentColor = triangles[i].color;
        vector<vec3> vertices(3);
        int aa = 24;
        vertices[0] = triangles[i].v0;
        vertices[1] = triangles[i].v1;
        vertices[2] = triangles[i].v2;  
        DrawPolygon(vertices);
    }
    if (SDL_MUSTLOCK(screen))
        SDL_UnlockSurface(screen);
    SDL_UpdateRect(screen, 0, 0, 0, 0);
}
void VertexShader(const vec3& v, Pixel& p)
{
    vec3 vPrime = (v - cameraPos)*R;
    p.zinv = 1 / vPrime.z;
    p.x = f * vPrime.x / vPrime.z + SCREEN_WIDTH / 2;
    p.y = f * vPrime.y / vPrime.z + SCREEN_HEIGHT / 2;
    //cout << p.x << "  this is it " << p.y << endl;
    depthBuffer[p.x][p.y] = pixel.zinv;
}
void ComputePolygonRows(const vector<Pixel>& vertexPixels,
    vector<Pixel>& leftPixels, vector<Pixel>& rightPixels)
{
    // Find y-min,max for the 3 vertices
    vec3 vp(vertexPixels[0].y, vertexPixels[1].y, vertexPixels[2].y);
    Pixel start; Pixel end; Pixel middle;
    int yMin = 1000;
    int yMax = -1000;
    int w=0; int s=0;
    for (int k = 0; k < vertexPixels.size(); ++k)
    {
        if (vp[k] <= yMin)
        {
            yMin = vp[k];
            end = vertexPixels[k];
            w = k;
        }
    }
    for (int k = 0; k < vertexPixels.size(); ++k)
    {
        if (vp[k] >= yMax)
        {
            yMax = vp[k];
            start = vertexPixels[k];
            s = k;
        }
    }
    for (int k = 0; k < vertexPixels.size(); ++k)
    {
        if (vertexPixels[k].y != start.y
            && vertexPixels[k].y != end.y)
        {
            middle = vertexPixels[k];
        }
        if (w!= k && s!= k)
        {
            middle = vertexPixels[k];
        }
    }
    int ROWS = yMax - yMin + 1;
    leftPixels.resize(ROWS);
    rightPixels.resize(ROWS);
    for (int i = 0; i<ROWS; ++i)
    {
        leftPixels[i].x = +numeric_limits<int>::max();
        rightPixels[i].x = -numeric_limits<int>::max();
    }
    int pixels1 = glm::abs(start.y - end.y) + 1;
    vector<Pixel> line1(pixels1);
    Interpolate2(end, start, line1);
    int pixels2 = glm::abs(end.y - middle.y) + 1;
    vector<Pixel> line2(pixels2);
    Interpolate2(end, middle, line2);
    int pixels3 = glm::abs(middle.y - start.y) + 1;
    vector<Pixel> line3(pixels3);
    Interpolate2(middle, start, line3);
    vector<Pixel> side1(ROWS);
    for (int i = 0; i < line2.size(); ++i)
    {
        side1[i] = line2[i];
    }
    for (int i = 0; i < line3.size(); ++i)
    {
        side1[line2.size()+i-1] = line3[i];
    }
    for (int i = 0; i < ROWS; ++i)
    {
        if (line1[i].x < leftPixels[i].x)
        {
            leftPixels[i] = line1[i];
        }
        if (line1[i].x > rightPixels[i].x)
        {
            rightPixels[i] = line1[i];
        }
        if (side1[i].x < leftPixels[i].x)
        {
            leftPixels[i] = side1[i];
        }
        if (side1[i].x > rightPixels[i].x)
        {
            rightPixels[i] = side1[i];
        }
    }
}
void DrawPolygonRows(const vector<Pixel>& leftPixels, const vector<Pixel>& rightPixels)
{
    //cout << cc++ << endl;
    for (int k = 0; k < leftPixels.size(); ++k)
    {
        int pixels = glm::abs(leftPixels[k].x - rightPixels[k].x) + 1;
        vector<Pixel> row(pixels);
        Interpolate2(leftPixels[k], rightPixels[k], row);
        for (int i = 0; i < pixels; ++i)
        {
            if (depthBuffer[row[i].x][row[i].y] < row[i].zinv)
            { 
                PutPixelSDL(screen, row[i].x, row[i].y, currentColor);
                depthBuffer[row[i].x][row[i].y] = row[i].zinv;
            }
        }
    }
}
void DrawPolygon(const vector<vec3>& vertices)
{
    int V = vertices.size();
    vector<Pixel> vertexPixels(V);
    for (int i = 0; i<V; ++i)
        VertexShader(vertices[i], vertexPixels[i]);
    vector<Pixel> leftPixels;
    vector<Pixel> rightPixels;
    ComputePolygonRows(vertexPixels, leftPixels, rightPixels);
    DrawPolygonRows(leftPixels, rightPixels);
}
void Interpolate2(Pixel a, Pixel b, vector<Pixel>& result)
{
    int N = result.size();
    float stepx = (b.x - a.x) / float(glm::max(N - 1, 1));
    float stepy = (b.y - a.y) / float(glm::max(N - 1, 1));
    float stepz = (b.zinv - a.zinv) / float(glm::max(N - 1, 1));
    float currentx = a.x;
    float currenty = a.y;
    float currentz = a.zinv;
    for (int i = 0; i<N; ++i)
    {
        result[i].x = currentx;
        result[i].y = currenty;
        result[i].zinv = currentz;
        currentx = a.x;
        currenty = a.y;
        currentz = a.zinv;
        currentx += stepx;
        currenty += stepy;
        currentz += stepz;
    }
}

最后一个函数中的最后一个循环对我来说似乎不正确。您在循环外定义currentx。然后,在循环中定义一个同名的局部变量,稍后在循环中使用。我建议循环内外的变量不要使用相同的名称,以使其更可读。此外,使用全局变量也会使代码难以阅读,因为我更喜欢将函数视为单独的实体进行分析。

相关内容

  • 没有找到相关文章

最新更新