Этот вопрос связан с этим вопросом . ответ показывает очень хороший способ выдавливания многоугольников с отверстиями (см. отличный живой пример ). Основное изучение ответа заключалось в том, что пути в three.js (r58) не могут иметь более одной команды moveTo и должны находиться в начале пути, что означает, что путь должен быть прерван с помощью moveTos, так что moveTo start всегда новый путь.

Экструзия в three.js означает, что 2D-контуры преобразуются в 3D-формы с использованием возможной фаски. Он подходит для выдавливания текста для создания трехмерных букв и слов, но может также использоваться для выдавливания пользовательских контуров.

Теперь возникает два вопроса:

  • как можно обрабатывать многоугольники, которые имеют несколько многоугольников с отверстиями и несколько многоугольников без отверстий?
  • как можно добавить текстуру к сгенерированной форме в целом?

Я привел пример этого как SVG в http://jsbin.com/oqomuj/1/edit:

enter image description here

Изображение создается по следующему пути:

<path d="
 M57.11,271.77 L57.11,218.33 L41.99,218.63 L105.49,165.77 L138.41,193.18 L138.41,172.2 L152.53,172.2 L152.53,204.93 L168.99,218.63 L153.21,218.63 L153.21,271.77Z
 M74.14,264.13 L105.49,264.13 L105.49,232.8 L74.14,232.8Z
 M115.35,250.7 L135.96,250.7 L135.96,232.61 L115.35,232.61Z
 M56.11,145.77 L56.11,92.33 L40.99,92.63 L104.49,39.77 L137.41,67.18 L137.41,46.2 L151.53,46.2 L151.53,78.93 L152.53,79.76 L155.55,77.23 L159.5,74.52 L168.65,69.81 L176.46,66.93 L188.04,64.16 L200.63,62.7 L213.65,62.7 L226.05,64.09 L234.83,66.06 L245.65,69.73 L252.87,73.27 L259.12,77.34 L262.63,80.33 L265.6,83.47 L268.01,86.76 L269.83,90.17 L271.08,93.68 L271.76,99.08 L271.04,104.64 L269.75,108.2 L267.87,111.63 L265.42,114.91 L262.44,118.01 L258.95,120.92 L255.02,123.63 L245.86,128.34 L238.06,131.22 L226.48,133.99 L213.88,135.44 L200.63,135.44 L188.04,133.99 L176.46,131.22 L168.65,128.34 L159.5,123.63 L155.55,120.92 L152.21,118.12 L152.21,145.77Z
 M73.14,138.13 L104.49,138.13 L104.49,106.8 L73.14,106.8Z
 M114.35,124.7 L134.96,124.7 L134.96,106.61 L114.35,106.61Z
 M207.26,117.33 L210.57,117.26 L216.87,116.53 L222.66,115.15 L227.8,113.18 L233.11,110 L236.34,106.99 L238.51,103.64 L239.42,100.48 L239.42,97.67 L238.51,94.51 L236.34,91.16 L233.11,88.15 L227.8,84.97 L222.66,83 L216.87,81.62 L210.57,80.89 L203.94,80.89 L197.65,81.62 L191.86,83 L186.71,84.97 L181.41,88.15 L178.18,91.16 L176.01,94.51 L175.1,97.67 L175.1,100.48 L176.01,103.64 L178.18,106.99 L181.41,110 L186.71,113.18 L191.86,115.15 L197.65,116.53 L203.94,117.26Z
"></path>

И этот путь преобразован в отдельные массивы вершин:

var lower_house_material = [{x:57.11,y:271.77},{x:57.11,y:218.33},{x:41.99,y:218.63},{x:105.49,y:165.77},{x:138.42,y:193.18},{x:138.42,y:172.2},{x:152.53,y:172.2},{x:152.53,y:204.93},{x:168.99,y:218.63},{x:153.21,y:218.63},{x:153.21,y:271.77}];
var lower_house_hole_1 = [{x:74.14,y:264.13},{x:105.49,y:264.13},{x:105.49,y:232.8},{x:74.14,y:232.8}];
var lower_house_hole_2 = [{x:115.35,y:250.7},{x:135.96,y:250.7},{x:135.96,y:232.61},{x:115.35,y:232.61}];

var upper_house_material = [{x:56.11,y:145.77},{x:56.11,y:92.33},{x:40.99,y:92.63},{x:104.49,y:39.77},{x:137.42,y:67.18},{x:137.42,y:46.2},{x:151.53,y:46.2},{x:151.53,y:78.93},{x:152.53,y:79.76},{x:155.55,y:77.23},{x:159.5,y:74.52},{x:168.65,y:69.81},{x:176.46,y:66.93},{x:188.04,y:64.16},{x:200.63,y:62.7},{x:213.65,y:62.7},{x:226.05,y:64.1},{x:234.83,y:66.06},{x:245.65,y:69.73},{x:252.87,y:73.27},{x:259.12,y:77.35},{x:262.63,y:80.33},{x:265.6,y:83.47},{x:268.01,y:86.76},{x:269.84,y:90.17},{x:271.08,y:93.68},{x:271.76,y:99.08},{x:271.04,y:104.64},{x:269.75,y:108.2},{x:267.87,y:111.63},{x:265.42,y:114.91},{x:262.44,y:118.01},{x:258.96,y:120.92},{x:255.02,y:123.63},{x:245.86,y:128.34},{x:238.06,y:131.22},{x:226.48,y:133.99},{x:213.88,y:135.45},{x:200.63,y:135.45},{x:188.04,y:133.99},{x:176.46,y:131.22},{x:168.65,y:128.34},{x:159.5,y:123.63},{x:155.55,y:120.92},{x:152.21,y:118.12},{x:152.21,y:145.77}];
var upper_house_hole_1 = [{x:73.14,y:138.13},{x:104.49,y:138.13},{x:104.49,y:106.8},{x:73.14,y:106.8}];
var upper_house_hole_2 = [{x:114.35,y:124.7},{x:134.96,y:124.7},{x:134.96,y:106.61},{x:114.35,y:106.61}];
var upper_house_hole_3 = [{x:207.26,y:117.33},{x:210.57,y:117.26},{x:216.87,y:116.53},{x:222.66,y:115.15},{x:227.8,y:113.18},{x:233.11,y:110},{x:236.34,y:106.99},{x:238.51,y:103.64},{x:239.42,y:100.48},{x:239.42,y:97.67},{x:238.51,y:94.51},{x:236.34,y:91.16},{x:233.11,y:88.15},{x:227.8,y:84.97},{x:222.66,y:83},{x:216.87,y:81.62},{x:210.57,y:80.89},{x:203.94,y:80.89},{x:197.65,y:81.62},{x:191.86,y:83},{x:186.71,y:84.97},{x:181.41,y:88.15},{x:178.18,y:91.16},{x:176.01,y:94.51},{x:175.1,y:97.67},{x:175.1,y:100.48},{x:176.01,y:103.64},{x:178.18,y:106.99},{x:181.41,y:110},{x:186.71,y:113.18},{x:191.86,y:115.15},{x:197.65,y:116.53},{x:203.94,y:117.26}];

Вопрос в том, как эту подобную структуру можно преобразовать в 3D-объект в three.js, чтобы ее можно было экструдировать с помощью THREE.ExtrudeGeometry( shape, extrusionSettings ), а затем текстурировать в целом?

Я могу исследовать данные пути, чтобы узнать, какое отверстие принадлежит какому многоугольнику, и обрабатывать все как отдельные фигуры, но поскольку я хочу использовать одно изображение текстуры для всех фигур , я думаю, что предпочтительным способом является обработка все полигоны материалов как одна форма, а полигоны отверстий как другая форма, и используйте что-то вроде:

var shape = [lower_house_material, upper_house_material];
shape.holes = [lower_house_hole_1, lower_house_hole_2, upper_house_hole_1, upper_house_hole_2, upper_house_hole_3];
var 3d_geometry = THREE.ExtrudeGeometry( shape, extrusionSettings );

Итак, 3d_geometry должен быть в конце одного меша, к которому я могу добавить текстуру следующим образом:

var textureFront = new THREE.ImageUtils.loadTexture( 'textureFront.png');
var textureSide = new THREE.ImageUtils.loadTexture( 'textureSide.png');
var materialFront = new THREE.MeshBasicMaterial( { map: textureFront } );
var materialSide = new THREE.MeshBasicMaterial( { map: textureSide } );
var materialArray = [ materialFront, materialSide ];
var faceMaterial = new THREE.MeshFaceMaterial(materialArray);
var final_mesh = new THREE.Mesh(3d_geometry, faceMaterial );

И одна из текстур может быть примерно такой (256x256px):

enter image description here

И текстура применена:

enter image description here

И поскольку сетка выдавлена, на приведенном выше изображении также присутствует 3D-толщина, но у вас есть идея текстурирования.

Я знаю, что y-координаты нужно перевернуть, но это тривиальная задача, и это не мой вопрос, но если у three.js есть готовая функция для обрезки y, это было бы полезно.

Я потратил часы на изучение исходного кода three.js, примеров и документации , но из-за того, что чаще всего встречается слово «todo», это не может сильно помочь. И я новичок в three.js, думаю, это может быть тривиальная задача для опытного пользователя three.js.

ОБНОВЛЕНИЕ: И чтобы убедиться, что полигоны отверстий всегда хорошо себя ведут, это означает, что полигоны отверстий всегда полностью внутри полигонов материала, и нет повторяющихся вершин или самопересечений ни в полигонах материалов, ни в полигонах дырок, и все такое. материалы-полигоны имеют порядок намотки по часовой стрелке, а отверстия - против часовой.

ОБНОВЛЕНИЕ: слияние геометрий не было решением для текстурирования всего выдавленного многоугольника, заданного одной текстурой: http://jsfiddle.net/C5dga. Текстура повторяется на всех отдельных формах, поэтому слияние геометрий в этом случае не имеет реального значения. Решение, возможно, можно найти при объединении форм до того, как они будут выдавлены, но решения для этого еще не найдено.

5
Timo Kähkönen 21 Апр 2013 в 00:10
Именно для этого были изобретены фильтры SVG. Я не знаком с синтаксисом three.js для них, но в основном вы втягиваете текстуру с помощью feImage, а затем выполняете feComposite operator = "in" с исходной графикой.
 – 
Michael Mullany
21 Апр 2013 в 05:26
Спасибо за комментарий. Верно, что браузеры, поддерживающие фильтры, могут производить такой же эффект в SVG, но в этом вопросе меня интересует текстурирование 3D-формы в three.js для рендеринга вывода в движке браузера webGL.
 – 
Timo Kähkönen
21 Апр 2013 в 05:31

1 ответ

Лучший ответ

Вы можете объединить геометрии, как в следующем фрагменте, в результате чего получится только одна сетка. Судя по предыдущим вопросам, вы уже знаете, как текстурировать отдельную геометрию.

var geometry1 = new THREE.ExtrudeGeometry( shape1, extrusionSettings );
var geometry2 = new THREE.ExtrudeGeometry( shape2, extrusionSettings );

geometry1.merge( geometry2 );

. . .

var mesh = new THREE.Mesh( geometry1, material );

scene.add( mesh );

Fiddle: http://jsfiddle.net/pHn2B/88/

Fiddle: http://jsfiddle.net/C5dga/13/ (с текстурой)

РЕДАКТИРОВАТЬ: В качестве альтернативы созданию отдельных геометрий и использованию утилиты merge вы можете вместо этого создать единую геометрию, используя следующий шаблон:

var geometry1 = new THREE.ExtrudeGeometry( [ shape1, shape2 ], extrusionSettings );

РЕДАКТИРОВАТЬ: обновлено до three.js r.70

6
WestLangley 22 Янв 2015 в 17:43
Спасибо за ответ! Я попытался добавить текстуру на всю сетку, но текстура отображается отдельно для каждой формы: jsfiddle.net/C5dga Есть идеи?
 – 
Timo Kähkönen
21 Апр 2013 в 02:54
Ага. Думаю, вы знаете, что вам нужно сделать - предоставить свой собственный УФ-генератор.
 – 
WestLangley
21 Апр 2013 в 04:15
У меня есть генератор ограничивающей рамки (jsfiddle.net/C5dga). Он масштабирует UV: s от координатного пространства геометрии до диапазона 0-1. Но проблема в том, что эти UV: s генерируются в THREE.ExtrudeGeometry для каждой отдельной геометрии перед объединением. Мне понадобится какая-то функция, чтобы преобразовать UV в объединенную геометрию. Так где же мне взять собственный УФ-генератор?
 – 
Timo Kähkönen
21 Апр 2013 в 04:33
А что касается другой части моего вопроса: есть ли какой-либо метод в three.js для преобразования массива вершин, например. [{x: 56.11, y: 145.77}, {x: 56.11, y: 92.33}, ...] в форму (или путь)? Или нужно использовать медленные методы moveto и lineto и в случаях, когда есть сотни или тысячи вершин?
 – 
Timo Kähkönen
21 Апр 2013 в 05:44
Вы можете редактировать UV вручную, чтобы получить то, что хотите. jsfiddle.net/C5dga/1. Я надеюсь, что вы сможете решить оставшиеся проблемы самостоятельно и согласитесь с этим ответом.
 – 
WestLangley
21 Апр 2013 в 06:40