一个简单的threejs盒剖切功能

支持六面方向拖拽、反向、切面填充.

代码:

TypeScript 复制代码
import * as THREE from 'three'
import { MouseHandler } from 'src/renderers/input/mouse'
import {mergeGeometries} from 'three/examples/jsm/utils/BufferGeometryUtils'
import {BaseHandle} from './base'
import {HANDLE_TYPES} from '../constant'

const DEFAULT_EMPTY_ARRAY:any=[]
function createPlaneStencilGroup(geometry:THREE.BufferGeometry, plane:THREE.Plane, renderOrder:number) {

    const group = new THREE.Group();
    const baseMat = new THREE.MeshBasicMaterial();
    baseMat.color.setHex(0x0000ff)
    baseMat.depthWrite = false;
    baseMat.depthTest = false;
    baseMat.colorWrite = false;
    baseMat.stencilWrite = true;
    baseMat.stencilFunc = THREE.AlwaysStencilFunc;

    // back faces
    const mat0 = baseMat.clone();
    mat0.side = THREE.BackSide;
    mat0.clippingPlanes = [plane];
    mat0.stencilFail = THREE.IncrementWrapStencilOp;
    mat0.stencilZFail = THREE.IncrementWrapStencilOp;
    mat0.stencilZPass = THREE.IncrementWrapStencilOp;

    const mesh0 = new THREE.Mesh(geometry, mat0);
    mesh0.renderOrder = renderOrder;
    group.add(mesh0);

    // front faces
    const mat1 = baseMat.clone();
    mat1.side = THREE.FrontSide;
    mat1.clippingPlanes = [plane];
    mat1.stencilFail = THREE.DecrementWrapStencilOp;
    mat1.stencilZFail = THREE.DecrementWrapStencilOp;
    mat1.stencilZPass = THREE.DecrementWrapStencilOp;

    const mesh1 = new THREE.Mesh(geometry, mat1);
    mesh1.renderOrder = renderOrder;

    group.add(mesh1);

    return group;

}


class ClipFace extends THREE.Mesh{
    materialActive:THREE.MeshBasicMaterial
    materialInactive:THREE.MeshBasicMaterial
    lines:ClipLine[]=[]
    constructor(public vertices:{dirty:boolean,position:THREE.Vector3}[],public axes:string){
        super()
        this.materialInactive=new THREE.MeshBasicMaterial({
            colorWrite:false,
            depthWrite:false,
        })
        this.materialActive=new THREE.MeshBasicMaterial({
            color:0x00aaff,
            transparent:true,
            opacity:0.3
        })
        this.geometry=new THREE.BufferGeometry()
        this.geometry.setAttribute('position',new THREE.BufferAttribute(new Float32Array(4*3),3));
        this.geometry.setIndex(new THREE.BufferAttribute(new Uint16Array([2,1,0,3,2,0]),1));
        (this.geometry.attributes.position as THREE.Float32BufferAttribute).setUsage(THREE.DynamicDrawUsage);
        this.setActive(false)
        this.updateVertices(true)

    }
    updateVertices(forceUpdate=false){
        let needsUpdate=false
        this.vertices.forEach((p,i)=>{
            if((forceUpdate||p.dirty)){
                needsUpdate=true
                const v=p.position;
                this.geometry.attributes.position.setXYZ(i,v.x,v.y,v.z)
            } 
       
        })
        this.geometry.attributes.position.needsUpdate=needsUpdate
       
    }
    setActive(active:boolean){
        this.material=active?this.materialActive:this.materialInactive
        this.lines.forEach(line=>{
            line.setActive(active)
        })
    }
}

class ClipLine extends THREE.LineSegments{
    activeColor:number=0x00aaff
    defaultColor:number=0x88aaff
    constructor(public vertices:{dirty:boolean,position:THREE.Vector3}[]){
        super()
        this.material=new THREE.LineBasicMaterial({
            color:this.defaultColor
        })
        this.geometry=new THREE.BufferGeometry()
        this.geometry.setAttribute('position',new THREE.BufferAttribute(new Float32Array(2*3),3));
        (this.geometry.attributes.position as THREE.Float32BufferAttribute).setUsage(THREE.DynamicDrawUsage);
        this.updateVertices(true)
    }
    updateVertices(forceUpdate=false){
        let needsUpdate=false
        this.vertices.forEach((p,i)=>{
            if((forceUpdate||p.dirty)){
                needsUpdate=true
                const v=p.position;
                this.geometry.attributes.position.setXYZ(i,v.x,v.y,v.z)
            } 
       
        })
        this.geometry.attributes.position.needsUpdate=needsUpdate
       
    }
    setActive(active:boolean){
        (this.material as THREE.LineBasicMaterial).color.setHex(active?this.activeColor:this.defaultColor)
    }
}

interface ClipBoxOptions{
    cap?:boolean
    negative?:boolean
    renderer:THREE.WebGLRenderer
    scene:THREE.Scene
    camera:()=>THREE.Camera
    update:()=>void
    onDragRange?:()=>void
    onDragStart?:()=>void
    onDragEnd?:()=>void
}
enum ClipBoxState{
    NONE,// 未激活
    CLIP,// 显示剖切框
    CLIP_EFFECT, // 隐藏剖切框,显示剖切效果
    EXIT // 退出
}
class ClipBox{
    min=new THREE.Vector3()
    max=new THREE.Vector3()
    initMin=new THREE.Vector3()
    initMax=new THREE.Vector3()
    box3=new THREE.Box3()
    target?:THREE.Object3D
    group:THREE.Group=new THREE.Group()
    planes?:THREE.Plane[]
    planeObjects?:THREE.Mesh[]
    vertices?:{dirty:boolean,position:THREE.Vector3}[]
    lines?:ClipLine[]
    faces?:ClipFace[]
    boxGeometry!:THREE.BoxGeometry
    basicMaterial?:THREE.MeshBasicMaterial
    hoverMaterial?:THREE.MeshBasicMaterial
    _clipScene=new THREE.Group()
    mouseHandle!:MouseHandler
    state:ClipBoxState=ClipBoxState.NONE
    constructor(public options:ClipBoxOptions){
            this.options={
                cap:false,
                negative:false,
                ...this.options
            }
    }
    get clipScene(){
        return this._clipScene
    }
    get renderer(){
        return this.options.renderer
    }
    get camera(){
        return this.options.camera()
    }

    initClipBox(){
      
        this.clipScene.matrixWorldAutoUpdate=false;
        this.clipScene.matrixAutoUpdate=false
        this.clipScene.matrixWorldNeedsUpdate=false;
        this.box3.setFromObject(this.target!).expandByScalar(1.2)
        this.min.copy(this.box3.min)
        this.initMin.copy(this.box3.min)
        this.max.copy(this.box3.max)
        this.initMax.copy(this.box3.max)
        this.initPlanes()
        this.initVertices()
        this.initFaces()
        this.initLines()
        this.updatePlanes()
        this.initEvents()
        this.initCap()
        this.updateTargetClipPlanes()
        this.options.scene.add(this.clipScene)
      
    }
    // 还原
    reset(){
        this.min.copy(this.initMin)
        this.max.copy(this.initMax)
        this.update()
    }
    // 显示剖切框
    showClip(){
        if(this.state===ClipBoxState.CLIP){
            return
        }
        if(this.state===ClipBoxState.NONE){
            this.initClipBox()
        }else if(this.state===ClipBoxState.EXIT){
            this.updateTargetClipPlanes()
        }
        this.updateAllClipBox()
        this.renderer.localClippingEnabled=true;
        this.state=ClipBoxState.CLIP
        this.options.scene.add(this.clipScene)
        this.attachInteractive()
        this.update()
   
    }
    // 隐藏剖切框
    hideClip(){
        if(this.state===ClipBoxState.CLIP){
            this.state=ClipBoxState.CLIP_EFFECT
            this.options.scene.remove(this.clipScene)
            this.mouseHandle.detachEvents()
            this.update()
        }
    }
    attach(obj:THREE.Object3D){
        this.target=obj
    }
    update(){
        this.options.update()
    }
    detach(){
        this.target=undefined    
    }
    exit(){
        if(this.state===ClipBoxState.EXIT){
            return
        }
        this.min.copy(this.initMin)
        this.max.copy(this.initMax)
        this.renderer.localClippingEnabled=false
        this.state=ClipBoxState.EXIT
        this.options.scene.remove(this.clipScene)
        this.mouseHandle.detachEvents()
        this.resetTargetClipPlanes()
        this.target=undefined    
        this.update()

    }
    initEvents(){
        this.mouseHandle=new MouseHandler(this.renderer.domElement,document,()=>this.camera)
        const plane=new THREE.Plane()
        const cameraDirection=new THREE.Vector3()
        const startPoint=new THREE.Vector3()
        const deltaPoint=new THREE.Vector3()
        const intersectionPoint=new THREE.Vector3()
        this.mouseHandle.addEventListener('object-enter',e=>{
               (e.intersections[0].object as ClipFace).setActive(true)
               this.update()
        })
        this.mouseHandle.addEventListener('object-leave',e=>{
            (e.intersections[0].object as ClipFace).setActive(false)
            this.update()
        })

        this.mouseHandle.addEventListener('select',e=>{
            this.camera.getWorldDirection(cameraDirection)
            plane.setFromNormalAndCoplanarPoint(cameraDirection,e.target.selectedIntersections[0].point)
            if(this.mouseHandle.raycaster.ray.intersectPlane(plane,intersectionPoint)){
                startPoint.copy(intersectionPoint)
            }
            this.options.onDragStart?.()
            e.target.pointerEvent?.stopImmediatePropagation()
        })
        this.mouseHandle.addEventListener('object-drag',e=>{
            this.mouseHandle.updateRaycaster()
            if(this.mouseHandle.raycaster.ray.intersectPlane(plane,intersectionPoint)){
                const dragObject=e.target.selectedIntersections[0].object as ClipFace
                deltaPoint.copy(intersectionPoint).sub(startPoint)
                startPoint.copy(intersectionPoint)
                
                if(dragObject.axes==='x+'){
                    this.max.x=Math.min(this.initMax.x,Math.max(this.initMin.x,this.max.x+deltaPoint.x))
                } 
                if(dragObject.axes==='x-'){
                    this.min.x=Math.min(this.initMax.x,Math.max(this.initMin.x,this.min.x+deltaPoint.x))
                }
                if(dragObject.axes==='y+'){
                    this.max.y=Math.min(this.initMax.y,Math.max(this.initMin.y,this.max.y+deltaPoint.y))
                }
                if(dragObject.axes==='y-'){
                    this.min.y=Math.min(this.initMax.y,Math.max(this.initMin.y,this.min.y+deltaPoint.y))
                }
                if(dragObject.axes==='z+'){
                    this.max.z=Math.min(this.initMax.z,Math.max(this.initMin.z,this.max.z+deltaPoint.z))
                }
                if(dragObject.axes==='z-'){
                    this.min.z=Math.min(this.initMax.z,Math.max(this.initMin.z,this.min.z+deltaPoint.z))
                }
       
                this.updateClipBox(dragObject)
                this.options.onDragRange?.()
                this.update()
            }
        })
        this.mouseHandle.addEventListener('pointerup',e=>{
            this.options.onDragEnd?.()
        })
    }
    attachInteractive(){
        this.mouseHandle.hoverObjects=this.faces!.slice()
        this.mouseHandle.selectObjects=this.faces!.slice();
        this.mouseHandle.attachEvents()
    }
    initPlanes(){
        this.planes=[
            new THREE.Plane(new THREE.Vector3(1, 0, 0), 0),// 左
            new THREE.Plane(new THREE.Vector3(-1, 0, 0), 0), // 右
            new THREE.Plane(new THREE.Vector3(0, 1, 0), 0),// 下
            new THREE.Plane(new THREE.Vector3(0, -1, 0), 0),// 上
            new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), // 后
            new THREE.Plane(new THREE.Vector3(0, 0, -1), 0), // 前
        ]
      
    }
    initVertices(){
        this.vertices=[
            {dirty:false,position:new THREE.Vector3(this.min.x,this.min.y,this.min.z)},// left bottom
            {dirty:false,position: new THREE.Vector3(this.min.x,this.max.y,this.min.z)},// left top
            {dirty:false,position:new THREE.Vector3(this.max.x,this.max.y,this.min.z)}, // right top
            {dirty:false,position:new THREE.Vector3(this.max.x,this.min.y,this.min.z)}, // right bottom
            // positive
            {dirty:false,position:new THREE.Vector3(this.min.x,this.min.y,this.max.z)},// left bottom
            {dirty:false,position:new THREE.Vector3(this.min.x,this.max.y,this.max.z)},// left top
            {dirty:false,position:new THREE.Vector3(this.max.x,this.max.y,this.max.z)}, // right top
            {dirty:false,position:new THREE.Vector3(this.max.x,this.min.y,this.max.z)}, // right bottom
        ]
    }
    initFaces(){
        this.faces=[
            new ClipFace([7,6,2,3].map(i=>this.vertices![i]),'x+'),// x+
            new ClipFace([0,1,5,4].map(i=>this.vertices![i]),'x-'), // x-
            new ClipFace([5,1,2,6].map(i=>this.vertices![i]),'y+'),// y+
            new ClipFace([7,3,0,4].map(i=>this.vertices![i]),'y-'),// y-
            new ClipFace([3,2,1,0].map(i=>this.vertices![i]),'z-'), // z-
            new ClipFace([4,5,6,7].map(i=>this.vertices![i]),'z+'), // z+
        ]
        this.faces.forEach(face=>{
            this.clipScene.add(face)
        })
    }
    initLines(){

        this.lines=[
            new ClipLine([0,1].map(i=>this.vertices![i])),// positive left 0
            new ClipLine([1,2].map(i=>this.vertices![i])),// positive top  1
            new ClipLine([2,3].map(i=>this.vertices![i])),// positive right 2
            new ClipLine([3,0].map(i=>this.vertices![i])),// positive bottom 3

            new ClipLine([4,5].map(i=>this.vertices![i])),// negative left 4
            new ClipLine([5,6].map(i=>this.vertices![i])),// negative top 5
            new ClipLine([6,7].map(i=>this.vertices![i])),// negative right 6
            new ClipLine([7,4].map(i=>this.vertices![i])),// negative bottom 7

            new ClipLine([1,5].map(i=>this.vertices![i])),// left top 8
            new ClipLine([0,4].map(i=>this.vertices![i])),// left bottom 9

            
            new ClipLine([2,6].map(i=>this.vertices![i])),// right top 10
            new ClipLine([3,7].map(i=>this.vertices![i])),// right bottom 11
        ]
        this.faces![0].lines=[10,11,2,6].map(d=>this.lines![d])
        this.faces![1].lines=[8,9,0,4].map(d=>this.lines![d])
        this.faces![2].lines=[8,10,1,5].map(d=>this.lines![d])
        this.faces![3].lines=[9,11,3,7].map(d=>this.lines![d])
        this.faces![4].lines=[0,1,2,3].map(d=>this.lines![d])
        this.faces![5].lines=[4,5,6,7].map(d=>this.lines![d])
        this.lines.forEach(line=>{
            this.clipScene.add(line)
        })
    }
    capRemoves=[]
    initCap(){
        if(!this.options.cap&&this.planeObjects){
            this.capRemoves.forEach(obj=>{
                this.clipScene.remove(obj)
            })
            this.planeObjects=undefined
            this.capRemoves=[]
        }
        if(this.planeObjects){
            return
        }

                const planeObjects = this.planeObjects=[] as THREE.Mesh[];
                const size=new THREE.Vector3()
                this.box3.getSize(size)
               // const center=this.box3.getCenter(new THREE.Vector3())
                const max=Math.max(size.x,size.y,size.z)
				const planeGeom = new THREE.PlaneGeometry(max,max);
   
                let planes=this.planes!;
        
                const geometries:THREE.BufferGeometry[]=[]
                this.target!.updateMatrix()
                this.target?.updateMatrixWorld(true)
                this.target?.traverse((obj)=>{
                    if((obj as any).isMesh||obj.isLine){
                        const geometry=(obj as THREE.BufferGeometry).geometry.clone()
                        geometry.applyMatrix4(obj.matrixWorld)
                        geometries.push(geometry)
                    }
                })
                const geometry=mergeGeometries(Array.from(geometries))

                const object = new THREE.Group();
                object.name='stencilGroup'
				this.clipScene.add( object );
                this.capRemoves.push(object)
				for ( let i = 0; i < planes.length; i ++ ) {

					const poGroup = new THREE.Group();
					const plane = planes[ i ];
					const stencilGroup = createPlaneStencilGroup( geometry, plane, i + 1 );
					const planeMat =
						new THREE.MeshNormalMaterial( {
						//	color: 0xff0000,
                         //   depthTest:false,
                            polygonOffset:true,
                            polygonOffsetFactor:1,
                            polygonOffsetUnits:0,
							clippingPlanes: planes.filter( p => p !== plane ),
							stencilWrite: true,
							stencilRef: 0,
                           // side:THREE.DoubleSide,
							stencilFunc: THREE.NotEqualStencilFunc,
							stencilFail: THREE.ReplaceStencilOp,
							stencilZFail: THREE.ReplaceStencilOp,
							stencilZPass: THREE.ReplaceStencilOp,
						} );
					const po = new THREE.Mesh( planeGeom, planeMat );
					po.onAfterRender = function ( renderer ) {
						renderer.clearStencil();
					};
					po.renderOrder = i + 1.1;
					object.add( stencilGroup );
					poGroup.add( po );
					planeObjects.push(po);
                    this.capRemoves.push(poGroup)
					this.clipScene.add( poGroup );
				}
        
			
    }
    resetTargetClipPlanes(){
        this.target!.traverse((obj:any)=>{
            if(obj.isMesh||obj.isLine){
                if(Array.isArray(obj.material)){
                    obj.material.forEach((m:any)=>{
                        m.clipIntersection=false;
                        m.clippingPlanes=DEFAULT_EMPTY_ARRAY
                    })
                }else{
                    obj.material.clipIntersection=false
                    obj.material.clippingPlanes=DEFAULT_EMPTY_ARRAY
                }
            }
        })
    }
    updateTargetClipPlanes(){
        this.target!.traverse((obj:any)=>{
            if(obj.isMesh||obj.isLine){
                if(Array.isArray(obj.material)){
                    obj.material.forEach((m:any)=>{
                        m.clipIntersection=this.options.negative
                        m.clippingPlanes=this.planes
                    })
                }else{
                    obj.material.clipIntersection=this.options.negative
                    obj.material.clippingPlanes=this.planes
                }
            }
        })
    }
    updatePlanes(){
        const planes=this.planes!;
        planes[0].normal.set(1, 0, 0)
        planes[1].normal.set(-1, 0, 0)
        planes[2].normal.set(0, 1, 0)
        planes[3].normal.set(0, -1, 0)
        planes[4].normal.set(0, 0, 1)
        planes[5].normal.set(0, 0, -1)


        planes[0].constant=-this.min.x;
        planes[1].constant=this.max.x;
        planes[2].constant=-this.min.y;
        planes[3].constant=this.max.y;
        planes[4].constant=-this.min.z;
        planes[5].constant=this.max.z;
        if(this.options.negative){
            planes.forEach(plane=>{
                plane.negate()
            })
        }
       
    }
    updateVertices(){
        const vertices=this.vertices!;
        vertices[0].position.set(this.min.x,this.min.y,this.min.z)
        vertices[1].position.set(this.min.x,this.max.y,this.min.z)
        vertices[2].position.set(this.max.x,this.max.y,this.min.z)
        vertices[3].position.set(this.max.x,this.min.y,this.min.z)
        vertices[4].position.set(this.min.x,this.min.y,this.max.z)
        vertices[5].position.set(this.min.x,this.max.y,this.max.z)
        vertices[6].position.set(this.max.x,this.max.y,this.max.z)
        vertices[7].position.set(this.max.x,this.min.y,this.max.z)

    }
    updateClipBox(face: ClipFace){
        this.updateVertices()
        face.vertices.forEach(v=>{
            v.dirty=true;
        })
        this.faces?.forEach(face=>{
            face.updateVertices()
        })
        this.lines?.forEach(line=>{
            line.updateVertices()
        })
        this.vertices?.forEach(v=>{
            v.dirty=false;
        })
        this.updatePlanes()
        this.updateClipCap()
    }
    updateAllClipBox(){
        this.initCap()
        this.updateVertices()
        this.faces?.forEach(face=>{
            face.vertices.forEach(v=>{
                v.dirty=true;
            })
        })
      
        this.faces?.forEach(face=>{
            face.updateVertices()
        })
        this.lines?.forEach(line=>{
            line.updateVertices()
        })
        this.vertices?.forEach(v=>{
            v.dirty=false;
        })
        this.updatePlanes()
        this.updateClipCap()
        this.updateTargetClipPlanes()
        this.update()
    }
    updateClipBoxFromAxes(axes:string){
        this.updateVertices()
        this.faces?.forEach(face=>{
            if(face.axes.charAt(0)===axes.toLowerCase()){
                face.vertices.forEach(v=>{
                    v.dirty=true;
                })
            }
        })
      
        this.faces?.forEach(face=>{
            face.updateVertices()
        })
        this.lines?.forEach(line=>{
            line.updateVertices()
        })
        this.vertices?.forEach(v=>{
            v.dirty=false;
        })
        this.updatePlanes()
        this.updateClipCap()
    }
    updateClipCap(){
        if(!this.options.cap){
            return
        }
        const planes=this.planes!;
        const planeObjects=this.planeObjects!;
        const center=this.initMin.clone().add(this.initMax).multiplyScalar(0.5)
        const targetDist=[this.min.x-center.x,center.x-this.max.x,this.min.y-center.y,center.y-this.max.y,this.min.z-center.z,center.z-this.max.z]
        const size=new THREE.Vector3()
        this.box3.getSize(size)
        const max=Math.max(size.x,size.y,size.z)
        for ( let i = 0; i < planeObjects.length; i ++ ) {

            const po = planeObjects[ i ];
            const plane = planes[i];
           // plane.coplanarPoint( po.position );
             po.material.clipIntersection=this.options.negative
            if(this.options.negative){
                po.material.clippingPlanes=this.planes.map(p=>{
                    return p.clone().translate(p.normal.clone().negate());
                })
            }else{
               po.material.clippingPlanes=this.planes?.filter(p=>p!==plane)
            }
            // po.lookAt(
            //     po.position.x - plane.normal.x,
            //     po.position.y - plane.normal.y,
            //     po.position.z - plane.normal.z,
            // );
            //      if(!this.helpers[i]){
            //     this.helpers[i]=new THREE.Mesh(new THREE.PlaneGeometry(max,max),new THREE.MeshBasicMaterial({
            //         color:[0xff000,0xffff00,0x0000ff,0x00ffff,0x00ff00,0xff00ff][i],
            //         //side:THREE.DoubleSide,
            //         depthTest:true,
            //     }))
            //     this.clipScene.add(this.helpers[i])
               
            // }
            // this.helpers[i].position.set(0,0,0)
            // this.helpers[i].lookAt(plane.normal.clone().negate())
            // this.helpers[i].position.copy(plane.normal).multiplyScalar(targetDist[i])
            // this.helpers[i].position.add(center)


          //  po.position.set(0,0,0)
          //  po.lookAt(plane.normal.clone().negate())
            po.position.copy(plane.normal).multiplyScalar(targetDist[i])
            po.position.add(center)

            po.lookAt(
                po.position.x - plane.normal.x,
                po.position.y - plane.normal.y,
                po.position.z - plane.normal.z,
            );
            po.updateMatrixWorld()
        }
    }
    helpers=[]
    negativeClip(){
        this.options.negative=!this.options.negative;
        this.updatePlanes()
        this.updateClipCap()
        this.updateTargetClipPlanes()
    
        this.update()
    }
   

}

export class BoxSliceHandle extends BaseHandle<{},{
     'value-change':{}
}>{
    static handleName: HANDLE_TYPES=HANDLE_TYPES.CUTTING_BOX;
    clipBox?:ClipBox;
    init(): void {

        this.clipBox=new ClipBox({
            renderer:this.renderer.renderer,
            scene:this.renderer.scene,
            camera:()=>this.renderer.camera,
            onDragStart:()=>{
                this.renderer.disableControls()
            },
            onDragEnd:()=>{
                this.renderer.enableControls()
            },
            update:()=>{
                this.renderer.refresh()
            },
            onDragRange:()=>{
                this.dispatchEvent({type:'value-change'})
            }
        })
    }
    resetClip(){
        this.clipBox?.reset()
    }

    setBoxClipValue(axes:string,min:number,max:number){
        const clipBox=this.clipBox!;
        if(axes==='x'){
            clipBox.min.x=min
            clipBox.max.x=max
        }else if(axes==='y'){
            clipBox.min.y=min
            clipBox.max.y=max
        }else if(axes==='z'){
            clipBox.min.z=min
            clipBox.max.z=max
        }
        this.clipBox?.updateClipBoxFromAxes(axes)
        this.refresh()
    }
    getBoxClipValue(){
        const clipBox=this.clipBox!;
        return [clipBox.min.clone(),clipBox.max.clone()]
    }
    getBoxClipRange(){
        const clipBox=this.clipBox!;
        return [clipBox.initMin.clone(),clipBox.initMax.clone()]
    }
    onEnter(options?: {} | undefined): void {
        this.clipBox?.attach(this.renderer.modelScene)
        this.clipBox?.showClip()
    }
    onLeave(): void {
        this.clipBox?.hideClip()
    }
    exitBoxClip(){
        this.clipBox?.exit()
        this.ownerHandle.switchNone()
    }
    dispose(): void {
        
    }
   
    handlePointer(e: { target: MouseHandler; type: string;intersections:THREE.Intersection[] }): void {
           if(e.type==='object-enter'){
               // e.intersections[0]
           }else if(e.type==='pointerup'){
            //this.switch(HANDLE_TYPES.NONE)

           }
    }

}
相关推荐
2401_857026233 分钟前
拖动未来:WebKit 完美融合拖放API的交互艺术
前端·交互·webkit
星辰中的维纳斯1 小时前
vue新手入门教程(项目创建+组件导入+VueRouter)
前端·javascript·vue.js
嫣嫣细语1 小时前
css实现鼠标禁用(鼠标滑过显示红色禁止符号)
前端·css
Days20501 小时前
web前端主要包括哪些技术
前端
XF鸭2 小时前
HTML-CSS 入门介绍
服务器·前端·javascript
forwardMyLife2 小时前
element-plus 的form表单组件之el-radio(单选按钮组件)
前端·javascript·vue.js
fs哆哆2 小时前
ExcelVBA运用Excel的【条件格式】(二)
linux·运维·服务器·前端·excel
安冬的码畜日常3 小时前
【CSS in Depth 2精译】2.5 无单位的数值与行高
前端·css
ilisi_3 小时前
导航栏样式,盒子模型
前端·javascript·css
吉吉安3 小时前
grid布局下的展开/收缩过渡效果【vue/已验证可正常运行】
前端·javascript·vue.js