ThreeJS更新相机位置,使平面世界位置与DIV屏幕位置匹配

Dan*_*nze 5 html javascript three.js

目标

我想更新摄像机位置,以便平面世界位置与DIV 屏幕位置匹配.

在更新之前 更新后 不同的观点

初步想法

我需要计算camera.position.z- 这样即使调整画布大小,飞机的面也会匹配DIV- 的大小.

this.computeZ = function(meshHandle, cameraHandle, faceHeight, targetHeight){
    var face = meshHandle.geometry.vertices[2]
    var vFOV = cameraHandle.fov * Math.PI / 180;  
    var vHeightPartial = 2 * Math.tan( vFOV / 2 );
    var p1 = faceHeight * window.innerHeight;
    var p2 = face.z * vHeightPartial;
    var p3 = targetHeight * vHeightPartial;
    var p4 = targetHeight * p2;
    var p5 = p1 + p4;
    var z = p5/p3;
    return z;
}
Run Code Online (Sandbox Code Playgroud)

computeZ在这里看到行动.

下一步

世界面部大小现在与DIV屏幕像素大小匹配.

接下来我们需要找到一个camera.position.xcamera.position.y- 以便面部直接重叠DIV.

我已经研究过...
如何使相机适合对象
Three.js - 视图宽度
THREE.JS:获取相对于屏幕上的相机和对象位置的对象大小
使用投影将World坐标转换为Three.js中的屏幕坐标

......但是一直在努力构建适合computeX和的东西computeY

请帮忙

看看我提供的小提琴中的功能computeXcomputeY功能.这些功能是我最好的尝试 - 但不起作用.

我如何构建这些功能?

更新

我在Craig的帖子的帮助下想出了一个解决方案.这个类基于他的方法来覆盖resize事件.

Cra*_*.Li 6

<!DOCTYPE html>

<html>

<head>
    <title>SO code</title>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>
    <style>
          html,body{
		  height:100%;
		  width:100%;
		  padding:0px;
		  margin:0px;
		}
		#content{
		  width:100%;
		  height:100%;
		  position:relative;
		}
		#box{
		  position:absolute;
		  background:orange;
		  height:100px;
		  width:100px;
		  bottom:100px;
		  right:100px;
		}
    </style>
    </head>
	<body>
	<div id="content">
	  <div id="box"></div>
	</div>
<script>
	function Terrain(){

	  this.container = document.getElementById('content');
	  this.camera;
	  this.scene; 
	  this.renderer;
	  this.light;

	  this.computeZ = function(meshHandle, cameraHandle, faceHeight, targetHeight){
	  	var face = meshHandle.geometry.vertices[2]
			var vFOV = cameraHandle.fov * Math.PI / 180;  
			var vHeightPartial = 2 * Math.tan( vFOV / 2 );
			var p1 = faceHeight * window.innerHeight;
			var p2 = face.z * vHeightPartial;
			var p3 = targetHeight * vHeightPartial;
			var p4 = targetHeight * p2;
			var p5 = p1 + p4;
			var z = p5/p3;
      
			//calculate dom element center coordinate
			var screenPositionX = 0;
			var screenPositionY = 0;
			var div = document.getElementById('box');
			var divDim = div.getBoundingClientRect();
			screenPositionX = (divDim.left + divDim.right) / 2;
			screenPositionY = (divDim.bottom + divDim.top) / 2;
			var vector = new THREE.Vector3((screenPositionX / window.innerWidth) * 2 -1, (screenPositionY / window.innerHeight) * 2 -1, 0.5);
    //unproject camera
			vector = vector.unproject(this.camera);
			var distanceZ = this.camera.position.z - vector.z ;
			var offsetX = vector.x * (z-10) / distanceZ;
			var offsetY = vector.y * (z-10) / distanceZ;
			var cameraPosition = new THREE.Vector3(offsetX,offsetY,z);
			return cameraPosition;
		}
	  
		this.computeX = function(meshHandle, cameraHandle, faceHeight, targetWidth){
	  	var div = document.getElementById('box');
			var divDim = div.getBoundingClientRect();
			var y =  ((divDim.left + (targetWidth/2)) / window.innerHeight ) * 2 + 1;
			return y;
	  }
	  
	  this.computeY = function(meshHandle, cameraHandle, faceHeight, targetHeight){
			var div = document.getElementById('box');
			var divDim = div.getBoundingClientRect();
			var y =  ((divDim.top + (targetHeight/2)) / window.innerHeight ) * 2 + 1;
			return y;
	  }
	  this.onDocumentClick = function(event)
	  {
	  			var vector = new THREE.Vector3(( event.clientX / (window.innerWidth) ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
                vector = vector.unproject(this.camera);

                console.log(vector);
	  }
	  this.init();
	}

	Terrain.prototype.init = function () {

		this.camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 );
		this.scene = new THREE.Scene();

		this.geometry = new THREE.BoxGeometry(20, 20, 20);
		this.material = new THREE.MeshPhongMaterial();
		this.mesh = new THREE.Mesh( this.geometry, this.material );
		this.scene.add( this.mesh );
		
		var ambient = new THREE.AmbientLight( 0x00ff00, 0.5 );
		this.scene.add( ambient );

		this.renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
		this.renderer.setPixelRatio( window.devicePixelRatio );
		this.renderer.setSize( window.innerWidth, window.innerHeight );
		this.container.appendChild(this.renderer.domElement );
	  
		window.animations['terrain'] = this.animate.bind(this);
		window.addEventListener( 'resize', this.onWindowResize.bind(this), false );
		document.addEventListener('click',this.onDocumentClick.bind(this), false);
	}

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

	Terrain.prototype.animate = function(){
	  	//this.camera.position.x = this.computeX(this.mesh, this.camera, 20, 100);
	  //this.camera.position.y = this.computeY(this.mesh, this.camera, 20, 100);
	  this.renderer.render( this.scene, this.camera );
	}

	function animate(){
	  for(var i in window.animations){
	    window.animations[i]();
	  };
	  window.requestAnimationFrame(animate);
	}

	window.animations = {};
	var terrain = new Terrain();
	window.requestAnimationFrame(animate);
	var newPosition = terrain.computeZ(terrain.mesh,terrain.camera,20,100);
	terrain.camera.position.x -= newPosition.x;
	terrain.camera.position.y += newPosition.y;
	terrain.camera.position.z += newPosition.z;
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我给出了这两个步骤,1:获取3D空间中的dom元素坐标.2:使用类似的三角形计算x和y的偏移量.我将向您展示如何使用类似的三角形.

在此输入图像描述

因为相机是透视相机.现在dom元素,相机和网格可以形成一个三角形,如果我们忽略Y维度,三角形看起来就像这张图片.

现在,我们知道3D空间中的dom元素坐标,你得到了正确的'z',我们也知道绿色立方体的深度.我们需要计算偏移量x(图中的紫色线).很明显,图片中的这些三角形是相似的三角形.vector.x / offsetX = vector.z / z - mesh.geometry.parameters.depth.我们可以做同样的事情来获得offsetY.