首页 前端知识 `DragControls` 是 Three.js 库中的一个辅助类,用于实现在 Three.js 场景中拖拽控制对象的功能。它的主要作用是让用户能够通过鼠标拖拽来移动场景中的3D对象。

`DragControls` 是 Three.js 库中的一个辅助类,用于实现在 Three.js 场景中拖拽控制对象的功能。它的主要作用是让用户能够通过鼠标拖拽来移动场景中的3D对象。

2024-06-19 23:06:19 前端知识 前端哥 824 524 我要收藏

拖拽功能体验地址》》

DragControls 是 Three.js 库中的一个辅助类,用于实现在 Three.js 场景中拖拽控制对象的功能。它的主要作用是让用户能够通过鼠标拖拽来移动场景中的对象。

下面是 DragControls 的详细使用方式,包括入参、出参以及使用示例:

入参:

  • objects:一个包含了需要拖拽的对象的数组。
  • camera:场景中的相机对象。
  • domElement:渲染器所在的 DOM 元素,通常是 renderer.domElement

出参:

  • 无返回值。

使用方式:

  1. 首先,确保在您的 Three.js 项目中包含了 DragControls.js 文件,通常可以在 Three.js 的示例文件中找到或从 Three.js 的官方 GitHub 仓库中下载。

  2. 然后,创建 DragControls 实例并传入需要拖拽的对象数组、相机对象和渲染器所在的 DOM 元素。

  3. 在渲染循环中调用 DragControlsupdate() 方法,以更新拖拽控制器的状态。

下面是一个简单的示例代码,演示了如何使用 DragControls

// 创建 DragControls 实例
const controls = new DragControls(objects, camera, renderer.domElement);

// 监听 drag 事件,并在事件发生时触发 render 函数重新渲染场景
controls.addEventListener('drag', render);

// 渲染循环中更新拖拽控制器的状态
function animate() {
    requestAnimationFrame(animate);
    controls.update(); // 更新拖拽控制器状态
    render(); // 渲染场景
}
animate();

在这个示例中,objects 是包含了需要拖拽的对象的数组,camera 是场景中的相机对象,renderer.domElement 是渲染器所在的 DOM 元素。render 是一个函数,用于渲染 Three.js 场景。

通过上述步骤,您就可以在 Three.js 场景中使用 DragControls 实现拖拽功能了。


function init() {
    // 创建一个容器并将其添加到页面中
    container = document.createElement('div');
    document.body.appendChild(container);

    // 创建透视相机
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 500);
    camera.position.z = 25;

    // 创建场景并设置背景颜色
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0xf0f0f0);

    // 添加环境光
    scene.add(new THREE.AmbientLight(0xaaaaaa));

    // 创建聚光灯
    const light = new THREE.SpotLight(0xffffff, 10000);
    light.position.set(0, 25, 50);
    light.angle = Math.PI / 9;

    light.castShadow = true;
    light.shadow.camera.near = 10;
    light.shadow.camera.far = 100;
    light.shadow.mapSize.width = 1024;
    light.shadow.mapSize.height = 1024;

    scene.add(light);

    // 创建一个组并将其添加到场景中
    group = new THREE.Group();
    scene.add(group);

    // 创建一个立方体几何体,并根据循环创建多个立方体对象并添加到场景中
    const geometry = new THREE.BoxGeometry();
    for (let i = 0; i < 200; i++) {
        const object = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff }));

        // 随机设置立方体的位置、旋转和缩放
        object.position.x = Math.random() * 30 - 15;
        object.position.y = Math.random() * 15 - 7.5;
        object.position.z = Math.random() * 20 - 10;

        object.rotation.x = Math.random() * 2 * Math.PI;
        object.rotation.y = Math.random() * 2 * Math.PI;
        object.rotation.z = Math.random() * 2 * Math.PI;

        object.scale.x = Math.random() * 2 + 1;
        object.scale.y = Math.random() * 2 + 1;
        object.scale.z = Math.random() * 2 + 1;

        object.castShadow = true;
        object.receiveShadow = true;

        scene.add(object);

        objects.push(object);
    }

    // 创建渲染器并将其添加到容器中
    renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFShadowMap;

    container.appendChild(renderer.domElement);

    // 创建拖拽控制器并将其添加到场景中
    controls = new DragControls([...objects], camera, renderer.domElement);
    controls.rotateSpeed = 2;
    controls.addEventListener('drag', render);

    // 监听窗口大小变化事件
    window.addEventListener('resize', onWindowResize);

    // 监听点击事件
    document.addEventListener('click', onClick);
    // 监听键盘按下事件
    window.addEventListener('keydown', onKeyDown);
    // 监听键盘释放事件
    window.addEventListener('keyup', onKeyUp);

    // 渲染场景
    render();
}




function onWindowResize() {
    // 更新相机的长宽比并更新投影矩阵
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    // 调整渲染器的大小以适应窗口大小变化
    renderer.setSize(window.innerWidth, window.innerHeight);

    // 渲染场景
    render();
}

function onKeyDown(event) {
    // 按下Shift键时启用选择功能
    enableSelection = (event.keyCode === 16) ? true : false;

    // 按下"M"键时切换控制模式(平移/旋转)
    if (event.keyCode === 77) {
        controls.mode = (controls.mode === 'translate') ? 'rotate' : 'translate';
    }
}

function onKeyUp() {
    // 松开键盘时禁用选择功能
    enableSelection = false;
}

function onClick(event) {
    // 阻止默认的点击事件
    event.preventDefault();

    // 如果启用了选择功能
    if (enableSelection === true) {
        // 获取可拖拽的对象
        const draggableObjects = controls.getObjects();
        draggableObjects.length = 0;

        // 计算鼠标点击位置的二维标准化设备坐标
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

        // 根据鼠标位置和相机创建一条射线
        raycaster.setFromCamera(mouse, camera);

        // 检查射线与场景中的对象是否相交
        const intersections = raycaster.intersectObjects(objects, true);

        // 如果有对象被点击到
        if (intersections.length > 0) {
            const object = intersections[0].object;

            // 如果对象已经在组中,则将其从组中移除并附加到场景中
            if (group.children.includes(object) === true) {
                object.material.emissive.set(0x000000);
                scene.attach(object);
            } else {
                // 否则,将对象从场景中移除并附加到组中
                object.material.emissive.set(0xaaaaaa);
                group.attach(object);
            }

            // 启用组的变换并将其添加到可拖拽的对象列表中
            controls.transformGroup = true;
            draggableObjects.push(group);
        }

        // 如果组中没有对象,则禁用组的变换,并将所有对象添加到可拖拽的对象列表中
        if (group.children.length === 0) {
            controls.transformGroup = false;
            draggableObjects.push(...objects);
        }
    }

    // 渲染场景
    render();
}

// 渲染函数
function render() {

				renderer.render( scene, camera );

			}

完整源码



<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - drag controls</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
		<style>
			body {
				background-color: #f0f0f0;
				color: #444;
			}
			a {
				color: #08f;
			}
		</style>
	</head>
	<body>

		<div id="info">
			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - drag controls<br />
			Use "Shift+Click" to add/remove objects to/from a group.<br />
			Use "M" to toggle between rotate and translate mode.<br />
			Grouped objects can be transformed as a union.
		</div>

		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "./jsm/"
				}
			}
		</script>

		<script type="module">

			import * as THREE from 'three';

			import { DragControls } from 'three/addons/controls/DragControls.js';

			let container;
			let camera, scene, renderer;
			let controls, group;
			let enableSelection = false;

			const objects = [];

			const mouse = new THREE.Vector2(), raycaster = new THREE.Raycaster();

			init();

			function init() {

				container = document.createElement( 'div' );
				document.body.appendChild( container );

				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.1, 500 );
				camera.position.z = 25;

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

				scene.add( new THREE.AmbientLight( 0xaaaaaa ) );

				const light = new THREE.SpotLight( 0xffffff, 10000 );
				light.position.set( 0, 25, 50 );
				light.angle = Math.PI / 9;

				light.castShadow = true;
				light.shadow.camera.near = 10;
				light.shadow.camera.far = 100;
				light.shadow.mapSize.width = 1024;
				light.shadow.mapSize.height = 1024;

				scene.add( light );

				group = new THREE.Group();
				scene.add( group );

				const geometry = new THREE.BoxGeometry();

				for ( let i = 0; i < 200; i ++ ) {

					const object = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } ) );

					object.position.x = Math.random() * 30 - 15;
					object.position.y = Math.random() * 15 - 7.5;
					object.position.z = Math.random() * 20 - 10;

					object.rotation.x = Math.random() * 2 * Math.PI;
					object.rotation.y = Math.random() * 2 * Math.PI;
					object.rotation.z = Math.random() * 2 * Math.PI;

					object.scale.x = Math.random() * 2 + 1;
					object.scale.y = Math.random() * 2 + 1;
					object.scale.z = Math.random() * 2 + 1;

					object.castShadow = true;
					object.receiveShadow = true;

					scene.add( object );

					objects.push( object );

				}

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

				container.appendChild( renderer.domElement );

				controls = new DragControls( [ ... objects ], camera, renderer.domElement );
				controls.rotateSpeed = 2;
				controls.addEventListener( 'drag', render );

				//

				window.addEventListener( 'resize', onWindowResize );

				document.addEventListener( 'click', onClick );
				window.addEventListener( 'keydown', onKeyDown );
				window.addEventListener( 'keyup', onKeyUp );

				render();

			}

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

				render();

			}

			function onKeyDown( event ) {

				enableSelection = ( event.keyCode === 16 ) ? true : false;
				
				if ( event.keyCode === 77 ) {

					controls.mode = ( controls.mode === 'translate' ) ? 'rotate' : 'translate';
			
				}

			}

			function onKeyUp() {

				enableSelection = false;

			}

			function onClick( event ) {

				event.preventDefault();

				if ( enableSelection === true ) {

					const draggableObjects = controls.getObjects();
					draggableObjects.length = 0;

					mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
					mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

					raycaster.setFromCamera( mouse, camera );

					const intersections = raycaster.intersectObjects( objects, true );

					if ( intersections.length > 0 ) {

						const object = intersections[ 0 ].object;

						if ( group.children.includes( object ) === true ) {

							object.material.emissive.set( 0x000000 );
							scene.attach( object );

						} else {

							object.material.emissive.set( 0xaaaaaa );
							group.attach( object );

						}

						controls.transformGroup = true;
						draggableObjects.push( group );

					}

					if ( group.children.length === 0 ) {

						controls.transformGroup = false;
						draggableObjects.push( ...objects );

					}

				}

				render();

			}

			function render() {

				renderer.render( scene, camera );

			}

		</script>

	</body>
</html>

本内容来源于小豆包,想要更多内容请跳转小豆包 》

转载请注明出处或者链接地址:https://www.qianduange.cn//article/12852.html
标签
评论
发布的文章

Markdown基础与进阶语法

2024-06-30 22:06:12

零基础 HTML 入门(详细)

2024-06-30 22:06:09

CSS3基本语法

2024-06-30 22:06:51

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!