Обзор: как создать 3D-рельеф для iOS. Это предполагает базовые знания программирования на iOS (как создать проект и добавить в него файлы).
Я работал над приложением для iOS, которое использует cocos3d и алгоритм генерации холмов Роберта , которые создают хорошие холмы, которые напоминают мне о ранних уровнях Mario. Например:
Вы можете скачать библиотеку поколения холмов с Github . Я преобразовал код Роба из C ++ в Objective-C и добавил поддержку прямоугольной местности (вместо просто квадратной местности).
Чтобы создать свой собственный ландшафт, загрузите и установите cocos3d и создайте новый проект cocos3d2 под названием «TerrainGenerator». Это создаст 3D «Привет, мир!» заявление. Нажмите кнопку «Play», чтобы убедиться, что он работает:
Чтобы добавить код генерации холма, загрузите библиотеку с Github и добавьте HillTerrain.m и HillTerrain.h в свой проект.
Замените содержимое TerrainGeneratorScene.m следующим образом :
#import "TerrainGeneratorScene.h" #import "CC3PODResourceNode.h" #import "CC3ActionInterval.h" #import "CC3MeshNode.h" #import "CC3Camera.h" #import "CC3Light.h" #import "CC3ParametricMeshNodes.h" #import "HillTerrain.h" @implementation TerrainGeneratorScene -(void) dealloc { [super dealloc]; } -(void) initializeScene { // Lights CC3Light* lamp = [CC3Light nodeWithName: @"Lamp"]; lamp.location = cc3v(-2.0, 0.0, 0.0); lamp.isDirectionalOnly = NO; // Camera CC3Camera* cam = [CC3Camera nodeWithName: @"Camera"]; cam.location = cc3v(128.0, 0.0, 300.0); [cam rotateByAngle:15 aroundAxis:cc3v(1.0, 0.0, 0.0)]; [cam addChild: lamp]; [self addChild: cam]; // Action! (Well, okay, just terrain.) [self createTerrain]; // OpenGL fun. [self createGLBuffers]; [self releaseRedundantContent]; [self selectShaderPrograms]; } -(void) createTerrain { HillTerrain *terrain = [[HillTerrain alloc] init]; [terrain generate]; CC3MeshNode *mesh = [[[CC3MeshNode alloc] init] retain]; mesh.vertexContentTypes = kCC3VertexContentLocation | kCC3VertexContentColor | kCC3VertexContentNormal; [mesh populateAsRectangleWithSize:CGSizeMake(terrain.size.width, terrain.size.height) andRelativeOrigin:CGPointZero andTessellation:CC3TessellationMake(terrain.size.width-1, terrain.size.height-1)]; int count = 0; for (int j = 0; j < terrain.size.height; ++j) { for (int i = 0; i < terrain.size.width; ++i) { float height = [terrain getCell:cc3p(i,j)]; [mesh setVertexLocation:CC3VectorMake(i, j, height * 128) at:count]; [mesh setVertexColor4F:ccc4f(0.0, height, 1.0-height, 1.0) at:count]; ++count; } } [mesh setShouldUseLighting:YES]; [self addChild:mesh]; [terrain release]; } @end |
Сохраните и запустите, и вы должны увидеть что-то вроде этого:
В методе createTerrain происходит вся магия, поэтому давайте рассмотрим его по одному разделу за раз:
Генерация местности
Вот часть, которая на самом деле генерирует ландшафт:
HillTerrain *terrain = [[HillTerrain alloc] init]; [terrain generate]; |
Вы можете изменить любые параметры здесь, например, давайте попробуем другое начальное число:
HillTerrain *terrain = [[HillTerrain alloc] init]; [terrain setSeed:123]; // Because I'm so creative. [terrain generate]; |
Это создает хороший диапазон гор:
Создание чего-то, что OpenGL может использовать
Следующая часть отображает эту местность на массив вершин. Сначала мы создаем сетку , то есть поверхность, которую мы хотим отобразить. Вы можете изобразить это как рыболовную сеть, которую будете драпировать по ландшафту.
CC3MeshNode *mesh = [[[CC3MeshNode alloc] init] retain]; |
Указание типов хранилища нам понадобится
Далее, мы должны сообщить Cocos3d, какой тип информации мы хотим сохранить об этом меше. Для нас это включает в себя:
- Расположение каждой вершины, потому что в этом смысл всего этого.
- Цвет каждой вершины, потому что он будет варьироваться в зависимости от высоты.
- Нормали каждой вершины, которая является направление свет будет отражаться от него. Это автоматически заполняется Cocos3d, поэтому вам не нужно беспокоиться об этом сейчас. Тем не менее, интересно попробовать удалить этот и посмотреть, как выглядит местность.
mesh.vertexContentTypes =
kCC3VertexContentLocation | kCC3VertexContentColor | kCC3VertexContentNormal;
|
Выделение сетки
Теперь, когда мы сообщили Cocos3d о типах хранилищ, которые нам нужны, мы сообщим ему форму и размер для выделения: прямоугольную сетку того же размера, что и наш ландшафт.
[mesh populateAsRectangleWithSize:CGSizeMake(terrain.size.width, terrain.size.height) andRelativeOrigin:CGPointZero andTessellation:CC3TessellationMake(terrain.size.width-1, terrain.size.height-1)]; |
andTessellation указывает, сколько будет квадратов на местности, поэтому вы хотите, чтобы это число было на единицу меньше числа имеющихся у вас вершин. Например, если у вас было тесселяция 1 квадрат на 1 квадрат, вам понадобится 4 вершины (по одной на каждый угол квадрата). Таким образом, -1с.
Отображение местности на сетку
Сначала мы получаем высоту в одной из координат карты. Это будет число от 0 до 1, поэтому мы увеличим его до чего-то разумного, учитывая наш масштаб ( height*128
в данном случае).
float height = [terrain getCell:cc3p(i,j)]; [mesh setVertexLocation:CC3VectorMake(i, j, height * 128) at:count]; |
Затем мы устанавливаем цвет, делая самые высокие местоположения самыми зелеными, а самые низкие — голубыми:
[mesh setVertexColor4F:ccc4f(0.0, height, 1.0-height, 1.0) at:count]; |
at:count
Указывает индекс в мы заходящего вершины. Cocos3d хранит все вершины в большом массиве, и это его индекс.
Включение света
Наконец, мы говорим OpenGL наложить свет на меш. (Попробуйте удалить эту строку и посмотрите, как она выглядит.)
[mesh setShouldUseLighting:YES]; |
И мы добавляем меш как ребенка в нашу сцену и освобождаем память ландшафта:
[self addChild:mesh]; [terrain release]; |
Это оно! Если у кого-то есть какие-либо предложения или улучшения, пожалуйста, не стесняйтесь подать запрос на получение . Я еще не слишком доволен поколением островов: я не нашел правильную комбинацию вариантов, поэтому мои острова — это не просто комочки.
Если вам интересно, алгоритм Роба довольно интересный и простой для понимания. Я рекомендую прочитать его описание, если вы планируете использовать его в проекте.