Use ray threejs learning

Content: Use threejs create a grid of 20x20, the mouse moves, box moves with it, placed in the box when you click anywhere on the grid, press shift, delete the current position of the box.

Process is as follows:

  • Create a grid
  • Create a plane with the same size grids
  • Create a box with the same size of the grid mesh_1
  • A grid with the same block geometry_2, not added in the scene
  • Three events:
    • Mouse motion events, as the mouse moves, changes mesh_1 position, and re-render
    • Mouse click events, at the intersection of position, creating a new mesh, if the object is not intersecting plane, then delete the current object
    • keydown, keyup, whether to delete the status change

Detailed code is as follows:


import * as THREE from './build/three.module'
import { stat } from 'fs';

var camera, scene, renderer;
var moveMesh, staticGeo,staticMat, plane;
var objects = [];
var raycaster, mouse;
var isShiftDown = false;

function init() {
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 10000);
    camera.position.set(500, 800, 1300);
    camera.lookAt(0, 0, 0);

    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xf0f0f0);

    // lights
    var light = new THREE.AmbientLight(0x606060);
    scene.add(light);

    // grids
    var grid = new THREE.GridHelper(1000, 20); 
    scene.add(grid);

    // plane, 辅助碰撞检测
    var planeGeo = new THREE.PlaneBufferGeometry(1000, 1000);
    var planMat = new THREE.MeshBasicMaterial({color: 0xffff00, visible : true});
    plane = new THREE.Mesh(planeGeo, planMat);
    plane.rotateX(-Math.PI /2);
    scene.add(plane);
    objects.add(plane);

    // 射线 raycaster = new THREE.Raycaster();
    mouse = new THREE.Vector2();

    // moveCube;
    var moveGeo = new THREE.BoxBufferGeometry(50, 50, 50);
    var moveMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, opacity: 0.5, transparent: true });
    moveMesh = new THREE.Mesh(moveGeo, moveMaterial);
    scene.add(moveMesh);

    // static cube
    staticGeo = new THREE.BoxBufferGeometry(50, 50, 50);
    staticMat = new THREE.MeshLambertMaterial({ color: 0xfeb74c, map: new THREE.TextureLoader().load('textures/square-outline-textured.png') });

    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);

    document.body.appendChild(renderer.domElement);
    document.body.addEventListener('mousemove', onDocuementMouseMove, false);
    document.body.addEventListener('mousedown', onDocumentMouseDown, false);
    document.body.addEventListener('keydown', onDocuementKeyDown, false);
    document.body.addEventListener('keyup', onDocuementKeyUp, false);

    window.addEventListener('resize', onWindowResize, false);
}


function onDocumentMouseDown(event) {
    event.preventDefault();

    // 鼠标位置归一化
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

    // 通过摄像机与鼠标更新射线
    raycaster.setFromCamera(mouse, camera);
    var intersects = raycaster.intersectObjects(objects);
    if(intersects.length > 0) {
        var intersect = intersects[0];
        if (isShiftDown) {
            if(intersect.object !== plane) {
                scene.remove(intersect.object);
                objects.splice(objects.indexOf(intersect.object), 1);
            }
        }
        else
        {
            var staticMesh = new THREE.Mesh(staticGeo, staticMat);
            staticMesh.position.copy(intersect.point).add(intersect.face.normal);
            staticMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25);
            scene.add(staticMesh);
            objects.push(staticMesh);
        }
    }
    
}

function onDocuementMouseMove(event) {
    event.preventDefault();
    // 鼠标位置归一化
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

    // 通过摄像机与鼠标更新射线
    raycaster.setFromCamera(mouse, camera);
    var intersects = raycaster.intersectObjects(objects);

    if(intersects.length > 0) {
        intersect = intersects[0];
        // 移动位置到目标点
        moveMesh.position.copy(intersect.point).add(intersect.face.normal);
        // 计算具体方格
        moveMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25);
    }
    render();
}

function onDocuementKeyDown(event) {
    switch (event.keyCode) {
        case 16: isShiftDown = true; break;
    }
}

function onDocuementKeyUp(event) {
    switch (event.keyCode) {
        case 16: isShiftDown = false; break;
    }
}

function onWindowResize() {
    camera.aspect = window.innerWidth/ window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);

}

function render()
{
    renderer.render(scene, camera);
}

Guess you like

Origin www.cnblogs.com/yaolin1228/p/11374596.html