У меня есть <circle>
элемента в SVG документе, к которому я применяю <radialGradient>
дать иллюзию того, что это сфера:рендеринг изображения в качестве узла Three.js с SVGRenderer (или иначе рендеринг сфер)
<svg version="1.1" id="sphere_svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="640px" height="640px" viewBox="0 0 640 640" enable-background="new 0 0 640 640" xml:space="preserve">
<defs>
<radialGradient id="sphere_gradient" cx="292.3262" cy="287.4077" r="249.2454" fx="147.7949" fy="274.5532" gradientTransform="matrix(1.0729 0 0 1.0729 -23.3359 -23.3359)" gradientUnits="userSpaceOnUse">
<stop id="sphere_gradient_0" offset="0" style="stop-color:#F37D7F"/>
<stop id="sphere_gradient_1" offset="0.4847" style="stop-color:#ED1F24"/>
<stop id="sphere_gradient_2" offset="1" style="stop-color:#7E1416"/>
</radialGradient>
</defs>
<circle fill="url(#sphere_gradient)" cx="320" cy="320" r="320"/>
</svg>
это выглядит примерно так:
Я могу вынести это в three.js WebGLRenderer
контейнере с помощью Gabe Lerner's canvg
library:
/* sphere_asset is a div containing the svg element */
var red_svg_html = new String($('#sphere_asset').html());
var red_svg_canvas = document.createElement("canvas");
canvg(red_svg_canvas, red_svg_html);
var red_svg_texture = new THREE.Texture(red_svg_canvas);
var red_particles = new THREE.Geometry();
var red_particle_material = new THREE.PointCloudMaterial({
map: red_svg_texture,
transparent: true,
size: 0.15,
alphaTest: 0.10
});
var red_particle_count = 25;
for (var p = 0; p < red_particle_count; p++) {
var pX = 0.9 * (Math.random() - 0.5),
pY = 0.9 * (Math.random() - 0.5),
pZ = 0.9 * (Math.random() - 0.5),
red_particle = new THREE.Vector3(pX, pY, pZ);
red_particles.vertices.push(red_particle);
}
var red_particle_system = new THREE.PointCloud(red_particles, red_particle_material);
scene.add(red_particle_system);
До сих пор, так хорошо. Я даже могу программно изменить градиент и визуализации различных категорий частиц:
То, что я хотел бы сделать теперь перейти от WebGLRenderer
с помощью SVGRenderer
, так что я могу позволить конечному пользователю установить желаемую ориентацию, а затем экспортировать векторное изображение (SVG или преобразованное в PDF на заднем конце), которое можно использовать для работы с качеством публикации.
Использование SVG sandbox example от three.js в качестве основы для экспериментов, я пробовал пару разных методов и не имел большой удачи. Я надеюсь, что у кого-то, у кого есть опыт работы с three.js, могут быть предложения.
Моя первая попытка была использовать canvg
для визуализации SVG в PNG изображения, а затем применить его к <image>
узлу:
var red_svg_html = new String($('#sphere_asset').html());
var red_svg_canvas = document.createElement("canvas");
canvg(red_svg_canvas, red_svg_html);
var red_png_data = red_svg_canvas.toDataURL('image/png');
var red_node = document.createElementNS('http://www.w3.org/2000/svg', 'image');
red_node.setAttributeNS('http://www.w3.org/1999/xlink', 'href', red_png_data);
red_node.setAttributeNS('http://www.w3.org/2000/svg', 'height', '10');
red_node.setAttributeNS('http://www.w3.org/2000/svg', 'width', '10');
var red_particle_count = 25;
for (var i = 0; i < red_particle_count; i++) {
var object = new THREE.SVGObject(red_node.cloneNode());
object.position.x = 0.9 * (Math.random() - 0.5);
object.position.y = 0.9 * (Math.random() - 0.5);
object.position.z = 0.9 * (Math.random() - 0.5);
scene.add(object);
}
Нет узлы не отображаются в моем ViewBox.
Следующая вещь, которую я попытался было THREE.Sprite
объект, используя canvg
и THREE.Texture
процедуры:
var red_svg_html = new String($('#sphere_asset').html());
var red_svg_canvas = document.createElement("canvas");
canvg(red_svg_canvas, red_svg_html);
var red_svg_texture = new THREE.Texture(red_svg_canvas);
red_svg_texture.needsUpdate = true;
var red_sprite = THREE.ImageUtils.loadTexture(red_png_data);
var red_particle_count = 25;
for (var p = 0; p < red_particle_count; p++) {
var material = new THREE.SpriteMaterial({
map: red_svg_texture,
transparent: true,
size: 0.15,
alphaTest: 0.10
});
var sprite = new THREE.Sprite(material);
sprite.position.x = 0.9 * (Math.random() - 0.5),
sprite.position.y = 0.9 * (Math.random() - 0.5),
sprite.position.z = 0.9 * (Math.random() - 0.5),
sprite.scale.set(0.1, 0.1, 0.1);
scene.add(sprite);
}
Это было немного лучше, в том, что я получаю белые, непрозрачные коробки, где сферы иначе появляются в оказанной ViewBox ,
Третья была сделана попытка создать <svg>
в гнездо в пределах родительского узла SVG, который содержит ссылку-состояние <radialGradient>
с идентификатором #sphere_gradient
:
var xmlns = "http://www.w3.org/2000/svg";
var svg = document.createElementNS(xmlns, 'svg');
svg.setAttributeNS(null, 'version', '1.1');
svg.setAttributeNS(null, 'x', '0px');
svg.setAttributeNS(null, 'y', '0px');
svg.setAttributeNS(null, 'width', '640px');
svg.setAttributeNS(null, 'height', '640px');
svg.setAttributeNS(null, 'viewBox', '0 0 640 640');
svg.setAttributeNS(null, 'enable-background', 'new 0 0 640 640');
var defs = document.createElementNS(xmlns, "defs");
var radialGradient = document.createElementNS(xmlns, "radialGradient");
radialGradient.setAttributeNS(null, "id", "sphere_gradient");
radialGradient.setAttributeNS(null, "cx", "292.3262");
radialGradient.setAttributeNS(null, "cy", "287.4077");
radialGradient.setAttributeNS(null, "r", "249.2454");
radialGradient.setAttributeNS(null, "fx", "147.7949");
radialGradient.setAttributeNS(null, "fy", "274.5532");
radialGradient.setAttributeNS(null, "gradientTransform", "matrix(1.0729 0 0 1.0729 -23.3359 -23.3359)");
radialGradient.setAttributeNS(null, "gradientUnits", "userSpaceOnUse");
var stop0 = document.createElementNS(null, "stop");
stop0.setAttributeNS(null, "offset", "0");
stop0.setAttributeNS(null, "stop-color", "#f37d7f");
radialGradient.appendChild(stop0);
var stop1 = document.createElementNS(null, "stop");
stop1.setAttributeNS(null, "offset", "0.4847");
stop1.setAttributeNS(null, "stop-color", "#ed1f24");
radialGradient.appendChild(stop1);
var stop2 = document.createElementNS(null, "stop");
stop2.setAttributeNS(null, "offset", "1");
stop2.setAttributeNS(null, "stop-color", "#7e1416");
radialGradient.appendChild(stop2);
defs.appendChild(radialGradient);
svg.appendChild(defs);
var red_circle = document.createElementNS(xmlns, "circle")
red_circle.setAttribute('fill', 'url(#sphere_gradient)');
red_circle.setAttribute('r', '320');
red_circle.setAttribute('cx', '320');
red_circle.setAttribute('cy', '320');
svg.appendChild(red_circle);
var red_particle_count = 25;
for (var i = 0; i < red_particle_count; i++) {
var object = new THREE.SVGObject(svg.cloneNode(true));
object.position.x = 0.85 * (Math.random() - 0.5);
object.position.y = 0.85 * (Math.random() - 0.5);
object.position.z = 0.85 * (Math.random() - 0.5);
scene.add(object);
}
Нет узлов не предоставляются. Корректировки элементов <circle>
r
, cx
или cy
не изменяют конечный результат.
Интересно, что если изменить атрибут fill
от url(#sphere_gradient)
к red
, я получаю большой круг в основном вынесенный за пределами моего ViewBox, которая не прикрепленный к сцене (она не вращается вместе с другими элементами в моей родительской сцене, как стороны куба).
Существует ли (рабочий и исполнительный) способ рисования сфер или закругленных сферических частиц в пространстве с использованием SVGRenderer
в трёхмерном пространстве?
Спасибо за предложение. Модификация атрибута 'href' для' xlink: href' не изменила конечный результат (* i.e. *, ни один из узлов не отображается, все еще). –
Хорошо, спасибо - изменение пространства имен помогает в том, что теперь применяется градиент! Однако, похоже, что преобразование, применяемое к этому вложенному элементу '
У меня был некоторый успех, переместив группу '' в код' SVGRenderer', так что он является частью самого «root-most» ', но я получаю проблемы с рендерингом, где' 'элементы не рисуются в порядке", которая разрушает иллюзию глубины. В частности, элемент '', который находится ближе к камере, сначала нарисован перед другим элементом, который находится дальше от камеры. В результате элемент, который находится ближе к камере (и который должен находиться на переднем плане), вместо этого отображается под элементом дальше. Вращение сцены разрушает иллюзию глубины. –