![]() Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву ![]() Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Глава 50. Практика. Создание мираСодержание книги
Поиск на нашем сайте
Здесь описывается создание земли, по земле ходит актёр с камерой от первого и третьего лица, вокруг растут деревья, а под деревьями грибы. Ну и ещё сделаем воду. Начали. Поместим на форму 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; просмотров: 407; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.216.36.138 (0.011 с.) |