Докуметация Cтарт Статьи Форум Лента Вход
Не официальное русскоязычное сообщество
Главная
    Документация jMonkeyEngine
        jMonkeyEngine Уроки и Документация
            Вклады
                jMonkey CSG - Конструктивная Сплошная Геометрия

jMonkey CSG — Конструктивная Сплошная Геометрия

Опубликованно: 31.05.2018, 13:54
Последняя редакция, Andry: 10.06.2018 13:54

Сложные 3D-фигуры, созданные путем объединения простых примитивов

Скачать, Полный исходник

Конструктивная сплошная геометрия (КБГ) (англ. Constructive Solid Geometry, CSG) — это метод, используемый в 3D моделировании твёрдых тел. Конструктивная сплошная геометрия позволяет моделеру создавать сложную поверхность или объект с помощью булевых операторов для комбинирования объектов. Часто CSG представляет собой модель или поверхность, которая кажется визуально сложной, но на самом деле представляет собой немногим более, чем умные комбинации или декомбинации простых объектов.

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

  • Булево объединение(Union) — слияние (добавление) двух объектов в один
  • Булево пересечение(Intersection) — общая часть для обоих объектов
  • Булева разность(Difference) — что останется, когда вы удалите один объект из другого

Несколько личных заметок об истории этого кода (1 квартал 2015 года)

После моего ухода из профессиональной жизни инженера-программиста которая длилась более четырех десятилетий, у меня появилась возможность побаловать себя капризами и теперь можно исследовать такие вещи, как 3D-графика. Экспериментировав с Java с момента его первоначального выпуска в 1995 году и разрабатывая коммерческие Java-приложения уровня предприятия с 2000 года, jMonkey показался мне идеальным местом что бы начать игру.

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

Насколько я могу судить, Эван Уоллас собрал библиотеку Javascript для поддержки CSG в браузерах, поддерживающих WebGL. Основным алгоритмом обработки является BSP — Двоичное разбиение пространства(Binary Space Partitioning) смотрите csg.js (это действительно впечатляет).
Он был преобразован в jMonkey совместимый Java что сделал fabsterpal и отправлен в репозиторий Github что сделал andychase. И вроде бы, все было правильно размещено и аннотировано для полностью открытых исходников.

Во время работы с Java-кодом я споткнулся о некоторые ошибки и обнаружил много мест, где мне бы хотелось получить более полные комментарии. Мой личный стиль обучения — это работа с рабочим примером. Туда я могу вносить небольшие, изменения, которые помогают мне понять более общую картину. С этой целью я переопределил удобным мне способом Java код, и структуру.
Но логика и алгоритмы основаны непосредственно на том, что я нашел в исходном коде Javascript/Java.

К сожалению, личный опыт работы с этим кодом и дальнейшее изучение информации в Интернете привели меня к пониманию того, что у BSP есть свойственные ей проблемы. Из-за недостаточной точности, на любом реальном компьютере, получаются дефекты в достаточно сложных фигурах. Поэтому я применил другой алгоритм, основанный на работе Данило Бальби, Сильвы Кастанхайры, которые разместили свою работу в качестве общественного достояния.

Другими словами, я резвюсь в своей песочнице… Но, будучи твердым сторонником открытых исходников, я делаю свои эксперименты доступными для всех. Если для вас есть что-то ценное, не стесняйтесь использовать его. Я буду пытаться сохранить действующий код полностью работоспособным, но на данный момент я не делаю никаких обещаний относительно обратной совместимости.
Если вы обнаружили проблему, составьте соответствующий Ticket в SourceForge.

Структура кода

Я пытаюсь сохранить CSG-код в виде достаточно независимого подключаемого модуля, не требующего изменений, в случае обновления ядра jme3 в новых версиях движка. Вы найдете интересный материал в пакете «net.wcomohundro.jme3.csg». От некоторых привычек отказаться очень тяжело (ну, они действительно не уходят вообще), поэтому я работаю в среде Eclipse IDE, используя исходник jMonkey, предоставленные последним стабильным релизом jme3 SDK. По состоянию на 30 Мая 2018, это версия 3.2.1

К тому что было сказано выше, у меня есть набор вещей зависимых от изменений ядра jme3, об этом сказано в репозитории CSG SVN. (о, ты же знал, что это произойдет). Я нашел Savable с поддержкой через XML, что является отличным способом управления моими тестовыми случаями. Мои вещей зависимых от изменение кода ядра в основном связаны с предоставлением разумных (т.е. не NullPointerException) значений по умолчанию для элементов, отсутствующих в XML. И я создал простой плагин XMLLoader для AssetManager, который позволяет мне загружать Игровые Ресурсы(Assets) из файлов XML. Это позволяет мне очень легко создавать тестовые случаи CSG, вручную редактируя XML файлы. Предоставляя разумные значения по умолчанию, я могу сократить мои XML-файлы до минимума.

Ядро, классы CSG реализованные в WCOmoCSG321… jar. Этот jar может быть включен в любой jMonkey IDE проект, который затем может использовать все функции ядра. Однако, если вы хотите использовать функции XML загрузчика, вам нужно будет включить WCOmoCSGjme321… jar и поместить его перед любыми стандартными jme3 jar-ми. После этого станут доступны функции импорта XML. Тестовые файлы и связанные с ними игровые ресурсы доступны в WCOmoCSGtest321… jar. Любой или все исходники могут быть загружены из SourceForge.

Особенности

  • Примитивные фигуры, основанные на любой произвольной Сетке
  • Составная геометрия на основе булевого смешивания фигур
  • Материалы, применённые к фигуре, применяются к поверхности, сгенерированной этой фигурой в конечной геометрии. Другими словами, результат может иметь несколько Материалов.
  • CSG определённые примитивные фигуры поддерживают грани с различным масштабированием текстур и материалами, применяемыми к различным поверхностям (например спереди, сзади, сверху, снизу, …)
  • Локальное Освещение, применённое к фигуре, применяются к поверхности, сгенерированной этой фигурой в конечной геометрии. Другими словами, результат может иметь Узлы-видимости освещений, которые применяются только к выбранным под-поверхностям.

Базовые элементы

Чтобы использовать CSG, вы будете работать с фигурами и геометрией.

Базовый Элемент  Описание
CSGShape  Базовый примитив CSG, основанный на любом произвольном Сетке(Mesh).
CSGGeometry  Булева точка смешивания для различных CSGShapes, которая даёт окончательную фигуру, к которой применяется один материал.
CSGGeonode  Булевая точка смешивания для различных CSGShapes, каждая из которых имеет собственный дополнительный материал, которая даёт окончательную фигуру. Материалы и локальное освещение, присвоенные примитивам, переносятся на поверхность которую они производят в конечном результате. Примитивы без явно заданного материала используют материал, присвоенный CSGGeonode в целом.

Целью моего первоначального дизайна, было реализовать CSGGeometry для точки смешивания, с возможностью поддержки нескольких материалов. Когда я узнал больше о jMonkey, я обнаружил, что Геометрия легко, может поддерживать только одну Сетку(Mesh). Чтобы предоставить несколько материалов, которые присвоены примитивам, вам действительно будет нужно использовать Узел с потомками Геометриями. Поэтому был создан CSGGeonode. Производится несколько сеток, соответствующих различным материалам. CSGGeometry больше не требуется, поскольку CSGGeonode предоставляет все те же возможности. Но CSGGeometry обеспечивает оптимизированную обработку только для тех объектов, которые имеют один материал.

Примитивные фигуры CSG

CSGShape можно построить из любой сетки. Никаких дополнительных примитивов, кроме тех, которые предоставляются ядром jMonkey, не требуется, и цель моего первоначального дизайна проекта была в том, чтобы не создавать какие-либо специальные примитивы для CSG. Но во время моих тестирований я споткнулся о проблемы связанные текстурами для Кубов, Цилиндров и Сфер. Поэтому я создал некоторые примитивы CSG.

CSG примитивы пытаются обеспечить единый подход их реализации. Это включает в себя идею фигур, созданных несколькими срезами, взятыми вдоль оси z. И включает концепцию грани (передняя, ​​задняя, ​​верхняя, нижняя, …), где текстуры на каждой поверхности могут иметь разный масштаб и могут применятся различные материал.

  • Для CSGBox это означает, что одна повторяющаяся текстура может быть соответствующим образом масштабироваться, оставаясь при этом неискаженной для любого продолговатого края.
  • Для CSGCylinder или CSGPipe грани концов не искажены радиально, а просто представляют собой круглый вырез текстуры, который может независимо масштабироваться.
  • Для CSGSphere в настоящее время нет специальной реализации поверхности.

Другие улучшения включают:

  • Радиальное искажение текстуры на полюсах Сферы устранено.
  • Вы можете использовать криволинейную текстуру поверхности Цилиндра по высоте, а не по окружности.
  • Шкала x/y может применяться к каждому отдельному срезу вдоль оси z.
  • Вращение может быть применено к каждому отдельному срезу вокруг оси z. Это приводит к скрученности конечной фигуры.
  • Простой Сплайн генератор, который может легко создавать торы или спирали.
  • Обработка LOD поддерживается за счет уменьшения количества срезов на определенный процент.
  • В будущем также улучшится сокращение числа радиальных точек.
  • Генерация TangentBinormal может быть вызвана настройками в файле XML Savable.

Лицензированние — BSD как и jMonkey

Новая BSD лицензия (3-пункта). Другими словами, вы сможете делать всё то, что сделает вас счастливыми!

Загрузить/Получить доступ к коду

Управление jMonkeyCSG осуществляется через проект SourceForge, ссылка на который здесь. Файлы .jar и .zip можно скачать здесь. Все исходники доступны через репозиторий SourceForge SVN.

JMonkey IDE

Как я уже говорил ранее, я работаю в Eclipse, ссылаясь на исходники jme3, из стабильной версией jme3 SDK. Я не очень хорошо знаком с IDE jMonkey, но у меня CSG в ней заработал, после того как я просто включил файл ядра CSG в разделе Библиотеки проекта jMonkey IDE.

С чего начать

Самый простой пример — добавить некоторые фигуры в геометрию, регенерируйте эту геометрию и примените Материал и добавить геометрию в свою сцену.

    	// Смешивание фигур в геометрии
    	CSGGeometry aGeometry = new CSGGeometry();
    	aGeometry.setMaterial( new Material( assetManager, "Common/MatDefs/Misc/ShowNormals.j3md" ) );

    	// Начните со сферы
    	CSGShape aSphere = new CSGShape( "Sphere1", new Sphere( 32, 32, 1.3f ) );
    	aGeometry.addShape( aSphere );

    	// Отнимем куб
    	CSGShape aCube = new CSGShape( "Box", new Box(1,1,1) );
    	aGeometry.subtractShape( aCube );
    	
    	// Произведём окончательную фигуру
    	aGeometry.regenerate();
    	
    	// Теперь добавьте aGeometry в вашу сцену

Если вы хотите применить материалы к примитивам, что бы эти материалы появились на соответствующих поверхностях в конечном результате, сделайте следующее.

    	// Смешаем фигуры в geonode с общим материалом
    	CSGGeonode aGeometry = new CSGGeonode();
    	aGeometry.setMaterial( new Material( assetManager, "Common/MatDefs/Misc/ShowNormals.j3md" ) );

    	// Начнём с куба
    	CSGShape aCube = new CSGShape( "Box", new Box(1,1,1) );
    	aGeometry.addShape( aCube );

    	// Отнимем окрашенный цилиндр
    	CSGShape aCylinder = new CSGShape( "Cylinder", new Cylinder( 32, 32, 1.1f, pLength, true ) );
    	Material mat1 = new Material( assetManager, "Common/MatDefs/Misc/Unshaded.j3md" );
    	mat1.setColor( "Color", ColorRGBA.Yellow );
        aCylinder.setMaterial( mat1 );

    	aGeometry.subtractShape( aCylinder );
    	
    	// Произведём окончательную фигуру
    	aGeometry.regenerate();
    	
    	// Теперь добавьте aGeometry в вашу сцену

Испытательные случаи

Различные тестовые случаи включены в репозиторий SVN, все они основаны на формате Savable XML. Например, коридор может быть создан путем вычитания цилиндра из вытянутого куба, и затем вырезания дверного проема. Как вы можете видеть, довольно легко и быстро создавать комбинированные примеры, редактируя XML файл.

    <net.wcomohundro.jme3.csg.CSGLinkNode fname='CSGSample'>
        <lights class='com.jme3.light.LightList'>
            <lights>
                <com.jme3.light.AmbientLight name='WhiteLight' enabled='true'>
                    <color class='com.jme3.math.ColorRGBA' r='1' g='1' b='1' a='1'/>
                </com.jme3.light.AmbientLight>
            </lights>
        </lights>
        <children>
            <net.wcomohundro.jme3.csg.CSGGeonode name='ACorridor'
                    materialName='Textures/Rock/Rock1Rpt.xml'>
                <shapes>
                    <net.wcomohundro.jme3.csg.CSGShape name='Exterior'>
                        <mesh class='net.wcomohundro.jme3.csg.shape.CSGBox' 
                                xExtent='1.0' yExtent='1.0' zExtent='1.0'>
                            <faceProperties>
                                <net.wcomohundro.jme3.csg.shape.CSGFaceProperties face='FRONT_BACK' scaleX='1' scaleY='1.0'/>
                                <net.wcomohundro.jme3.csg.shape.CSGFaceProperties face='LEFT_RIGHT' scaleX='10' scaleY='1.0'/>
                                <net.wcomohundro.jme3.csg.shape.CSGFaceProperties face='TOP_BOTTOM' scaleX='1' scaleY='10.0'/>
                            </faceProperties>
                        </mesh>
                        <transform class='com.jme3.math.Transform'>
                            <scale class='com.jme3.math.Vector3f' x='1.0' y='1.0' z='10.0'/>
                        </transform>
                    </net.wcomohundro.jme3.csg.CSGShape>
                    
                    <net.wcomohundro.jme3.csg.CSGShape name='Interior' operator='DIFFERENCE'
                            materialName='Textures/BrickWall/BrickWallRpt.xml'>
                        <mesh class='net.wcomohundro.jme3.csg.shape.CSGCylinder' 
                                closed='true' height='1.0' radius='0.5' textureMode='FLAT_LINEAR'>
                            <faceProperties>
                                <net.wcomohundro.jme3.csg.shape.CSGFaceProperties face='SIDES' scaleX='9.95' scaleY='3.0'/>
                            </faceProperties>
                        </mesh>
                        <transform class='com.jme3.math.Transform'>
                            <scale class='com.jme3.math.Vector3f' x='1.95' y='1.95' z='19.9'/>
                        </transform>
                    </net.wcomohundro.jme3.csg.CSGShape>
		
                    <net.wcomohundro.jme3.csg.CSGShape name='Doorway' operator='DIFFERENCE'>
                        <mesh class='net.wcomohundro.jme3.csg.shape.CSGBox' 
                             xExtent='0.9' yExtent='0.5' zExtent='0.9'/>
                        <transform class='com.jme3.math.Transform'>
                            <translation class='com.jme3.math.Vector3f' x='0' y='0.5' z='10'/>
                        </transform>
                    </net.wcomohundro.jme3.csg.CSGShape>
                </shapes>
            </net.wcomohundro.jme3.csg.CSGGeonode>
        </children>
    </net.wcomohundro.jme3.csg.CSGLinkNode>

Смотрите так же:


Переведено для jmonkeyengine.ru, оригинал
Автор перевода: Andry

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

jMonkeyEngine.ru © 2017. Все права сохранены.