Эта статья является частью серии технологий веб-разработки от Microsoft. Спасибо за поддержку партнеров, которые делают возможным использование SitePoint.
Сегодня я хотел бы поделиться с вами основами столкновений, физики и ограничивающих рамок, играя с движком WebGL babylon.js и компаньоном физического движка по имени oimo.js.
Вот демонстрация, которую мы собираемся построить вместе: демонстрация Espilit Physics с помощью Oylon.js babylon.js
Вы можете запустить его в WebGL-совместимом браузере — например, IE11, Firefox, Chrome, Opera Safari 8 или Project Spartan в Windows 10 Technical Preview — и затем перемещаться внутри сцены, как в игре FPS. Нажмите клавишу «s», чтобы запустить несколько сфер / шаров, и клавишу «b», чтобы запустить несколько ящиков. Используя мышь, вы можете нажать на одну из сфер или рамок, чтобы применить к ней также импульсную силу.
Понимание столкновений
Глядя на определение обнаружения столкновения в Википедии, мы можем прочитать, что:
«Обнаружение столкновения обычно относится к вычислительной проблеме обнаружения пересечения двух или более объектов. Хотя эта тема чаще всего связана с ее использованием в видеоиграх и других физических симуляциях , она также имеет приложения в робототехнике . В дополнение к определению, столкнулись ли два объекта, системы обнаружения столкновений могут также рассчитывать время удара (TOI) и сообщать контактный коллектор (набор пересекающихся точек). [1] Реакция на столкновение связана с моделированием того, что происходит при обнаружении столкновения (см. Физический движок , физика рэгдолла ). Решение проблем обнаружения столкновений требует широкого использования концепций линейной алгебры и вычислительной геометрии ».
Давайте теперь распакуем это определение в классную трехмерную сцену, которая станет нашей отправной точкой для этого урока.
Вы можете перемещаться в этом великом музее, как в реальном мире. Вы не будете падать сквозь пол, проходить сквозь стены или летать. Мы моделируем гравитацию. Все это кажется довольно очевидным, но требует кучу вычислений для имитации этого в виртуальном трехмерном мире. Первый вопрос, который нам нужно решить, когда мы думаем об обнаружении столкновений, — насколько он должен быть сложным? Действительно, тестирование, если сталкиваются 2 сложные сетки, может стоить много ресурсов ЦП, даже дороже с движком JavaScript, где сложно перенести это на что-то, кроме потока пользовательского интерфейса.
Чтобы лучше понять, как мы справляемся с этой сложностью, перейдите в музей Эспилит рядом с этим столом:
Вы заблокированы столом, даже если справа есть свободное место. Это ошибка в нашем алгоритме столкновений? Нет, это не так (babylon.js не содержит ошибок! ;-)). Это потому, что Мишель Руссо, 3D-художник, который создал эту сцену, сделал это по своему выбору. Чтобы упростить обнаружение столкновений, он использовал определенный коллайдер.
Что такое коллайдер?
Вместо того, чтобы проверять столкновения с полными подробными сетками, вы можете поместить их в простые невидимые геометрии. Эти коллайдеры будут действовать как представление сетки и будут использоваться движком коллизий. Большую часть времени вы не увидите различий, но это позволит нам использовать гораздо меньше процессорных ресурсов, поскольку математические вычисления намного проще для вычисления.
Каждый движок поддерживает как минимум 2 типа коллайдеров: ограничивающую рамку и ограничивающую сферу. Вы лучше поймете, посмотрев на эту картинку:
Извлечено из: компьютерной визуализации, трассировки лучей, видеоигр, замены ограничивающих рамок
Эта красивая желтая колода является сеткой для отображения. Вместо того, чтобы проверять столкновения с каждой из его граней, мы можем попытаться вставить его в лучшую ограничивающую геометрию. В этом случае коробка кажется лучшим выбором, чем сфера, чтобы действовать как самозванец сетки. Но выбор действительно зависит от самой сетки.
Давайте вернемся к сцене Espilit и отобразим невидимый ограничивающий элемент полупрозрачным красным цветом:
Теперь вы можете понять, почему вы не можете двигаться по правой стороне стола. Это потому, что вы сталкиваетесь (ну, камера babylon.js сталкивается) с этой коробкой. Если вы хотите это сделать, просто измените его размер, уменьшив ширину, чтобы она идеально подходила ширине стола.
Примечание: если вы хотите начать изучать babylon.js, вы можете пройти наш бесплатный учебный курс в Microsoft Virtual Academy (MVA). Например, вы можете перейти непосредственно к разделу « Введение в WebGL 3D с HTML5 и Babylon.js — Использование Babylon.js для начинающих », где мы рассмотрим эту часть столкновения в Babylon.js. Вы также можете взглянуть на код внутри нашего интерактивного инструмента для игровых площадок: Babylon.js площадка — пример столкновений .
Исходя из сложности столкновения или физического движка, существуют другие типы коллайдеров: например, капсула и сетка.
Извлечено из: Начало работы с Unity — Коллайдеры и UnityScript
Капсула полезна для людей или гуманоидов, так как она лучше подходит нашему телу, чем коробка или сфера. Сетка почти никогда не является самой полной сеткой, а скорее упрощенной версией исходной сетки, на которую вы нацеливаетесь, но она все же намного точнее, чем коробка, сфера или капсула.
Загрузка стартовой сцены
Чтобы загрузить нашу сцену Espilit, у вас есть различные варианты:
Опция 1 :
Загрузите его из нашего репозитория GitHub , а затем следуйте разделу Введение в WebGL 3D с HTML5 и Babylon.js — Загрузка ресурсов нашего курса MVA, чтобы узнать, как загрузить сцену .babylon. По сути, вам нужно разместить ресурсы и движок Babylon.js на веб-сервере и установить правильные типы MIME для расширения .babylon.
Вариант 2:
Загрузите это готовое решение Visual Studio (файл .zip).
Примечание: если вы не знакомы с Visual Studio, ознакомьтесь с этой статьей: Веб-разработчики, Visual Studio может быть отличным бесплатным инструментом для разработки… Обратите внимание, что версия Pro теперь бесплатна для множества различных сценариев. Он называется Visual Studio 2013 Community Edition .
Конечно, вы все равно можете следовать этому руководству, если не хотите использовать Visual Studio. Вот код для загрузки нашей сцены. Помните, что хотя большинство браузеров сейчас поддерживают WebGL, вам следует протестировать Internet Explorer даже на вашем Mac.
// <reference path="/scripts/babylon.js" />
var engine;
var canvas;
var scene;
document.addEventListener("DOMContentLoaded", startGame, false);
function startGame() {
if (BABYLON.Engine.isSupported()) {
canvas = document.getElementById("renderCanvas");
engine = new BABYLON.Engine(canvas, true);
BABYLON.SceneLoader.Load("Espilit/", "Espilit.babylon", engine, function (loadedScene) {
scene = loadedScene;
// Wait for textures and shaders to be ready
scene.executeWhenReady(function () {
// Attach camera to canvas inputs
scene.activeCamera.attachControl(canvas);
// Once the scene is loaded, just register a render loop to render it
engine.runRenderLoop(function () {
scene.render();
});
});
}, function (progress) {
// To do: give progress feedback to user
});
}
}
Используя этот материал, вы получите выгоду только от встроенного движка столкновений Babylon.js. Действительно, мы делаем различие между нашим двигателем столкновения и физическим двигателем. Механизм столкновения в основном предназначен для камеры, взаимодействующей со сценой. Вы можете включить гравитацию или нет на камере, вы можете включить опцию checkCollision
Механизм столкновения также может помочь вам узнать, сталкиваются ли две сетки. Но это все (на самом деле это уже много!). Движок столкновения не будет генерировать действия, силу или импульс после столкновения двух объектов Babylon.js. Вам нужен физический движок, чтобы оживить объекты.
Мы интегрировали физику в Babylon.js, используя механизм плагинов. Вы можете прочитать больше об этом здесь: Добавление собственного плагина физического движка в babylon.js . Мы поддерживаем два физических движка с открытым исходным кодом: cannon.js и oimo.js. Oimo теперь является предпочтительным физическим движком по умолчанию.
Если вы выбрали «вариант 1» для загрузки сцены, вам нужно скачать Oimo.js с нашего GitHub. Это слегка обновленная версия, которую мы сделали для лучшей поддержки Babylon.js. Если вы выбрали «вариант 2», на него уже есть ссылка и он доступен в решении VS в папке scripts
Включение поддержки физики в сцене для превращения коллайдеров в «физиков-самозванцев»
Первое, что нужно сделать, это включить физику на сцене. Для этого, пожалуйста, добавьте эту строку кода:
scene.enablePhysics(new BABYLON.Vector3(0, -10, 0), new BABYLON.OimoJSPlugin());
Вы устанавливаете уровень гравитации (-10 на оси Y в этом примере кода, который более или менее похож на то, что у нас есть на Земле) и физический движок, который вы хотели бы использовать. Мы будем использовать Oimo.js, но закомментированная строка показывает, как использовать cannon.js.
Теперь нам нужно перебрать все невидимые коллайдеры, используемые движком столкновений, и активировать физические свойства на нем. Для этого вам просто нужно найти все сетки, где checkCollisions
for (var i = 1; i < scene.meshes.length; i++) {
if (scene.meshes[i].checkCollisions && scene.meshes[i].isVisible === false) {
scene.meshes[i].setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, { mass: 0,
friction: 0.5, restitution: 0.7 });
meshesColliderList.push(scene.meshes[i]);
}
}
Пожалуйста, объявите meshesColliderList также:
var meshesColliderList = [];
И мы сделали! Мы готовы бросить некоторые объекты в нашу сцену и положить много беспорядка в этом красивом, но спокойном музее.
Создание сфер и рамок с физическими состояниями
Теперь мы собираемся добавить несколько сфер (с текстурой Amiga) и несколько блоков (с текстурой дерева) к сцене. Эта сетка будет иметь установленное состояние физики. Например, это означает, что они будут подпрыгивать на полу, если вы запустите их в воздухе, подпрыгните между ними после обнаружения столкновения и так далее. Физическому движку нужно знать, какой вид самозванца вы хотите использовать для сетки (плоскость, сфера или прямоугольник сегодня), свойства массы и трения.
Если вы выбрали « вариант 1 », вы можете скачать две текстуры здесь: physasassets.zip
Добавьте этот код в ваш проект:
function CreateMaterials() {
materialAmiga = new BABYLON.StandardMaterial("amiga", scene);
materialAmiga.diffuseTexture = new BABYLON.Texture("assets/amiga.jpg", scene);
materialAmiga.emissiveColor = new BABYLON.Color3(0.5, 0.5, 0.5);
materialAmiga.diffuseTexture.uScale = 5;
materialAmiga.diffuseTexture.vScale = 5;
materialWood = new BABYLON.StandardMaterial("wood", scene);
materialWood.diffuseTexture = new BABYLON.Texture("assets/wood.jpg", scene);
materialWood.emissiveColor = new BABYLON.Color3(0.5, 0.5, 0.5);
}
function addListeners() {
window.addEventListener("keydown", function (evt) {
// s for sphere
if (evt.keyCode == 83) {
for (var index = 0; index < 25; index++) {
var sphere = BABYLON.Mesh.CreateSphere("Sphere0", 10, 0.5, scene);
sphere.material = materialAmiga;
sphere.position = new BABYLON.Vector3(0 + index / 10, 3, 5 + index / 10);
sphere.setPhysicsState(BABYLON.PhysicsEngine.SphereImpostor, { mass: 1 });
}
}
// b for box
if (evt.keyCode == 66) {
for (var index = 0; index < 10; index++) {
var box0 = BABYLON.Mesh.CreateBox("Box0", 0.5, scene);
box0.position = new BABYLON.Vector3(0 + index / 5, 3, 5 + index / 5);
box0.material = materialWood;
box0.setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, { mass: 4 });
}
}
});
}
Вы можете видеть, что коробки тяжелее сфер на 4.
Примечание: если вам нужно понять, как материал работает в babylon.js, посмотрите на этот модуль: Введение в WebGL 3D с HTML5 и Babylon.js — Понимание материалов и входных данных или поиграйте с нашим специальным примером Playground: Babylon.js Playground — Пример материалов
Добавьте эти две строки кода после строки scene.enablePhysics
CreateMaterials();
addListeners();
И запустить веб-проект. Перейдите к центру музея и нажмите скорее клавиши «s» или «b». Вы получите этот забавный результат:
Добавление поддержки выбора для нажатия на сетки
Давайте добавим еще одну интересную функцию: возможность щелкнуть один из объектов, чтобы выбросить их. Для этого вам нужно отправить луч из 2D-координат мыши внутри 3D-сцены, проверить, касается ли этот луч одной из интересных сеток, и, если это так, применить к нему импульсную силу, чтобы попытаться переместить его.
Примечание: чтобы понять, как работает комплектация, просмотрите этот модуль MVA: Введение в WebGL 3D с HTML5 и Babylon.js — расширенные функции или поиграйте с нашим онлайн-примером: Babylon.js Playground — Пример комплектации .
Добавьте этот код в addListeners()
canvas.addEventListener("mousedown", function (evt) {
var pickResult = scene.pick(evt.clientX, evt.clientY, function (mesh) {
if (mesh.name.indexOf("Sphere0") !== -1 || mesh.name.indexOf("Box0") !== -1) {
return true;
}
return false;
});
if (pickResult.hit) {
var dir = pickResult.pickedPoint.subtract(scene.activeCamera.position);
dir.normalize();
pickResult.pickedMesh.applyImpulse(dir.scale(1), pickResult.pickedPoint);
}
});
Запустите свой код в вашем любимом браузере. Теперь вы можете нажать на свои физические сетки, чтобы играть с ними.
Отображение ограничивающих рамок, чтобы лучше понять всю историю
Наконец, мы собираемся создать сцену отладки, чтобы позволить вам отображать / скрывать коллайдеры и активировать / деактивировать физические свойства на них.
Мы собираемся ввести пользовательский интерфейс в этот div:
<div id="lcContainer">
<ul id="listColliders">
</ul>
</div>
И мы будем использовать эту функцию для обработки пользовательского интерфейса:
function CreateCollidersHTMLList() {
var listColliders = document.getElementById("listColliders");
for (var j = 0; j < meshesColliderList.length; j++) {
var newLi = document.createElement("li");
var chkVisibility = document.createElement('input');
chkVisibility.type = "checkbox";
chkVisibility.name = meshesColliderList[j].name;
chkVisibility.id = "colvis" + j;
var chkPhysics = document.createElement('input');
chkPhysics.type = "checkbox";
chkPhysics.name = meshesColliderList[j].name;
chkPhysics.id = "colphysx" + j;
(function (j) {
chkVisibility.addEventListener(
"click",
function (event) {
onChangeVisibility(j, event);
},
false
);
chkPhysics.addEventListener(
"click",
function (event) {
onChangePhysics(j, event);
},
false
);
})(j)
newLi.textContent = meshesColliderList[j].name + " visibility/physx ";
newLi.appendChild(chkVisibility);
newLi.appendChild(chkPhysics);
listColliders.appendChild(newLi);
}
function onChangeVisibility(id, event) {
if (!meshesColliderList[id].isVisible) {
meshesColliderList[id].isVisible = true;
meshesColliderList[id].material.alpha = 0.75;
meshesColliderList[id].material.ambientColor.r = 1;
}
else {
meshesColliderList[id].isVisible = false;
}
}
function onChangePhysics(id, event) {
if (!meshesColliderList[id].checkCollisions) {
meshesColliderList[id].checkCollisions = true;
meshesColliderList[id].setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, { mass: 0,
friction: 0.5, restitution: 0.7 });
}
else {
meshesColliderList[id].checkCollisions = false;
meshesColliderList[id].setPhysicsState(BABYLON.PhysicsEngine.NoImpostor);
}
}
}
Я знаю, он генерирует очень уродливый интерфейс, но мне было лень тратить на него больше времени. Не стесняйтесь улучшать это! :-П
Вызовите эту новую функцию и запустите веб-проект. Теперь, например, отобразим коллайдеры 12 и 17:
Вы также можете, со вторым флажком, включить / отключить физические свойства. Например, если вы отключите физические свойства на коллайдере 12 и запустите сферы, они теперь пройдут через эту стену! Это показано на следующем снимке экрана как сфера, окруженная красным квадратом:
Вывод
Вы можете поиграть с этим примером отладки прямо в вашем браузере здесь: babylon.js Демоверсия отладки Espilit Physics .
Пожалуйста, взгляните также на это удивительное демо, созданное Сэмюэлем Жирардином, которое также использует Oimo.js для некоторых забавных персонажей:
Надеюсь, вам понравился этот урок! Не стесняйтесь пинговать меня в Твиттере, чтобы прокомментировать это.
Эта статья является частью серии технологий веб-разработки от Microsoft. Мы рады поделиться с вами Project Spartan и его новым механизмом рендеринга . Получите бесплатные виртуальные машины или проведите удаленное тестирование на устройстве Mac, iOS, Android или Windows с помощью modern.IE .