Четверг, 05.12.2024, 22:30 Приветствую вас Гость | Группа "Гости" 
[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 1
  • 1
Модератор форума: Neo, xXxSh@dowxXx  
[C/C++] Простейший 3D мир
Волк-1024Дата: Воскресенье, 18.01.2015, 19:40 | Сообщение # 1
Авторитетный
Зарегистрирован: 24.07.2011
Группа: Модераторы
Сообщений: 469
Статус: Offline
С недавних пор я занялся изучением программированием 3D графики, посему выкладываю свои недописанные наброски на С.
В интернете достаточно много примеров, но они все слишком громоздкие и труднопонимаемые. Я же постарался сделать всё кратко.
Изначально всё писалось с использованием библиотеки Freeglut.dll, но чтобы не отступать от своих принципов, сделал всё на голых вызовах и WinApi)

Из недописанного по причине лени(выкинуто из кода): стрейф камеры, загрузка текстур и свет.
Если данный пример вас заинтересует, то в следующий раз я реализую недописанное, возможно на Делфи. biggrin

Управление: мышь + wasd, выход на Esc.

Код

#include <windows.h>
#include <gl/glu.h>
#include <gl/gl.h>
#include <math.h>

#define VK_W  0x057
#define VK_S  0x053
#define VK_A  0x041
#define VK_D  0x044

typedef struct TVector3D
{
    GLdouble  x;
    GLdouble  y;
    GLdouble  z;
}
TVector3D;

typedef struct TCameraObject
{
    TVector3D  Pos;  // Вектор позиции камеры.
    TVector3D  View; // Вектор направления камеры.
    TVector3D  Up;   // Вертикальная ось.
}
TCameraObject;

HDC hDC;
HGLRC hRC;
HWND hMainWindow;
int AppWidth, AppHeight;

TCameraObject Camera = {{0.0, 2.5, 5.0}, {0.0, 2.5, 0.0}, {0.0, 1.0, 0.0}}; // А вот такого в Делфи нельзя

TVector3D NormalizeVector(TVector3D Vector)
{
    TVector3D Result;

    double Length = sqrt((Vector.x * Vector.x) + (Vector.y * Vector.y) + (Vector.z * Vector.z));

    Result.x = Vector.x / Length;
    Result.y = Vector.y / Length;
    Result.z = Vector.z / Length;

    return Result;
}

TVector3D CrossVectors(TVector3D Vector1, TVector3D Vector2)
{
    TVector3D Result;

    Result.x = ((Vector1.y * Vector2.z) - (Vector1.z * Vector2.y));
    Result.y = ((Vector1.z * Vector2.x) - (Vector1.x * Vector2.z));
    Result.z = ((Vector1.x * Vector2.y) - (Vector1.y * Vector2.x));

    return Result;
}

void RotateCamera(double Speed)
{
    TVector3D Vector;

    Vector.x = Camera.View.x - Camera.Pos.x;
    Vector.z = Camera.View.z - Camera.Pos.z;

    Camera.View.z = Camera.Pos.z + sin(Speed) * Vector.x + cos(Speed) * Vector.z;
    Camera.View.x = Camera.Pos.x + cos(Speed) * Vector.x - sin(Speed) * Vector.z;
}

void MoveCamera(double Speed)
{
    TVector3D Vector = {0};
    /*
      Получаем вектора(направление) взгляда
    */
    Vector.x = Camera.View.x - Camera.Pos.x;
    Vector.z = Camera.View.z - Camera.Pos.z;

    Vector = NormalizeVector(Vector);
    /*
      Полученное направление, помноженное на скорость, прибавляем к позиции камеры и к позиции взгляда.
      Тем самым передвигая камеру вперёд или, если Speed отрицательное - назад.
    */
    Camera.Pos.x  += Vector.x * Speed;
    Camera.Pos.z  += Vector.z * Speed;
    Camera.View.x += Vector.x * Speed;
    Camera.View.z += Vector.z * Speed;
}

void DrawGrid()
{
    for (float i = -50; i <= 100; i += 5)
    {
       glBegin(GL_LINES);
           glVertex3f(-50, 0, i);
           glVertex3f(100, 0, i);
           glVertex3f(i, 0,-50);
           glVertex3f(i, 0, 100);
       glEnd();
    }
}

void RenderScene(HDC hDC)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Очищаем буфер цвета и буфер глубины.
    glLoadIdentity();
    /*
        Устанавливаем вектора камеры.
    */
    gluLookAt(Camera.Pos.x,  Camera.Pos.y,  Camera.Pos.z,
              Camera.View.x, Camera.View.y, Camera.View.z,
              Camera.Up.x,   Camera.Up.y,   Camera.Up.z);

    DrawGrid(); // Рисуем сетку.
    glTranslatef(0.0, 30.0, 0.0); // Вторую сетку поднимим на 30 чего-то там по Y)
    DrawGrid();;

    SwapBuffers(hDC);
}

void MouseMove(int xMouse, int yMouse)
{
    double xAngle = (double)((AppWidth >> 1)  - xMouse) * 0.0005;
    double yAngle = (double)((AppHeight >> 1) - yMouse) * 0.0010;

    if (Camera.View.y > 8.0)  Camera.View.y = 8.0;
    if (Camera.View.y < -3.0) Camera.View.y = -3.0;

    Camera.View.y += yAngle;
    RotateCamera(-xAngle);

    SetCursorPos(AppWidth >> 1, AppHeight >> 1);
    RenderScene(hDC);
}

void KeyboardInput(int Key)
{
    switch (Key)
    {
      case VK_W: MoveCamera(0.5);      // Движние вперёд.
                 break;
      case VK_S: MoveCamera(-0.5);     // Назад.
                 break;
      case VK_D: RotateCamera(0.025);  // Вправо.
                 break;
      case VK_A: RotateCamera(-0.025); // Влево
                 break;

      case VK_ESCAPE:
               {
                 PostQuitMessage(0);
               }
    }
}

void ResizeScene(int nWidth, int nHeight)
{
    AppWidth  = nWidth;
    AppHeight = nHeight;

    glViewport(0, 0, nWidth, nHeight);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, nWidth / nHeight, 0.1, 0); // Устнавливаем поле обзора в 45 градусов, соотношение сторон, передний и задний план.
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void EnableOpenGL(HWND hWindow, HDC* hDC, HGLRC* hRC)
{
    PIXELFORMATDESCRIPTOR PixelFormat = {0};

    PixelFormat.nSize      = sizeof(PIXELFORMATDESCRIPTOR);
    PixelFormat.nVersion   = 1;
    PixelFormat.dwFlags    = PFD_DRAW_TO_WINDOW |
                             PFD_SUPPORT_OPENGL |
                             PFD_DOUBLEBUFFER;
    PixelFormat.iPixelType = PFD_TYPE_RGBA;
    PixelFormat.cColorBits = 24;              // Глубина цвета.
    PixelFormat.cDepthBits = 16;              // Размер буфера глубины.
    PixelFormat.iLayerType = PFD_MAIN_PLANE;  // Тип плоскости.

    if (!(*hDC = GetDC(hWindow)))
       return;

    if (!(SetPixelFormat(*hDC, (ChoosePixelFormat(*hDC, &PixelFormat)), &PixelFormat)))
       return;

    if (!(*hRC  = wglCreateContext(*hDC)))
       return;

    if (!(wglMakeCurrent(*hDC, *hRC)))
       return;
}

LRESULT CALLBACK WindowProc(HWND hWindow, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
       case WM_SIZE      : ResizeScene(LOWORD(lParam), (HIWORD(lParam))); // Обработка изменения размеров главного окна.
                           break;
       case WM_PAINT     : RenderScene(hDC);                    // Отрисовка кадра.
                           break;
       case WM_CREATE    : EnableOpenGL(hWindow, &hDC, &hRC);             // Инициализация OpenGL.
                           break;
       case WM_KEYDOWN   : KeyboardInput(wParam);                         // Обработка нажатий клавиш на клавиатуре.
                           break;
       case WM_MOUSEMOVE : MouseMove(LOWORD(lParam), (HIWORD(lParam)));   // Обработка движения мыши.
                           break;
       default:
            return DefWindowProc(hWindow, uMsg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG Msg;
    WNDCLASSEX WindowClass;

    WindowClass.cbSize        = sizeof(WNDCLASSEX);
    WindowClass.style         = CS_OWNDC;
    WindowClass.lpfnWndProc   = WindowProc;
    WindowClass.cbClsExtra    = 0;
    WindowClass.cbWndExtra    = 0;
    WindowClass.hInstance     = hInstance;
    WindowClass.hIcon         = LoadIcon(0, IDI_APPLICATION);
    WindowClass.hCursor       = LoadCursor(0, IDC_ARROW);
    WindowClass.hbrBackground = 0;
    WindowClass.lpszMenuName  = 0;
    WindowClass.lpszClassName = "GLClass";
    WindowClass.hIconSm       = LoadIcon(0, IDI_APPLICATION);

    if (!RegisterClassEx(&WindowClass))
    {
       MessageBox(0, "Невозможно зарегистрировать класс окна.", "Шайссе!", MB_ICONERROR);
       return 0;
    }

    hMainWindow = CreateWindowEx(0,
                    "GLClass",
                    "OpenGL 3D",
                    WS_POPUPWINDOW, // Окно создастся без оконной рамки.
                    0,
                    0,
                    800,            // Ширина окна.
                    600,            // Высота.
                    0,
                    0,
                    hInstance,
                    0);
     if (!hMainWindow)
     {
       MessageBox(0, "Невозможно создать окно.", "Шайссе!", MB_ICONERROR);
       return 0;
     }

     ShowWindow(hMainWindow, SW_MAXIMIZE);
     ShowCursor(0);

     while (Msg.message != WM_QUIT)
     {
        if (PeekMessage(&Msg, 0, 0, 0, PM_REMOVE))
        {
           TranslateMessage(&Msg);
           DispatchMessage(&Msg);
        }
        else
           SendMessage(hMainWindow, WM_PAINT, 0, 0); // Посылаем окну сообщение на отрисовку следующего кадра. (Лучше сделать в отдельном потоке)
     }
    return Msg.wParam;
}

Волк-1024 (с)
Прикрепления: 5620279.zip (12.6 Kb)


Pascal, C\C++, Assembler, Python

Сообщение отредактировал Волк-1024 - Воскресенье, 18.01.2015, 22:55
 
xXxSh@dowxXxДата: Понедельник, 19.01.2015, 21:13 | Сообщение # 2
Авторитетный
Зарегистрирован: 22.01.2012
Группа: Модераторы
Сообщений: 702
Статус: Offline
Очень даже неплохо, да можно конечно многое сказать, но для начала очень даже, поздравляю! smile
 
XSPYДата: Среда, 21.01.2015, 20:04 | Сообщение # 3
Продвинутый
Зарегистрирован: 28.01.2010
Группа: Пользователи
Сообщений: 263
Статус: Offline
круто, пиши еще, но в 2-х форматах: СИ и Делфи =) я подписываюсь на тему!

Я не крекер,а программист!
Я не преступник-я свободный человек!
Лучше один раз накодить,чем сто раз качать билды!
 
Волк-1024Дата: Пятница, 23.01.2015, 19:46 | Сообщение # 4
Авторитетный
Зарегистрирован: 24.07.2011
Группа: Модераторы
Сообщений: 469
Статус: Offline
Вот, на скорую руку перегнал код на Делфи:

Прикрепления: 8822019.zip (77.7 Kb)


Pascal, C\C++, Assembler, Python

Сообщение отредактировал Волк-1024 - Пятница, 23.01.2015, 19:56
 
  • Страница 1 из 1
  • 1
Поиск:

delphicode.ru © 2008 - 2024 Хостинг от uCoz