5

我试图通过使用 Three.js 挤出形状来为 SVG 路径(lineto 和 moveto)赋予 3D 感觉,但该过程会导致一些我无法删除的伪影。

什么会导致我渲染的 3D 形状出现奇怪的伪影?有没有办法删除它们?

在下面的示例图像中,工件用箭头标记。

在此处输入图像描述

现场示例在这里:http: //jsfiddle.net/pHn2B/24/

代码在这里:

// 使用回调挑选

// 三.js r.52
var 容器,
    信息,
    相机,
    场景,
    光,
    几何学,
    网,
    投影仪,
    渲染器,
    控制;
    对象 = [];

// dom
容器 = document.createElement('div');
document.body.appendChild( 容器 );

// 信息
info = document.createElement('div');
info.style.position = '绝对';
info.style.top = '10px';
info.style.width = '100%';
info.style.textAlign = '中心';
info.innerHTML = "拖动旋转相机;点击选择";
容器.appendChild(信息);

// 渲染器
渲染器 = 新的 THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);

// 场景
场景 = 新的三个场景();

// 相机
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.set(0, 300, 500);
场景。添加(相机);

// 控件
控制=新的三个。轨道控制(相机);

// 光
场景.add(新的三个环境光(0x222222));

// 光
灯 = 新的三点灯(0xaaaaaa);
light.position = camera.position;
场景.添加(灯光);

// 几何学
几何=新的三立方几何(100、100、500);

// 材料
材料=新三。MeshLambertMaterial({颜色:0xff0000,环境:0xff0000,过度绘制:真});

// 网
网格=新的三。网格(几何,材料);
网格.position.set(-100, -100, 200);
mesh.name = "红色对象";
mesh.callback = function() { info.innerHTML = this.name; }
场景.add(网格);

对象.push(网格);

// 几何学
////////////
    // 风俗 //
    ////////////

var starPoints2 = new THREE.Shape();

starPoints2.moveTo(307.94,275.49);
starPoints2.lineTo(296.26,275.23);
starPoints2.lineTo(286.64,272.99);
starPoints2.lineTo(279.78,269.31);
starPoints2.lineTo(274.14,263.55);
starPoints2.lineTo(271.65,260.21);
starPoints2.lineTo(269.2,261.06);
starPoints2.lineTo(254.83,268.51);
starPoints2.lineTo(242.11,272.97);
starPoints2.lineTo(227.59,275.23);
starPoints2.lineTo(209.91,275.48);
starPoints2.lineTo(197.47,273.63);
starPoints2.lineTo(187.91,270.13);
starPoints2.lineTo(180.48,265.09);
starPoints2.lineTo(175.32,258.88);
starPoints2.lineTo(172.2,251.44);
starPoints2.lineTo(171.1,242.23);
starPoints2.lineTo(172.24,233.63);
starPoints2.lineTo(175.49,226.24);
starPoints2.lineTo(181,219.54);
starPoints2.lineTo(189.42,213.3);
starPoints2.lineTo(201.36,207.73);
starPoints2.lineTo(217.23,203.25);
starPoints2.lineTo(238.28,200.1);
starPoints2.lineTo(269.37,198.47);
starPoints2.lineTo(269.98,182.93);
starPoints2.lineTo(268.74,171.32);
starPoints2.lineTo(266.05,163.7);
starPoints2.lineTo(261.58,157.72);
starPoints2.lineTo(255.24,153.24);
starPoints2.lineTo(247.06,150.32);
starPoints2.lineTo(235.44,149.13);
starPoints2.lineTo(224.71,150.05);
starPoints2.lineTo(215.91,153);
starPoints2.lineTo(210.23,156.86);
starPoints2.lineTo(207.64,160.85);
starPoints2.lineTo(207.19,165.28);
starPoints2.lineTo(209.34,169.86);
starPoints2.lineTo(212.01,174.15);
starPoints2.lineTo(212.14,177.99);
starPoints2.lineTo(209.8,181.78);
starPoints2.lineTo(204.22,185.79);
starPoints2.lineTo(197.62,187.68);
starPoints2.lineTo(188.65,187.43);
starPoints2.lineTo(182.41,185.39);
starPoints2.lineTo(178.45,181.77);
starPoints2.lineTo(176.2,176.9);
starPoints2.lineTo(176.03,170.64);
starPoints2.lineTo(178.2,164.13);
starPoints2.lineTo(183.09,157.69);
starPoints2.lineTo(191.04,151.36);
starPoints2.lineTo(202.01,145.82);
starPoints2.lineTo(216.09,141.57);
starPoints2.lineTo(232.08,139.24);
starPoints2.lineTo(250.07,139.18);
starPoints2.lineTo(266.13,141.23);
starPoints2.lineTo(279.05,145.06);
starPoints2.lineTo(289.15,150.3);
starPoints2.lineTo(295.91,156.19);
starPoints2.lineTo(300.73,163.41);
starPoints2.lineTo(303.85,172.47);
starPoints2.lineTo(305.07,183.78);
starPoints2.lineTo(305.07,241.97);
starPoints2.lineTo(306,251.51);
starPoints2.lineTo(308.18,256.39);
starPoints2.lineTo(311.72,259.09);
starPoints2.lineTo(317.31,260.01);
starPoints2.lineTo(324.71,259.01);
starPoints2.lineTo(332.45,255.86);
starPoints2.lineTo(335.57,257.53);
starPoints2.lineTo(337.6,260.44);
starPoints2.lineTo(336.94,262.33);
starPoints2.lineTo(328.27,268.74);
starPoints2.lineTo(317.89,273.41);
starPoints2.lineTo(307.94,275.49);
/*
starPoints2.moveTo(245.79,125.33);
starPoints2.lineTo(232.93,124.53);
starPoints2.lineTo(222.21,121.74);
starPoints2.lineTo(213.14,117.11);
starPoints2.lineTo(207.36,111.92);
starPoints2.lineTo(203.7,105.75);
starPoints2.lineTo(201.94,98.18);
starPoints2.lineTo(202.34,90.12);
starPoints2.lineTo(204.86,83.4);
starPoints2.lineTo(210.01,76.81);
starPoints2.lineTo(217.49,71.33);
starPoints2.lineTo(227.17,67.31);
starPoints2.lineTo(238.35,65.2);
starPoints2.lineTo(243.99,64.95);
starPoints2.lineTo(255.92,66.06);
starPoints2.lineTo(266.21,69.28);
starPoints2.lineTo(274.98,74.44);
starPoints2.lineTo(280.64,80.19);
starPoints2.lineTo(284.02,86.85);
starPoints2.lineTo(285.26,94.52);
starPoints2.lineTo(284.27,102.84);
starPoints2.lineTo(281.24,109.66);
starPoints2.lineTo(276.03,115.43);
starPoints2.lineTo(267.89,120.46);
starPoints2.lineTo(257.68,123.93);
starPoints2.lineTo(245.79,125.33);
*/
var smileyEye1Path = new THREE.Path();

笑脸1Path.moveTo(221.69,258.13);
笑脸1Path.lineTo(215.2,255.08);
笑脸1Path.lineTo(210.86,250.57);
笑脸1Path.lineTo(208.4,244.49);
笑脸1Path.lineTo(207.92,237.03);
笑脸1Path.lineTo(209.69,230.71);
笑脸1Path.lineTo(213.82,224.85);
笑脸1Path.lineTo(220.9,219.34);
笑脸1Path.lineTo(230.95,214.67);
笑脸1Path.lineTo(245.76,210.86);
笑脸1Path.lineTo(266.59,208.36);
笑脸1Path.lineTo(269.48,208.76);
笑脸1Path.lineTo(269.99,212.88);
笑脸1Path.lineTo(269.99,244.81);
笑脸1Path.lineTo(269.34,247.02);
笑脸1Path.lineTo(266.07,250.04);
笑脸1Path.lineTo(255.27,255.23);
笑脸1Path.lineTo(242.52,258.58);
笑脸1Path.lineTo(230.57,259.43);
笑脸1Path.lineTo(221.69,258.13);

/*
笑脸1Path.moveTo(238.44,116.65);
笑脸1Path.lineTo(231.99,114.29);
笑脸1Path.lineTo(227.23,110.22);
笑脸1Path.lineTo(223.94,104.53);
笑脸1Path.lineTo(222.41,96.92);
笑脸1Path.lineTo(223.05,88.57);
笑脸1Path.lineTo(225.65,82.21);
笑脸1Path.lineTo(230.07,77.36);
笑脸1Path.lineTo(235.93,74.4);
笑脸1Path.lineTo(243.68,73.34);
笑脸1Path.lineTo(246.08,73.43);
笑脸1Path.lineTo(253.37,75.08);
笑脸1Path.lineTo(258.65,78.43);
笑脸1Path.lineTo(262.47,83.41);
笑脸1Path.lineTo(264.59,90.25);
笑脸1Path.lineTo(264.64,98.93);
笑脸1Path.lineTo(262.63,106.12);
笑脸1Path.lineTo(258.87,111.5);
笑脸1Path.lineTo(253.73,115.1);
笑脸1Path.lineTo(246.81,116.94);
笑脸1Path.lineTo(238.44,116.65);
*/
var starShape = starPoints2;

starShape.holes.push(smileyEye1Path);

    变种挤压设置 = {
        //大小:1,高度:1,曲线段:100,步长= 10,
        // 字体,粗细,样式,
        数量:20,
        bevelEnabled:真,
        斜面厚度:0.5,
        斜角尺寸:0.5,
        bevelSegments: 8,
        // 拉伸路径:
        //弯曲路径:
        材料:0,
        挤出材料:1
        //,
        //uvGenerator: BoundingUVGenerator
       //uvGenerator: THREE.ExtrudeGeometry.WorldUVGenerator
    };

    var starGeometry = new THREE.ExtrudeGeometry(starShape,extrusionSettings);

    var materialFront = new THREE.MeshLambertMaterial({颜色:0xffff00,环境:0xffff00,过度绘制:false,透明:false,不透明度:1.0,侧面:THREE.DoubleSide});
    var materialSide = new THREE.MeshLambertMaterial({颜色:0xff8800,环境:0xff8800,过度绘制:false,透明:false,不透明度:1.0,侧面:THREE.DoubleSide});

//var crateTexture = new THREE.ImageUtils.loadTexture('http://www.kahkonen.com/asiakkaat/crate2.gif');
//var crateTexture = new THREE.ImageUtils.generateDataTexture(10,10,{r:255,g:0,b:0});

//var materialFront = new THREE.MeshBasicMaterial( { map: crateTexture } );

var materialArray = [ materialFront, materialSide ];
var materialArray = [ materialFront, materialSide ];

var starMaterial = new THREE.MeshFaceMaterial(materialArray);

    var star = new THREE.Mesh(starGeometry, starMaterial);

    star.position.set(-150,-150,0);
    场景.add(star);
/*  
    // 为模型添加线框
    var wireframeTexture = new THREE.MeshBasicMaterial({颜色:0x000000,线框:真,透明:假});
    var star = new THREE.Mesh(starGeometry,wireframeTexture);
    星.position.set(50,10,0);
    场景.add(star);
*/
对象.push(明星);

// 投影仪
投影仪=新三。投影仪();

// 监听器
document.addEventListener('mousedown', onDocumentMouseDown, false)

// 键盘处理程序
函数 onDocumentMouseDown( 事件 ) {

    event.preventDefault();

    var 向量 = 新的 THREE.Vector3(
        ( event.clientX / window.innerWidth ) * 2 - 1,
        - ( event.clientY / window.innerHeight ) * 2 + 1,
        0.5);

    投影仪.unprojectVector(矢量,相机);

    var ray = new THREE.Ray(camera.position, vector.subSelf(camera.position).normalize());

    var intersects = ray.intersectObjects( 对象 );    

    if ( intersects.length > 0 ) {

        相交[0].object.callback();

    }

}

// 使成为
函数渲染(){

    控制.更新()

    renderer.render(场景,相机);
}

// 动画            
(函数动画(){

    requestAnimationFrame( 动画 );
    使成为();
}());

我试图通过附加纹理来去除伪影,但根本没有显示纹理:

在此处输入图像描述

其他问题(可能与工件问题相关或不相关)是可以通过边缘看到背景。

纹理不是必须的,但去除伪影是必须的。

我用来添加纹理的代码如下,小提琴中的完整代码(链接在代码之后):

var crateTexture = new THREE.ImageUtils.loadTexture( 'http://www.kahkonen.com/asiakkaat/crate.gif'); var crateTexture = new THREE.ImageUtils.generateDataTexture(10,10,{r:255,g:0,b:0}); var materialFront = new THREE.MeshBasicMaterial( { map: crateTexture } );

// http://jsfiddle.net/pHn2B/27/

示例图像来自 Chrome。同样的行为也发生在 Firefox 中。

4

3 回答 3

3

CanvasRenderer这是由 z 缓冲问题引起的已知限制。您的几何形状具有许多细长的面,这使情况变得更糟。模型使用 正确渲染WebGLRenderer

ExtrudeGeometry最初是为文本编写的,如果您查看它生成的 UV,它只使用 UV 的顶点位置的 x 和 y 分量,在您的情况下,产生超出范围 [ 0, 1 ] 的值. 您可以选择在回调函数中提供自己的 UV 生成器。

确保您可以先成功地将纹理添加到立方体。

三.js r.58

于 2013-04-19T15:32:16.923 回答
2

仅供参考。@Westlangley 的回答让我找到了正确的方向来获得形状上的纹理。关键是将值从一个范围缩放到另一个范围,从世界坐标到形状内部 UV 范围,该范围必须为 0-1。

所以我复制了 THREE.ExtrudeGeometry.WorldUVGenerator 并将其重命名为 THREE.ExtrudeGeometry.BoundingBoxUVGenerator 并在成员函数 generateTopUV() 中替换了这些行:

        返回 [
            新的 THREE.Vector2(ax, ay),
            新的 THREE.Vector2(bx, by ),
            新的 THREE.Vector2(cx, cy)
        ];

用这些:

    var bb = extrudedShape.getBoundingBox();
    var bb_minX = bb.minX;
    var bb_minY = bb.minY;
    var bb_width = bb.maxX - bb_minX;
    var bb_height = bb.maxY - bb_minY;
        如果 (bb_width == 0) bb_width = 1;
        如果 (bb_height == 0) bb_height = 1;
        返回 [新的 THREE.Vector2( (ax - bb_minX) / bb_width, (ay - bb_minY) / bb_height ),
            新的 THREE.Vector2( (bx - bb_minX) / bb_width, (by - bb_minY) / bb_height ),
            新的 THREE.Vector2( (cx - bb_minX) / bb_width, (cy - bb_minY) / bb_height )
        ];

并且纹理“神奇地”出现在正确的位置!

(对于从https://github.com/mrdoob/three.js/issues/1811尝试过类似命名函数的人。它不起作用,因为范围转换是以某种奇怪的方式进行的。)

这也适用于顶点坐标确实在 0-1 范围内的情况,以及坐标为负数的情况。如果由于某种原因宽度和高度为 0,则返回 0。

对于大多数可能的目的,这比默认的 THREE.ExtrudeGeometry.WorldUVGenerator 有用得多。我什至无法想象默认生成器的任何用途,因为它仅适用于坐标在 0-1 范围内的顶点。但我是three.js 的新手,可能有一些我还无法想象的原因。

于 2013-04-20T04:11:26.773 回答
1

我以前也有同样的问题。
我还替换了成员函数 generateSideWallUV()
这些行:

if ( Math.abs( ay - by ) < 0.01 ) {
            return [
                new THREE.Vector2( ax, 1 - az ),
                new THREE.Vector2( bx, 1 - bz ),
                new THREE.Vector2( cx, 1 - cz ),
                new THREE.Vector2( dx, 1 - dz )
            ];
} else {
            return [
                new THREE.Vector2( ay, 1 - az ),
                new THREE.Vector2( by, 1 - bz ),
                new THREE.Vector2( cy, 1 - cz ),
                new THREE.Vector2( dy, 1 - dz )
            ];
        }

这些行:

var amount = extrudeOptions.amount;
if ( Math.abs( ay - by ) < 0.01 ) {
            return [
                new THREE.Vector2( (ax - bb_minX) / bb_width, 1-(az / amount) ),
                new THREE.Vector2( (bx - bb_minX) / bb_width, 1-(bz  / amount) ),
                new THREE.Vector2( (cx - bb_minX) / bb_width, 1-(cz  / amount) ),
                new THREE.Vector2( (dx - bb_minX) / bb_width, 1- (dz  / amount) )
            ];
        } else {
            return [
                new THREE.Vector2( (ay - bb_minY) / bb_height, 1-(az / amount )),
                new THREE.Vector2( (by - bb_minY) / bb_height, 1-(bz / amount )),
                new THREE.Vector2( (cy - bb_minY) / bb_height, 1-(cz / amount )),
                new THREE.Vector2( (dy - bb_minY) / bb_height, 1-(dz / amount ))
            ];
        }`
于 2013-11-01T16:25:50.910 回答