Создаем простейший HTML5 3D движок на JS и HTML5 Canvas API



Вероятно, что если бы вы создавали полномасштабный 3D-движок, в комплекте с трехмерной матрицой преобразования, точечных объектов, плоских объектов, тенями и других пространственных вычислений — это было бы довольно трудно.

Но что, если мы хотим создать оптимизированный 3D JavaScript движок, который поддерживает переходы и повороты? Неужели это так трудно?

Так вот, чтобы создать такой движок нам понадобиться всего лишь 40 строчек кода! В этой небольшой статье я вам расскажу о создании примитивном 3d javascript движка, который вы сможете использовать в анимации, игра и пр.

Представление о 3D проекции

Прежде чем создать свой 3D движок, мы должны сперва понять как создают иллюзию 3D пространства в 2D, так называемую 3D проекцию. Вся суть заключается в проецировании точек из 3D пространства на плоскость. В нашем случае — в трехмерном пространстве мы моделируем расположение нашего объекта, переносим в двухмерную плоскость и отрендериваем на экран.

Изображения этого куба получилось именно таким способом — сначала мы создали его трехмерную модель, а потом представили в следующем виде на двухмерной плоскости с помощью трех ромбо-подобных 2D фигур — грани куба. Создали иллюзию 3D.



Проектирование плоскости с помощью эллипса

К сожалению, калькуляция трехмерных проекций потребует не малых усилий в программировании. Как нам упростить задачу?

Представьте себе как вы видите вращающуюся прямоугольную плоскость. Все четыре ее угла будут описывать идеальную окружность, радиус которой равен половине диагонали этой плоскости.

Теперь представьте что мы наклонили эту плоскость в 3D пространстве. Что произошло? Этот воображаемый круг стал эллипсом, чья высота стала меньше чем ширина.

Это означает, что мы можем создать простую 3D проекцию плоскостями, чьи углы будут находится вдоль очертания эллипса.

Если мы определяем поворот плоскости с углом ? (Тета), то расчет 3D проекции становиться намного проще!

Любая точка в нашей трехмерной плоскости может быть представлена следующими двумя уравнениями, которые описывают точки, находящиеся на грани эллипса:

x = A * cos(theta)
y = B * sin(theta)

, где A — это половина ширины эллипса, а B — половина высоты.

Простой 3D движок

Если наш движок запросто создает плоскости в 3D пространстве, мы можем построить несколько поперечных плоскостей и получить в итоге некую 3D модель, где плоскости будут ее псевдо полигонами.


Пример рендера такой модели


Диграмма поперечного сечения плоскостей

Результат

Эта 3D модель была создана с помощью трех поперечных сечений плоскостей — верхняя, средняя и нижняя плоскости. Эти мнимые плоскости предоставляют нам все точки, которые нам нужны чтобы построить 3D модель и отрендерить ее используя HTML5 Canvas API.

Только что мы создали функцию, которая может генерировать и поворачивать плоскости поперечного сечения, которая и стоит в основе нашего простого 3D движка.

Исходный код:

// This simple 3D engine was provided by www.Html5CanvasTutorials.com
// for the purpose of creating 3D HTML5 renderings
function Plane(centerX,centerY, planeLength, planeWidth, planeTilt, planeTheta) {
   this.centerX = centerX;
   this.centerY = centerY;
   this.planeLength = planeLength;
   this.planeTheta = planeTheta;

   var lastPerspectiveX = null;
   var lastPerspectiveX2 = null;
   var planeNextCornerAngle = 2*Math.asin(planeWidth/planeLength);

   this.rotate = function(newTheta) {
   	planeTheta = newTheta - planeNextCornerAngle/2;
   }

   this.translate = function(newCenterX, newCenterY) {
   	centerX = newCenterX;
   	centerY = newCenterY;
   }

   this.generate = function() {
   	var ovalLength = planeLength;
   	var ovalWidth = ovalLength * planeTilt;

   	var perspectiveX = (ovalLength / 2) * Math.cos(planeTheta);
   	var perspectiveY = (ovalWidth / 2) * Math.sin(planeTheta);            
   	var perspectiveX2 = (ovalLength / 2) * Math.cos(planeTheta + planeNextCornerAngle);
   	var perspectiveY2 = (ovalWidth / 2) * Math.sin(planeTheta + planeNextCornerAngle);

   	this.topLeftX = (perspectiveX *1) + centerX;
   	this.topLeftY = (perspectiveY * -1) + centerY;
  	this.bottomRightX = (perspectiveX*-1) + centerX;
   	this.bottomRightY = (perspectiveY*1) + centerY
   	this.topRightX = (perspectiveX2 *1) + centerX;
  	this.topRightY = (perspectiveY2 *-1) + centerY;
   	this.bottomLeftX = (perspectiveX2 *-1) + centerX;
   	this.bottomLeftY = (perspectiveY2 *1) + centerY;
   }
 }


Source

1 комментарий

avatar
Немножко бы поподробнее с последним кодом. Хотябы несколько основных строчек разобрать.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.