Опубликован: 02.12.2011 | Доступ: свободный | Студентов: 980 / 117 | Оценка: 5.00 / 4.00 | Длительность: 09:26:00
Специальности: Программист
Теги: .net, open source, opengl
Лекция 7:

Освещение объектов

< Лекция 6 || Лекция 7: 12 || Лекция 8 >

Нормали

Направление нормалей имеет значение для двух составляющих освещения: диффузной и отраженной. Направление нормали может быть определено индивидуально для каждой вершины. Для определения нормали используется команда:

Normal [3] [b s I f d][v] (coords)

И в Object Pascal и в C# для реализации команды используется набор процедур (Object Pascal) и статических методов класса GL (C#), которые различаются параметрами. Ниже приведен один из вариантов реализации команды:

C#:
  void Normal3(float nx, float ny, float nz);
Object Pascal:
  procedure glNormal3f (nx, ny, nz: GLFloat);

По умолчанию направление нормалей [0,0,1], т.е. они направлены вдоль оси OZ и имеют единичный размер.

Пример программы

В качестве примера построим три квадрата, составляющих грани куба, с использованием библиотеки OpenTK на языке C# ( пример 6.3) и на языке программирования Object Pascal ( пример 6.4).

private void glControl1_Paint(object sender, PaintEventArgs e)
{
// очистка буферов цвета и глубины
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
// поворот изображения
GL.LoadIdentity();
GL.Rotate(AngleX, 1.0, 0.0, 0.0);
GL.Rotate(AngleY, 0.0, 1.0, 0.0);
GL.Rotate(AngleZ, 0.0, 0.0, 1.0);
// формирование осей координат
GL.Enable(EnableCap.Lighting);
GL.Enable(EnableCap.Light0);
float n = 0.5f; // половина длины ребра куба
GL.Color3(1f, 0f, 0f);
GL.Begin(BeginMode.Quads);
GL.Normal3(0f, 0f, 1f);
GL.Vertex3(0.5f, 0.5f, 0.5f);
GL.Vertex3(-0.5f, 0.5f, 0.5f);
GL.Vertex3(-0.5f, -0.5f, 0.5f);
GL.Vertex3(0.5f, -0.5f, 0.5f);
GL.End();
GL.Color3(0f, 1f, 0f);
GL.Begin(BeginMode.Quads);
GL.Normal3(0f, 0f, -1f);
GL.Vertex3(0.5f, 0.5f, -0.5f);
GL.Vertex3(0.5f, -0.5f, -0.5f);
GL.Vertex3(-0.5f, -0.5f, -0.5f);
GL.Vertex3(-0.5f, 0.5f, -0.5f);
GL.End();
GL.Color3(0f, 0f, 1f);
GL.Begin(BeginMode.Quads);
GL.Normal3(-1f, 0f, 0f);
GL.Vertex3(-0.5f, 0.5f, 0.5f);
GL.Vertex3(-0.5f, 0.5f, -0.5f);
GL.Vertex3(-0.5f, -0.5f, -0.5f);
GL.Vertex3(-0.5f, -0.5f, 0.5f);
GL.End();
GL.Disable(EnableCap.Lighting);
// завершение формирования изображения
GL.Flush();
GL.Finish();
glControl1.SwapBuffers();
}
Листинг 6.3. Пример использования режима освещения с использованием библиотеки OpenTK на C#
procedure TForm1.FormPaint(Sender: TObject);
var
  n: Double;
begin
  glClearColor (1, 1, 1, 1); // цвет фона
  glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  // установка видовой матрицы в качестве текущей
  glMatrixMode(GL_MODELVIEW);
  // поворот изображения
  glLoadIdentity;
  glRotatef(AngleX, 1.0, 0.0, 0.0);
  glRotatef(AngleY, 0.0, 1.0, 0.0);
  glRotatef(AngleZ, 0.0, 0.0, 1.0);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  n := 0.5; // половина длины ребра куба
  glColor3f(1, 0, 0);
  glBegin (GL_QUADS);
    //glNormal3f(0, 0, -1);
    glVertex3f (0.5, 0.5, 0.5);
    glVertex3f (-0.5, 0.5, 0.5);
    glVertex3f (-0.5, -0.5, 0.5);
    glVertex3f (0.5, -0.5, 0.5);
  glEnd;
  glColor3f(0, 1, 0);
  glBegin (GL_QUADS);
    //glNormal3f(0, 0, 1);
    glVertex3f (0.5, 0.5, -0.5);
    glVertex3f (0.5, -0.5, -0.5);
    glVertex3f (-0.5, -0.5, -0.5);
    glVertex3f (-0.5, 0.5, -0.5);
  glEnd;
  glColor3f(0, 0, 1);
  glBegin (GL_QUADS);
    //glNormal3f(1, 0, 0);
    glVertex3f (-0.5, 0.5, 0.5);
    glVertex3f (-0.5, 0.5, -0.5);
    glVertex3f (-0.5, -0.5, -0.5);
    glVertex3f (-0.5, -0.5, 0.5);
  glEnd;
  glDisable(GL_LIGHTING);
  // завершение формирования изображения
  glFlush;
  glFinish;
  SwapBuffers(DC);
end; 
Листинг 6.4. Пример использования режима освещения на Obejct Pascal

В пример 6.3 и пример 6.4 хотя и вызывается команда Color перед формированием каждого квадрата, но она игнорируется библиотекой OpenGL, так как предварительно включен режим освещения. Получаемый результат представлен на рис. 6.1

Вид освещённого фрагмента куба без указания направления нормалей для примитивов

Рис. 6.1. Вид освещённого фрагмента куба без указания направления нормалей для примитивов
Вид освещённого фрагмента куба с указанием направления нормалей для примитивов

Рис. 6.2. Вид освещённого фрагмента куба с указанием направления нормалей для примитивов

На рис. 6.1 видно, что прямоугольники освещаются неестественно, так как все грани имеют одинаковую освещенность. Объясняется это направлением нормалей. По умолчанию (после инициализации библиотеки) нормали направлены вдоль оси OZ, поэтому для всех граней интенсивность освещенности оказывается одинаковой.

Для реальных объектов направление нормали перпендикулярно касательной к их поверхности. В библиотеке OpenGL направление нормалей может быть задано для каждой вершины произвольным.

Чтобы получить более реалистичное освещение необходимо определить направление нормалей для каждой грани. Для этого в пример 6.3 и пример 6.4 достаточно убрать комментарии со строчек кода с командой Normal ( рис. 6.2).

Как можно наблюдать на рис. 6.2, после указания направления нормалей перпендикулярно граням, освещённость стала для граней различной и зависит от их ориентации в пространстве. Освещение прямоугольников стало более естественным.

Направление нормали указывается для каждой вершины. Если нормаль не указана перед вызовом команды Vertex, то используется текущее значение нормали, которое было последний раз задано с помощью команды Normal или значение нормали по умолчанию. Возможность индивидуального определения нормалей для вершин позволяет реализовать довольно сложные визуальные эффекты.

На рис. 6.1 и рис. 6.2 освещены только лицевые грани примитивов. Это связано с направлением нормалей к граням примитивов. Нормали направлены изнутри наружу, поэтому освещаются внешние грани. Если изменить направление нормалей на противоположное, то будут освещаться обратные грани примитивов.

Цвет примитивов на рисунках имеет различные оттенки серого цвета. Это обусловлено свойствами "нулевого" источника света и свойствами материала по умолчанию.

Определение нормалей для сложных поверхностей

В пример 6.3 и пример 6.4 направление нормалей было довольно просто определить, так как расположение примитивов было перпендикулярно осям координат. В некоторых других случаях определение направления нормалей также не является сложной задачей. Например, для вершин сферы направление нормалей совпадает с радиус-вектором. Для боковой грани цилиндра – с радиус вектором окружности.

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

Для вычисления нормали необходимо выбрать 3 вершины многоугольника, которые не лежат на одной прямой. Если V1, V2, V3 – координаты выбранных вершин, то вектора \vec{V} и \vec{W} , построенные на основе этих вершин:

\vec{V}=V1-V2\\\vec{W}=V3-V3

Векторное произведение \vec{V} и \vec{W} можно определить по формуле:

\vec{N}=(v_x,V_y,V_z)\times(W_x,W_y,W_z)=[(V_y\timesW_z-W_y\timesV_z), (V_x\timesW_z-W_x\timesV_z), (V_x\timesW_y-W_x\timesV_y)]

При вычисленении нормалей они могут получить различный размер. Так как на освещенность примитивов влияет не только направление нормалей, но и их размер, то это также необходимо учитывать.

Если не предполагается специально для задания интенсивности освещения использовать размер нормалей, то необходимо чтобы размер всех нормалей был единичным.

Операцию приведения размера нормали к единичному при сохранении её направления называют нормализацией нормали.

Длина исходного вектора:N=\sqrt{x^2+y^2+z^2}.

Нормализованный вектор: \vec{N_n}=(x/N,y/N,z/N).

OpenGL может выполнить автоматически нормализацию нормалей. По умолчанию этот режим отключен. Для включения и отключения используются соответственно команды Enable и Disable со значением параметра:

C#:
  EnableCap.Normalize
Object Pascal:
  GL_NORMALIZE

Краткие итоги

В лекции рассмотрена инициализация режима освещения, измененение свойств материала, формирование нормалей.

< Лекция 6 || Лекция 7: 12 || Лекция 8 >
Владислав Нагорный
Владислав Нагорный

Подскажите, пожалуйста, планируете ли вы возобновление программ высшего образования? Если да, есть ли какие-то примерные сроки?

Спасибо!

Лариса Парфенова
Лариса Парфенова

1) Можно ли экстерном получить второе высшее образование "Программная инженерия" ?

2) Трудоустраиваете ли Вы выпускников?

3) Можно ли с Вашим дипломом поступить в аспирантуру?