Array ( )
Вход:




Главная | OpenGL | GLSL | AI | Сеть | Примеры | Библиотека

OpenGL: Вершинное освещение






В этом уроке мы научимся создавать вершинное освещение.
Исходные файлы main.cpp, main.h, init.h взяты из урока "Начало - инициализация".


Обьявим глобальную переменную позиции света в файле main.h:
extern float g_LightPosition[4];    // Позиция источника света




Итак, в первую очередь нам нужно инициализировать освещение.
Сделаем мы это в файле init.cpp:

// Сразу переходим к функции InitializeOpenGL().
// В конец функции, перед закрывающейся скобкой, дописываем новый код.

// Лучше всего устанавливать цвет пространства в цвет "темноты" - отсутствия освещения.
// Так как мы будем использовать белый как цвет освещения, установим цвет
// пространства в черный:

glClearColor(0, 0, 0, 1);

// Ниже создадим два массива цветов. Первый, ambience[] - цвет "рассеянного света", когда
// на полигон не падает прямое освещение. Если мы не установим этот цвет, не освещенные полигоны
// будут совершенно черными, и мы их не увидим. Цвет освещения мы сделаем белый, а рассеянный
// свет установим в половину этого значения.
// Второй массив, diffuse[], это цвет направленного света. Мы выбрали белый. Первые три
// цифры массивы - R,G,B, последняя - значение альфа. Пока что не беспокойтесь о нём.
//
// Для рассеянного света выберем глубоко серый цвет, для дифузного - среднее между
// белым и черным.

    float ambience[4] = {0.3f, 0.3f, 0.3f, 1.0};    // Цвет мирового света
    float diffuse[4] = {0.5f, 0.5f, 0.5f, 1.0}; // Цвет позиционного света

// Чтобы установить мировое освещене, нужно передать OpenGL наши массивы.
// OpenGL даёт нам возможность использовать несколько источников света. Общее количество
// источников зависит от переменной GL_MAX_LIGHTS. Для первого используемого источника будем
// использовать дефайн OpenGL GL_LIGHT0. После указания используемого источника передаём
// OpenGL флаг говорящий, что мы устанавливаем значение ambience, и массив ambience-цветов.
// Точно то же делаем с diffuse и GL_DIFFUSE.

    // Устанавливаем цвет рассеянного цвета (без направленного света)
    glLightfv( GL_LIGHT0, GL_AMBIENT,  ambience );
    // И диффузный цвет (цвет света)
    glLightfv( GL_LIGHT0, GL_DIFFUSE,  diffuse );

// Далее нам нужно установить позицию источника света. У нас может быть много простых
// источников в разных местах, но в этом уроке будет использоваться только один.
// Для последующих источников нужно использовать GL_LIGHT1, GL_LIGHT2, GL_LIGHT3 и т.д...
// Мы сможем изменять позицию источника клавишами '+' и '-'. Позиция по умолчанию - (0,1,0,1).
// Это расположит источник прямо над центральной пирамидой. Последнее значение в массиве
// g_LightPosition сообщает OpenGL, нужен ли нам ПОЗИЦИОННЫЙ или НАПРАВЛЕННЫЙ свет.
// Если значение = 1, цвет будет позиционным, иначе он будет направлен от камеры.
// Если мы установим направленный свет, он будет освещать всё "по дороге" от нашего "глаза".
// Если же свет будет позиционным, он "повиснет" в координатах x,y,z и будет освещать
// всё вокруг себя. Это то, что нам нужно, так что установим значение в единицу.

glLightfv( GL_LIGHT0, GL_POSITION, g_LightPosition );

// После инициализации источника света нам нужно включить его:
glEnable(  GL_LIGHT0   );

// Но недостаточно включить один источник; кроме этого нужно включить само
// освещение в OpenGL:
glEnable(GL_LIGHTING);

// Следующая строка позволяет закрашивать полигоны цветом при включенном освещении:
glEnable(GL_COLOR_MATERIAL);


Помните, если мы используем функции glColor*() вместе с освещением,
они будут проигнорированы, пока мы не включим GL_COLOR_MATERIALS.

В init.cpp мы инициализировали освещение в функции InicializeOpenGL().


Теперь используем освещение в main.cpp
// В начале файла, после включения хидеров, добавим переменные:
float g_LightPosition[4] = {0, 1, 0, 1};         // Позиция источника света
float g_bLight = true;                           // Включен ли свет

float rotY = 0.0f;                           // Вращение по Y





// Напишем функцию, создающую пирамиду:
void CreatePyramid(float x, float y, float z, int width, int height)
{

    glBegin(GL_TRIANGLES);

// Ниже мы добавим что-то новое: НОРМАЛИ. Значение, насколько сильно нужно
// осветить конкретный полигон, OpenGL рассчитывает из его нормалей. Что такоей нормаль?
// Нормаль - это направление полигона. Вы заметите, что мы присваиваем заднему полигону
// нормаль (0,1,-1). Это значит, что полигон направлен в обратную сторону по оси Z (внутрь
// экрана). Запомните, нормали - это не координаты, а только направления.
// Функция glNormal3f() позволяют нам указать нормаль для вершин, переданных за ней.
// Сейчас мы напишем нормали вручную, но вы можете вернутся к урокам камеры, где есть
// ничто иное, как функция для рассчета нормалей.

        // Задняя сторона
        glNormal3f(0, 1, -1);    // Полигон направлен назад и вверх
        glColor3ub(255, 0, 0);   glVertex3f(x, y + height, z);
        glColor3ub(0, 255, 255); glVertex3f(x - width, y - height, z - width);
        glColor3ub(255, 0, 255); glVertex3f(x + width, y - height, z - width);

        // Передняя сторона
        glNormal3f(0, 1, 1);
        glColor3ub(255, 0, 0);   glVertex3f(x, y + height, z);
        glColor3ub(0, 255, 255); glVertex3f(x + width, y - height, z + width);
        glColor3ub(255, 0, 255); glVertex3f(x - width, y - height, z + width);

        // Левая сторона
        glNormal3f(-1, 1, 0);
        glColor3ub(255, 0, 0);   glVertex3f(x, y + height, z);
        glColor3ub(255, 0, 255); glVertex3f(x - width, y - height, z + width);
        glColor3ub(0, 255, 255); glVertex3f(x - width, y - height, z - width);

        // Передняя правая сторона
        glNormal3f(1, 1, 0);
        glColor3ub(255, 0, 0);   glVertex3f(x, y + height, z);
        glColor3ub(255, 0, 255); glVertex3f(x + width, y - height, z - width);
        glColor3ub(0, 255, 255); glVertex3f(x + width, y - height, z + width);

    glEnd();

    // Теперь отрендерим дно пирамиды

    glBegin(GL_QUADS);

        // Эти вершины образуют дно пирамиды
        glNormal3f(0, -1, 0);
        glColor3ub(0, 0, 255); glVertex3f(x - width, y - height, z + width);
        glColor3ub(0, 0, 255); glVertex3f(x + width, y - height, z + width);
        glColor3ub(0, 0, 255); glVertex3f(x + width, y - height, z - width);
        glColor3ub(0, 0, 255); glVertex3f(x - width, y - height, z - width);
    glEnd();
}


//////////////////////////////////////////////////////////////////////////
// Внесём изменения в обработку клавиш, блок WM_KEYDOWN функции WinProc():

    case WM_KEYDOWN:
        switch (wParam)
        {
// Ниже мы позволяем пользователю увеличивать и уменьшать позицию Y источника света
// клавишами '+' и '-'. После изменения позиции необходимо сообщить об этом
// OpenGL вызовом glLightfv(). Мы передаём номер источника (GL_LIGHT0) и флаг
// GL_POSITION, плюс саму позицию.
// Нажатием 'L' свет включается и выключается.

            case VK_ESCAPE:
                PostQuitMessage(0);
                break;

            case VK_ADD:    // Если нажата ПЛЮС
                g_LightPosition[1] += 0.1f;  // Увеличиваем значение Y
                    // Убедимся, что не превысили 5
                if(g_LightPosition[1] > 5) g_LightPosition[1] = 5;
                break;

            case VK_SUBTRACT: // Если МИНУС
                g_LightPosition[1] -= 0.1f;// Уменьшим значение Y
                    // Убедиммся, что оно не меньше -5
                if(g_LightPosition[1] < -5) g_LightPosition[1] = -5;
                break;

            case 'L':

                g_bLight = !g_bLight;   // Выключим свет

                if(g_bLight)        // Включим свет
                    glEnable(GL_LIGHTING);
                else
                    glDisable(GL_LIGHTING); // Выключим свет
                break;
        }
        break;

////////////////////////////////////////////////////////////////////////


// И, наконец, изменим функцию RenderScene():
void RenderScene()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    // Обновим позицию света ДО вызова glLookAt(), чтобы свет обновился
    // корректно. Опустите функцию вниз, чтобы увидеть, что иначе случится.
    // Если источник не двигается, вызывать эту функцию заново не нужно.
    glLightfv( GL_LIGHT0, GL_POSITION, g_LightPosition );


    gluLookAt(0, 0, 6,     0, 0, 0,     0, 1, 0);

    glRotatef(rotY, 0.0f, 1.0f, 0.0f);  // Вращаем пирамиду вокруг оси Y

    // Это создаёт 3д пирамиду в центре (0,0,0)
    CreatePyramid(0, 0, 0, 1, 1);

    // Создадим пирамиды вокруг:

    CreatePyramid(3, 0, -3, 1, 1);
    CreatePyramid(-3, 0, -3, 1, 1);
    CreatePyramid(0, 0, 5, 1, 1);

    // Увеличиваем впращение.

    rotY += 0.6f;

    SwapBuffers(g_hDC);
}

 


Итак, вот шаги, которые мы проделали:

1) Установили ambience-цвет мира:
glLightfv( GL_LIGHT0, GL_AMBIENT, ambienceArray );

2) Установили diffuse-цвет источника света:
glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuseArray);

3) Установили позицию источника света:
glLightfv( GL_LIGHT0, GL_POSITION, positionArray);

4) Включили источник света:
glEnable( GL_LIGHT0 );

5) И освещение в OpenGL:
glEnable( GL_LIGHTING);








Исходные коды к уроку




Комментарии:

Войдите, чтобы оставить комментарий:












Яндекс.Метрика
 Яндекс цитирования.