Pull to refresh

Карта галактики на WebGL Three.js

JavaScript *
Awaiting invitation
Решил как-то исполнить свою давнюю идею — сделать карту галактики на three.js, т.е. на WebGL. Внимание: карту галактики, а не красивейшую визуализацию галактики.



Дисклаймер

Всё делалось в учебных целях всего за два дня, так что не судите строго.

Браузеры

Первая строчка такова:

if(Detector.webgl)
        renderer = new THREE.WebGLRenderer();
else
{
        alert("Увы, ваш браузер не поддерживает WebGL.")
        return;
}


Если речь идет о WebGL, сразу встает вопрос о браузерах. Я сознательно отказался от использования THREE.CanvasRenderer, ибо убедился эти два рендера во многом не совместимы, и то что работает с одним, с другим далеко не факт, что будет работать.

Тестировал только в виндовых версиях бразуеров, а именно в FF, Chrome, Opera. Opera Next, IE11. В FF и Хроме всё отлично работает, в Опере запускается, но работает плохо. В Opera Next (та инновационная, без закладок) всё работает отлично. IE11 какой-то странный, вроде поддержка WebGL есть, но когда я попытался запустить, то получил симпатичный такой лог:

THREE.WebGLRenderer 58THREE.WebGLRenderer: Float textures not supported.
THREE.WebGLRenderer: Standard derivatives not supported.
THREE.WebGLRenderer: Anisotropic texture filtering not supported.
THREE.WebGLRenderer: S3TC compressed textures not supported.

Причем любые примеры на Three.js именно так рисуются.

Я не хочу читать дальше, дай посмотреть!

Ну ладно, управление простейшее — drag&drop+mouse wheel, вот ссылка (надеюсь VPS выдержит): тык

Скучный Код

В общем плане код довольно обычен, вот, к примеру, инициализация:

renderer.setClearColor(0x000000);
renderer.setSize( window.innerWidth - 15, window.innerHeight - 15 );
renderer.sortObjects = false;
renderer.autoClear = false;
document.body.appendChild( renderer.domElement );

Создание сцен, используются как слои, для управления последовательностью отрисовки:

//Создаем сцены
scene = new THREE.Scene(); //Звезды и деления квадрантов
sceneNames = new THREE.Scene(); //Название звезд
sceneSectors = new THREE.Scene(); //Деления секторов

Самая обычная камера:
//Камера
camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 100000000 );
camera.position.set( 0, 0, 1000 );


Чуть менее Скучный Код

Как рисуется галактика? Используется логарифмическая спираль (wiki). Алгоритм взят отсюда: ссылка.
Код переписал на JS, каждая точка-звезда записывается в THREE.Geometry, и потом, вместе с материалом, создается система частиц. Если делать подобное без системы частиц, то высокого FPS'а точно не будет(звезд то 16 000, если создавать отдельные частицы, то… кхм.).

function initStars()
{
        particle_system_geometry = new THREE.Geometry();

	var x = 0, y = 0;
	var NUM_STARS = 16000;

	var A = 1.1;
	var B = 0.17;
	var WINDINGS = 3.7;
	var T_MAX = 2.0 * Math.PI * WINDINGS;		
	var DRIFT = 0.3

	for (var i = 0; i < 1800; i++) 
	{
		setStar(Math.sRandom(-1.7, 1.7), Math.sRandom(-1.7,1.7), GenShortName());
	}
	for (var i = 0; i < NUM_STARS; i++) 
	{
	  var t = T_MAX * Math.random();
	  var x = A * Math.exp(B * t) * Math.cos(t);
	  x = x + (DRIFT*x*Math.random()) - (DRIFT*x*Math.random());
	  var y = A * Math.exp(B * t) * Math.sin(t);
	  y = y + (DRIFT*y*Math.random()) - (DRIFT*y*Math.random())
	  if (Math.random() > 0.5)
	  {
 	     setStar(x, y, GenShortName());
	  }
          else
	  {
	     setStar(-x, -y, GenShortName());
	   }
	}

        ...

	var particle_system_material = new THREE.ParticleBasicMaterial({
          color: 0xeeeeee,
          size: 3
        });
	
        particleSystem = new THREE.ParticleSystem(
          particle_system_geometry,
            particle_system_material
        );
        scene.add(particleSystem);

}

Чуть-чуть кода генерации

Собственно функция генерации названий звездных систем. Написана была мною множество времени назад на C#, тоже перенес на JS.

function GenShortName()
{
    var abs = ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "A", "S", "D", "F", "G",
                                             "H", "J", "K", "L", "Z", "X", "C", "V", "B",
                                             "N", "M"
                                         ];
    var result;

    var variant = Math.sRandom(0, 100);

    if (variant < 65)
    {
        //Элемент буквеный
        var el="";
        //Элемент численый
        var numEl="";
        //Максимум букв в буквеном элементе
        var maxCountAbs = 3;
        //Максимум цифр в цифреном элементе
        var maxCountNum = 2;
        //рандом количество
        var countAbs = Math.floor(Math.sRandom(1, maxCountAbs));

        for(var i = 0; i < countAbs; i++)
            el += abs[Math.floor(Math.sRandom(0, abs.length - 1)*Math.random())];

        //рандом количество
        var countNum = Math.floor(Math.sRandom(1, maxCountNum));

        for(var i = 0; i < countNum; i++)
            numEl += Math.floor(Math.sRandom(0, 9)).toString();

        result = el+"-"+numEl;
    }

    if (variant >= 65)
    {
        //Элемент буквеный
        var el="";
        //Элемент буквеный 2
        var el2="";
        //Максимум букв в буквеном элементе
        var maxCountEl = 3;
        //Максимум букв в буквеном элементе 2
        var maxCountEl2 = 3;
        //рандом количество
        var countAbs = Math.floor(Math.sRandom(1, maxCountEl));

        for(var i = 0; i < countAbs; i++)
            el += abs[Math.floor(Math.sRandom(0, abs.Count - 1)*Math.random())];

        //рандом количество
        var countNum = Math.floor(Math.sRandom(1, maxCountEl2));

        for(var i = 0; i < countNum; i++)
            el2 += abs[Math.floor(Math.sRandom(0, abs.Count - 1)*Math.random())];

        result = el+"-"+el2;
    }


    return result;
}


Заключение

Ну, вот, в основном, самое интересное. Код выложил на гитхаб, если есть какие-то советы по улучшению, буду рад услышать.
Tags:
Hubs:
You can’t comment this post because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.