Using THREE.JS to render to SVG

I came across a blog post that demonstrates using THREE.js to create SVG images. Since that demo was done in CoffeeScript, it took me a while to understand it and build an equivalent JavaScript demo (and the source code).

The SVGRenderer is undocumented in the THREE.js website and it requires a few extra files that are not a part of the standard THREE.js distribution. This post will help you pull the necessary parts together.

My demo is loosly based on this great THREE.js tutorial. I modified it to show the WebGL output on the left-hand side and the SVG capture on the right-hand side. Clicking the arrow updates the SVG capture and shows the code for the SVG on the bottom of the page.

When you hover your mouse cursor over the right-hand side, the paths of the SVG will highlight in red. These correspond to triangles in the original THREE.js model.

three-to-svg

The nice thing about rendering THREE.js models as SVG is that the visible faces will become path elements in the DOM, allowing you to highlight them with a single style sheet rule:

path:hover {
   stroke:       red;
   stroke-width: 2px;
}

This rule tells the web browser to stroke all path elements in a solid red line whenever the user hovers the mouse cursor over them.

How it works:

The demo uses the undocumented SVGRenderer object from THREE.js. The SVGRenderer object depends on another object called Projector. Neither are part of the official THREE.js build, so I grabbed the two source files from the “examples/js/renderer” directory of the THREE.js distribution from GitHub and placed them in my “lib” directory.

When the user clicks the arrow, the SVG on the right side is updated using a new instance of the SVGRenderer object. Here is what the code looks like:

var svgRenderer = new THREE.SVGRenderer();
svgRenderer.setClearColor(0xffffff);
svgRenderer.setSize(width,height);
svgRenderer.setQuality('high');
svgRenderer.render(scene,camera);

The SVGRenderer will store the SVG data in the domElement attribute of itself. In the following code fragment, I insert it into a parent DIV and remove the width and height attributes from the svg element so that I can scale it with style sheet rules.

svgContainer.appendChild(svgRenderer.domElement);
svgRenderer.domElement.removeAttribute('width');
svgRenderer.domElement.removeAttribute('height');

The SVG source for the bottom panel comes from the svgContainer.innerHTML attribute (domElement.outerHTML would work too). I use a regular expression to break up the source into lines and then post it into the destination text field:

document.getElementById('source').value = svgContainer.innerHTML.replace(/<path/g, "\n<path");
Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s