MegaCraZy6
@MegaCraZy6
Юзерь

Как поступить с данным кодом переписать или можно оптимизировать?

Прочитал книгу по С++, решил попытаться закрепить как нибудь знания, и написать первую какую нибудь интересную программу с использованием новых знаний.

Выбор пал на самый простой 3д рендер. Все казалось довольно простым, кроме одного момента а именно как правильно и быстро рисовать полигоны. Решил что качество меня не особо волнует так как это перваяяя попытка и все такое.

И вот в готовой версии появилась проблема, рисовать то оно все рисует но все очень сильно лагает не знаю дело в кривости кода, или можно как-то решить проблему оптимизации.

Использую WinAPI
Код который отвечает за класс полигона а именно треугольника:
class Triangle{
private:
    double lenght = 0; double GlobalLenght = 0;
    Point center,new_p1,new_p2,new_p3;

    Point step( Point temp1, Point temp2, Point temp3 ){
        Point temp = temp1;
        lenght = round(sqrt(abs(pow(temp2.x - temp3.x, 2)+pow(temp2.y - temp3.y, 2)+pow(temp2.z - temp3.z, 2))));
        lenght *= 2.5;
        temp.x = temp.x / lenght; temp.y = temp.y / lenght; temp.z = temp.z / lenght;
        return temp;
    }

    void draw_line( Point temp2 ){
        Point temp1,temp3;
        temp1 = temp2 - new_p1;
        temp1 = step(temp1, temp2,new_p1);
        temp3 = new_p1;
        for(int i = 0; i < lenght; i++ ){
                if ( temp3.z >= 0 ){
                    if( (int)temp3.y < 480 && (int)temp3.x < 640 ){
                        if ( buffer_z[(int)temp3.y][(int)temp3.x] > temp3.z ){
                        SetPixel(mem_dc,(int)temp3.x,(int)temp3.y,RGB(t,0,100));
                        buffer_z[(int)temp3.y][(int)temp3.x] = temp3.z;
                        }
                    }
                }
                temp3 = temp3 + temp1;
        }
    }

public:
    char t = '#';
    Point p1,p2,p3;
    Triangle(){ t = '#'; }

    Triangle(char ch){
        t = ch;
    }

// Здесь инициализация полигона
    Triangle(Point A, Point B, Point C){
        Set(A,B,C);
    }

// Здесь инициализация полигона
    void Set( Point A, Point B, Point C ){ 
        p1 = A; p2 = B; p3 = C;
        double l1,l2;
        l1 = ::lenght(A,C);
        l2 = ::lenght(B,C);
        if ( l1 > l2 ){
            p1= B; p2 = A; p3 = C;
        }
        else if ( ::lenght(A,B) > l2) {
            p1 = C; p2 = A; p3 = B;
        }
    }

// Здесь вход в  функцию которая выводит полигон в видео буфер
// Вектор отрезка BC делиться на длину, 
// После чего из точки A рисую отрезки к всем точкам что лежать на отрезке BC
// Так заполняется вся площадь треугольника, и я могу сравнить координату Z с той что в буфере.
// ( Придумал сам поэтому более чем уверен что лаги именно из за этого алгоритма )
    void draw_to_buffer()
    {

         Point temp1, temp2;
         perspective();
         temp1 = new_p3 - new_p2;
         temp1 = step(temp1,new_p3,new_p2);
         GlobalLenght = lenght;
         temp2 = new_p2;
         for(int ai = 0; ai <= GlobalLenght; ai++ )
         {
           draw_line(temp2);
           temp2 = temp2 + temp1;
         }
    }


// Преобразует точки ортогональной проекции в центральную ( если не ошибаюсь вот так называется )
    void perspective(){
        center.Set(640/2,480/2,0);
        new_p1 = p1;
        new_p2 = p2;
        new_p3 = p3;
        new_p3 = new_p3 - center;
        new_p3.x = new_p3.x / new_p3.z;
        new_p3.y = new_p3.y / new_p3.z;
        new_p2 = new_p2 - center;
        new_p2.x = new_p2.x / new_p2.z;
        new_p2.y = new_p2.y / new_p2.z;
        new_p1 = new_p1 - center;
        new_p1.x = new_p1.x / new_p1.z;
        new_p1.y = new_p1.y / new_p1.z;
        new_p1 = new_p1 + center;
        new_p2 = new_p2 + center;
        new_p3 = new_p3 + center;
    }

};


Класс представляет из себя три переменных типа Double где хранятся координаты X,Y,Z
Код всей программки тут:
https://pastebin.com/y2Ns2S1P
  • Вопрос задан
  • 84 просмотра
Решения вопроса 3
vt4a2h
@vt4a2h Куратор тега C++
Senior software engineer (C++/Qt/boost)
Есть инструменты профилирования. Они могут помочь вам найти узкое место. Только не забудьте релизную сборку использовать.
Ответ написан
Комментировать
@vanyamba-electronics
Константы в коде, они ведь что-то обозначают.
const int viewport_width = 640;
const int viewport_width = 480;

Ещё один момент - из конструктора невозможно вызвать виртуальную функцию, а это часто требуется, когда программа разрастается. Поэтому нужно делать так:
class Triangle
{
public:
    static Triangle* create(Triangle* instance = nullptr) {
        if (instance == nullptr) {
             instance = new Triangle;
             if (instance == nullptr)
                 throw Exception("Can't create Triangle object");
        }
        // инициализация
       instance->A = 0;
       instance->B = 0;
       instance->C = 0;
       return instance;
    }
};
...
Triangle* myTriangle = Triangle::create();
Ответ написан
maaGames
@maaGames
Погроммирую программы
SetPixel очень плохая сточки зрения производительнсоти функция. У тебя есть буфер (битмап), верни из него массив байт и записывай значения непосредственно в него, это сразу сильно ускорит отрисовку. Только учти, что ширина строки не равна числу пикселей в этой строке и величину смещения нужно запросить отдельно.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы