/* Gizmo move ref: Blender 4 0 9-10 *----------------->>>> | | | 5+ | +6 | | v 假设轴尺寸为10 箭头长度为2,直径为2 双轴调节正方形,长宽为1,位置为5,5 中心球半径为1 */ #include"GizmoResource.h" #include #include #include #include #include #include #include #include #include VK_NAMESPACE_BEGIN namespace { /** * 移动 Gizmo 节点 */ class GizmoMoveNode:public SceneNode,io::MouseEvent { struct GizmoMoveAxis { MaterialInstance *mi; //材质实例 MeshComponent *cylinder; //圆柱 MeshComponent *cone; //圆锥 MeshComponent *square; //双轴调节正方形 }; MaterialInstance *pick_mi; MeshComponent *sphere=nullptr; GizmoMoveAxis axis[3]{}; //X,Y,Z 三个轴 protected: int CurAXIS=-1; //当前鼠标选中轴 float CurDist=0; //当前距离 int PickAXIS=-1; //拾取轴 float PickDist=0; //拾取辆距离轴心的距离 TransformTranslate3f CurTranslate; public: using SceneNode::SceneNode; io::EventDispatcher *GetEventDispatcher() override { return this; // GizmoMoveNode 处理鼠标事件 } SceneNode *CreateNode()const override { return(new GizmoMoveNode); } void DuplicationComponents(SceneNode *node) const override { GizmoMoveNode *gmn=(GizmoMoveNode *)node; if(!gmn) return; gmn->pick_mi=pick_mi; #define DUPLICATION_COMPONENT(c) gmn->c=(MeshComponent *)(c->Duplication()); \ gmn->AttachComponent(gmn->c); DUPLICATION_COMPONENT(sphere); for(size_t i=0;i<3;i++) { gmn->axis[i].mi=axis[i].mi; // 复制材质实例 DUPLICATION_COMPONENT(axis[i].cylinder); DUPLICATION_COMPONENT(axis[i].cone); DUPLICATION_COMPONENT(axis[i].square); } #undef DUPLICATION_COMPONENT } bool CreateGizmoGeometry(RenderFramework *render_framework) { ComponentDataPtr SpherePtr =GetGizmoMeshCDP(GizmoShape::Sphere); ComponentDataPtr CylinderPtr=GetGizmoMeshCDP(GizmoShape::Cylinder); ComponentDataPtr ConePtr =GetGizmoMeshCDP(GizmoShape::Cone); ComponentDataPtr SquarePtr =GetGizmoMeshCDP(GizmoShape::Square); if(!SpherePtr )return(false); if(!CylinderPtr )return(false); if(!ConePtr )return(false); if(!SquarePtr )return(false); CreateComponentInfo cci(this); pick_mi=GetGizmoMI3D(GizmoColor::Yellow); //获取拾取材质实例 sphere=render_framework->CreateComponent(&cci,SpherePtr); //中心球 sphere->SetOverrideMaterial(GetGizmoMI3D(GizmoColor::White)); //白色 { Transform tm; GizmoMoveAxis *gma; const Vector3f one_scale(1); const Vector3f square_scale(2); const Vector3f cylinder_scale(GIZMO_CYLINDER_RADIUS,GIZMO_CYLINDER_RADIUS,GIZMO_CYLINDER_HALF_LENGTH); { gma=axis+size_t(AXIS::Z); gma->mi=GetGizmoMI3D(GizmoColor::Blue); tm.SetScale(cylinder_scale); tm.SetTranslation(0,0,GIZMO_CYLINDER_OFFSET); cci.mat=tm; gma->cylinder=render_framework->CreateComponent(&cci,CylinderPtr); //Z 向上圆柱 gma->cylinder->SetOverrideMaterial(gma->mi); tm.SetScale(one_scale); tm.SetTranslation(0,0,GIZMO_CONE_OFFSET); cci.mat=tm; gma->cone=render_framework->CreateComponent(&cci,ConePtr); //Z 向上圆锥 gma->cone->SetOverrideMaterial(gma->mi); tm.SetScale(square_scale); tm.SetTranslation(GIZMO_TWO_AXIS_OFFSET,GIZMO_TWO_AXIS_OFFSET,0); cci.mat=tm; gma->square=render_framework->CreateComponent(&cci,SquarePtr); gma->square->SetOverrideMaterial(gma->mi); } { gma=axis+size_t(AXIS::X); gma->mi=GetGizmoMI3D(GizmoColor::Red); tm.SetScale(cylinder_scale); tm.SetRotation(AxisVector::Y,90); tm.SetTranslation(GIZMO_CYLINDER_OFFSET,0,0); cci.mat=tm; gma->cylinder=render_framework->CreateComponent(&cci,CylinderPtr); //X 向右圆柱 gma->cylinder->SetOverrideMaterial(gma->mi); tm.SetScale(one_scale); tm.SetTranslation(GIZMO_CONE_OFFSET,0,0); cci.mat=tm; gma->cone=render_framework->CreateComponent(&cci,ConePtr); //Z 向上圆锥 gma->cone->SetOverrideMaterial(gma->mi); tm.SetScale(square_scale); tm.SetTranslation(0,GIZMO_TWO_AXIS_OFFSET,GIZMO_TWO_AXIS_OFFSET); cci.mat=tm; gma->square=render_framework->CreateComponent(&cci,SquarePtr); gma->square->SetOverrideMaterial(gma->mi); } { gma=axis+size_t(AXIS::Y); gma->mi=GetGizmoMI3D(GizmoColor::Green); tm.SetScale(cylinder_scale); tm.SetRotation(AxisVector::X,-90); tm.SetTranslation(0,GIZMO_CYLINDER_OFFSET,0); cci.mat=tm; gma->cylinder=render_framework->CreateComponent(&cci,CylinderPtr); //X 向右圆柱 gma->cylinder->SetOverrideMaterial(gma->mi); tm.SetScale(one_scale); tm.SetTranslation(0,GIZMO_CONE_OFFSET,0); cci.mat=tm; gma->cone=render_framework->CreateComponent(&cci,ConePtr); //Z 向上圆锥 gma->cone->SetOverrideMaterial(gma->mi); tm.SetScale(square_scale); tm.SetTranslation(GIZMO_TWO_AXIS_OFFSET,0,GIZMO_TWO_AXIS_OFFSET); cci.mat=tm; gma->square=render_framework->CreateComponent(&cci,SquarePtr); gma->square->SetOverrideMaterial(gma->mi); } } return(true); } io::EventProcResult OnPressed(const Vector2i &mp,io::MouseButton mb) override { GizmoMoveNode::OnMove(mp); if(CurAXIS>=0&&CurAXIS<3) { PickAXIS=CurAXIS; PickDist=CurDist; CurTranslate.SetOffset(Vector3f(0,0,0)); //重置当前平移偏移 } return io::EventProcResult::Continue; } io::EventProcResult OnReleased(const Vector2i &,io::MouseButton mb) override { return io::EventProcResult::Continue; } io::EventProcResult OnMove(const Vector2i &mouse_coord) override { CameraControl *cc=GetCameraControl(); if(!cc) return io::EventProcResult::Continue; Ray ray; cc->SetMouseRay(&ray,mouse_coord); Matrix4f l2w=GetLocalToWorldMatrix(); Vector3f center=TransformPosition(l2w,Vector3f(0,0,0)); Vector3f axis_vector; Vector3f start; Vector3f end; Vector3f p_ray,p_ls; float axis_radius; float dist; float pixel_per_unit; float center_ppu; MaterialInstance *mi; center_ppu=cc->GetPixelPerUnit(center); //求原点坐标相对屏幕空间象素的缩放比 CurAXIS=-1; for(int i=0;i<3;i++) { axis_vector=GetAxisVector(AXIS(i))*center_ppu; //取得轴向量 start =TransformPosition(l2w,axis_vector* GIZMO_CENTER_SPHERE_RADIUS); //将轴的起点转换到世界坐标 end =TransformPosition(l2w,axis_vector*(GIZMO_CENTER_SPHERE_RADIUS+GIZMO_CONE_LENGTH+GIZMO_CYLINDER_HALF_LENGTH)); //求射线与线段的最近点 ray.ClosestPoint(p_ray, //射线上的点 p_ls, //线段上的点 start,end); //线段 dist=glm::distance(p_ray,p_ls); //计算射线与线段的距离 //求p_ls坐标相对屏幕空间象素的缩放比 pixel_per_unit=cc->GetPixelPerUnit(p_ls); if(distSetOverrideMaterial(mi); axis[i].cone->SetOverrideMaterial(mi); //std::cout<<"Mouse: "<CreateGizmoGeometry(render_framework)) { delete sn_gizmo_move; sn_gizmo_move=nullptr; return(false); } return(true); } VK_NAMESPACE_END