Загрузка модели из Blender

Что ж, с рисованием точек, линий и треугольников мы справились. Теперь хотелось бы получить что-то более сложное. Например, тор — фигура популярная и в то же время посложнее треугольника. Но писать функцию генерации, а тем более задавать все точки вручную — дело долгое. Гораздо быстрее создать тор в 3D-редакторе и каким-то образом сделать экспорт в WebGL. Этим и займемся!

В качестве 3D-редактора я выбрал Blender — свободный продукт с огромным количеством возможностей. Помимо своего формата (.blend) Blender поддерживает экспорт в несколько других (obj, dxf, 3ds и прочие). Для наших целей отлично подойдет формат Collada — он довольно распространен и, что для нас очень важно, этот формат является текстовым (если точнее — XML).

Для создания нашего тора мы запускаем Blender, удаляем добавленный по умолчанию куб (Delete или X), затем нажимаем Shift+A для вызова меню добавления и в нем выбираем Mesh -> Torus.

Вот и все действия, которые были нужны для получения тора. Осталось лишь выгрузить его в нужном нам формате. Для этого выбираем File -> Export -> Collada (.dae), а затем помещаем полученный файл в директорию со скриптами. Необходимо учитывать, что при запуске примера на веб-сервере файл скорей всего будет заблокирован из-за его расширения, поэтому лучше заменить расширение на .xml (или другой разрешенный формат).

Blender немного затягивает, но попробуем все-таки оторваться и написать код. Ключевое место, конечно же, занимает функция, которая читает файл Collada. На роль полноценного парсера она не тянет, но для наших нужд ее вполне достаточно:


    function parseCollada(colladaXml) {
        var xmlDoc;
        
        // создаем парсер DOM
        if (window.DOMParser) {
            var parser = new DOMParser();
            xmlDoc = parser.parseFromString(colladaXml, "text/xml");
        } else { // Internet Explorer
            xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.async=false;
            xmlDoc.loadXML(colladaXml);
        }
        
        var jsonResult = {};
        // находим /COLLADA/library_geometries/geometry/mesh/source/float_array
        var mesh = xmlDoc.getElementsByTagName("mesh")[0];
        var verticesSources = mesh.getElementsByTagName("source")[0];
        var verticesNode = verticesSources.getElementsByTagName("float_array")[0];
        // в этой секции хранятся координаты через пробел - получаем их массив
        jsonResult.vertices = verticesNode.textContent.split(" ");
        
        // находим /COLLADA/library_geometries/geometry/mesh/polylist/p
        var polyNode = mesh.getElementsByTagName("polylist")[0];
        var indecesNode = polyNode.getElementsByTagName("p")[0];
        var allIndices = indecesNode.textContent.split(" ");
        jsonResult.indices = [];
        // нужные нам индексы вершин находятся в 0, 3, 6 и т.д.
        for (var i = 0; i < allIndices.length; i += 2) {
            jsonResult.indices.push(allIndices[i]);
        }
        return jsonResult;
    }

Формат Collada хранит информацию о камере, освещении и многом другом. Но нам в рамках текущего примера нужны только координаты вершин и индексы. Переменная allIndices содержит индексы вершин, нормалей и UV-координаты. Нам нужны только индексы вершин, поэтому в цикле мы выбираем только каждое третье значение.

Следующая по значимости идет функция загрузки модели:


    function loadJsonModel() {
        var request = new XMLHttpRequest();
        request.open("GET", "torus.xml");
        request.onreadystatechange = function() {
            if (request.readyState == 4) {
                var colladaJson = parseCollada(request.responseText);
                vertices = colladaJson.vertices;
                indices = colladaJson.indices;
                initBuffers();
                drawScene();
            }
        }
        request.send();
    }

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

Вот такое колесо мы получили. Хотя хотели получить тор... Но несмотря на это цель можно считать достигнутой! Для бОльшего эффекта добавим вращение по оси X - это и будет нашим финальным вариантом:

Исходный код можно скачать на GitHub.

Загрузка модели из Blender
Метки:    

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *