简体   繁体   中英

Trouble rendering a 2D SVG in Three.js & WebGL

I have a ThreeJS Scene (below, or here on CodePen ) with some objects in it - one is a Mesh object of a cat, one is a cube, and now, I'm trying to render a 2D SVG illustration I made. I want to put the SVG illustration in the scene in between the cat image and the cube, displayed the same way the cat image appears (upright, and 2D).

It has taken me days to figure out how to render my own SVG, I find the documentation and examples on ThreeJs.org for SVGRenderer and SVGLoader extremely cumbersome and hard to pick apply to my own image (I'm a novice). The closest I've come to rendering my SVG is using the code from this SO thread that uses a LegacySVG Loader. Problem is, I'm completely lost on how to render this code onto a canvas versus a DOM, and it appears this LegacySVG Loader was a solution to a bug which makes it extremely hard to find resources.

So, essentially, I have rendered an SVG in an individual CodePen using the above resources and now I am lost on how to render it onto the same scene as my cube and cat image. Is it possible to use LegacySVG to render onto a canvas? Or, is there a simpler way to get my SVG onto the same canvas as the other objects?

 let renderer; let camera; //let controls; let scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(54, window.innerWidth / window.innerHeight, 0.1, 1000); renderer = new THREE.WebGLRenderer({ antialias: true, canvas: document.getElementById("viewport") }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(new THREE.Color(0xfefefe)); // document.body.appendChild(renderer.domElement); camera.position.x = 1; camera.position.y = 1; camera.position.z = 15; let light = new THREE.AmbientLight(0xFFFFFF); scene.add(light); let gridHelper = new THREE.GridHelper(10, 10); scene.add(gridHelper); // example code const geometry1 = new THREE.BoxGeometry(1, 1, 1); const material1 = new THREE.MeshStandardMaterial({ color: 0xff0000 }); const topBox = new THREE.Mesh(geometry1, material1); scene.add(topBox); var loader = new THREE.TextureLoader(); // Load an image file into a custom material var material = new THREE.MeshLambertMaterial({ map: loader.load('https://images.unsplash.com/photo-1518791841217-8f162f1e1131?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2850&q=80') }); // create a plane geometry for the image with a width of 10 // and a height that preserves the image's aspect ratio var geometry = new THREE.PlaneGeometry(2, 1.5); // combine our image geometry and material into a mesh var mesh = new THREE.Mesh(geometry, material); // set the position of the image mesh in the x,y,z dimensions mesh.position.set(0,0,5); // add the image to the scene scene.add(mesh); let animate = function() { requestAnimationFrame(animate); //controls.update(); renderer.render(scene, camera); }; ////////////////// animate(); function updateCamera(ev) { camera.position.z = 15 - window.scrollY / 250.0; } window.addEventListener("scroll", updateCamera);
 body { overflow-x: hidden; overflow-y: scroll; padding: 0; margin: 0; } canvas { position: fixed; height: 100vh; } #threeD { position: fixed; margin: 0; padding: 0; left: 0; top: 0; right: 0; bottom: 0; } .page-wrapper { padding: 0px; position: absolute; left: 0; top: 0; width: 100%; height: 4000vh; } #container { height: 500vh; position: fixed; }
 <html> <script src="https://raw.githubusercontent.com/mrdoob/three.js/master/src/loaders/LoadingManager.js"></script> <script src="https://unpkg.com/three@0.102.1/build/three.min.js"></script> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="https://cdn.rawgit.com/mrdoob/three.js/r68/examples/js/loaders/SVGLoader.js"></script> <script src="https://raw.githubusercontent.com/mrdoob/three.js/master/examples/js/renderers/SVGRenderer.js"></script> <link rel="stylesheet" type="text/css" href="index1.css" /> <body> <canvas id="viewport"></canvas> <div class="page-wrapper" > <h1> scroll! </h1> </div> </body> <script src="index1.js"></script> </html>

There are a few things you need to keep in mind.

  1. SVGRenderer does not render the same things as WebGLRenderer .

    a. SVGRenderer takes items inside an <svg> element and applies transformations to its internal <path> , <circle> , <rect> , etc, elements. You can see the svg_sandbox example . All SVG elements are 2D, but can give the impression of being 3D when rotated.

    b.WebGLRenderer draws onto a <canvas> element, and can render all kinds of true 3D geometry. If you want to draw an SVG in WebGL, you'll need to first convert the SVG file into a geometry that WebGL can understand by using THREE.SVGLoader . You can see how that's done in the webgl_loader_svg example , (the source code is available by clicking on the <> button on the bottom right).

  2. You cannot have <svg> elements co-existing in the same 3D space as WebGL elements in the <canvas> . If you want to add cubes and planes with cat images to the same space, I recommend you use the WebGLRenderer approach.

  3. I noticed in your code snippet that you're using files from many different sources, and all kinds of Three.js revisions. Some files are r102.1 , some are r68 , and some are the latest, which is r113 . You should stick to one revision to avoid conflicts when trying to get older files to work with newer ones. For example:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM