> 技术文档 > osg hudcamera-GizmoAxis

osg hudcamera-GizmoAxis

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

constexpr int NUM_OBJECTS = 10;
constexpr float OBJECT_SPACING = 0.1F;

template
osg::ref_ptr  createScene()
{
    osg::ref_ptr root = new osg::Group;

    for (int m = 0; m < NUM_OBJECTS; ++m)
    {
        for (int n = 0; n < NUM_OBJECTS; ++n)
        {
            for (int k = 0; k < NUM_OBJECTS; ++k)
            {
                osg::ref_ptr geode = new osg::Geode;

                osg::ref_ptr shapeDrawable = new osg::ShapeDrawable(new T(osg::Vec3(m + m * OBJECT_SPACING, n + n * OBJECT_SPACING, k + k * OBJECT_SPACING), 1.0F));
                geode->addDrawable(shapeDrawable);
                root->addChild(geode);
            }
        }
    }
    return root;
}

osg::ref_ptr createBoxFromObj(osg::ref_ptr nd)
{
    osg::ComputeBoundsVisitor visitor;
    nd->accept(visitor);
    const auto& bound = visitor.getBoundingBox();
    if (!bound.valid())
    {
        return nullptr;
    }

    osg::Vec3 center = bound.center();
    double half_x = bound.xMax() - bound.xMin();
    double half_y = bound.yMax() - bound.yMin();
    double half_z = bound.zMax() - bound.zMin();

    osg::ref_ptr node = new osg::Geode();

    node->addChild(new osg::ShapeDrawable(new osg::Box(center, half_x, half_y, half_z)));

    return node;

}
enum GizmoAxis : std::uint8_t
{
    X_Axis,
    Y_Axis,
    Z_Axis
};

osg::ref_ptr createAxis(GizmoAxis axis, const osg::Vec4& color)
{
    osg::ref_ptr pos = new osg::PositionAttitudeTransform();
    osg::ref_ptr geometry = new osg::Geometry;

    constexpr float                         radius = 0.02F;
    constexpr float                            rr = radius + radius;
    constexpr float                         half_height = 0.8F;
    constexpr float                            top_position = half_height + 0.1F;
    osg::ref_ptr const vertices = new osg::Vec3Array;
    vertices->push_back(osg::Vec3(-radius, -radius, 0.0F));
    vertices->push_back(osg::Vec3(radius, -radius, 0.0F));
    vertices->push_back(osg::Vec3(radius, radius, 0.0F));
    vertices->push_back(osg::Vec3(-radius, radius, 0.0F));
    vertices->push_back(osg::Vec3(-radius, -radius, half_height));
    vertices->push_back(osg::Vec3(radius, -radius, half_height));
    vertices->push_back(osg::Vec3(radius, radius, half_height));
    vertices->push_back(osg::Vec3(-radius, radius, half_height));

    vertices->push_back(osg::Vec3(0.0F, 0.0F, top_position));
    vertices->push_back(osg::Vec3(-rr, 0.0F, half_height));
    vertices->push_back(osg::Vec3(0.0F, rr, half_height));
    vertices->push_back(osg::Vec3(rr, 0.0F, half_height));
    vertices->push_back(osg::Vec3(0.0F, -rr, half_height));

    geometry->setVertexArray(vertices);

    osg::ref_ptr const indices = new osg::DrawElementsUInt(GL_TRIANGLES);
    indices->push_back(0);
    indices->push_back(1);
    indices->push_back(2); // 前面
    indices->push_back(0);
    indices->push_back(2);
    indices->push_back(3);
    indices->push_back(4);
    indices->push_back(5);
    indices->push_back(6); // 后面
    indices->push_back(4);
    indices->push_back(6);
    indices->push_back(7);
    indices->push_back(0);
    indices->push_back(1);
    indices->push_back(5); // 底面
    indices->push_back(0);
    indices->push_back(5);
    indices->push_back(4);
    indices->push_back(2);
    indices->push_back(3);
    indices->push_back(7); // 顶面
    indices->push_back(2);
    indices->push_back(7);
    indices->push_back(6);
    indices->push_back(0);
    indices->push_back(3);
    indices->push_back(7); // 左面
    indices->push_back(0);
    indices->push_back(7);
    indices->push_back(4);
    indices->push_back(1);
    indices->push_back(2);
    indices->push_back(6); // 右面
    indices->push_back(1);
    indices->push_back(6);
    indices->push_back(5);

    indices->push_back(8);
    indices->push_back(9);
    indices->push_back(10);
    indices->push_back(8);
    indices->push_back(10);
    indices->push_back(11);
    indices->push_back(8);
    indices->push_back(11);
    indices->push_back(12);
    indices->push_back(8);
    indices->push_back(12);
    indices->push_back(9);
    geometry->addPrimitiveSet(indices);
    geometry->setUseVertexBufferObjects(true);
    osg::ref_ptr const color_array = new osg::Vec4Array;
    color_array->push_back(color);
    geometry->setColorArray(color_array);
    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
    osg::Quat quat;
    if (axis == GizmoAxis::X_Axis) { // X轴
        quat.makeRotate(osg::DegreesToRadians(90.0), osg::Vec3(0.0f, 1.0f, 0.0f));
    }
    else if (axis == GizmoAxis::Y_Axis) { // Y轴
        quat.makeRotate(osg::DegreesToRadians(-90.0), osg::Vec3(1.0f, 0.0f, 0.0f));
    }
    else { // Z轴 (默认已沿Z轴)
        // 不需要旋转
    }
    pos->setAttitude(quat);
    pos->addChild(geometry.get());

    return pos.release();
}

// 函数:创建整个Gizmo坐标组
osg::Group* createGizmo()
{
    osg::ref_ptr gizmoGroup = new osg::Group();
    constexpr  float  len = 1.0F;
    // X轴 (红色)
    osg::ref_ptr xAxis = createAxis(GizmoAxis::X_Axis, osg::Vec4(len, 0.0f, 0.0f, len));
    gizmoGroup->addChild(xAxis.get());

    // Y轴 (绿色)
    osg::ref_ptr yAxis = createAxis(GizmoAxis::Y_Axis, osg::Vec4(0.0f, len, 0.0f, len));
    gizmoGroup->addChild(yAxis.get());

    // Z轴 (蓝色)
    osg::ref_ptr zAxis = createAxis(GizmoAxis::Z_Axis, osg::Vec4(0.0f, 0.0f, len, len));
    gizmoGroup->addChild(zAxis.get());

    gizmoGroup->addChild(new osg::ShapeDrawable(new osg::Sphere({ 0.0F,0.0F,0.0F }, 0.05F)));

    return gizmoGroup.release();
}

class GizmoUpdater : public osg::NodeCallback
{
public:
    GizmoUpdater(osg::Camera* camera, osg::MatrixTransform* gizmoTransform)
        : _camera(camera), _gizmoTransform(gizmoTransform) {
    }

    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
    {
        if (_camera.valid() && _gizmoTransform.valid())
        {
            // 获取操纵器的视图矩阵
            osg::Matrix viewMatrix = _camera->getViewMatrix();

            // 提取旋转部分 (去除平移)
            osg::Quat rotation = viewMatrix.getRotate();

            osg::Vec3 scale;
            osg::Quat oldRotation; // 我们要替换这个旧旋转
            osg::Vec3 translation;
            osg::Quat so; // unused
            _gizmoTransform->getMatrix().decompose(translation, oldRotation, scale, so);

            osg::Quat cameraRotation = viewMatrix.getRotate();

            osg::Matrix newMatrix = osg::Matrix::scale(scale) *
                osg::Matrix::rotate(cameraRotation) *
                osg::Matrix::translate(translation) ;

            _gizmoTransform->setMatrix(newMatrix );
        }

        // 继续遍历场景图
        traverse(node, nv);
    }

protected:
    osg::observer_ptr _camera;
    osg::observer_ptr _gizmoTransform;
};

osg::Camera* createHudCamera(int width, int height, osg::Camera* cam)
{
    osg::ref_ptr hudCam = new osg::Camera();

    float gizmosize = width / 10.0F;
    float padding = gizmosize / 10.0F;
    hudCam->setProjectionMatrixAsOrtho2D(0, width, 0, height);

    hudCam->setViewMatrix(osg::Matrix::identity());

    hudCam->setClearMask(GL_DEPTH_BUFFER_BIT);

    hudCam->setRenderOrder(osg::Camera::POST_RENDER);

    hudCam->setReferenceFrame(osg::Camera::ABSOLUTE_RF);

    hudCam->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

    osg::ref_ptr gizmoPlacement = new osg::MatrixTransform();

    float gizmoX = width - padding - gizmosize;
    float gizmoY = padding + gizmosize;

    osg::Matrix transformMatrix =
        osg::Matrix::scale(gizmosize, gizmosize, gizmosize) *
        osg::Matrix::translate(gizmoX, gizmoY, 0.0F);

    gizmoPlacement->setMatrix(transformMatrix );
    gizmoPlacement->addChild(createGizmo());
    gizmoPlacement->setUpdateCallback(new GizmoUpdater(cam, gizmoPlacement));
    hudCam->addChild(gizmoPlacement);

    return hudCam.release();
}

int main()
{
    osg::DisplaySettings::instance()->setNumMultiSamples(4);
    std::puts(\"hello from test_large_render\");
    constexpr int width = 1920 >> 1;
    constexpr int height = 960 >> 1;

    osgViewer::Viewer viewer;

    osg::ref_ptr root = new osg::Group();

    osg::ref_ptr lodNode = new osg::LOD();

    auto highdetail = createScene();

    auto lowdetail = createScene();

    osg::ref_ptr fardetail = createBoxFromObj(lowdetail);

    constexpr float base_size = 50.0F;

    lodNode->addChild(highdetail, 0.0F, base_size);

    lodNode->addChild(lowdetail, base_size, base_size * 2);

    lodNode->addChild(fardetail, base_size * 2, 1000);

    root->addChild(lodNode);
    root->addChild(createHudCamera(width, height, viewer.getCamera()));

    viewer.setSceneData(root);

    viewer.addEventHandler(new osgViewer::StatsHandler);

    viewer.setUpViewInWindow(100, 100, width, height);

    viewer.run();

    return 0;
}