이 페이지에서

Qt Quick 3D Physics - 질량 예시

물체의 질량과 관성을 설정하는 다양한 방법을 보여줍니다.

초록색 표면 위에 세 개의 구체가 겹쳐진 모습을 보여주는 3D 렌더링 스크린샷으로, 왼쪽부터 오른쪽 순서로 파란색, 보라색, 빨간색으로 칠해져 있다.

이 예제는 물체의 질량과 관성을 설정하는 세 가지 다른 방법을 보여줍니다. 이 장면은 세 개의 구체가 수직으로 쌓여 있는 세 개의 물체로 구성되어 있습니다. 이 물체들은 모두 같은 질량을 가지고 있지만, 질량 중심과 관성 텐서가 서로 다르기 때문에 충돌 시 서로 다른 거동을 보입니다.

설정

먼저 ‘ PhysicsWorld ’를 추가합니다:

PhysicsWorld {
    running: true
    gravity: Qt.vector3d(0, -9.81, 0)
    typicalLength: 1
    typicalSpeed: 10
    scene: viewport.scene
}

환경, 카메라, 조명을 설정하는 일반적인 과정을 수행합니다:

environment: SceneEnvironment {
    clearColor: "lightblue"
    backgroundMode: SceneEnvironment.Color
}

PerspectiveCamera {
    id: camera
    position: Qt.vector3d(0, 2, 5)
    eulerRotation: Qt.vector3d(-10, 0, 0)
    clipFar: 100
    clipNear: 0.01
}

DirectionalLight {
    eulerRotation.x: -45
    eulerRotation.y: 45
    castsShadow: true
    brightness: 1
    shadowFactor: 50
    shadowBias: 0.1
    pcfFactor: 0.01
}

물리적 객체

일반적인 정적 평면을 준비합니다:

StaticRigidBody {
    position: Qt.vector3d(0, 0, 0)
    eulerRotation: Qt.vector3d(-90, 0, 0)
    collisionShapes: PlaneShape {}
    Model {
        source: "#Rectangle"
        materials: PrincipledMaterial {
            baseColor: "green"
        }
        castsShadows: false
        receivesShadows: true
    }
}

이 물체들은 소위 ‘롤리폴리 장난감’처럼 움직이기 때문에, 본체를 위한 사용자 정의 QML 클래스를 RolyPoly라고 명명합니다. RolyPoly는 세 개의 구형 충돌 형상을 가진 DynamicRigidBody 입니다:

DynamicRigidBody {
    id: body
    property string color: "blue"

    collisionShapes: [
        SphereShape {
            id: sphere0
            diameter:  1
        },
        SphereShape {
            id: sphere1
            diameter:  0.8
            position: Qt.vector3d(0, 0.6, 0)
        },
        SphereShape {
            id: sphere2
            diameter:  0.6
            position: Qt.vector3d(0, 1.1, 0)
        }
    ]

    Model {
        source: "#Sphere"
        position: sphere0.position
        scale: Qt.vector3d(1,1,1).times(sphere0.diameter*0.01)
        materials: PrincipledMaterial {
            baseColor: body.color
        }
    }

    Model {
        source: "#Sphere"
        position: sphere1.position
        scale: Qt.vector3d(1,1,1).times(sphere1.diameter*0.01)
        materials: PrincipledMaterial {
            baseColor: body.color
        }
    }

    Model {
        source: "#Sphere"
        position: sphere2.position
        scale: Qt.vector3d(1,1,1).times(sphere2.diameter*0.01)
        materials: PrincipledMaterial {
            baseColor: body.color
        }
    }
}

그런 다음 씬에 세 개의 RolyPoly를 추가합니다:

RolyPoly {
    position: Qt.vector3d(-2, 0.5, 0)
    color: "blue"

    mass: 0.9
    centerOfMassPosition: Qt.vector3d(0, -0.5, 0)
    inertiaTensor: Qt.vector3d(0.217011, 0.0735887, 0.217011)
    massMode: DynamicRigidBody.MassAndInertiaTensor
}

RolyPoly {
    position: Qt.vector3d(0, 0.5, 0)
    color: "purple"

    mass: 0.9
    centerOfMassPosition: Qt.vector3d(0, -0.5, 0)
    inertiaTensor: Qt.vector3d(0.05, 100, 100)
    massMode: DynamicRigidBody.MassAndInertiaTensor
}

RolyPoly {
    position: Qt.vector3d(2, 0.5, 0)
    color: "red"

    mass: 0.9
    massMode: DynamicRigidBody.Mass
}

보라색과 파란색 롤리폴리 물체는 사용자 정의 질량 중심과 관성 텐서를 가지고 있습니다. 물체는 기본적으로 균일한 밀도를 사용하며 질량과 관성을 자동으로 계산하므로, 보라색과 파란색 물체의 `massMode`를 ` DynamicRigidBody.MassAndInertiaTensor`로 설정하여 우리가 제공한 질량 및 관성 텐서를 대신 사용하도록 합니다. 질량 중심이 낮게 설정되어 있어, 이 물체들은 밀려 넘어진 후에도 항상 다시 일어섭니다. 보라색 물체의 관성 텐서 덕분에 한 방향으로는 쉽게 흔들리지만, 반대 방향으로는 거의 흔들리지 않습니다. 빨간색 물체는 질량 중심이 자동으로 계산되므로, 넘어진 후에는 계속 누워 있게 됩니다.

공 쏘기

다양한 물체의 동작을 테스트하기 위해 공을 쏘는 노드를 추가합니다:

Node {
    id: shapeSpawner
    property var spheres: []
    property var sphereComponent: Qt.createComponent("Sphere.qml")

    function createBall(position, forward) {
        let diameter = 0.2
        let speed = 20
        let sphere = sphereComponent.createObject(shapeSpawner, {
                                                      "position": position,
                                                      "sphereDiameter": diameter
                                                  })
        sphere.setLinearVelocity(forward.times(speed))

        var pair = {
            "sphere": sphere,
            "date": Date.now()
        }

        spheres.push(pair)

        if (sphere === null) {
            console.log("Error creating object")
        }
    }

    function clean() {
        spheres = spheres.filter(sphere => {
            let diff = Date.now() - sphere['date'];
            if (diff > 5000) {
                sphere['sphere'].destroy();
                return false;
            }
            return true;
        });
    }

    Timer {
        interval: 200
        running: true
        repeat: true
        onTriggered: shapeSpawner.clean()
    }
}

그런 다음 카메라를 이동시키고, 물체를 조준하여 공을 쏠 수 있도록 ‘ WasdController ’를 추가합니다:

WasdController {
    speed: 0.01
    shiftSpeed: 0.1
    controlledObject: camera
    Keys.onPressed: (event) => {
        handleKeyPress(event);
        if (event.key === Qt.Key_Space) {
            shapeSpawner.createBall(camera.position, camera.forward);
        }
    }
    Keys.onReleased: (event) => { handleKeyRelease(event) }
}

파일:

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.