Низкая производительность с 3D движком в стиле Doom в SDL? - PullRequest
1 голос
/ 03 июля 2019

Я пытаюсь создать движок рендеринга в стиле дум, используя SDL2, но у меня немного проблем с производительностью. Я использую его на своем ноутбуке, который использует AMD Radeon R7 M260X, но я едва могу поддерживать стабильную скорость работы программы со скоростью 60 кадров в секунду, и программа использует около 40% графического процессора. окно, в которое я рендеринг, - 1067/600.

на данный момент камера использует фиксированный угол наклона камеры

void drawWall(XY p1, XY p2, XY p3, XY p4, float dis1, float dis2)
{

    float dx1 = 0;
    float dx2 = 0;
    float dDis = 0;
    float y1 = p1.Y;
    float y2 = p3.Y;
    float dis = dis1;
    int xLen = p2.X - p1.X;

    if (p2.X - p1.X != 0) 
        dx1 = (p2.Y - p1.Y) / (p2.X - p1.X);
    if (p4.X - p3.X != 0) 
        dx2 = (p4.Y - p3.Y) / (p4.X - p3.X);
    if (dis2 - dis1 != 0)
        dDis = (dis2 - dis1) / (p2.X - p1.X);
    float du = 0;
    if (p1.X < 0)
    {
        int d1 = - p1.X;
        du = d1;
        p1.X = 0;
        y1 += dx1*d1;
        y2 += dx2*d1;
        dis += dDis*d1;
    }



    float o =  100*(1/(dis));

    for (int x1 = p1.X; x1 <= p2.X && x1 < SCREEN_WIDTH; x1++, y1 += dx1, y2 += dx2, dis += dDis, du++)
    {
        SDL_Rect r1 = { (du / (xLen+1))*gField4.getWidth(), 0, 1,  gField4.getHeight()};
        SDL_Rect r2 = {x1, y2, 1, y1-y2};
        //float shade = 252 - dis;
        //gField4.setColorMod(shade, shade, shade);
        gField4.render(0, 0, &r1, &r2);
    }


}


void drawFloor(XY Camera, float height)
{

    float fowHalf = M_PI / 4;
    float farP = height;
    float nearP = 0;
    XY far1 = {Camera.X +  cosf(-M_PI/2 - fowHalf)*farP, Camera.Y + sinf(-M_PI / 2 - fowHalf)*farP };
    XY near1 = { Camera.X + cosf(-M_PI / 2 - fowHalf)*nearP, Camera.Y + sinf(-M_PI / 2 - fowHalf)*nearP };
    XY far2 = { Camera.X + cosf(-M_PI / 2 + fowHalf)*farP, Camera.Y + sinf(-M_PI / 2 + fowHalf)*farP };
    XY near2 = { Camera.X + cosf(-M_PI / 2 + fowHalf)*nearP, Camera.Y + sinf(-M_PI / 2 + fowHalf)*nearP };

    for (int i = 1; i < SCREEN_HEIGHT/2; i++)
    {
        float sampleDept = (float)i / ((float)SCREEN_HEIGHT / 2.0f);

        XY start = {(far1.X - near1.X)/sampleDept + near1.X, (far1.Y - near1.Y)/sampleDept + near1.Y };
        XY end = { (far2.X - near2.X)/sampleDept + near2.X, (far2.Y - near2.Y)/sampleDept + near2.Y };
        SDL_Rect r1 = {start.X*gField3.getWidth(),start.Y*gField3.getHeight(),  end.X*gField3.getWidth()- start.X*gField3.getWidth() , 1 };
        SDL_Rect r2 = {0, i+ SCREEN_HEIGHT / 2, SCREEN_WIDTH, 1 };
        if (r1.x < 0)
        {
            float d = -(float)r1.x / (float)r1.w;
            r2.x = SCREEN_WIDTH*d;
            r2.w = SCREEN_WIDTH - SCREEN_WIDTH*d;
        }
        if (r1.x+ r1.w > gField3.getWidth())
        {
            float d = ((float)r1.x + (float)r1.w - (float)gField3.getWidth())/ (float)r1.w;
            r2.w = r2.w - r2.w*d;
        }

        gField3.render(0, 0, &r1, &r2);
    }

}

void drawWalls(XY Camera, double height)
{
    for (Wall wall  : walls)
    {
        XY xy1 = wall.xy1;
        XY xy2 = wall.xy2;
        if (wall.xy1.X < wall.xy2.X)
        {
            xy2 = wall.xy1;
            xy1 = wall.xy2;
        }

        XY l1 = { xy1.X - Camera.X, xy1.Y - Camera.Y };
        XY l2 = { xy2.X - Camera.X, xy2.Y - Camera.Y };



        double Zdis1 = l1.Y;
        double Xdis1 = l1.X;
        double Zdis2 = l2.Y;
        double Xdis2 = l2.X;


        XY point1 = { -Xdis1 * (SCREEN_WIDTH / 2) / Zdis1, 10*SCREEN_WIDTH / Zdis1 };
        XY point2 = { -Xdis2 * (SCREEN_WIDTH / 2) / Zdis2, 10*SCREEN_WIDTH / Zdis2 };
        XY p1 = { SCREEN_WIDTH / 2 + point1.X, SCREEN_HEIGHT / 2 - (wall.h1 - height)*point1.Y };
        XY p2 = { SCREEN_WIDTH / 2 + point2.X, SCREEN_HEIGHT / 2 - (wall.h1 - height)*point2.Y };
        XY p3 = { SCREEN_WIDTH / 2 + point1.X, SCREEN_HEIGHT / 2 - (wall.h2 - height)*point1.Y };
        XY p4 = { SCREEN_WIDTH / 2 + point2.X, SCREEN_HEIGHT / 2 - (wall.h2 - height)*point2.Y };


        if (!((p1.X < 0 && p2.X < 0) || (p1.X > SCREEN_WIDTH && p2.X > SCREEN_WIDTH)))
        {
            drawWall( p1, p2, p3, p4, l1.Y, l2.Y);
        }
    }
}

метод .render () для полей g рендеринга фрагмента текстуры с использованием SDL_RenderCopyEx ()

Я пытался закомментировать вызовы метода gfields.render (), что снижает использование графического процессора до 40%, поэтому я предполагаю, что это потому, что я вызываю SDL_RenderCopyEx () пару раз по 1000 раз за кадр, что вызывая проблему с производительностью. Но я на самом деле не знаю, что я могу сделать, чтобы это исправить, так как я должен отрисовывать каждую линию стены и пола по отдельности, кто-нибудь знает, как я могу повысить производительность здесь?

...