Skip to content

Commit

Permalink
Merge pull request #11359 from linev/fastsvg
Browse files Browse the repository at this point in the history
Improve performance of SVGRenderer
  • Loading branch information
mrdoob authored May 20, 2017
2 parents 0560434 + 0daa689 commit e7621bf
Showing 1 changed file with 62 additions and 57 deletions.
119 changes: 62 additions & 57 deletions examples/js/renderers/SVGRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ THREE.SVGRenderer = function () {
_viewMatrix = new THREE.Matrix4(),
_viewProjectionMatrix = new THREE.Matrix4(),

_svgPathPool = [], _svgLinePool = [], _svgRectPool = [],
_svgNode, _pathCount = 0, _lineCount = 0, _rectCount = 0,
_quality = 1;
_svgPathPool = [],
_svgNode, _pathCount = 0, _currPath, _currStyle,
_quality = 1, _precision = null;

this.domElement = _svg;

Expand Down Expand Up @@ -104,11 +104,15 @@ THREE.SVGRenderer = function () {

};

this.setPrecision = function ( precision ) {

_precision = precision;

};

function removeChildNodes() {

_pathCount = 0;
_lineCount = 0;
_rectCount = 0;

while ( _svg.childNodes.length > 0 ) {

Expand All @@ -118,10 +122,26 @@ THREE.SVGRenderer = function () {

}

function getSvgColor ( color, opacity ) {

var arg = Math.floor( color.r * 255 ) + ',' + Math.floor( color.g * 255 ) + ',' + Math.floor( color.b * 255 );

if ( opacity === undefined || opacity === 1 ) return 'rgb(' + arg + ')';

return 'rgba(' + arg + ',' + opacity + ')';

}

function convert ( c ) {

return _precision !== null ? c.toFixed(_precision) : c;

}

this.clear = function () {

removeChildNodes();
_svg.style.backgroundColor = 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')';
_svg.style.backgroundColor = getSvgColor( _clearColor, _clearAlpha );

};

Expand All @@ -139,7 +159,7 @@ THREE.SVGRenderer = function () {
if ( background && background.isColor ) {

removeChildNodes();
_svg.style.backgroundColor = 'rgb(' + Math.floor( background.r * 255 ) + ',' + Math.floor( background.g * 255 ) + ',' + Math.floor( background.b * 255 ) + ')';
_svg.style.backgroundColor = getSvgColor( background );

} else if ( this.autoClear === true ) {

Expand All @@ -160,6 +180,7 @@ THREE.SVGRenderer = function () {
_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );

calculateLights( _lights );
_currPath = _currStyle = ""; // reset accumulated path

for ( var e = 0, el = _elements.length; e < el; e ++ ) {

Expand Down Expand Up @@ -220,6 +241,8 @@ THREE.SVGRenderer = function () {

}

flushPath(); // just to flush last svg:path

scene.traverseVisible( function ( object ) {

if ( object instanceof THREE.SVGObject ) {
Expand Down Expand Up @@ -331,37 +354,28 @@ THREE.SVGRenderer = function () {
scaleY *= material.size;
}

_svgNode = getRectNode( _rectCount ++ );

_svgNode.setAttribute( 'x', v1.x - ( scaleX * 0.5 ) );
_svgNode.setAttribute( 'y', v1.y - ( scaleY * 0.5 ) );
_svgNode.setAttribute( 'width', scaleX );
_svgNode.setAttribute( 'height', scaleY );
var path = 'M' + convert( v1.x - scaleX * 0.5 ) + ',' + convert( v1.y - scaleY * 0.5 ) + 'h' + convert( scaleX ) + 'v' + convert( scaleY ) + 'h' + convert(-scaleX) + 'z';
var style = "";

if ( material.isSpriteMaterial || material.isPointsMaterial ) {

_svgNode.setAttribute( 'style', 'fill: ' + material.color.getStyle() );
style = 'fill:' + getSvgColor( material.color, material.opacity );

}

_svg.appendChild( _svgNode );
addPath( style, path );

}

function renderLine( v1, v2, element, material ) {

_svgNode = getLineNode( _lineCount ++ );

_svgNode.setAttribute( 'x1', v1.positionScreen.x );
_svgNode.setAttribute( 'y1', v1.positionScreen.y );
_svgNode.setAttribute( 'x2', v2.positionScreen.x );
_svgNode.setAttribute( 'y2', v2.positionScreen.y );
var path = 'M' + convert( v1.positionScreen.x ) + ',' + convert( v1.positionScreen.y ) + 'L' + convert( v2.positionScreen.x ) + ',' + convert( v2.positionScreen.y );

if ( material instanceof THREE.LineBasicMaterial ) {

_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + material.color.getStyle() + '; stroke-width: ' + material.linewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.linecap + '; stroke-linejoin: ' + material.linejoin );
var style = 'fill:none;stroke:' + getSvgColor( material.color, material.opacity ) + ';stroke-width:' + material.linewidth + ';stroke-linecap:' + material.linecap + ';stroke-linejoin:' + material.linejoin;

_svg.appendChild( _svgNode );
addPath( style, path );

}

Expand All @@ -372,8 +386,8 @@ THREE.SVGRenderer = function () {
_this.info.render.vertices += 3;
_this.info.render.faces ++;

_svgNode = getPathNode( _pathCount ++ );
_svgNode.setAttribute( 'd', 'M ' + v1.positionScreen.x + ' ' + v1.positionScreen.y + ' L ' + v2.positionScreen.x + ' ' + v2.positionScreen.y + ' L ' + v3.positionScreen.x + ',' + v3.positionScreen.y + 'z' );
var path = 'M' + convert( v1.positionScreen.x ) + ',' + convert( v1.positionScreen.y ) + 'L' + convert( v2.positionScreen.x ) + ',' + convert( v2.positionScreen.y ) + 'L' + convert( v3.positionScreen.x ) + ',' + convert( v3.positionScreen.y ) + 'z';
var style = '';

if ( material instanceof THREE.MeshBasicMaterial ) {

Expand Down Expand Up @@ -413,75 +427,66 @@ THREE.SVGRenderer = function () {

if ( material.wireframe ) {

_svgNode.setAttribute( 'style', 'fill: none; stroke: ' + _color.getStyle() + '; stroke-width: ' + material.wireframeLinewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.wireframeLinecap + '; stroke-linejoin: ' + material.wireframeLinejoin );
style = 'fill:none;stroke:' + getSvgColor( _color, material.opacity ) + ';stroke-width:' + material.wireframeLinewidth + ';stroke-linecap:' + material.wireframeLinecap + ';stroke-linejoin:' + material.wireframeLinejoin;

} else {

_svgNode.setAttribute( 'style', 'fill: ' + _color.getStyle() + '; fill-opacity: ' + material.opacity );
style = 'fill:' + getSvgColor( _color, material.opacity );

}

_svg.appendChild( _svgNode );
addPath( style, path );

}

function getLineNode( id ) {

if ( _svgLinePool[ id ] == null ) {
function addPath ( style, path ) {

_svgLinePool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'line' );
if ( _currStyle == style ) {

if ( _quality == 0 ) {
_currPath += path

_svgLinePool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
} else {

}
flushPath();

return _svgLinePool[ id ];
_currStyle = style;
_currPath = path;

}

return _svgLinePool[ id ];

}

function getPathNode( id ) {

if ( _svgPathPool[ id ] == null ) {

_svgPathPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
function flushPath() {

if ( _quality == 0 ) {

_svgPathPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed

}
if ( _currPath ) {

return _svgPathPool[ id ];
_svgNode = getPathNode( _pathCount ++ );
_svgNode.setAttribute( 'd', _currPath );
_svgNode.setAttribute( 'style', _currStyle );
_svg.appendChild( _svgNode );

}

return _svgPathPool[ id ];

_currPath = _currStyle = "";
}

function getRectNode( id ) {
function getPathNode( id ) {

if ( _svgRectPool[ id ] == null ) {
if ( _svgPathPool[ id ] == null ) {

_svgRectPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'rect' );
_svgPathPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );

if ( _quality == 0 ) {

_svgRectPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
_svgPathPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed

}

return _svgRectPool[ id ];
return _svgPathPool[ id ];

}

return _svgRectPool[ id ];
return _svgPathPool[ id ];

}

Expand Down

0 comments on commit e7621bf

Please sign in to comment.