将SVG转换为Three.js路径

时间:2018-06-15 03:44:14

标签: svg three.js

尝试使用https://threejs.org/examples/#webgl_geometry_extrude_shapes2演示的示例SVG解析代码。它没有适当地支持' a'路径命令。我在https://gist.github.com/IkarosKappler/d3c39db08115085bcb18和我自己的一些引用https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes中发现了一些更正,但仍然出现了问题。

这是显示原始SVG的示例。

https://codepen.io/matelich/pen/rKzXZV

由于堆栈需要代码,因此这是错误地解析和解释A和路径的代码:

            // - elliptical arc
            case "A":
            case "a":
                rx = eatNum();
                ry = eatNum();
                xar = eatNum() * DEGS_TO_RADS;
                laf = eatNum(); //large arc flag
                sf = eatNum(); //sweep flag
                nx = eatNum();
                ny = eatNum();

                if (activeCmd == "a") {
                    // relative
                    nx += x;
                    ny += y;
                }

                if(rx != 0 && ry != 0) {

                    console.debug(
                        "Read arc params: rx=" + rx + ", ry=" + ry + ", xar=" + xar + ", laf=" + laf + ", sf=" + sf + ", nx=" + nx + ", ny=" + ny
                    );

                    //might need to bring this back if absellipse doesn't work
                    //if (rx !== ry)
                    //    console.warn("Forcing elliptical arc to be a circular one :(",  rx, ry);

                    // SVG implementation notes does all the math for us! woo!
                    // http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
                    // step1, using x1 as x1'
                    x1 = Math.cos(xar) * (x - nx) / 2 + Math.sin(xar) * (y - ny) / 2;
                    y1 = -Math.sin(xar) * (x - nx) / 2 + Math.cos(xar) * (y - ny) / 2;
                    // step 2, using x2 as cx'
                    console.debug( "TMP x1=" + x1 + ", y1=" + y1 + ", (rx*rx * y1*y1 + ry*ry * x1*x1)=" + (rx * rx * y1 * y1 + ry * ry * x1 * x1) + ", (rx*rx * ry*ry - rx*rx * y1*y1 - ry*ry * x1*x1)=" + (rx * rx * ry * ry - rx * rx * y1 * y1 - ry * ry * x1 * x1));
                    var norm = Math.sqrt(
                        Math.abs(
                            (rx * rx * ry * ry - rx * rx * y1 * y1 - ry * ry * x1 * x1) /
                                (rx * rx * y1 * y1 + ry * ry * x1 * x1)
                        )
                    );
                    if (laf === sf) norm = -norm;
                    x2 = norm * rx * y1 / ry;
                    y2 = norm * -ry * x1 / rx;
                    console.debug("TMP norm=" + norm + ", x2=" + x2 + ", y2=" + y2);
                    // step 3
                    cx = Math.cos(xar) * x2 - Math.sin(xar) * y2 + (x + nx) / 2;
                    cy = Math.sin(xar) * x2 + Math.cos(xar) * y2 + (y + ny) / 2;
                    console.debug("TMP cx=" + cx + ", cy=" + cy);

                    var u = new THREE.Vector2(1, 0),
                        v = new THREE.Vector2((x1 - x2) / rx, (y1 - y2) / ry);
                    var startAng = Math.acos(u.dot(v) / u.length() / v.length());
                    if (u.x * v.y - u.y * v.x < 0) startAng = -startAng;

                    // we can reuse 'v' from start angle as our 'u' for delta angle
                    u.x = (-x1 - x2) / rx;
                    u.y = (-y1 - y2) / ry;

                    var deltaAng = Math.acos(v.dot(u) / v.length() / u.length());
                    // This normalization ends up making our curves fail to triangulate...
                    if (u.x * v.y - u.y * v.x < 0) deltaAng = -deltaAng;
                    if (!sf && deltaAng > 0) deltaAng -= Math.PI * 2;
                    if (sf && deltaAng < 0) deltaAng += Math.PI * 2;

                    console.debug(
                        "Building arc from values: cx=" + cx + ", cy=" + cy + ", startAng=" + startAng + ", deltaAng=" + deltaAng + ", endAng=" + (startAng + deltaAng) + ", sweepFlag=" + sf );
                    // path.absarc(cx, cy, rx, startAng, startAng + deltaAng, sf);
                    path.absellipse(cx, cy, rx, ry, startAng, startAng + deltaAng, sf);
                } else {
                    path.lineTo(nx, ny);
                }

或者,也许它只是我的ShapePath黑客?

THREE.ShapePath.prototype.absarc = function( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
   this.currentPath.absarc(aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise);
};
THREE.ShapePath.prototype.absellipse = function( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) {
   this.currentPath.absellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise );
};

1 个答案:

答案 0 :(得分:2)

您仍然可以使用SVGLoader加载SVG并检索ShapePath对象的数组。然后,您可以使用ShapePath.toShapes并使用这些形状来创建ExtrudeBufferGeometry&#39; s。它实际上与webgl_loader_svg.html中的工作流程相同,只是使用ExtrudeBufferGeometry