{
В этом уроке я научу вас использовать три различных метода фильтрации текстур.
Научите вас, как использовать клавиатуру для перемещения объектов на сцене, а также научитесь применять простое освещение в сцене OpenGL.
Этот урок содержит много контента. Если у вас есть вопросы по предыдущим урокам, вернитесь и сначала просмотрите их.
Прежде чем углубляться в его код, важно хорошо понимать основы.
Мы по-прежнему модифицируем код из первого урока.
Отличие от предыдущего в том, что всякий раз, когда происходят какие-либо большие изменения, я пишу весь код.
Сначала нам нужно добавить модуль SysUtils и модуль Glaux.
}
Использование
СисУтилс,
опенгл,
окна,
Сообщения,
Глаукс В '../../GLAUX/Glaux.pas';
//Следующие строки добавляют новые переменные.
//Добавляем три логические переменные.
// Переменная света отслеживает, включен ли свет.
//Переменные lp и fp используются для хранения информации о том, нажаты ли клавиши «L» и «F».
//Я объясню важность этих переменных позже. Пока отложите это в сторону.
Light : Boolean // источник света вкл/выкл;
lp : Boolean; // Нажата ли клавиша L?
fp : Boolean; // Нажата ли клавиша F?
//Теперь установите 5 переменных для управления размером шага угла поворота вокруг осей X и Y,
//И скорость вращения вокруг осей X и Y.
//Кроме того, создается переменная z для управления расстоянием в глубину экрана.
xrot : GLfloat // вращение по оси X;
yrot: GLfloat // вращение по оси Y;
xspeed : GLfloat // скорость вращения по оси X;
yspeed : GLfloat // скорость вращения по оси Y;
z : GLfloat = -5.0 f // Расстояние вглубь экрана
//Затем устанавливаем массив, используемый для создания источника света.
//Мы будем использовать два разных источника света.
//Первый из них называется рассеянным светом. Окружающий свет исходит со всех сторон.
//Все объекты в сцене освещены окружающим светом.
//Второй тип источника света называется рассеянным светом.
//Рассеянный свет генерируется конкретным источником света и создает отражения на поверхностях объектов вашей сцены.
//Любая поверхность объекта, непосредственно освещенная рассеянным светом, становится очень яркой,
//Области, которые едва освещены, кажутся темнее.
//Это создаст очень хороший эффект тени на краях созданного нами деревянного ящика.
//Процесс создания источника света точно такой же, как и создание цвета.
//Первые три параметра — это трехцветные компоненты RGB, а последний — параметр альфа-канала.
//Поэтому в следующем коде мы получаем полуяркий (0,5f) белый окружающий свет.
//Если нет окружающего света, области, на которые не попадает рассеянный свет, станут очень темными.
LightAmbient: Array[0..3] Of GLfloat = (0.5, 0.5, 0.5, 1.0 //Параметры окружающего освещения (новое)
//Следующей строкой кода мы генерируем самый яркий рассеянный свет.
//Все значения параметров принимаются к максимальному значению 1.0f.
//Он будет сиять на передней части нашего деревянного ящика и хорошо выглядеть.
LightDiffuse: Array[0..3] Of GLfloat = (1.0, 1.0, 1.0, 1.0 // Параметры рассеянного света (новое);
//Наконец, мы сохраняем положение источника света.
//Первые три параметра такие же, как в glTranslate.
//Смещения по оси XYZ соответственно.
//Поскольку мы хотим, чтобы свет падал прямо на переднюю часть деревянного ящика, оба смещения по оси XY равны 0,0.
//Третье значение — смещение по оси Z.
//Чтобы гарантировать, что свет всегда находится перед деревянным ящиком,
//Итак, мы перемещаем источник света от экрана к наблюдателю (которым являетесь вы).
//Мы обычно называем положение экрана, то есть экранного стекла монитора, точкой 0,0 оси Z.
//Итак, смещение по оси Z наконец установлено равным 2,0.
//Если вы видите источник света, значит, он плавает перед вашим монитором.
//Конечно, деревянную коробку не видно, если она не за стеклом монитора.
//『Примечание переводчика: Я ценю терпение НеХе.
//Честно говоря, меня иногда раздражает, почему он говорит такую ерунду о такой простой вещи?
//Но если бы всё было понятно, вы бы всё равно листали такие страницы бесконечно? 』
//Последний параметр принимается равным 1.0f.
//Это сообщит OpenGL, что указанные здесь координаты являются положениями источников света. Подробнее я объясню в будущих уроках.
LightPosition: Array[0..3] Of GLfloat = (0.0, 0.0, 2.0, 1.0 // Положение источника света (новое);
//Переменная фильтра отслеживает тип текстуры, используемый при отображении.
//Первая текстура (текстура 0) создается с использованием метода фильтрации gl_nearest (негладкая).
//Вторая текстура (текстура 1) использует метод gl_linear (линейная фильтрация),
//Изображение ближе к экрану выглядит более плавным.
//Третья текстура (текстура 2) использует метод фильтрации с использованием мип-отображения,
//Это создаст очень красивую текстуру.
//В зависимости от типа использования значение переменной фильтра равно 0, 1 или 2 соответственно.
//Начнем с первой текстуры.
//текстура выделяет место для хранения трех разных текстур.
//Они расположены в текстурах[0], текстуре[1] и текстуре[2] соответственно.
фильтр: GLUint; // Тип фильтра;
текстура: Array[0..2] Of GLuint // Место для хранения 3 текстур;
PROcedure glGenTextures (n: GLsizei; Var текстуры: GLuint external);
opengl32;
Процедура glBindTexture (цель: GLenum; текстура: GLuint);
opengl32;
Функция gluBuild2DMipmaps (цель: GLenum; компоненты, ширина, высота: GLint;
формат, тип: GLenum; данные: указатель): целое число; внешнее имя glu32;
'gluBuild2DMipmaps';
{
Теперь загрузите растровое изображение и используйте его для создания трех разных текстур.
В этом уроке для загрузки растровых изображений используется вспомогательная библиотека glaux.
Поэтому вам следует убедиться, включена ли библиотека glaux при компиляции.
Я знаю, что и Delphi, и VC++ включают библиотеку glaux, но ее наличие в других языках не гарантируется.
«Примечание переводчика: glaux — это вспомогательная библиотека OpenGL. Согласно кроссплатформенным характеристикам OpenGL,
Код должен быть общим для всех платформ. Но вспомогательная библиотека не является официальной стандартной библиотекой OpenGL.
Доступно не на всех платформах. Но он доступен на платформе Win32.
Ха-ха, конечно, BCB тоже не проблема. 』Здесь я только аннотирую только что добавленный код.
Если у вас есть вопросы по поводу определенной строки кода, ознакомьтесь с уроком 6.
В этом уроке очень подробно объясняется загрузка и создание текстур.
После предыдущего фрагмента кода и перед glResizeWnd(),
Мы добавили следующий код. Это почти идентично коду, использованному в уроке 6 для загрузки растрового изображения.
}
Функция LoadBmp (имя файла: pchar): PTAUX_RGBImageRec;
Вар
BitmapFile: Thandle // дескриптор файла;
Начинать
If Filename = '' Тогда // Убедитесь, что указано имя файла.
результат := Nil // Если не указано, возвращаем NULL;
BitmapFile := FileOpen(Filename, fmOpenWrite); //Попытаемся открыть файл.
Если BitmapFile > 0 Тогда // Существует ли файл?
Начинать
FileClose(BitmapFile); //Дескриптор закрытия
result := auxDIBImageLoadA(filename); //Загружаем растровое изображение и возвращаем указатель
Конец
Еще
результат := Nil // Если загрузка не удалась, верните NiL;
Конец;
Функция LoadTexture: boolean; //Загружаем растровое изображение и преобразуем его в текстуру.
Вар
Статус: логическое значение // Индикатор состояния;
TextureImage : Array[0..1] Of PTAUX_RGBImageRec // Создаём место для хранения текстур;
Начинать
Статус: = ложь;
ZeroMemory(@TextureImage, sizeof(TextureImage)); // Устанавливаем указатель в NULL
TextImage[0] := LoadBMP('Walls.bmp');
Если TextImage[0] <> Nil Тогда
Начинать
Статус := ИСТИНА // Установить статус ИСТИНА;
glGenTextures(1, текстура[0]); // Создаем текстуру
//В уроке 6 мы использовали наложение текстур с линейной фильтрацией.
//Это требует от машины довольно большой вычислительной мощности, но выглядят они довольно хорошо.
//В этом уроке первая текстура, которую мы собираемся создать, использует метод GL_NEAREST.
//В принципе, этот метод фактически не выполняет фильтрацию.
//Он потребляет очень мало вычислительной мощности и выглядит плохо.
//Единственное преимущество в том, что наш проект может нормально работать как на быстрых, так и на медленных машинах.
//Вы заметите, что мы используем GL_NEAREST как для MIN, так и для MAG,
//Вы можете смешивать GL_NEAREST и GL_LINEAR.
//Текстура будет выглядеть лучше, но нас больше волнует скорость, поэтому мы используем все карты низкого качества.
//MIN_FILTER используется, когда изображение нарисовано меньше исходного размера текстуры.
//MAG_FILTER используется, когда изображение нарисовано больше исходного размера текстуры.
// Создать карту ближайшего фильтра
glBindTexture (GL_TEXTURE_2D, текстура [0]);
// Генерируем текстуру
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // (новое)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // (новое)
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
Текстурное изображение[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
ТекстурноеИзображение[0].data);
//Следующая текстура такая же, как в уроке 6, линейная фильтрация. Разница лишь в том, что на этот раз он помещен
//текстура[1]. Потому что это вторая текстура. Если установлено
//текстура[0] перезапишет ранее созданную текстуру GL_NEAREST.
glBindTexture(GL_TEXTURE_2D,texture[1]); //Используем типичную текстуру, сгенерированную из растровых данных
// Генерируем текстуру
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0].sizeX,
TextureImage[0].sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE,
ТекстурноеИзображение[0].data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Линейная фильтрация;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Линейная фильтрация;
//Ниже представлен новый способ создания текстур. Мипмэппинг!
//『Примечание переводчика: я не могу перевести это слово на китайский, но это не имеет значения. Прочитав этот абзац, вы поймете, что смысл важнее всего. 』
//Вы можете заметить, что когда изображение на экране становится меньше, теряется много деталей.
//Шаблон, который только что выглядел хорошо, стал уродливым. Когда вы указываете OpenGL создать текстуру с мип-отображением,
//OpenGL попытается создать высококачественные текстуры разных размеров. Когда вы рисуете мип-текстуру на экране,
//OpenGL выберет наиболее выглядящую текстуру (с большей детализацией), которую он создал, для рисования,
//Вместо того, чтобы просто масштабировать исходное изображение (что приведет к потере деталей).
//Я как-то сказал, что есть способы обойти ограничения OpenGL на ширину и высоту текстуры - 64, 128, 256 и т.д.
//Решение — gluBuild2DMipmaps. Судя по тому, что я нашел, вы можете использовать произвольные растровые изображения для создания текстур.
//OpenGL автоматически масштабирует его до нормального размера.
//Поскольку это третья текстура, мы сохраняем ее в текстуру[2]. Таким образом были созданы все три текстуры в этом уроке.
//Создаем текстуру MipMapped
glBindTexture(GL_TEXTURE_2D, текстура[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST); // (новый)
//Следующая строка генерирует текстуру с мип-отображением.
//Мы используем три цвета (красный, зеленый, синий) для создания 2D-текстуры.
//TextureImage[0].sizeX — ширина растрового изображения,
//TextureImage[0].sizeY — высота растрового изображения,
//(====По какой-то причине эта функция в Delphi не имеет параметра высоты,
//Но есть ли это в помощи? Я не знаю, что будет дальше делать Delphi, и это меня вводит в депрессию...
//Наконец, я сам ранее написал gluBuild2DMipmaps,
//Чтобы загрузить функцию gluBuild2DMipmaps в glu32.dll =====)
//GL_RGB означает, что мы по очереди используем цвета RGB.
//GL_UNSIGNED_BYTE означает, что единицей данных текстуры являются байты.
//TextureImage[0].data указывает на растровое изображение, которое мы используем для создания текстуры.
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0].sizeX,
TextureImage[0].sizey, GL_RGB, GL_UNSIGNED_BYTE,
TextImage[0].data); //(новый) }
Конец;
Если назначено(TextureImage[0]) Тогда // Существует ли текстура
Если присвоено(TextureImage[0].data) Тогда // Существует ли изображение текстуры
TextureImage[0].data := Nil // Освободите память, занятую изображением текстуры;
TextureImage[0] := Nil // Освобождаем структуру изображения;
результат := Статус // Возвращаемый статус;
Конец;
//Затем пришло время загрузить текстуру и инициализировать настройки OpenGL.
//Первая строка функции GLInit использует приведенный выше код для загрузки текстуры.
//После создания текстуры мы вызываем glEnable(GL_TEXTURE_2D), чтобы включить наложение 2D-текстуры.
//Режим тени установлен на плавное затенение (плавное затенение).
//Цвет фона установлен на черный, мы включаем тестирование глубины, а затем включаем оптимизированные расчеты перспективы.
Процедура glInit() // Здесь начинаются все настройки OpenGL.
Начинать
If (Not LoadTexture) then // Вызов подпрограммы загрузки текстуры
выход; // Если не удалось загрузиться, выходим
glEnable(GL_TEXTURE_2D); // Включаем наложение текстур
glShadeModel(GL_SMOOTH); // Включаем сглаживание теней;
glClearColor(0.0, 0.0, 0.0, 0.0); // черный фон;
glClearDepth(1.0); //Устанавливаем буфер глубины
glEnable(GL_DEPTH_TEST); // Включаем тестирование глубины
glDepthFunc(GL_LESS); // Тип выполненной проверки глубины
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //Высокооптимизированный расчет перспективной проекции
//Теперь приступаем к настройке источника света. Следующая строка ниже устанавливает количество излучаемого окружающего света:
//Источник света Light1 начинает излучать свет.
//В начале этого урока мы сохраняем количество окружающего света в массиве LightAmbient.
//Теперь мы будем использовать этот массив (окружающий свет половинной яркости).
glLightfv(GL_LIGHT1, GL_AMBIENT, @LightAmbient[0]); // Устанавливаем окружающий свет
//Далее мы устанавливаем количество рассеянного света. Он хранится в массиве LightDiffuse (белый свет полной яркости).
glLightfv(GL_LIGHT1, GL_DIFFUSE, @LightDiffuse[0]); // Устанавливаем рассеянный свет
//Затем устанавливаем положение источника света.
//Позиция сохраняется в массиве LightPosition
//(Точно в центре передней части деревянного ящика, X-0.0, Y-0.0, сдвинуты на 2 единицы к наблюдателю в направлении Z <за пределы экрана>).
glLightfv(GL_LIGHT1, GL_POSITION, @LightPosition); // Положение источника света;
//Наконец, мы включаем источник света номер один. Мы еще не включили GL_LIGHTING,
//Значит, вы не видите света.
//Помните: просто настроить, расположить или даже включить источник света не получится.
//Если мы не включим GL_LIGHTING.
glEnable(GL_LIGHT1); // Включаем источник света №1;
Конец;
//Следующий фрагмент кода рисует текстурированный куб. Я только аннотирую новый код.
//Если у вас есть вопросы по коду без аннотаций, вернитесь к уроку 6.
Процедура glDraw(); // Все рисование начинается отсюда
Начинать
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT // Очищаем экран и буфер глубины);
glLoadIdentity(); //Сбрасываем матрицу наблюдения текущей модели
//Следующие три строки кода размещают и вращают куб текстуры.
//glTranslatef(0.0,0.0,z) перемещает куб на Z единиц вдоль оси Z.
//glRotatef(xrot,1.0f,0.0f,0.0f) вращает куб вокруг оси X xrot.
//glRotatef(yrot,0.0f,1.0f,0.0f) вращает куб yrot вокруг оси Y.
glTranslatef(0.0, 0.0, z); // Перемещение по экрану на z единиц;
glRotatef(xrot, 1.0, 0.0, 0.0 // Поворот вокруг оси X);
glRotatef(yrot, 0.0, 1.0, 0.0 // Поворот вокруг оси Y);
//Следующая строка аналогична той, что мы делали в уроке 6.
//Разница в том, что на этот раз мы связываем текстуру text[filter],
//Вместо текстуры[0] в предыдущем уроке.
//Каждый раз, когда мы нажимаем клавишу F, значение фильтра будет увеличиваться.
//Если это значение больше 2, переменная filter будет сброшена в 0.
//При инициализации программы значение переменной filter также будет установлено в 0.
//Используя переменный фильтр, мы можем выбрать любую из трёх текстур.
glBindTexture(GL_TEXTURE_2D,texture[filter]); //Выбираем текстуру, определенную фильтром
glBegin(GL_QUADS); // Начинаем рисовать четырехугольники
//glNormal3f — новичок в этом уроке. Нормальный значит нормальный.
//Так называемая нормаль – это прямая линия, проходящая через точку на поверхности (многоугольнике) и перпендикулярная этой поверхности (многоугольнику).
//При использовании источника света необходимо указать нормаль. Нормаль сообщает OpenGL ориентацию многоугольника и указывает переднюю и заднюю стороны многоугольника.
//Если не указаны нормали, могут произойти странные вещи: подсвечиваются поверхности, которые не должны быть освещены, а также освещается обратная сторона полигона....
//Кстати, нормаль должна указывать на внешнюю сторону многоугольника. Глядя на переднюю часть коробки, вы заметите, что нормаль направлена в том же направлении, что и положительная ось Z.
//Это означает, что нормаль указывает на наблюдателя — на вас самих. Это именно то, на что мы надеемся.
//Для задней части деревянного ящика, как мы и хотим, нормаль обращена от зрителя.
//Если куб повернут на 180 градусов по оси X или Y, нормаль на передней стороне по-прежнему обращена к наблюдателю, а нормаль на обратной стороне по-прежнему обращена от наблюдателя.
//Другими словами, независимо от того, какая это поверхность, пока она обращена к наблюдателю, нормаль этой поверхности указывает на наблюдателя.
//Поскольку источник света находится непосредственно рядом с наблюдателем, каждый раз, когда нормаль обращена к наблюдателю, эта поверхность будет освещена.
//И чем ближе нормаль к источнику света, тем ярче он будет казаться.
//Если вы поместите точку наблюдения внутри куба, вы получите темноту внутри нормали.
//Потому что нормаль направлена наружу. Если внутри куба нет источника света, то, конечно, он будет абсолютно черным.
// Передний
glNormal3f(0.0, 0.0, 1.0); // нормаль указывает на наблюдателя
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, 1.0); // Текстура и левый нижний угол квадрата;
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, 1.0); // Текстура и правая нижняя часть четырехугольника;
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, 1.0); //Текстура и правая верхняя часть квадрата;
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0); //Текстура и верхний левый угол квадрата
// позже
glNormal3f(0.0, 0.0, -1.0); // Нормальные лица от зрителя
glTexCoord2f(1.0, 0.0);
glVertex3f(-1.0, -1.0, -1.0 // Текстура и правая нижняя часть квадрата);
glTexCoord2f(1.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0); //Текстура и правая верхняя часть квадрата;
glTexCoord2f(0.0, 1.0);
glVertex3f(1.0, 1.0, -1.0); //Текстура и верхний левый угол квадрата
glTexCoord2f(0.0, 0.0);
glVertex3f(1.0, -1.0, -1.0); // Текстура и левый нижний угол четырехугольника;
// верхняя поверхность
glNormal3f(0.0, 1.0, 0.0); // нормально вверх
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0); //Текстура и верхний левый угол четырехугольника;
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, 1.0, 1.0); // Текстура и левый нижний угол четырехугольника;
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, 1.0, 1.0); // Текстура и правая нижняя часть четырехугольника;
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, -1.0); //Текстура и правая верхняя часть квадрата;
// Нижний
glNormal3f(0.0, -1.0, 0.0); // нормаль вниз
glTexCoord2f(1.0, 1.0);
glVertex3f(-1.0, -1.0, -1.0); // Текстура и верхняя правая часть четырехугольника;
glTexCoord2f(0.0, 1.0);
glVertex3f(1.0, -1.0, -1.0); //Текстура и верхний левый угол квадрата
glTexCoord2f(0.0, 0.0);
glVertex3f(1.0, -1.0, 1.0); // Текстура и левый нижний угол четырехугольника;
glTexCoord2f(1.0, 0.0);
glVertex3f(-1.0, -1.0, 1.0); // Текстура и правая нижняя часть квадрата;
// верно
glNormal3f(1.0, 0.0, 0.0); // нормально вправо
glTexCoord2f(1.0, 0.0);
glVertex3f(1.0, -1.0, -1.0); // Текстура и правая нижняя часть квадрата;
glTexCoord2f(1.0, 1.0);
glVertex3f(1.0, 1.0, -1.0); //Текстура и правая верхняя часть квадрата;
glTexCoord2f(0.0, 1.0);
glVertex3f(1.0, 1.0, 1.0); //Текстура и верхняя левая часть квадрата
glTexCoord2f(0.0, 0.0);
glVertex3f(1.0, -1.0, 1.0); // Текстура и левый нижний угол четырехугольника;
// левый
glNormal3f(-1.0, 0.0, 0.0 // нормаль влево);
glTexCoord2f(0.0, 0.0);
glVertex3f(-1.0, -1.0, -1.0 // Текстура и левый нижний угол квадрата);
glTexCoord2f(1.0, 0.0);
glVertex3f(-1.0, -1.0, 1.0); // Текстура и правая нижняя часть квадрата;
glTexCoord2f(1.0, 1.0);
glVertex3f(-1.0, 1.0, 1.0); //Текстура и правая верхняя часть четырехугольника;
glTexCoord2f(0.0, 1.0);
glVertex3f(-1.0, 1.0, -1.0); //Текстура и верхний левый угол четырехугольника;
глКонец();
xrot := xrot + xspeed // xrot увеличивает скорость в единицах;
yrot := Yrot + yspeed // yrot увеличивает единицы скорости y;
Конец;
//Теперь переходим к основной функции WinMain().
//Здесь мы добавим код управления для включения и выключения источника света, вращения деревянного ящика, переключения методов фильтрации и перемещения деревянного ящика ближе и дальше.
// В конце функции WinMain() вы увидите строку кода SwapBuffers(hDC).
//Затем добавьте следующий код после этой строки.
//Код проверит, была ли нажата клавиша L.
//Если клавиша L была нажата, но значение lp не является ложным, это означает, что клавиша L не была отпущена и в этот момент ничего не произойдет.
SwapBuffers(h_DC); // буфер подкачки (двойной буфер)
Если (keys[ord('L')] И Не lp) Тогда
Начинать
//Если значение lp ложно,
//Это означает, что клавиша L еще не была нажата или отпущена, тогда для lp будет установлено значение TRUE.
//Причина одновременной проверки этих двух условий состоит в том, чтобы предотвратить нажатие клавиши L.
//Этот код выполняется неоднократно и заставляет форму непрерывно мигать.
//После того, как для lp установлено значение true, компьютер будет знать, что клавиша L была нажата.
//Мы можем соответствующим образом включать/выключать источник света: логическая переменная Light управляет включением/выключением источника света.
lp := true // lp установлен в TRUE;
свет := Не свет // Переключаем источник света на TRUE/FALSE;
Если нет света Тогда // Если нет источника света
glDisable(GL_LIGHTING) //Отключаем источник света
Остальное // Другие
glEnable(GL_LIGHTING); //Включаем источник света
Конец;
If Notkeys[ord('L')] Тогда //Отпущена ли клавиша L?
lp := FALSE // Если да, установите lp в FALSE;
//Затем делаем аналогичную проверку для клавиши «F».
//Если клавиша «F» нажата, а клавиша «F» не нажата или она никогда не нажималась,
//Устанавливаем переменную fp в true. Это означает, что клавиша нажата.
//Затем добавляем единицу в переменную фильтра. Если переменная фильтра больше 2
//(Поскольку здесь используется массив текстуры[3], текстуры размером больше 2 не существуют),
//Сбрасываем переменную фильтра в 0.
If (keys[ord('F')] And Not fp) Тогда // Нажата ли клавиша F?
Начинать
fp := TRUE // fp установлено в TRUE;
inc(filter); // Добавляем единицу к значению фильтра
Если фильтр > 2 Тогда // Это больше 2?
фильтр := 0 // Если сброшено в 0;
Конец;
If Notkeys[ord('F')] Тогда //Отпущена ли клавиша F?
fp := FALSE // Если для fp установлено значение FALSE;
//Эти четыре строки проверяют, нажата ли клавиша PageUp. Если да, уменьшите значение переменной z. Таким образом, вызов glTranslatef(0.0f,0.0f,z), включенный в функцию DrawGLScene, переместит деревянный ящик дальше от зрителя.
Если клавиши[VK_PRIOR] Тогда //PageUp нажата?
z := z - 0.02; // При нажатии переместим деревянный ящик внутрь экрана.
//Следующие четыре строки проверяют, нажата ли клавиша PageDown. Если да, увеличьте значение переменной z. Таким образом, вызов glTranslatef(0.0f,0.0f,z), включенный в функцию DrawGLScene, переместит деревянный ящик ближе к наблюдателю.
Если клавиши[VK_NEXT] Тогда // Нажата страница PageDown?
z := z + 0.02; //При нажатии переместим деревянный ящик к наблюдателю.
//Теперь проверим клавиши со стрелками. Нажимайте клавиши направления «влево» и «вправо», чтобы соответственно уменьшить или увеличить скорость.
//Нажимайте клавиши со стрелками вверх и вниз, чтобы соответственно уменьшить или увеличить скорость.
//Помните, что в будущих уроках, если значения xspeed и yspeed будут увеличены, куб будет вращаться быстрее.
//Если вы продолжите нажимать клавишу определенного направления, куб будет вращаться быстрее в этом направлении.
Ifkeys[VK_UP] Тогда // Нажата ли клавиша направления «Вверх»?
xspeed := xspeed - 0.01 //Если да, уменьшите xspeed;
Ifkeys[VK_DOWN] Тогда //Нажата ли клавиша направления вниз?
xspeed := xspeed + 0.01 //Если да, увеличьте xspeed;
Ifkeys[VK_RIGHT] Тогда //Нажата ли клавиша направления вправо?
yspeed := yspeed + 0.01 //Если да, увеличьте yspeed;
Ifkeys[VK_LEFT] Тогда //Нажата ли клавиша направления влево?
yspeed := yspeed - 0.01 //Если да, уменьшите yspeed;
If (keys[VK_ESCAPE]) Тогда // Если нажата клавиша ESC
закончено := Правда
Запустите и увидите эффект