Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Глава 50. Практика. Создание мира↑ ⇐ ПредыдущаяСтр 21 из 21 Содержание книги
Поиск на нашем сайте
Здесь описывается создание земли, по земле ходит актёр с камерой от первого и третьего лица, вокруг растут деревья, а под деревьями грибы. Ну и ещё сделаем воду. Начали. Поместим на форму GLScene1, GLSceneViewer1, GLCadencer1, GLNavigator1, GLUserInterface1, GLMaterialLibrary1, GLBitmapHDS1, Timer1. Пользуясь рисунком, создадим необходимые компоненты.
Кое-что поясню по поводу создания воды. Рекомендую поэкспериментировать с цветом у GLWaterPlane1. Зайдите в свойство Material у GLWaterPlane1 поставьте BlendingMode в bmTransparency чтобы изменения цвета отображались на воде. Для придания реалистичности сделайте воду прозрачной, для этого щёлкните на Front, и на вкладке Diffuse изменяйте свойство Alpha. С помощью свойства Elastic меняется эластичность воды, чем больше, тем менее эластична. Свойство RainTimeInterval регулирует, с какой частотой появляются капли на воде. Свойство RainForce регулирует силу волны. Замечание: при изменении какого-либо параметра изменения отображаются на воде только после второй компиляции (по крайней мере, у меня так). Ну что ж начнём кодить. Сначала подключим необходимые модули. uses Jpeg, Tga, GLkeyboard, VectorGeometry, GLFile3DS, GLFileMD2; Далее объявим переменные: public GLTree: TGLTree; // наше дерево proxy, proxy2: TGLProxyObject; // прокси-объекты дерева и гриба end; Следом загружаем всё необходимое. В OnCreate для формы пишем procedure TForm1.FormCreate(Sender: TObject); begin // загружаем модель гриба FreeForm2.LoadFromFile(‘media\mushroom.3ds’); // загружаем карту высот для нашей земли GLBitmapHDS1.Picture.LoadFromFile(‘media\terrain.bmp’); // загружаем текстуру на землю GLTerrainRenderer1.Material.Texture.Image. LoadFromFile(‘media\clover.jpg’); // модель актёра Actor1.LoadFromFile(‘media\waste.md2’); // его текстура Actor1.Material.Texture.Image.LoadFromFile(‘media\waste.jpg’); // его анимация Actor1.Animations.LoadFromFile(‘media\Quake2Animations.aaf’); // делаем его поменьше Actor1.Scale.SetVector(0.04, 0.04, 0.04, 0); // грузим нашему актёру пушку Actor2.LoadFromFile(‘media\WeaponWaste.md2’); // и текстуру к ней Actor2.Material.Texture.Image.LoadFromFile(‘media\WeaponWaste.jpg’); // анимация проигрывается циклически Actor1.AnimationMode:=aamLoop; // проигрывать анимацию стоять на месте Actor1.SwitchToAnimation(‘stand’); // активируем управление мышкой GLUserInterface1.MouseLookActivate; // далее добавляем текстуру для нашего дерева with GLMaterialLibrary1.AddTextureMaterial( ‘LeafFront’,’media\maple_multi.tga’) do begin Material.BlendingMode:=bmAlphaTest50; Material.Texture.TextureMode:=tmModulate; Material.Texture.TextureFormat:=tfRGBA; end; with GLMaterialLibrary1.AddTextureMaterial( ‘LeafBack’,’media\maple_multi.tga’) do begin Material.BlendingMode:=bmAlphaTest50; Material.Texture.TextureMode:=tmModulate; Material.Texture.TextureFormat:=tfRGBA; end; GLMaterialLibrary1.AddTextureMaterial(‘Branch’, ’media\zbark_016.jpg’).Material.Texture.TextureMode:=tmModulate; // добавляем прокси-деревья AddTree; // добавляем дерево NewTree; // добавляем грибы AddMushroms; end; Пора добавить дерево на сцену, для этого создадим процедуру NewTree: procedure TForm1.NewTree; begin // добавляем во FreeForm1 дерево GLTree:=TGLTree(FreeForm1.AddNewChild(TGLTree)); with GLTree do begin // присваиваем библиотеку материалов и берём от туда текстуры MaterialLibrary:=GLMaterialLibrary1; LeafMaterialName:=‘LeafFront’; LeafBackMaterialName:=‘LeafBack’; BranchMaterialName:=‘Branch’; // размеры Depth:=8; // регулирует, насколько дерево заросло листьями LeafSize:=0.2; // толщина ствола BranchRadius:=0.08; BranchNoise:=0.5; Randomize; Seed:=Round((2*Random-1)*(MaxInt-1)); end; end; Но что нам одно дерево, наделаем ему двойников, и опять нужно писать новую процедуру AddTree: procedure TForm1.AddTree; var i: Integer; s: TVector; f: Single; begin // создаём 50 клонов одного дерева, // которое содержится у нас во FreeForm1 for i:=0 to 50 do begin // создаем очередной прокси-объект proxy:=TGLProxyObject(DummyCube1.AddNewChild(TGLProxyObject)); with proxy do begin // наследуем только структуру объекта ProxyOptions:=[pooObjects]; //В свойство MasterObject записываем наше дерево-образец MasterObject:=FreeForm1; // ориентация в пространстве такая же, как и у FreeForm1 Direction.SetVector(FreeForm1.Direction.AsVector); Up.SetVector(FreeForm1.Up.AsVector); // делаем их разной величины s:=FreeForm1.Scale.AsVector; f:=(1*Random+1); ScaleVector(s, f); Scale.AsVector:=s; // позиция по X и Y выбирается случайно для // каждого созданного прокси-объекта Position.SetPoint(Random(990), Random(990), 0); // и ставим ровно на поверхность земли with Position do Z:=GLTerrainRenderer1.InterpolatedHeight(AsVector); // случайно поворачиваем на какой-то угол RollAngle:=Random(360); TransformationChanged; end; end; end;
Как мы достигаем, что деревья располагаются не абы как, а точно по склонам созданной нами земли. Объясняю: создаётся очередной прокси-объект, X и Y выбираются случайно, а Z присваивается значение высоты поверхности в точке с теми самыми случайными координатами X, Y. Всё, деревья растут точно по склонам, теперь надо, чтобы и грибы росли так же. Эта процедура аналогична предыдущей, поэтому просто скопируйте предыдущую (только мастер-объектом будет FreeForm2). Еще сделайте другое распределение грибов, а именно: Position.SetPoint(Random(1000)-(1000/5), Random(1000)-(1000/5), 0); Такой способ расположения объектов отличается от предыдущего тем, что он раскидывает грибы по кругу, а не в одну сторону, как это сделано с деревьями, т.к. деревья не очень смотрятся в воде. Ну вот и готово, растительность расставлена по местам. Осталось научить ходить нашего героя, для этого у GLCadencer1 в OnProgress запишем следующее: procedure TForm1.GLCadencer1Progress(Sender: TObject; const deltaTime, newTime: Double); var speed: Single; moving: string; begin // проигрывается анимация стоять на месте moving:=‘stand’; if IsKeyDown(VK_SHIFT) then begin // бежим быстрей Actor1.Interval:=100; // и ускоряем анимацию speed:=50*deltaTime end else begin // Бежим медленнее Actor1.Interval:=150; speed:=10*deltaTime; end; // при нажатии на Q (Й) переключаем камеру2 на камеру1 if IsKeyDown(Ord(‘Q’)) then GLSceneViewer1.Camera:=GLCamera1; // при нажатии на E (У) наоборот if IsKeyDown(Ord(‘E’)) then GLSceneViewer1.Camera:=GLCamera2; // обрабатывам нажатия клавиш движения if IsKeyDown(Ord(‘W’)) then begin GLNavigator1.MoveForward(speed); // играется анимация бежать moving:=‘run’; end; if IsKeyDown(Ord(‘S’)) then begin GLNavigator1.MoveForward(-speed); moving:=‘run’; end; if IsKeyDown(Ord(‘A’)) then begin GLNavigator1.StrafeHorizontal(-speed); moving:=‘run’; end; if IsKeyDown(Ord(‘D’)) then begin GLNavigator1.StrafeHorizontal(speed); moving:=‘run’; end; // при нажатии на эскейп завершаем программу if IsKeyDown(VK_ESCAPE) then Close; // удерживаем игрока на поверхности земли with DummyCube2.Position do Z:=GLTerrainRenderer1.InterpolatedHeight(AsVector)+1;
// играть анимацию которая находиться в moving if Actor1.CurrentAnimation<>moving then Actor1.SwitchToAnimation(moving); // синхронизируемся с первым актёром Actor2.Synchronize(Actor1);
// обрабатываем движение мыши GLUserInterface1.MouseUpdate; GLUserInterface1.MouseLook; end;
Добавим ещё кое что, а именно регулирование расстояния до актёра в виде от третьего лица колесиком мыши. Пишем в FormMouseWheel у Form1: GLCamera2.AdjustDistanceToTarget(Power(1.1, WheelDelta/120));
Ну и последний штрих в виде подсчёта фпс. В OnTimer у Timer1 пишем: Form1.Caption:=Format(‘%.2f FPS’, [GLSceneViewer1.FramesPerSecond]); GLSceneViewer1.ResetPerformanceMonitor; Теперь у нас в заголовке формы будет показываться сколько сейчас фпс. Похожая демка лежит здесь: Demos\meshes\actortwocam Приложение Структура рендера в GLScene Первым делом у вьювера вызывается пользовательское событие BeforeRender, сразу после это вызывается метод TGLSceneBuffer.Render который вызывает TGLSceneBuffer.DoBaseRender из которого уже вызывается TGLSceneBuffer.RenderScene, в каждой из процедур постепенно инициализируются/сбрасываются основные состояния ОГЛ, настраивается вьювер и камера, после чего идет вызов TGLBaseSceneObject.Render, и в конце рендеринга применяются все пост эффекты. Перед этим все объекты сортируются. Сама процедура TGLBaseSceneObject.Render так же простая. Первым делом идет отсечение невидимых объектов через фрастум куллинг. В сцене есть два способа это сделать: для каждого объекта и по иерархии (если родителя не видно - не рисуем чаилдов). Далее грузится модельная матрица объекта и вызывается виртуальный метод DoRender, который перекрывается потомками от TGLBaseSceneObject. Сам метод TGLBaseSceneObject.DoRender состоит из двух частей - первым идет вызов BuildList, в котором осуществляется создание геометрии с компиляцией ее в дисплейный список, и если список создан - вызывается внутренний рендер объекта. Вторая часть - рендеринг чаилдов, для чего вызывается метод RenderChildren. Работа с векторами
VectorMake/AffineVectorMake — возращают 4/3-вектор из набора координат или 3/4-вектора
VectorAdd — складывает два вектора. AddVector — складывает вектора v1, v2 и помещает результат в v1. Есть перегруженная функция, которая к каждой координате вектора v прибавляет число f. VectorSubtract — вычитает v2 из v1. Есть перегруженная функция, которая из каждой координаты вектора v1 вычитает число delta. SubtractVector — вычитает v2 из v1 и результат заносит в v1
VectorScale — каждую координату вектора v умножает на factor. VectorDivide — делит координаты v на соответствующие координаты divider. VectorNegate — возвращает противоположный вектор. VectorAbs — возвращает вектор из модулей координат исходного. У этих функций есть аналоги в форме процедур (ScaleVector, DivideVector, NegateVector, AbsVector).
VectorEquals — сравнивает два 4-вектора и возвращает true, если они равны. AffineVectorEquals — сравнивает два 3-вектора и возвращает true, если они равны. VectorIsNull — возвращает true если координаты X = Y = Z = 0, (w игнорируется). VectorLess/More(Equals)Then — сравнивает векторы различными способами.
VectorDotProduct — скалярное произведение векторов VectorCrossProduct — векторное произведение векторов VectorAngleCosine — возвращает косинус угла между векторами. PointProject — возвращает длину проекции вектора от origin до p на вектор из origin в направлении direction. Аналогичен VectorDotProduct(VectorSubtract(p, origin), direction).
VectorLength — вычисляет длину вектора: Result:= Sqrt (x*x + y*y + z*z + w*w). VectorNorm — вычисляет вторую норму: Result:= x*x+y*y+z*z+w*w (квадрат длины по сути). VectorNormalize — возвращает нормализованный вектор. NormalizeVector — нормализует вектор, т.е. делает длину вектора равной единице.
VectorDistance — вычисляет расстояние между двумя точками (длина разности). VectorDistance2 — вычисляет квадрат расстояния между двумя точками (первая норма разности) VectorSpacing — вычисляет первую норму разности векторов — сумму модулей разностей координат Result:= Abs(v1[x]-v2[x]) + Abs(v1[y]-v2[y]) + Abs(v1[z]-v2[z]) + Abs(v1[w]-v2[w])
RotateVector — поворачивает вектор относительно оси axis на угол angle. VectorRotateAroundX/Y/Z — поворачивает вектор вокруг оси X/Y/Z на угол alpha. VectorReflect — поворачивает V на 180 градусов относительно N (N должен быть нормализован)
VectorLerp — возвращает вектор, промежуточный между v1 и v2, t изменяется от 0 до 1 и задает, к какому из них результат будет ближе. Формула: Result:= v1 + t*(v2-v1). CombineVector — в переменную vr заносит линейную комбинацию векторов vr и v: vr:= vr + v*f. VectorCombine — линейная комбинация двух векторов по формуле Result:= V1*F1 + V2*F2. VectorCombine3 — линейная комбинация трех векторов: Result:= V1*F1 + V2*F2 + V3*F3. VectorTransform — преобразует вектор заданной матрицей преобразования Работа с матрицами
У каждого объекта в GLScene есть свойства, хранящие матрицы. В этих матрицах записаны ориентация, положение и масштаб объекта. Эти свойства: Matrix — локальная матрица объекта, содержащая его трансформации в системе координат родителя; AbsoluteMatrix — абсолютные трансормации объекта (в глобальной системе координат) InvAbsoluteMatrix — обращенная абсолютная матрица объекта. Также есть свойства, хранящие указатели на эти матрицы (удобны в некоторых случаях). Формат этих матриц (кроме, понятно, обращенной): Sx Dx Dy Dz U — компоненты Up Ux Sy Uy Uz D — компоненты Direction Lx Ly Sz Lz L — компоненты Left Px Py Pz 1 P — компоненты Position S — компоненты Scale
MatrixMultiply — перемножение двух матриц. ScaleMatrix — умножает все элементы матрицы на factor. MatrixInvert — вычисляет обратную матрицу. MatrixDeterminant — определитель матрицы. MatrixEquals — сравнивает матрицы. TransposeMatrix — транспонирование матрицы. Она может пригодиться, в частности, потому, что в OpenGL матрица записывается по столбцам, а в GLScene по строкам. Create***Matrix — возвращает матрицы разных преобразований. TranslateMatrix — к третьей строке (обычно позиция объекта) добавляет вектор v (W не учитывается) У MatrixMultiply и MatrixInvert есть процедурные аналоги.
Это не все функции для векторов и матриц. Также есть еще множество функций для работы с плоскостями, углами, кватернионами, функций проверки пересечений, оптимизированных тригонометрических и математических функций, и многих других. В общем, посмотрите сами. Методы объектов GLScene
Move, Lift, Slide — двигают объект вдоль вектора Direction/Up/Left. Translate — перемещает объект на соответствующее расстояние.
MoveObjectAround — вращает объект вокруг указанного на заданные углы по горизонтали и вертикали. Pitch, Turn Roll — поворачивают объект вокруг оси X/Y/Z. ResetRotations — сбрасывает все повороты и восстанавливает Direction и Up по умолчанию. ResetAndPitchTurnRoll — сбрасывает все повороты и затем вращает на заданные углы. PointTo — устанавливает Direction объекта по направлению на указанный объект или точку, требует вектор Up (ведь после поворота Left и Up могут быть искажены).
DistanceTo — возвращает расстояние до указанного объекта или точки. SqrDistanceTo — аналогично, но квадрат расстояния. Вычислительно проще, поэтому его лучше использовать для сравнения расстояний. PointInObject — проверяет, попадает ли точка в объект. Используйте с осторожностью: зачастую он проверяет только попадание точки в ограничивающий параллелепипед объекта. RayCastIntersect — проверяет, пересекается ли с объектом луч из rayStart в направлении rayVector.
MoveUp/Down/First/Last — перемещает объект в иерархии объекта-родителя. Действие остальных методов обычно понятно из названия.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Последнее изменение этой страницы: 2016-04-19; просмотров: 393; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.218.219.11 (0.008 с.) |