libGDX. Основы 3D программирования.
Создадим новый проект libGDX. Назовем его, например, Proba3D. Создание проекта и жизненный цикл ничем не отличается от 2D. Так что на них не останавливаемся. Сразу приступим к созданию объектов.
Сначала создадим 3D-камеру.
public class Proba3D extends ApplicationAdapter {
public PerspectiveCamera cam;
@Override
public void create () {
cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(10f, 10f, 10f);
cam.lookAt(0f, 0f, 0f);
cam.near = 1f;
cam.far = 300f;
cam.update();
}
Здесь мы создаем камеру перспективы PerspectiveCamera с углом обзора 67 градусов (это обычно используемый угол обзора) и растягиваем её по текущим размерам окна. Затем устанавливаем ее позицию 10 попугаев вправо, 10 вверх и 10 пять назад. Ось Z указывает на зрителя, т.е. положительные значения Z отодвигают камеру назад. Указываем направление камеры, чтобы она смотрела на начало координат. Затем ограничиваем границы видимости - камера будет видеть объекты, которые находятся от нее не ближе 1 единицы и не дальше 300 единиц. Обновляем камеру, чтобы применить все изменения.
Теперь создадим какой-нибудь трехмерный объект, например куб.
public class Proba3D extends ApplicationAdapter {
....
public Model model;
public ModelInstance instance;
@Override
public void create () {
.....
ModelBuilder modelBuilder = new ModelBuilder();
model = modelBuilder.createBox(5f, 5f, 5f, new Material(ColorAttribute.createDiffuse(Color.GREEN)), Usage.Position|Usage.Normal);
instance = new ModelInstance(model);
}
Для создания модели в коде используется ModelBuilder. Создаем куб с размерами 5х5х5, дабавляем на него материал с диффузным зеленым цветом. А также указываем атрибуты Usage.Position (является обязательным при создании модели) и Usage.Normal (для правильной работы с освещением).
Модель не содержит в себе информации о местоположении, вращении и масштабировании объекта. Поэтому мы не можем её использовать напрямую для отрисовки. Для этого нам нужен ModelInstance (экземпляр модели). По умолчанию он создается в точке (0, 0, 0) Пока нам это подходит, поэтому просто создаем объект ModelInstance и передаем ему созданную модель.
public class Proba3D extends ApplicationAdapter {
public ModelBatch modelBatch;
....
@Override
public void create () {
modelBatch = new ModelBatch();
.....
}
@Override
public void render () {
Gdx.gl.glViewport ( 0 , 0 , Gdx.graphics.getWidth (), Gdx.graphics.getHeight ());
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);
modelBatch.begin(cam);
modelBatch.render(instance, environment);
modelBatch.end();
}
Не забываем освободить память в dispose():
@Override
public void dispose(){
modelBatch.dispose();
model.dispose();
}
Запускаем и смотрим, что у нас получилось.

Как-то не очень, да? Грани и ребра сливаются. Это все потому, что у нас нет освещения. Добавим его.
public class Proba3D extends ApplicationAdapter {
public Environment environment;
....
@Override
public void create () {
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
.....
}
@Override
public void render () {
Gdx.gl.glViewport ( 0 , 0 , Gdx.graphics.getWidth (), Gdx.graphics.getHeight ());
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);
modelBatch.begin(cam);
modelBatch.render(instance, environment);
modelBatch.end();
}
Здесь мы создаем объект Environment (окружение) и устанавливаем сначала рассеянный свет AmbientLight (0.4, 0.4, 0.4) (альфа-канал игнорируется). Рассеянный свет - это свет не имеющий конкретного источника. Далее устанавливаем направленный свет с цветом (0,8, 0,8, 0,8) и направлением (-1,0, -0.8f, 0,2).
Запустим и посмотрим.

Теперь мы видим объект во всей трехмерной красе. Давайте сделаем камеру подвижной, чтобы посмотреть на куб со всех сторон.
public class Proba3D extends ApplicationAdapter {
......
public CameraInputController camController;
@Override
public void create () {
.....
camController = new CameraInputController(cam);
Gdx.input.setInputProcessor(camController);
.....
}
@Override
public void render () {
camController.update();
.....
}
Создаем CameraInputController передавая ему в качестве аргумента камеру. Для контроллера устанавливаем InputProcessor. И обновляем контроллер при рендеринге. Этого достаточно для базового управления камерой. Подвигайте мышью при нажатой левой кнопке. Колесиком можно удалять/приближать.
Полный листинг главного класса:
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.PerspectiveCamera;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.g3d.Environment;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.ColorAttribute;
import com.badlogic.gdx.graphics.g3d.environment.DirectionalLight;
import com.badlogic.gdx.graphics.g3d.utils.CameraInputController;
import com.badlogic.gdx.graphics.g3d.utils.ModelBuilder;
public class Proba3D extends ApplicationAdapter {
public PerspectiveCamera cam;
public Model model;
public ModelInstance instance;
public ModelBatch modelBatch;
public Environment environment;
public CameraInputController camController;
@Override
public void create () {
modelBatch = new ModelBatch();
environment = new Environment();
environment.set(new ColorAttribute(ColorAttribute.AmbientLight, 0.4f, 0.4f, 0.4f, 1f));
environment.add(new DirectionalLight().set(0.8f, 0.8f, 0.8f, -1f, -0.8f, -0.2f));
cam = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
cam.position.set(10f, 10f, 10f);
cam.lookAt(0f, 0f, 0f);
cam.near = 1f;
cam.far = 300f;
cam.update();
camController = new CameraInputController(cam);
Gdx.input.setInputProcessor(camController);
ModelBuilder modelBuilder = new ModelBuilder();
model = modelBuilder.createBox(5f, 5f, 5f, new Material(ColorAttribute.createDiffuse(Color.GREEN)), Usage.Position|Usage.Normal);
instance = new ModelInstance(model);
}
@Override
public void render () {
camController.update();
Gdx.gl.glViewport ( 0 , 0 , Gdx.graphics.getWidth (), Gdx.graphics.getHeight ());
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT|GL20.GL_DEPTH_BUFFER_BIT);
modelBatch.begin(cam);
modelBatch.render(instance, environment);
modelBatch.end();
}
@Override
public void dispose(){
modelBatch.dispose();
model.dispose();
}
}
Использованный источник - xoppa
Игра Flower. Ловим капли.
TexturePacker.Создаем атлас текстур.
Создаем проект на движке libGDX
Кастомизация EditText
Кастомизация SeekBar'а
9-patch изображения для Андроид
Кастомный ползунок в виде дуги (аналог SeekBar)
Анимация в Андроид
Кастомизация элементов управления в Android
Смартфон DEXP Ixion ML 5, обзор.
Создание кастомного View-элемента интерфейса.
Создание виджета - электронные часы с кастомным шрифтом
Будильник для Андроид "Разбуди меня" |