Как 3D-окно с неравными сторонами может заполнить окно просмотра, независимо от его ориентации в перспективе?

Как показано во включенном (Three.js) живой фрагмент (также вjsfiddle.net/gpolyn/une6tst5/21) *, У меня есть коробка с неравными сторонами, которую зритель может переместить, перетаскивая. Крайние левый, правый, верхний или нижний углы окна в области просмотра динамически обозначаются зелеными квадратными точками.

Моя задача моделирования заключается в следующем:Для данного видового экрана представьте мою коробку так, чтобы во всех положениях точки с наибольшим расстоянием между ними находились на соответствующих краях видового экрана..

Таким образом, для одной ориентации объекта объект может быть представлен с левыми и правыми точечными углами на левом и правом краях области просмотра, в то время как другая ориентация может привести к представлению верхних и нижних зеленых точечных углов в верхней и нижней части окна просмотра.

Мой текущий подход использует ограничивающую сферу, но это не достигает моей целикаждыйили даже множество объектных ориентаций.

Я подозреваю, что лучший подход может лежать где-то среди них:

В зависимости от координат окна наиболее экстремальных точек объекта измените матрицу вида или проекции, либо обе, чтобы представить объектПоменяйте подход ограничивающей сферы для подхода ограничивающей рамкиПолучите координаты окна «виртуальной» рамки вокруг зеленых пунктирных углов и спроецируйте изображение в рамке на окно (аналогично 1.)

* Мой код сильно зависит от отличной презентации Эрика Хейнса вwww.realtimerendering.com/udacity/transforms.htmlв то время как техника зеленой точки взята из одного из множества очень полезных ответов three.js, опубликованных на этом форумеWestLangley

	var renderer, scene, camera, controls;
	var object;
	var vertices3;
	var cloud;
	var boxToBufferAlphaMapping = {
	  0: 0,
	  2: 1,
	  1: 2,
	  3: 4,
	  6: 7,
	  7: 10,
	  5: 8,
	  4: 6
	}
	var lastAlphas = [];
	var canvasWidth, canvasHeight;
	var windowMatrix;
	var boundingSphere;

	init();
	render();
	afterInit();
	animate();

	function init() {

	  canvasWidth = window.innerWidth;
	  canvasHeight = window.innerHeight;

	  // renderer
	  renderer = new THREE.WebGLRenderer({
	    antialias: true
	  });
	  renderer.setSize(canvasWidth, canvasHeight);
	  document.body.appendChild(renderer.domElement);

	  // scene
	  scene = new THREE.Scene();

	  // object
	  var geometry = new THREE.BoxGeometry(4, 4, 6);

	  // too lazy to add edges without EdgesHelper...
	  var material = new THREE.MeshBasicMaterial({
	    transparent: true,
	    opacity: 0
	  });
	  var cube = new THREE.Mesh(geometry, material);
	  object = cube;

	  // bounding sphere used for orbiting control in render
	  object.geometry.computeBoundingSphere();
	  boundingSphere = object.geometry.boundingSphere;

	  cube.position.set(2, 2, 3)
	    // awkward, but couldn't transfer cube position to sphere...
	  boundingSphere.translate(new THREE.Vector3(2, 2, 3));

	  // save vertices for subsequent use
	  vertices = cube.geometry.vertices;

	  var edges = new THREE.EdgesHelper(cube)
	  scene.add(edges);
	  scene.add(cube);
	  addGreenDotsToScene(geometry);

	  // camera
	  camera = new THREE.PerspectiveCamera(17, window.innerWidth / window.innerHeight, 1, 10000);
	  camera.position.set(20, 20, 20);

	  // controls
	  controls = new THREE.OrbitControls(camera);
	  controls.maxPolarAngle = 0.5 * Math.PI;
	  controls.minAzimuthAngle = 0;
	  controls.maxAzimuthAngle = 0.5 * Math.PI;
	  controls.enableZoom = false;

	  // ambient
	  scene.add(new THREE.AmbientLight(0x222222));

	  // axes
	  scene.add(new THREE.AxisHelper(20));

	}

	 // determine which object points are in the most extreme top-,
	 // left-, right- and bottom-most positions in the window space
	 // and illuminate them
	function addExtrema() {

	  // object view-space points, using view (camera) matrix
	  var viewSpacePts = vertices3.map(function(vt) {
	    return vt.clone().applyMatrix4(camera.matrixWorldInverse);
	  })

	  // object clip coords, using projection matrix
	  var clipCoords = viewSpacePts.map(function(vt) {
	    return vt.applyMatrix4(camera.projectionMatrix);
	  })

	  // w-divide clip coords for NDC
	  var ndc = clipCoords.map(function(vt) {
	    return vt.divideScalar(vt.w);
	  })

	  // object window coordinates, using window matrix
	  var windowCoords = ndc.map(function(vt) {
	    return vt.applyMatrix4(windowMatrix);
	  })

	  // arbitrary selection to start
	  var topIdx = 0,
	    bottomIdx = 0,
	    leftIdx = 0,
	    rightIdx = 0;
	  var top = windowCoords[0].y;
	  var bottom = windowCoords[0].y
	  var right = windowCoords[0].x;
	  var left = windowCoords[0].x;

	  for (var i = 1; i < windowCoords.length; i++) {
	    vtx = windowCoords[i];
	    if (vtx.x < left) {
	      left = vtx.x;
	      leftIdx = i;
	    } else if (vtx.x > right) {
	      right = vtx.x;
	      rightIdx = i;
	    }

	    if (vtx.y < bottom) {
	      bottom = vtx.y;
	      bottomIdx = i;
	    } else if (vtx.y > top) {
	      top = vtx.y;
	      topIdx = i;
	    }
	  }

	  var alphas = cloud.geometry.attributes.alpha;

	  // make last points invisible
	  lastAlphas.forEach(function(alphaIndex) {
	    alphas.array[alphaIndex] = 0.0;
	  });
	  // now, make new points visible...
	  // (boxToBufferAlphaMapping is a BufferGeometry-Object3D geometry
	  // map between the object and green dots)
	  alphas.array[boxToBufferAlphaMapping[rightIdx]] = 1.0;
	  alphas.array[boxToBufferAlphaMapping[bottomIdx]] = 1.0;
	  alphas.array[boxToBufferAlphaMapping[topIdx]] = 1.0;
	  alphas.array[boxToBufferAlphaMapping[leftIdx]] = 1.0;

	  // store visible points for next cycle
	  lastAlphas = [boxToBufferAlphaMapping[rightIdx]];
	  lastAlphas.push(boxToBufferAlphaMapping[bottomIdx])
	  lastAlphas.push(boxToBufferAlphaMapping[topIdx])
	  lastAlphas.push(boxToBufferAlphaMapping[leftIdx])

	  alphas.needsUpdate = true;

	}

	function addGreenDotsToScene(geometry) {

	  var bg = new THREE.BufferGeometry();
	  bg.fromGeometry(geometry);
	  bg.translate(2, 2, 3); // yucky, and quick

	  var numVertices = bg.attributes.position.count;
	  var alphas = new Float32Array(numVertices * 1); // 1 values per vertex

	  for (var i = 0; i < numVertices; i++) {
	    alphas[i] = 0;
	  }

	  bg.addAttribute('alpha', new THREE.BufferAttribute(alphas, 1));

	  var uniforms = {
	    color: {
	      type: "c",
	      value: new THREE.Color(0x00ff00)
	    },
	  };

	  var shaderMaterial = new THREE.ShaderMaterial({
	    uniforms: uniforms,
	    vertexShader: document.getElementById('vertexshader').textContent,
	    fragmentShader: document.getElementById('fragmentshader').textContent,
	    transparent: true
	  });

	  cloud = new THREE.Points(bg, shaderMaterial);
	  scene.add(cloud);

	}

	function afterInit() {

	  windowMatrix = new THREE.Matrix4();
	  windowMatrix.set(canvasWidth / 2, 0, 0, canvasWidth / 2, 0, canvasHeight / 2, 0, canvasHeight / 2, 0, 0, 0.5, 0.5, 0, 0, 0, 1);

	  var vertices2 = object.geometry.vertices.map(function(vtx) {
	    return (new THREE.Vector4(vtx.x, vtx.y, vtx.z));
	  });

	  // create 'world-space' geometry points, using
	  // model ('world') matrix
	  vertices3 = vertices2.map(function(vt) {
	    return vt.applyMatrix4(object.matrixWorld);
	  })

	}

	function render() {

	  var dist = boundingSphere.distanceToPoint(camera.position);

	  // from stackoverflow.com/questions/14614252/how-to-fit-camera-to-object
	  var height = boundingSphere.radius * 2;
	  var fov = 2 * Math.atan(height / (2 * dist)) * (180 / Math.PI);

	  // not sure why, but factor is needed to maximize fit of object
	  var mysteryFactor = 0.875;
	  camera.fov = fov * mysteryFactor;
	  camera.updateProjectionMatrix();
	  camera.lookAt(boundingSphere.center);

	  renderer.render(scene, camera);

	}

	function animate() {

	  requestAnimationFrame(animate);
	  render();
	  addExtrema()

	}
			body {
			  background-color: #000;
			  margin: 0px;
			  overflow: hidden;
			}
			
<script src="https://rawgit.com/mrdoob/three.js/dev/build/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>
<script type="x-shader/x-vertex" id="vertexshader">

  attribute float alpha; varying float vAlpha; void main() { vAlpha = alpha; vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); gl_PointSize = 8.0; gl_Position = projectionMatrix * mvPosition; }

</script>

<script type="x-shader/x-fragment" id="fragmentshader">

  uniform vec3 color; varying float vAlpha; void main() { gl_FragColor = vec4( color, vAlpha ); }

</script>

Ответы на вопрос(1)

Ваш ответ на вопрос