圆半径相交(像一个圆形光标刷)-三个js

Circular radius intersection (like a circular cursor brush) - Three js

本文关键字:光标 js 三个 一个      更新时间:2023-09-26

我希望能够在圆形光标的半径内捕捉对象的面(如在绘画/photoshop中)。

我会告诉你它是什么https://jsfiddle.net/Shaggisu/w7ufmutr/9/

我不仅希望能够选择与鼠标点相交的单个面,而且希望能够选择可能在圆形半径内的所有面,我试图为该光标上传一些图像,但无法真正使其与jsfiddle中的外部文件一起工作。

我的问题是,是否有一些标准的方法来实现在指定半径内的多次选择/交叉,或者我是否应该设计一些代码,例如在特定时刻在鼠标点周围的周围面重复。

我对three.js还很陌生,所以我想问一些指导,特别是如果有一些可靠的方法来实现,任何提示都会很有帮助。

    var brushTexture = THREE.ImageUtils.loadTexture( '/cur_circle.png' );
var brushMaterial = new THREE.SpriteMaterial( { map: brushTexture, useScreenCoordinates: true, alignment: THREE.SpriteAlignment.center } );

  brushSprite = new THREE.Sprite( brushMaterial );
  brushSprite.scale.set( 32, 32, 1.0 );
  brushSprite.position.set( 50, 50, 0 );
  scene.add( brushSprite );
  //////////////////////////////////////////////////////////////////////
    // initialize object to perform world/screen calculations
    projector = new THREE.Projector();
    // when the mouse moves, call the given function
    document.addEventListener( 'mousedown', onDocumentMouseDown, false );
}
function onDocumentMouseDown( event ) 
{
    // the following line would stop any other event handler from firing
    // (such as the mouse's TrackballControls)
    event.preventDefault();
    console.log("Click.");

    // update the mouse variable
    mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
    // find intersections
    // create a Ray with origin at the mouse position
    //   and direction into the scene (camera direction)
    var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
    projector.unprojectVector( vector, camera );
    var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
    // create an array containing all objects in the scene with which the ray intersects
    var intersects = ray.intersectObjects( targetList );
    // if there is one (or more) intersections
    if ( intersects.length > 0 )
    {
  controls.enabled = false;  // stops camera rotation
        console.log("Hit @ " + toString( intersects[0].point ) );
        // change the color of the closest face.
        intersects[ 0 ].face.color.setRGB( 0.8 * Math.random() + 0.2, 0, 0 ); 
        intersects[ 0 ].object.geometry.colorsNeedUpdate = true;
    document.addEventListener( 'mousemove', onDocumentMouseMove, false );
    }
}
function onDocumentMouseMove( event){
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
brushSprite.position.set( event.clientX, event.clientY, 0);
// find intersections
    // create a Ray with origin at the mouse position
    //   and direction into the scene (camera direction)
    var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
    projector.unprojectVector( vector, camera );
    var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
    // create an array containing all objects in the scene with which the ray intersects
    var intersects = ray.intersectObjects( targetList );
    // if there is one (or more) intersections
    if ( intersects.length > 0 )
    {
        console.log("Hit @ " + toString( intersects[0].point ) );
        // change the color of the closest face.
        intersects[ 0 ].face.color.setRGB( 0.8 * Math.random() + 0.2, 0, 0 ); 
        intersects[ 0 ].object.geometry.colorsNeedUpdate = true;
    }
document.addEventListener( 'mouseup', onDocumentMouseUp, false );
}
function onDocumentMouseUp( event){
event.preventDefault();
document.removeEventListener( "mousemove", onDocumentMouseMove);
controls.enabled = true;
}

该代码是我用于实践的stemkoskis github的修改版本。我已经对它进行了一些扩展,用于交叉事件和连续选择的相机管理,但半径内多个面的选择是我现在最感兴趣的。

你可以在javascript中这样做,修改顶点颜色,就像你在示例中做的那样,但你会很快受到多边形数量的限制。

也就是说,把你的画笔想象成一个锥体,从光线开始。原点和射线方向延伸。笔刷的半径决定了圆锥体的半径

  • 遍历每个顶点。
  • 对于每一个,得到顶点到射线线之间的最小距离。
  • 根据这个顶点和Ray.origin之间的距离获得画笔/圆锥体的半径
  • 如果最小距离小于圆锥体半径,则顶点处于"内"状态。你也可以处理距离来创建一个平滑的画笔。

应该是这样的,有点像伪代码,你可能需要适应ThreeJs的数学库:

// Important, Ray origin and direction must be defined in the same space a vertices positions
// You may need to transform ray origin and direction in object local space.

// get the length of Ray.direction
// may be useless if 'direction' is normalized
var rayDirLenSq = ray.direction.length();
rayDirLenSq *= rayDirLenSq;
var brushRadius = 10.0;

for( var i=0;i< vertices.length;i++){
  // get the vertex
  var v = vertices[i];
  var vdir = v.sub( ray.origin );
  var dot = vdir.dot( ray.direction ) / rayDirLenSq;
  if( dot < 0 ){
    // handle vertices behind the camera if needed
  }
  // v2 : projection of the vertex onto ray line
  var v2 = ray.direction.clone().multiplyScalar( dot );
  // v3 : projection -> vertex
  var v3 = vdir.subtract( v2 )
  // dist is the distance between the vertex and the ray line
  var dist = v3.length()
  // 0 when vertex is at the brush border
  // 1 when vertex is in the brush center
  var paintingFactor = Math.max(0.0, 1.0 - dist/brushRadius )

}

根据你想要的,你可以存储每个顶点的绘画因子来获得每个面的平均因子。或者你可以独立修改每个顶点的顶点颜色,以在你的脸上获得渐变…

我没有测试代码,它可能包含一些错误:)

更高级的方法

你也可以使用纹理来绘制。你将摆脱顶点(和javascript)的限制。你将能够用纹理刷绘制,并在三角形内绘制细节(没有更多的顶点颜色)。

原则:你需要uv数据和纹理+ FBO为你的每个网格。

在预传中,对于每个网格,将其渲染到其uvs坐标中的Fbo

gl_Position = vec4( UVs*2.0-1.0, 0.0, 1.0 );

为片段着色器提供worldSpace顶点位置,这样您就可以访问对象纹理的每个像素的世界空间位置。

vVertexPosition = modelMatrix * aPosition;
在你的片段着色器中使用vVertexPosition,你可以使用与javascript相同的方法来获得每个像素的brushFactor。你甚至可以在基于光线的自定义投影矩阵中投影这个世界空间像素位置,以获得画笔纹理中像素的uv坐标,并使用纹理刷进行绘制。