Wie kann eine 3D-Box mit ungleichen Seiten das Ansichtsfenster ausfüllen, unabhängig von der Ausrichtung in der Perspektive?

Wie im beiliegenden three.js) Live-Snippet (auch bei jsfiddle.net / gpolyn / une6tst5 / 21) *, Ich habe eine Box mit ungleichen Seiten, die ein Betrachter durch Ziehen neu positionieren kann. Die äußersten linken, rechten, oberen oder unteren Kastenecken im Ansichtsfenster werden dynamisch durch grüne quadratische Punkte angezeigt.

Meine Modellierungsherausforderung lautet wie folgt:Stellen Sie für ein bestimmtes Ansichtsfenster meine Box so vor, dass sich die Punkte mit dem größten Fensterabstand zwischen ihnen in allen Positionen an den jeweiligen Rändern des Ansichtsfensters befinden..

So kann für eine Objektausrichtung das Objekt mit einer linken und einer rechten gepunkteten Ecke am linken und rechten Rand des Ansichtsfensters dargestellt werden, während eine andere Ausrichtung zu einer Darstellung der oberen und unteren grünen gepunkteten Ecken am oberen und unteren Rand des Ansichtsfensters führen kann.

ein aktueller Ansatz verwendet eine begrenzende Sphäre, aber das erreicht mein Ziel für @ nichjede oder sogar viele Objektorientierungen.

Ich vermute, dass ein besserer Ansatz irgendwo zwischen diesen liegen könnte:

Ändern Sie abhängig von den Fensterkoordinaten der meisten extremen Objektpunkte die Ansicht oder die Projektionsmatrix oder beides, um das Objekt darzustellen Tauschen Sie den Bounding-Sphere-Ansatz gegen einen Bounding-Box-Ansatz ausLesen Sie die Fensterkoordinaten eines 'virtuellen' Rahmens um die grün gepunkteten Ecken und projizieren Sie das gerahmte Bild auf das Fenster (ähnlich wie bei 1).

* Mein Code hängt stark von einer hervorragenden Präsentation von Eric Haines bei @ a www.realtimerendering.com / udacity / transforms.html, während die grüne Punkttechnik von einer der vielen höchst nützlichen three.js-Antworten stammt, die @ in diesem Forum gepostet h 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>

Antworten auf die Frage(2)

Ihre Antwort auf die Frage