Three.js: ๋ณตํ•ฉ Object3D ๊ฐœ์ฒด์˜ BoundingBox?

์— ๋งŒ๋“  2011๋…„ 09์›” 26์ผ  ยท  15์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: mrdoob/three.js

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„,

CubeGeometry ๋ฐ TextGeometry๋ฅผ ํฌํ•จํ•˜๋Š” Object3D ์ธ์Šคํ„ด์Šค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์งˆ๋ฌธ : ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค
์ด ๋ณตํ•ฉ ๊ธฐํ•˜ํ•™์˜ ๊ฒฝ๊ณ„ ์ƒ์ž? ๋‚˜๋Š” Object3D ํด๋ž˜์Šค์— boundingBox-Method๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์•˜ ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฌป์Šต๋‹ˆ๋‹ค.
Object3D ์ปจํ…Œ์ด๋„ˆ์— ํฌํ•จ ๋œ ๋ชจ๋“  ๊ฐœ์ฒด์— ๋Œ€ํ•ด ๊ณ„์‚ฐํ•  ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.

๋‚ด ์ƒ๊ฐ์€ Object3D ์ปจํ…Œ์ด๋„ˆ centeroid์— ๋”ฐ๋ผ ์นด๋ฉ”๋ผ๋ฅผ ์ค‘์•™์— ๋ฐฐ์น˜ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— boundingBox๋ฅผ ์•Œ์•„์•ผํ•ฉ๋‹ˆ๋‹ค.

Roundrobin ์ธ์‚ฌ๋ง

Question

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๋‚˜๋Š” ๋˜‘๊ฐ™์€ ๊ฒƒ์„ ์ฐพ๊ณ  ์ด๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ๊ณ  ๊ฒฐ๊ตญ ์ด๊ฒƒ์— ์ •์ฐฉํ–ˆ์Šต๋‹ˆ๋‹ค.

function getCompoundBoundingBox(object3D) {
    var box = null;
    object3D.traverse(function (obj3D) {
        var geometry = obj3D.geometry;
        if (geometry === undefined) return;
        geometry.computeBoundingBox();
        if (box === null) {
            box = geometry.boundingBox;
        } else {
            box.union(geometry.boundingBox);
        }
    });
    return box;
}

๋ชจ๋“  15 ๋Œ“๊ธ€

Object3D ์—๋Š” ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์—†์ง€๋งŒ Geometry ์—๋Š” ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ๊ธธ์„ ๋ฒ—์–ด๋‚˜๋ฉด ๋‹ค์Œ์„ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค .

์ง€๊ธˆ๊นŒ์ง€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์–ด์ฉŒ๋ฉด ๋‚ด๊ฐ€ ํ‹€๋ฆฐ ๊ฒƒ์„ ๋ฌป๊ณ , ๋‚ด ์˜๋„๋Š” ๋‘ ๊ฐœ์ฒด์˜ ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ์–ป๋Š” ๊ฒƒ์ด ์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ์ง€์˜ค๋ฉ”ํŠธ๋ฆฌ์— ๋Œ€ํ•œ ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ๋ณตํ•ฉ 3D ๊ฐœ์ฒด๊ฐ€์žˆ๋Š” ๊ฒฝ์šฐ ๋‘ ๊ฐœ์˜ ํ๋ธŒ์™€ ๊ฐ™์€ ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์ด์ „์— ํ•˜๋‚˜์˜ ์ง€์˜ค๋ฉ”ํŠธ๋ฆฌ๋กœ ๊ฐœ์ฒด๋ฅผ ๋ณ‘ํ•ฉํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?

๋‚˜๋Š” ๋‹น์‹ ์ด ๋‚ด ์š”์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค :) ์„ค๋ช…ํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ์ฐธ์กฐ. ์ง€๊ธˆ ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์€ ๋ชจ๋“  ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ๋น„๊ตํ•˜๊ณ  ๋ชจ๋“  ๊ฐ’์œผ๋กœ max() ๋ฐ min() ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ดœ์ฐฎ ๊ฐ์‚ฌ. ์„ฑ๊ณตํ•˜๋ฉด ๋‚ด ์†”๋ฃจ์…˜์„ ๊ฒŒ์‹œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ ๋‚ด ํ•ด๊ฒฐ์ฑ…์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜์— ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๊ธฐ ๋งŒํ•˜๋ฉด ์ž์‹์„ ํ†ตํ•ด ๊ฐ์ฒด์˜ ๋†’์ด / ๋„ˆ๋น„๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  ๋†’์ด ๋ฐ ๋„ˆ๋น„ ์†์„ฑ์„ ๊ฐ์ฒด์— ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

calculateDimensions(myObject);

...

/*
* Get the size of the compound object by computing the bounding box and getting the max/min of each of its children
*/
function calculateDimensions(_object) {

    var absoluteMinX = 0, absoluteMaxX = 0, absoluteMinY = 0, absoluteMaxY = 0, absoluteMinZ = 0, absoluteMaxZ = 0;

    for (var i = 0; i < _object.children.length; i++) {
        _object.children[i].geometry.computeBoundingBox();
        absoluteMinX = Math.min(absoluteMinX,_object.children[i].geometry.boundingBox.min.x);
        absoluteMaxX = Math.max(absoluteMaxX,_object.children[i].geometry.boundingBox.max.x);
        absoluteMinY = Math.min(absoluteMinY,_object.children[i].geometry.boundingBox.min.y);
        absoluteMaxY = Math.max(absoluteMaxY,_object.children[i].geometry.boundingBox.max.y);
        absoluteMinZ = Math.min(absoluteMinZ,_object.children[i].geometry.boundingBox.min.z);
        absoluteMaxZ = Math.max(absoluteMaxZ,_object.children[i].geometry.boundingBox.max.z);
    }

    // set generic height and width values
    _object.depth = (absoluteMaxX - absoluteMinX) * _object.scale.x;
    _object.height = (absoluteMaxY - absoluteMinY) * _object.scale.y;
    _object.width = (absoluteMaxZ - absoluteMinZ) * _object.scale.z;

    // remember the original dimensions
    if (_object.originalDepth === undefined) _object.originalDepth = _object.depth;
    if (_object.originalHeight === undefined) _object.originalHeight = _object.height;
    if (_object.originalWidth === undefined) _object.originalWidth = _object.width;

    console.log("Depth: " + _object.depth + ", Height: " + _object.height + ", Width: " + _object.width);
}


๋‚˜๋Š” ๋˜‘๊ฐ™์€ ๊ฒƒ์„ ์ฐพ๊ณ  ์ด๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ๊ณ  ๊ฒฐ๊ตญ ์ด๊ฒƒ์— ์ •์ฐฉํ–ˆ์Šต๋‹ˆ๋‹ค.

function getCompoundBoundingBox(object3D) {
    var box = null;
    object3D.traverse(function (obj3D) {
        var geometry = obj3D.geometry;
        if (geometry === undefined) return;
        geometry.computeBoundingBox();
        if (box === null) {
            box = geometry.boundingBox;
        } else {
            box.union(geometry.boundingBox);
        }
    });
    return box;
}

@NickLarsen ์ข‹์•„ ๋ณด์ธ๋‹ค!

2 ๋…„ ์ „ ๋ผ์šด๋“œ ๋กœ๋นˆ๊ณผ ๋˜‘๊ฐ™์€ ๋ฌธ์ œ์™€ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์„ค๋ช…ํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค ... @mrdoob ๋งํ–ˆ๋“ฏ์ด @NickLarsen์˜ ํ•ด๊ฒฐ์ฑ…์€ ์ •๋ง ์ข‹์€ ๋ณด์ด์ง€๋งŒ ํฐ ๋ฌธ์ œ๊ฐ€์žˆ๋‹ค.

๋‚ด ์žฅ๋ฉด์—๋Š” ํ•ญ์ƒ ๋ชจ๋“  ๋„ํ˜•์„ ํฌํ•จํ•˜๋Š” ํ•˜๋‚˜์˜ Object3D๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฐ˜๊ฒฝ๊ณผ y ์ขŒํ‘œ๊ฐ€ ๋‹ค๋ฅธ 8 ๊ฐœ์˜ ๊ตฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋‘ x = 0 ๋ฐ z = 0์— ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ ๋‹ค์Œ NickLarsen์˜ ํ•จ์ˆ˜๋กœ ์ „์ฒด ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ๊ณ„์‚ฐํ•˜๋ ค๊ณ ํ–ˆ์ง€๋งŒ ๊ฒฐ๊ณผ๊ฐ€ ๋งค์šฐ ์ด์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์˜ค๋ฅ˜๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ๋ชจ๋“  ๋‹จ์ผ ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ์ฝ˜์†”์— ๊ธฐ๋กํ–ˆ์Šต๋‹ˆ๋‹ค.

({์ตœ์†Œ : {x : -10, y : -10, z : -10}, ์ตœ๋Œ€ : {x : 10, y : 10, z : 10}})
({์ตœ์†Œ : {x : -20, y : -20, z : -20}, ์ตœ๋Œ€ : {x : 20, y : 20, z : 20}})
({์ตœ์†Œ : {x : -7, y : -7, z : -7}, ์ตœ๋Œ€ : {x : 7, y : 7, z : 7}})
({์ตœ์†Œ : {x : -18, y : -18, z : -18}, ์ตœ๋Œ€ : {x : 18, y : 18, z : 18}})
({๋ถ„ : {x : -15, y : -15, z : -15}, ์ตœ๋Œ€ : {x : 15, y : 15, z : 15}})
({์ตœ์†Œ : {x : -3, y : -3, z : -3}, ์ตœ๋Œ€ : {x : 3, y : 3, z : 3}})
({์ตœ์†Œ : {x : -10, y : -10, z : -10}, ์ตœ๋Œ€ : {x : 10, y : 10, z : 10}})
({์ตœ์†Œ : {x : -25, y : -25, z : -25}, ์ตœ๋Œ€ : {x : 25, y : 25, z : 25}})

๋ณด์‹œ๋‹ค์‹œํ”ผ ๊ฒฝ๊ณ„ ์ƒ์ž๋Š” ํ•ญ์ƒ ๋‹จ์ผ ๊ตฌ์˜ ๋กœ์ปฌ ์ขŒํ‘œ๊ณ„์—์„œ ๊ณ„์‚ฐ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ๋“ค์„ ๊ฒฐํ•ฉํ•˜๋ฉด ๋ง์ด๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค! ๋‚ด Object3D์˜ ์‹ค์ œ ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ์„ธ๊ณ„ ์ขŒํ‘œ์—์„œ ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ์–ด๋–ป๊ฒŒ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

r.59dev ๋ธŒ๋žœ์น˜์—์„œ Box3.setFromObject( object ) ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

@PanChan ๋‹น์‹ ์€ ์ด๊ฒƒ์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ๋ณ€ํ™˜์„ ์—ฌ๊ณผํ•ด์•ผํ•˜๋ฉฐ ์˜๋„ ํ•œ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๊ฐ ์˜ค๋ธŒ์ ํŠธ์˜ ์ง€์˜ค๋ฉ”ํŠธ๋ฆฌ๋ฅผ ๋ณต์ œํ•˜๊ณ  ๊ฒฝ๊ณ„ ์ƒ์ž๋ฅผ ๊ณ„์‚ฐํ•˜๊ธฐ ์ „์— ๋ณ€ํ˜•์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ์‹ค์ œ ๊ตฌํ˜„์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ๋‚˜๋Š” ์ด๊ฒƒ์— ๊ด€ํ•ด์„œ๋Š” ๊ฝค ๋ฉ์ฒญํ•œ ์‚ฌ๋žŒ์ด๋ฏ€๋กœ ํšŒ์˜๋ก ์„ ์ถฉ๋ถ„ํžˆ ๊ฐ€์ง€๊ณ  ๋‚ด ๊ตฌํ˜„์„ ์ทจํ•˜์‹ญ์‹œ์˜ค.

@NickLarsen ๋‚˜๋Š” ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์€ ๋˜ ๋‹ค๋ฅธ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. boundingbox๋ฅผ ๊ณ„์‚ฐ ํ•œ ํ›„ ์›”๋“œ ์‹œ์Šคํ…œ์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

var bb = geometry.boundingBox;
bb.translate(obj3D.localToWorld( new THREE.Vector3()));

๊ทธ๊ฒƒ์ด ์ข‹์€ ํ•ด๊ฒฐ์ฑ…์ธ์ง€๋Š” ๋ชจ๋ฅด์ง€๋งŒ ์ง€๊ธˆ์€ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ „๋ฌธ ์†”๋ฃจ์…˜์œผ๋กœ ์ƒˆ๋กœ์šด ๊ฐœ์ •ํŒ์„ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹ญ์‹œ์˜ค.) ์„ค๋ช…ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋‚ด ํ”„๋กœ์ ํŠธ์—์„œ @NickLarsen ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ์ฒด์˜ ๊ฒฝ๊ณ„ ์ƒ์ž๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ์•ฝ๊ฐ„ ์ตœ์ ํ™” ๋œ ๊ณ„์‚ฐ์ด๋ฏ€๋กœ ๋‹ค์‹œ ๊ณ„์‚ฐํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

function getComplexBoundingBox(object3D) {
    var box = null;
    object3D.traverse(function(obj3D) {
        if (obj3D.matrixWorldNeedsUpdate) obj3D.updateMatrixWorld();
        var geometry = obj3D.geometry;
        // If current is not a geometry (THREE.Geometry), proceed to the next one
        if (geometry === undefined) return null;
        // If this object is already bounding box, then use it
        if (geometry.boundingBox) { 
            var workableBox = geometry.boundingBox.clone();
            // Move the resulting bounding box to the position of the object itself
            workableBox.applyMatrix4(obj3D.matrixWorld);
            if (box === null) {
                box = workableBox;
            } else {
                box.union(workableBox);
            }
        // If there is no bounding box for current object - creating
        } else {
            var workableGeometry = geometry.clone();
            // Move the resulting geometry in the position of the object itself
            workableGeometry.applyMatrix(obj3D.matrixWorld);
            // Calculate the bounding box for the resulting geometry
            workableGeometry.computeBoundingBox();
            if (box === null) {
                box = workableGeometry.boundingBox;
            } else {
                box.union(workableGeometry.boundingBox);
            }
        }
    });
    return box;
}

5 IF ์กฐ๊ฑด-ํ™•์‹คํžˆ ์ข‹์€ ์ฝ”๋“œ์˜ ์˜ˆ๋Š” ์•„๋‹ˆ์ง€๋งŒ ๋ฌด์—‡์„ํ•ด์•ผํ• ๊นŒ์š”? :)

์ด๊ฒƒ์€ ์ •๋ง ์˜ค๋ž˜๋œ ์Šค๋ ˆ๋“œ์ž…๋‹ˆ๋‹ค. ์š”์ฆ˜์—๋Š” ์ƒˆ๋กœ์šด new THREE.Box3().setFromObject(object3d)

๋‚˜๋Š”์ด ๋ฐฉ๋ฒ•์„ ์‹œ๋„ ํ•  ๊ฒƒ์ด๋‹ค, ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋ฌธ์ œ ์—†์–ด์š”. ๋‚˜๋Š” ๋ช‡ ๋‹ฌ ์ž์‹  ์ „ ํ˜„์žฌ์ด ์‹คํ˜„์„ ๊ฒช์€ : https://github.com/danielribeiro/three-hub/commit/859f148349ca64ede9ee224d55ad2ea3f51c0da0#diff -0dad6abd7a4801d561b83deddedc1baa

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰