【问题标题】:Change color of an svg dynamically and apply as texture in three.js动态更改 svg 的颜色并在 three.js 中应用为纹理
【发布时间】:2018-07-22 19:07:04
【问题描述】:

我正在尝试使用 three.js 创建一个配置器,但我需要动态更改产品的颜色,尽管我可以使用 svg 作为纹理,但更改了 svg 的填充属性并轻松更新纹理,但效果不佳

我现在拥有的是

-一个 svg 的 3D 模型,使用 TextureLoader 作为纹理应用,但 svg 被放置在外部文件(“images/texture.svg”)中(也是three.js 正在减小纹理的大小,但我认为这是一个映射问题)

-svg 是分层分离的,所以我可以手动更改颜色并应用它

但我试图让它动态化,你选择一种颜色,它会自动更新作为纹理应用的 svg

有什么想法吗?

谢谢!

【问题讨论】:

    标签: javascript svg three.js


    【解决方案1】:

    我叉了别人的小提琴来展示解决方案。我添加了一个点击函数,它可以修改 SVG 并在模型上重绘材质。

    http://jsfiddle.net/L4pepnj7/

    单击示例中的任意位置以更改 SVG 中圆圈的颜色。

    将 SVG 转换为编码 URI 的操作需要在一个恒定循环中进行,但您可以在渲染器执行其自己的操作时将颜色更改放在单击事件中。我在现有的小提琴中添加了一个名为“clickBody”的函数,它改变了其中一个 SVG 元素的颜色。

    var mesh;
    var scene = new THREE.Scene();
    
    var camera = new THREE.PerspectiveCamera(50, 500 / 400, 0.1, 1000);
    camera.position.z = 10;
    
    var renderer = new THREE.WebGLRenderer({
        antialias: true
    });
    renderer.setSize(500, 400);
    document.body.appendChild(renderer.domElement);
    
    var svg = document.getElementById("svgContainer").querySelector("svg");
    var svgData = (new XMLSerializer()).serializeToString(svg);
    
    var canvas = document.createElement("canvas");
    var svgSize = svg.getBoundingClientRect();
    canvas.width = svgSize.width;
    canvas.height = svgSize.height;
    var ctx = canvas.getContext("2d");
    
    var img = document.createElement("img");
    var material;
    img.setAttribute("src", "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(svgData))));
    
    img.onload = function() {
        ctx.drawImage(img, 0, 0);
        var texture = new THREE.Texture(canvas);
        texture.needsUpdate = true;
        var geometry = new THREE.SphereGeometry(3, 50, 50, 0, Math.PI * 2, 0, Math.PI * 2);
        material = new THREE.MeshBasicMaterial({
            map: texture
        });
        material.map.minFilter = THREE.LinearFilter;
        mesh = new THREE.Mesh(geometry, material);
        scene.add(mesh);
    };
    
    
    
    var colors = ["red", "orange", "yellow", "green", "blue"];
    
    
    var c = 0;
    
    function clickBody() {
        document.getElementById("test").setAttribute("fill", colors[c]);
        var svgData = (new XMLSerializer()).serializeToString(svg);
        img.setAttribute("src", "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(svgData))));
        img.onload = function() {
            ctx.drawImage(img, 0, 0);
            var texture = new THREE.Texture(canvas);
            material.map = texture;
            material.map.needsUpdate = true;
            renderer.render(scene, camera);
        }
        c = c + 1;
        if (c == colors.length) {
            c = 0;
        }
    }
    document.body.addEventListener("click", clickBody)
    
    var render = function() {
        requestAnimationFrame(render);
        mesh.rotation.y += 0.01;
        renderer.render(scene, camera);
    };
    
    
    render();
    

    【讨论】:

    • 所以基本上这段代码所做的只是在 clickevent 中渲染更新的纹理?SVG 大小是否影响 UV 映射或成比例?我的意思是,一个 800x800 的 svg 纹理将在与 300x300 相同的 UV 空间?
    • @robertgarcia 是的。因此,在您的情况下,您有一个产品配置器来更改 3d 模型上的图形。在这种情况下,如果 SVG 通过单独的 UI 更新,例如通过 svg-edit 启用,您可以触发代码将 svg 重绘为编码的 uri,并将其设置为材质的新纹理。
    • 好吧,关键是根本不改变图形,只是我加载了一个 3D 模型,你可以在不同的设计(SVG 中的纹理)之间进行选择,一旦你有了你想要的,你就可以改变纹理的 SVG 属性与您的示例,颜色选择器界面,所以你的伎俩,谢谢!
    • 我并不是要批评您的方法,因为我不了解您的项目限制。但是,您所描述的似乎可以使用 SVG 图像的 PNG 版本来完成。将 SVG 与 Three.js 一起使用需要额外的密集步骤,以在用户的​​ CPU 上使用 JS 将图像转换为光栅,并且使用相当多的内存。除非您有使用 SVG 的特定原因,否则请使用 illustrator 等将 SVG 图像转换为 PNG,并将 PNG 图像提供给用户。更好的是 DDS,它是 GPU 原生的,它使 ram 的使用保持在 webGL 中 SVG、PNG 和 JPG ram 分配的一小部分。
    • 使用 PNG 的要点是您只能使用确定的颜色,但我使用的是 svg,因为您可以使用任何 HEX 颜色更改填充属性 也许我解释得很糟糕,假设我有一个 3D带有蓝色线条的衬衫,衬衫的背景颜色是绿色,使用 SVG 我可以将背景颜色和线条颜色动态更改为我想要的任何颜色,比如说#FFFFFF,使用 PNG 我可以存储可能 5 种不同的纹理它们各自的颜色,因此颜色变量限制为 5 当然我不认为您的评论是批评家,非常欢迎
    猜你喜欢
    • 1970-01-01
    • 2017-10-30
    • 2013-02-08
    • 2015-09-01
    • 1970-01-01
    • 2016-03-06
    • 2017-12-31
    • 1970-01-01
    相关资源
    最近更新 更多