如何使用three.js在运行时绘制一条线段

4

我是 Three.js 的新手,正在尝试实现 Microsoft Paint 中用于绘制线段的技术。我想在 onMouseDown 时获取一个点的坐标,然后在 onMouseMove 时延伸一条直线,直到 onMouseDown。请帮忙!

1个回答

8

three.js主要用于绘制3D图形。如果你想复制像画图这样的2D应用程序,那么使用2D画布可能会更容易:canvas.getContext("2d");

我假设你确实想在three.js中进行绘制。在这种情况下,我已经准备了这个示例。请按照以下步骤操作:

  1. 单击页面上的任何位置并拖动鼠标以绘制一条线。该线条在z平面上绘制。
  2. 单击Shapes按钮,注意一个形状更靠近和另一个更远,因为其中一个在z平面上方,另一个在后面。
  3. 单击Rotate按钮,这将导致相机缩小并在轴周围旋转。请注意,当您穿过z平面时,所有绘图都在该平面上。

查看代码,主要部分是:

您需要将鼠标点击坐标投影到平面上。可以使用以下函数完成:

function get3dPointZAxis(event)
{
    var vector = new THREE.Vector3(
                ( event.clientX / window.innerWidth ) * 2 - 1,
                - ( event.clientY / window.innerHeight ) * 2 + 1,
                0.5 );
    projector.unprojectVector( vector, camera );
    var dir = vector.sub( camera.position ).normalize();
    var distance = - camera.position.z / dir.z;
    var pos = camera.position.clone().add( dir.multiplyScalar( distance ) );    
    return pos;
}

然后从之前的点画一条线到这个点:
geometry.vertices.push(lastPoint);
geometry.vertices.push(pos);
var line = new THREE.Line(geometry, material);
scene.add(line);

请注意,当你旋转接近通过z平面时,对于Z轴的投影会很偏离,导致越界。为了防止这种情况发生,进行以下检查:
if( Math.abs(lastPoint.x - pos.x) < 500 && Math.abs(lastPoint.y - pos.y) < 500 && Math.abs(lastPoint.z - pos.z) < 500 )

供参考,我在这里(SO答案)和这里(three.js示例)找到了关于投影鼠标坐标的信息。

更新

要从mousedown位置绘制到mouseup位置,请参见此演示。 代码更改是改为仅在鼠标抬起时在点之间进行绘制。

function stopDraw(event)
{
     if( lastPoint )
    {
        var pos = get3dPointZAxis(event);
        var material = new THREE.LineBasicMaterial({
            color: 0x0000ff
        });
        var geometry = new THREE.Geometry();
        if( Math.abs(lastPoint.x - pos.x) < 2000 && Math.abs(lastPoint.y - pos.y) < 2000 && Math.abs(lastPoint.z - pos.z) < 2000 )
        {
            geometry.vertices.push(lastPoint);
            geometry.vertices.push(pos);

            var line = new THREE.Line(geometry, material);
            scene.add(line);
            lastPoint = pos;        
        }
        else
        {
            console.debug(lastPoint.x.toString() + ':' + lastPoint.y.toString() + ':' + lastPoint.z.toString()  + ':' + 
                        pos.x.toString() + ':' + pos.y.toString()  + ':' + pos.z.toString());
        }
    }
}      

非常感谢!这个例子给了我很多想法。我想要画一条直线。这个例子呈现了在Paint中使用笔/铅笔的效果,而不是画线。您能告诉我如何修改上面的代码以实现从鼠标按下到鼠标松开事件绘制一条直线吗?提前感谢您。 - user3359133
好的!现在我明白了。非常感谢!仍有一个疑问,就是如何在 x-y 平面上实现此代码?我知道这很简单,但我无法得到结果 :( - user3359133
@user3359133 这条线将被画在z=0的平面上,即xy平面。如果你想知道如何只用2D来做到这一点,那么你应该使用HTML 5 Canvas而不是three.js。然后您将使用canvas.getContext("2d");LineTo。请参阅http://www.html5canvastutorials.com/tutorials/html5-canvas-lines/ 和 http://www.html5canvastutorials.com/tutorials/html5-canvas-line-caps/ 和 http://www.tutorialspoint.com/html5/canvas_drawing_lines.htm。 - acarlon
你是如何选择2000这个值的?在这段代码中:- if( Math.abs(lastPoint.x - pos.x) < 2000 && Math.abs(lastPoint.y - pos.y) < 2000 && Math.abs(lastPoint.z - pos.z) < 2000 ) - user3359133

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接