日常生活的交流与学习

首页 新随笔 联系 管理

click点击添加物体,shirft+click点击删除物体

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="utf-8">
	<title>three.js webgl - interactive - voxel painter</title>
	<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> - voxel painter - webgl<br>
		<strong>click</strong>: add voxel, <strong>shift + click</strong>: remove voxel
	</div>

	<!-- Import maps polyfill -->
	<!-- Remove this when import maps will be widely supported -->
	<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

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

	<script type="module">

		import * as THREE from 'three';

		let camera, scene, renderer;
		let plane;
		let pointer, raycaster, isShiftDown = false;

		let rollOverMesh, rollOverMaterial;
		let cubeGeo, cubeMaterial;

		// objects数组用来存放地平面和所有的小方块
		const objects = [];

		init();
		render();

		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);

			// roll-over helpers

			const rollOverGeo = new THREE.BoxGeometry(50, 50, 50);
			rollOverMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, opacity: 0.5, transparent: true });
			rollOverMesh = new THREE.Mesh(rollOverGeo, rollOverMaterial);
			scene.add(rollOverMesh);

			// cubes

			cubeGeo = new THREE.BoxGeometry(50, 50, 50);
			cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xfeb74c, map: new THREE.TextureLoader().load('textures/square-outline-textured.png') });

			// grid

			const gridHelper = new THREE.GridHelper(1000, 20);
			scene.add(gridHelper);

			//

			raycaster = new THREE.Raycaster();
			pointer = new THREE.Vector2();

			const geometry = new THREE.PlaneGeometry(1000, 1000);
			geometry.rotateX(- Math.PI / 2);

			plane = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ visible: false }));
			scene.add(plane);

			objects.push(plane);

			// lights

			const ambientLight = new THREE.AmbientLight(0x606060);
			scene.add(ambientLight);

			const directionalLight = new THREE.DirectionalLight(0xffffff);
			directionalLight.position.set(1, 0.75, 0.5).normalize();
			scene.add(directionalLight);

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

			document.addEventListener('pointermove', onPointerMove);
			document.addEventListener('pointerdown', onPointerDown);
			document.addEventListener('keydown', onDocumentKeyDown);
			document.addEventListener('keyup', onDocumentKeyUp);

			//

			window.addEventListener('resize', onWindowResize);

		}

		function onWindowResize() {

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

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

			render();

		}

		function onPointerMove(event) {

			pointer.set((event.clientX / window.innerWidth) * 2 - 1, - (event.clientY / window.innerHeight) * 2 + 1);

			raycaster.setFromCamera(pointer, camera);

			const intersects = raycaster.intersectObjects(objects, false);

			if (intersects.length > 0) {

				// eslint-disable-next-line computed-property-spacing
				const intersect = intersects[0];

				rollOverMesh.position.copy(intersect.point).add(intersect.face.normal);
				rollOverMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25);

				render();

			}

		}

		function onPointerDown(event) {

			pointer.set((event.clientX / window.innerWidth) * 2 - 1, - (event.clientY / window.innerHeight) * 2 + 1);
			raycaster.setFromCamera(pointer, camera);
			const intersects = raycaster.intersectObjects(objects, false);

			if (intersects.length > 0) {

				const intersect = intersects[0];

				// delete cube
				if (isShiftDown) {

					if (intersect.object !== plane) {

						//除了从场景中删除小方块,还要从物体数组中删除小方块
						scene.remove(intersect.object);
						objects.splice(objects.indexOf(intersect.object), 1);

					}

					// create cube

				} else {

					const voxel = new THREE.Mesh(cubeGeo, cubeMaterial);
					voxel.position.copy(intersect.point).add(intersect.face.normal);
					voxel.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25);
					scene.add(voxel);

					objects.push(voxel);

				}

				render();

			}

		}

		function onDocumentKeyDown(event) {

			switch (event.keyCode) {

				case 16: isShiftDown = true; break;

			}

		}

		function onDocumentKeyUp(event) {

			switch (event.keyCode) {

				case 16: isShiftDown = false; break;

			}

		}

		function render() {

			renderer.render(scene, camera);

		}

	</script>

</body>

</html>
posted on 2023-04-06 23:19  lazycookie  阅读(207)  评论(0编辑  收藏  举报