three.js 3d 空间中的 .svg 资产

Posted

技术标签:

【中文标题】three.js 3d 空间中的 .svg 资产【英文标题】:.svg asset in three.js 3d space 【发布时间】:2018-03-25 01:30:16 【问题描述】:

我正在尝试将.svg 资产加载到我的three.js 场景中,作为平面矢量图层;我在另一篇文章中找到了这个带有SVGLoaderSVGRenderer 的示例,但我无法让它工作。

加载的 svg 卡在 2d 空间中并且没有响应相机的移动,我无法访问它的位置。 我尝试切换到WebGLRenderer,但没有加载 svg。

将其加载为精灵的选项会很好,但我希望精灵不要面对相机并保持在 3d 空间中。

var svgManager = new THREE.SVGLoader();
var url = 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Europe_laea_location_map.svg';

function svg_loading_done_callback(doc) 
  init();
  svg(new THREE.SVGObject(doc));
  ico();
  animate();
;

svgManager.load(url,
  svg_loading_done_callback,
  function() 
    console.log("Loading SVG...");
  ,
  function() 
    console.log("Error loading SVG!");
  );


var AMOUNT = 100;
var container, camera, scene, renderer;

function init() 
  scene = new THREE.Scene();
  renderer = new THREE.SVGRenderer();
  renderer.setClearColor(0x00ff00);
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  var container = document.getElementById('container');
  container.appendChild(renderer.domElement);

  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.z = 1100;
  controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.enableZoom = true;
  window.addEventListener('resize', onWindowResize, false);


function svg(svgObject) 
  svgObject.position.x = 510;
  svgObject.position.y = -110;
  svgObject.position.z = 0;
  scene.add(svgObject);


function ico() 
  geometry = new THREE.IcosahedronGeometry(100, 1)
  material = new THREE.MeshNormalMaterial();
  ico = new THREE.Mesh(geometry, material);
  ico.position.y = -300;
  scene.add(ico);
  ico2 = new THREE.Mesh(geometry, material);
  ico2.position.y = 500;
  ico2.position.x = -500;
  ico2.position.z = -50;
  scene.add(ico2);


function onWindowResize() 
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);


function animate() 
  requestAnimationFrame(animate);
  controls.update;
  render();


function render() 
  renderer.render(scene, camera);
body 
  margin: 0;


canvas 
  width: 100%;
  height: 100%
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">

<div id="container"></div>

<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/renderers/SVGRenderer.js"></script>
<script src="https://threejs.org/examples/js/renderers/Projector.js"></script>
<script src="https://threejs.org/examples/js/loaders/SVGLoader.js"></script>
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

【问题讨论】:

对此有何想法? 【参考方案1】:

SVGLoaderSVGRenderer 是两个不同的东西。第一个加载一个 SVG 文件并将其转换为 three.js 形状(尽管有一些限制,即可以读取非常简单的 SVG,不渲染笔触而只渲染填充对象等),而后者使用 SVG 元素渲染三个.js 原语而不是 WebGL。从某种意义上说,它们是相互对立的。

因此,首先,您需要为您的案例使用WebGLRenderer

然后,您需要更改 SVG 加载回调。它接收一组路径,您可以使用这些路径来渲染 SVG。

查看svg_loading_done_callbackinitsvg函数的变化,并在JSFiddle中运行:

var svgManager = new THREE.SVGLoader();
var url = 'https://upload.wikimedia.org/wikipedia/commons/f/f7/Europe_laea_location_map.svg';

function svg_loading_done_callback(paths) 
  init();
  svg(paths);
  ico();
  animate();
;

svgManager.load(url,
  svg_loading_done_callback,
  function() 
    console.log("Loading SVG...");
  ,
  function() 
    console.log("Error loading SVG!");
  );


var AMOUNT = 100;
var container, camera, scene, renderer;

function init() 
  scene = new THREE.Scene();
  renderer = new THREE.WebGLRenderer();
  renderer.setClearColor(0x00ff00);
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  var container = document.getElementById('container');
  container.appendChild(renderer.domElement);

  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.z = 1100;
  controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.enableZoom = true;
  window.addEventListener('resize', onWindowResize, false);


function svg(paths) 

  var group = new THREE.Group();
  group.position.x = 510;
  group.position.y = -110;
  group.position.z = 0;

  for ( var i = 0; i < paths.length; i ++ ) 

    var path = paths[ i ];

    var material = new THREE.MeshBasicMaterial( 
      color: path.color,
      side: THREE.DoubleSide,
      depthWrite: false
     );

    var shapes = path.toShapes( true );

    for ( var j = 0; j < shapes.length; j ++ ) 

      var shape = shapes[ j ];

      var geometry = new THREE.ShapeBufferGeometry( shape );
      var mesh = new THREE.Mesh( geometry, material );

      group.add( mesh );

    

  

  scene.add( group );


function ico() 
  geometry = new THREE.IcosahedronGeometry(100, 1)
  material = new THREE.MeshNormalMaterial();
  ico = new THREE.Mesh(geometry, material);
  ico.position.y = -300;
  scene.add(ico);
  ico2 = new THREE.Mesh(geometry, material);
  ico2.position.y = 500;
  ico2.position.x = -500;
  ico2.position.z = -50;
  scene.add(ico2);


function onWindowResize() 
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);


function animate() 
  requestAnimationFrame(animate);
  controls.update;
  render();


function render() 
  renderer.render(scene, camera);

PS:检查SVG Loader 看看它能解析什么

【讨论】:

谢谢,我有一个不使用 svg 资产的解决方法。下次需要的时候我会回来的!

以上是关于three.js 3d 空间中的 .svg 资产的主要内容,如果未能解决你的问题,请参考以下文章

将 three.js 模型转换为 svg

在 THREE.js 中获取鼠标相对于 3D 空间的坐标

THREE.js:计算物体上一点的世界空间位置

使用 Three.js 将 3D 对象旋转到鼠标

Three.js 中的操纵杆、游戏手柄或 3D 鼠标支持

three.js 中挤出形状的奇怪工件和空纹理