含まれている ( three.js ) ライブ スニペット ( jsfiddle.net/gpolyn/une6tst5/21 にもあります) * に示されているように、視聴者がドラッグして再配置できる不等辺のボックスがあります。ビューポートの左端、右端、上端、または下端のボックス コーナーは、動的に緑色の四角の点で示されます。
私のモデリングの課題は次のとおりです。特定のビューポートに対して、すべての位置でウィンドウ間の距離が最も長い点がそれぞれのビューポートの端にくるようにボックスを表示します。
したがって、あるオブジェクトの向きでは、オブジェクトはビューポートの左右の端にある左右の点線のコーナーで表示される場合がありますが、別の向きでは、ビューポートの上下に緑色の点線の上下のコーナーが表示される場合があります。
私の現在のアプローチでは境界球を使用していますが、それはすべての、または多くのオブジェクト指向に対して私の目標を達成するものではありません。
より良いアプローチがこれらのどこかにあるのではないかと思います:
- 最も極端なオブジェクト ポイントのウィンドウ座標に応じて、オブジェクトを表すために、ビューまたは射影行列、またはその両方を変更します。
- 境界球アプローチをバウンディング ボックス アプローチに交換する
- 緑色の点線の角の周りの「仮想」フレームのウィンドウ座標を取得し、フレーム化された画像をウィンドウに投影します (1. と同様)。
*私のコードはwww.realtimerendering.com/udacity/transforms.htmlでのEric Haines による優れたプレゼンテーションに大きく依存していますが、緑色のドット手法は、このフォーラムにWestLangleyによって投稿された多くの非常に有用な three.js の回答の 1 つからのものです。
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>