Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 三.曲线路径和自定义标记_Javascript_Three.js - Fatal编程技术网

Javascript 三.曲线路径和自定义标记

Javascript 三.曲线路径和自定义标记,javascript,three.js,Javascript,Three.js,我正在使用Three.JS创建一个游戏,我已经建模并成功导入了在Sketchup中创建的城市。我现在需要动态添加一些“跟随我”箭头(根据下面模型中的黄色箭头)。我相信我可能需要使用Three.CurvePath来实现这一点,但我不确定这是否是最好的方法-我是否需要手动建模路径并计算每个箭头对象的切线,以便它们自然指向拐角(根据模型中的左转) 希望这有意义 我可能有个解决办法。 有一段时间没有使用three.js了,所以不确定这是否是最优雅的解决方案。 我从以下内容开始: 如何按程序构建路径(使

我正在使用Three.JS创建一个游戏,我已经建模并成功导入了在Sketchup中创建的城市。我现在需要动态添加一些“跟随我”箭头(根据下面模型中的黄色箭头)。我相信我可能需要使用Three.CurvePath来实现这一点,但我不确定这是否是最好的方法-我是否需要手动建模路径并计算每个箭头对象的切线,以便它们自然指向拐角(根据模型中的左转)

希望这有意义

我可能有个解决办法。 有一段时间没有使用three.js了,所以不确定这是否是最优雅的解决方案。 我从以下内容开始:

  • 如何按程序构建路径(使用同时处理曲线的命令)
  • 如何从这样的路径中提取点
  • 因此,我将问题分为:

  • 生成路径
  • 遍历路径和插值(位置和旋转)
  • 生成路径 我重复使用了圆角矩形定义,它看起来类似于屏幕截图的一部分

    var roundedRectShape = new THREE.Shape();
    
                    ( function roundedRect( ctx, x, y, width, height, radius ){
    
                        ctx.moveTo( x, y + radius );
                        ctx.lineTo( x, y + height - radius );
                        ctx.quadraticCurveTo( x, y + height, x + radius, y + height );
                        ctx.lineTo( x + width - radius, y + height) ;
                        ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius );
                        ctx.lineTo( x + width, y + radius );
                        ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
                        ctx.lineTo( x + radius, y );
                        ctx.quadraticCurveTo( x, y, x, y + radius );
    
                    } )( roundedRectShape, 0, 0, 200, 200, 20 );
    
    您的路径可能不是圆角矩形,但可用的曲线函数类型(quadraticCurveTo、bezierrcurveto、splineThru)非常有用

    我想到的另一个想法是使用Ruby脚本将路径坐标从Sketchup导出到three.js。要么从头开始编写,要么使用现有脚本。这是 很容易在谷歌上找到

    遍历路径

    幸运的是,three.js已经通过路径的
    getPoint(t)
    实现了这一点,其中t是一个从0.0到1.0的数字,表示路径上的遍历。因此,获取位置与获取路径上的下一个插值位置一样简单。然后只需使用
    Math.atan2()
    获得旋转:

    t = (t + s)%1.0;//increment t while maintaining it between 0.0 and 1.0
                    var p = path.getPoint(t);//point at t
                    var pn = path.getPoint((t+s)%1.0);//point at next t iteration
    
                    if(p != null && pn != null){
                        //move to current position
                        arrow.position.x = p.x;
                        arrow.position.y = p.y;
                        //get orientation based on next position
                        arrow.rotation.z = Math.atan2(pn.y-p.y,pn.x-p.x);
    
                    }
    
    总之,bellow是一个基本示例(使用立方体而不是箭头形状),用于说明基于形状示例在three.js中生成和遍历路径:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>path interpolation</title>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
            <style>
                body {
                    font-family: Monospace;
                    background-color: #f0f0f0;
                    margin: 0px;
                    overflow: hidden;
                }
            </style>
        </head>
        <body>
            <canvas id="debug" style="position:absolute; left:100px"></canvas>
    
            <script src="../build/three.min.js"></script>
    
            <script src="js/libs/stats.min.js"></script>
    
    
            <script>
    
                var container, stats;
    
                var camera, scene, renderer;
    
                var text, plane;
    
                var targetRotation = 0;
                var targetRotationOnMouseDown = 0;
    
                var mouseX = 0;
                var mouseXOnMouseDown = 0;
    
                var windowHalfX = window.innerWidth / 2;
                var windowHalfY = window.innerHeight / 2;
    
                init();
                animate();
    
                var t = 0.0;//traversal on path
                var s = 0.001;//speed of traversal
                var arrow;//mesh to move/rotate on path
                var path;//Path object to traverse
    
                function init() {
    
                    container = document.createElement( 'div' );
                    document.body.appendChild( container );
    
                    camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
                    camera.position.set( 0, 150, 500 );
    
                    scene = new THREE.Scene();
    
                    parent = new THREE.Object3D();
                    parent.position.y = 50;
                    scene.add( parent );
    
                    arrow = new THREE.Mesh( new THREE.CubeGeometry(20,10,10),new THREE.MeshBasicMaterial({color: 0x009900}));
                    parent.add(arrow);
                    //this is helpful as a visual aid but not crucial
                    function addShape( shape, extrudeSettings, color, x, y, z, rx, ry, rz, s ) {
    
                        var points = shape.createPointsGeometry();
                        var spacedPoints = shape.createSpacedPointsGeometry( 50 );
    
                        // transparent line from equidistance sampled points
    
                        var line = new THREE.Line( spacedPoints, new THREE.LineBasicMaterial( { color: color, opacity: 0.2 } ) );
                        line.rotation.set( rx, ry, rz );
                        parent.add( line );
    
                        // equidistance sampled points
    
                        var pgeo = spacedPoints.clone();
                        var particles2 = new THREE.ParticleSystem( pgeo, new THREE.ParticleBasicMaterial( { color: color, size: 2, opacity: 0.5 } ) );
                        particles2.rotation.set( rx, ry, rz );
                        parent.add( particles2 );
    
                    }
    
    
                    // Rounded rectangle
                    //generating the path and populating it is crucial tough
                    var roundedRectShape = new THREE.Shape();
    
                    ( function roundedRect( ctx, x, y, width, height, radius ){
    
                        ctx.moveTo( x, y + radius );
                        ctx.lineTo( x, y + height - radius );
                        ctx.quadraticCurveTo( x, y + height, x + radius, y + height );
                        ctx.lineTo( x + width - radius, y + height) ;
                        ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius );
                        ctx.lineTo( x + width, y + radius );
                        ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
                        ctx.lineTo( x + radius, y );
                        ctx.quadraticCurveTo( x, y, x, y + radius );
    
                    } )( roundedRectShape, 0, 0, 200, 200, 20 );
                    path = roundedRectShape;
    
                    var extrudeSettings = { amount: 20 }; // bevelSegments: 2, steps: 2 , bevelSegments: 5, bevelSize: 8, bevelThickness:5
                    extrudeSettings.bevelEnabled = true;
                    extrudeSettings.bevelSegments = 2;
                    extrudeSettings.steps = 2;
    
                    addShape( roundedRectShape, extrudeSettings, 0x000000, -150, 150, 0, 0, 0, 0, 1 );
    
                    renderer = new THREE.WebGLRenderer( { antialias: true } );
                    renderer.setSize( window.innerWidth, window.innerHeight );
    
                    container.appendChild( renderer.domElement );
    
                    stats = new Stats();
                    stats.domElement.style.position = 'absolute';
                    stats.domElement.style.top = '0px';
                    container.appendChild( stats.domElement );
    
                    document.addEventListener( 'mousedown', onDocumentMouseDown, false );
                    document.addEventListener( 'touchstart', onDocumentTouchStart, false );
                    document.addEventListener( 'touchmove', onDocumentTouchMove, false );
    
                    //
    
                    window.addEventListener( 'resize', onWindowResize, false );
    
                }
    
                function onWindowResize() {
    
                    windowHalfX = window.innerWidth / 2;
                    windowHalfY = window.innerHeight / 2;
    
                    camera.aspect = window.innerWidth / window.innerHeight;
                    camera.updateProjectionMatrix();
    
                    renderer.setSize( window.innerWidth, window.innerHeight );
    
                }
    
                //
    
                function onDocumentMouseDown( event ) {
    
                    event.preventDefault();
    
                    document.addEventListener( 'mousemove', onDocumentMouseMove, false );
                    document.addEventListener( 'mouseup', onDocumentMouseUp, false );
                    document.addEventListener( 'mouseout', onDocumentMouseOut, false );
    
                    mouseXOnMouseDown = event.clientX - windowHalfX;
                    targetRotationOnMouseDown = targetRotation;
    
                }
    
                function onDocumentMouseMove( event ) {
    
                    mouseX = event.clientX - windowHalfX;
    
                    targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;
    
                }
    
                function onDocumentMouseUp( event ) {
    
                    document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
                    document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
                    document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
    
                }
    
                function onDocumentMouseOut( event ) {
    
                    document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
                    document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
                    document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
    
                }
    
                function onDocumentTouchStart( event ) {
    
                    if ( event.touches.length == 1 ) {
    
                        event.preventDefault();
    
                        mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
                        targetRotationOnMouseDown = targetRotation;
    
                    }
    
                }
    
                function onDocumentTouchMove( event ) {
    
                    if ( event.touches.length == 1 ) {
    
                        event.preventDefault();
    
                        mouseX = event.touches[ 0 ].pageX - windowHalfX;
                        targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
    
                    }
    
                }
    
                //
    
                function animate() {
    
                    requestAnimationFrame( animate );
    
                    render();
                    stats.update();
    
                }
    
                function render() {
                    t = (t + s)%1.0;//increment t while maintaining it between 0.0 and 1.0
                    var p = path.getPoint(t);//point at t
                    var pn = path.getPoint((t+s)%1.0);//point at next t iteration
    
                    if(p != null && pn != null){
                        //move to current position
                        arrow.position.x = p.x;
                        arrow.position.y = p.y;
                        //get orientation based on next position
                        arrow.rotation.z = Math.atan2(pn.y-p.y,pn.x-p.x);
    
                    }
    
                    parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05;
                    renderer.render( scene, camera );
    
                }
    
            </script>
    
        </body>
    </html>
    

    回答得不错。我给了您一个向上投票,并将您的示例的一个版本放在JSFIDLE中,以便人们可以看到它运行。非常彻底的回答-谢谢。我可能忽略了一些东西,但当使用粒子系统时,有什么方法可以控制粒子的方向吗?我希望能够渲染为一系列围绕路径跟踪的箭头(很像模型中由箭头组成的路径)。无论哪种情况,都接受这个答案,因为它是一个很好的开端。@Sidebp没有太多地使用ParticleSystem,但我认为它可以是动态的(必须在某个地方有一个示例),因此您可以更新位置。感谢Crossphire Development的JSFIDLE,我创建了一个更新来说明如何在路径上移动多个对象(可以是自定义网格/粒子等):看一看。关于箭头形状,它们可以是
    形状
    实例,粒子可以是双板/精灵,或者因为所有东西都在一个平面内,所以所有东西都可以是在画布元素中按程序生成的2D纹理,也可以是精灵表。相关: