Как создать поворот на перспективной камере на Three.js? - PullRequest
0 голосов
/ 12 октября 2018

Я построил небольшую 3D-TileMap в Three.js.

В настоящее время у меня проблемы с моим PerspectiveCamera.Я не хочу добавлять немного обработки камеры, как Map rotating или zooming.Масштабирование всегда работает, здесь я использую только field of view и mousewheel.

Но как я могу реализовать поворот моей карты?Когда я использую координаты camera для изменения x , y или z , я неправильно понимаю вычисление.

Вот моя текущая работа:

function Input(renderer, camera) {
				var press = false
				var sensitivity = 0.2

				renderer.domElement.addEventListener('mousemove', event => {
					if(!press){ return }

					camera.position.x += event.movementX * sensitivity
					camera.position.y += event.movementY * sensitivity 
					camera.position.z += event.movementY * sensitivity / 10
				})    

				renderer.domElement.addEventListener('mousedown', () => { press = true })
				renderer.domElement.addEventListener('mouseup', () => { press = false })
				renderer.domElement.addEventListener('mouseleave', () => { press = false })

				renderer.domElement.addEventListener('mousewheel', event => {
					// Add MIN/MAX LIMITS
					const ratio = camera.position.y / camera.position.z
					camera.position.y -= (event.wheelDelta * sensitivity * ratio)
					camera.position.z -= (event.wheelDelta * sensitivity)
					camera.updateProjectionMatrix()
				})
			}
			var controls;
			const Type = 'WebGL'; // WebGL or Canvas
			var _width, _height, CUBE_SIZE, GRID, TOTAL_CUBES, WALL_SIZE, HALF_WALL_SIZE,
				MAIN_COLOR, SECONDARY_COLOR, cubes, renderer, camera, scene, group
			var clock = new THREE.Clock();
			clock.start();
			var FOV = 45;
			_width = window.innerWidth
			_height = window.innerHeight

			CUBE_SIZE = 80 /* width, height */
			GRID = 12 /* cols, rows */
			TOTAL_CUBES = (GRID * GRID)
			WALL_SIZE = (GRID * CUBE_SIZE)
			HALF_WALL_SIZE = (WALL_SIZE / 2)
			MAIN_COLOR = 0xFFFFFF
			SECONDARY_COLOR = 0x222222
			cubes = []
			var directions = [];
			var normalized = [];
			
			switch(Type) {
				case 'WebGL':
					renderer = new THREE.WebGLRenderer({antialias: true})
				break;
				case 'Canvas':
					renderer = new THREE.CanvasRenderer({antialias: true})				
				break;
			}
			
			camera = new THREE.PerspectiveCamera(FOV, (_width / _height), 0.1, 10000)
			scene = new THREE.Scene()
			group = new THREE.Object3D()

			/* -- -- */
			setupCamera(0, 0, 800)
			setupBox(group)
			setupFloor(group)
			setupCubes(group)
			setupLights(group)
			group.position.y = 10
			group.rotation.set(-60 * (Math.PI/180), 0, -45 * (Math.PI/180))
			scene.add(group)
			setupRenderer(document.body)
			window.addEventListener('resize', resizeHandler, false)
			new Input(renderer, camera);
			/* -- -- */
			function resizeHandler() {
				_width = window.innerWidth
				_height = window.innerHeight
				renderer.setSize(_width, _height)
				camera.aspect = _width / _height
				camera.updateProjectionMatrix()
			}

			/* -- CAMERA -- */
			function setupCamera(x, y, z) {
				camera.position.set(x, y, z)
				scene.add(camera)
			}

			/* -- BOX -- */
			function setupBox(parent) {
				var i, boxesArray, geometry, material

				boxesArray = []
				geometry = new THREE.BoxGeometry(WALL_SIZE, WALL_SIZE, 0.05)
				geometry.faces[8].color.setHex(SECONDARY_COLOR)
				geometry.faces[9].color.setHex(SECONDARY_COLOR)
				geometry.colorsNeedUpdate = true
				material = new THREE.MeshBasicMaterial({
					color : MAIN_COLOR,
					vertexColors : THREE.FaceColors,
					overdraw: 0.5
				})

				for (i = 0; i < 5; i++) {
					boxesArray.push(new THREE.Mesh(geometry, material))
				}

				// back
				boxesArray[0].position.set(0, HALF_WALL_SIZE, -HALF_WALL_SIZE)
				boxesArray[0].rotation.x = 90 * (Math.PI/180)

				// right
				boxesArray[1].position.set(HALF_WALL_SIZE, 0, -HALF_WALL_SIZE)
				boxesArray[1].rotation.y = -90 * (Math.PI/180)

				// front
				boxesArray[2].position.set(0, -HALF_WALL_SIZE, -HALF_WALL_SIZE)
				boxesArray[2].rotation.x = -90 * (Math.PI/180)

				// left
				boxesArray[3].position.set(-HALF_WALL_SIZE, 0, -HALF_WALL_SIZE)
				boxesArray[3].rotation.y = 90 * (Math.PI/180)

				// bottom
				boxesArray[4].position.set(0, 0, -WALL_SIZE)

				boxesArray.forEach(function(box) {
					box.renderOrder = 1;
					parent.add(box)
				
				});
				
			}

			/* -- FLOOR -- */
			function setupFloor(parent) {
				var i, tilesArray, geometry, material

				tilesArray = []
				geometry = new THREE.PlaneBufferGeometry(WALL_SIZE, WALL_SIZE)
				material = new THREE.MeshLambertMaterial({
					color : MAIN_COLOR,
					overdraw: 1
				})

				for (i = 0; i < 8; i++) {
					tilesArray.push(new THREE.Mesh(geometry, material))
				}

				tilesArray[0].position.set(-WALL_SIZE, WALL_SIZE, 0)
				tilesArray[1].position.set(0, WALL_SIZE, 0)
				tilesArray[2].position.set(WALL_SIZE, WALL_SIZE, 0)
				tilesArray[3].position.set(-WALL_SIZE, 0, 0)
				tilesArray[4].position.set(WALL_SIZE, 0, 0)
				tilesArray[5].position.set(-WALL_SIZE, -WALL_SIZE, 0)
				tilesArray[6].position.set(0, -WALL_SIZE, 0)
				tilesArray[7].position.set(WALL_SIZE, -WALL_SIZE, 0)

				tilesArray.forEach(function(tile) {
					tile.receiveShadow = true
					tile.renderOrder = 4;
					parent.add(tile)
				})
			}

			/* -- CUBES --*/
			function setupCubes(parent) {
			
				var i, geometry, material, x, y, row, col

				geometry = new THREE.BoxGeometry(CUBE_SIZE, CUBE_SIZE, 0.05)
				
				material = new THREE.MeshPhongMaterial( {
					map: new THREE.TextureLoader().load('http://ak.game-socket.de/assets/grass.png'),
					normalMap: new THREE.TextureLoader().load('http://ak.game-socket.de/assets/paper_low_nmap.png'),
					overdraw: 1,
					depthTest: true,
					depthWrite: true
				} );
			
			
				x = 0
				y = 0
				row = 0
				col = 0

				for (i = 0; i < TOTAL_CUBES; i++) {
					cubes.push(new THREE.Mesh(geometry, material))

					if ((i % GRID) === 0) {
						col = 1
						row++
					} else col++

					x = -(((GRID * CUBE_SIZE) / 2) - ((CUBE_SIZE) * col) + (CUBE_SIZE/2))
					y = -(((GRID * CUBE_SIZE) / 2) - ((CUBE_SIZE) * row) + (CUBE_SIZE/2))

					cubes[i].position.set(x, y, 0)
				}

				cubes.forEach(function(cube, index) {
					if(index % 2 == 0) {
						directions[index] = -1;
						normalized[index] = false;
					} else {
						directions[index] = 1;
						normalized[index] = true;
					}
					
					cube.castShadow = true
					cube.receiveShadow = true
					cube.rotation.x = 0;
					cube.renderOrder = 3;
					cube.doubleSide = true;
					parent.add(cube)
				})
			}

			/* -- LIGHTS -- */
			function setupLights(parent) {
				var light, soft_light
				light = new THREE.DirectionalLight(MAIN_COLOR, 1.25)
				soft_light = new THREE.DirectionalLight(MAIN_COLOR, 1.5)
				light.position.set(-WALL_SIZE, -WALL_SIZE, CUBE_SIZE * GRID)
				light.castShadow = true
				soft_light.position.set(WALL_SIZE, WALL_SIZE, CUBE_SIZE * GRID)
				parent.add(light).add(soft_light)
			}

			/* -- RENDERER -- */
			function setupRenderer(parent) {
				renderer.setSize(_width, _height)
				renderer.setClearColor(MAIN_COLOR, 1.0);
				parent.appendChild(renderer.domElement)
			}

			var speed = 0.003;
			var reach = 40;
			
			function render() {
				var delta = clock.getDelta();
				requestAnimationFrame(render);
				
				cubes.forEach(function(cube, index) {
					cube.castShadow = true
					cube.receiveShadow = true
					
					if(directions[index] >= 1) {
						++directions[index];
						
						if(directions[index] >= reach) {
							directions[index] = -1
						}
						
						cube.rotation.x += speed;
					} else if(directions[index] <= -1) {
						--directions[index];
						
						if(directions[index] <= -reach) {
							directions[index] = 1
						}
						
						cube.rotation.x -= speed;
					}
				});
				
				renderer.render(scene, camera)
			}

			render();
html, body, canvas {
				padding: 0;
				margin: 0;
				width: 100%;
				height: 100%;
				display: block;
			}
<script src="https://rawcdn.githack.com/mrdoob/three.js/dev/build/three.min.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/dev/examples/js/renderers/CanvasRenderer.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/dev/examples/js/renderers/Projector.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/dev/examples/js/controls/TrackballControls.js"></script>
<script src="https://rawcdn.githack.com/mrdoob/three.js/dev/examples/js/shaders/ParallaxShader.js"></script>

По желанию, я не хочу, чтобы поворот / масштабирование доходили до конца карты - пользователь не может смотреть подкарта, как пример.

...