opengles实现场景控制

本例实现,鼠标点击场景中任何一点,场景中的正方体即移动到鼠标指定点,右键按住不放,旋转场景,鼠标滚轮实现场景缩放

核心实现:

1,相机类  (摄像机根据输入事件改变自己的观察矩阵)

	//相机类
	class CELL3RDCamera
	{
	public:
		float3 _eye;
		float3 _up;
		float3 _right;
		float3 _target;
		float3 _dir;
		float _radius;
		matrix4 _matView;
		matrix4 _matProj;
		matrix4 _matWorld;
		float2 _viewSize;

		float _yaw;//偏离度

	public:
		CELL3RDCamera()
		{
			_radius = 400;
			_yaw = 0;
			_viewSize = float2(100,100);
			_matView.identify();//初始化为单位矩阵
			_matProj.identify();
			_matWorld.identify();
		}

		float getRadius() const
		{
			return _radius;
		}

		void setRadius(float val)
		{
			_radius = val;
		}

		CELL::float3 getEye() const
		{
			return _eye;
		}

		//设置眼睛位置
		void setEye(CELL::float3 val)
		{
			_eye = val;
		}

		//计算方向
		void calcDir()
		{
			_dir = _target - _eye;//得到运动方向向量
			_dir = normalize(_dir);//归一化  
		}

		CELL::float3 getTarget() const
		{
			return _target;
		}

		void    setTarget(CELL::float3 val)
		{
			_target = val;
		}

		CELL::float3 getUp() const
		{
			return _up;
		}
		void    setUp(CELL::float3 val)
		{
			_up = val;
		}
		float3  getDir() const
		{
			return  _dir;
		}

		float3  getRight() const
		{
			return  _right;
		}

		void update()
		{
			//归一化
			float3 upDir = normalize(_up);
			_eye = _target - _dir*_radius;
			_right = normalize(cross(_dir,upDir));

			//设置摄像机观察矩阵
			_matView = CELL::lookAt(_eye,_target,_up);
		}

		void    setViewSize(const float2& viewSize)
		{
			_viewSize = viewSize;
		}
		void    setViewSize(float x, float y)
		{
			_viewSize = float2(x, y);
		}

		float2  getViewSize()
		{
			return  _viewSize;
		}

		void setProject(const matrix4& proj)
		{
			_matProj = proj;
		}

		const matrix4& getProject() const
		{
			return _matProj;
		}

		const matrix4& getView() const
		{
			return _matView;
		}

		void perspective(float fovy, float aspect, float zNear, float zFar)
		{
			_matProj = CELL::perspective<float>(fovy,aspect,zNear,zFar);
		}


		/**
		*   世界坐标转化为窗口坐标
		*/
		bool    project(const float4& world, float4& screen)
		{
			screen = (_matProj * _matView * _matWorld) * world;
			if (screen.w == 0.0f)
			{
				return false;
			}
			screen.x /= screen.w;
			screen.y /= screen.w;
			screen.z /= screen.w;

			// map to range 0 - 1
			screen.x = screen.x * 0.5f + 0.5f;
			screen.y = screen.y * 0.5f + 0.5f;
			screen.z = screen.z * 0.5f + 0.5f;

			// map to viewport
			screen.x = screen.x * _viewSize.x;
			screen.y = _viewSize.y - (screen.y * _viewSize.y);
			return  true;
		}


		/**
		*   世界坐标转化为窗口坐标
		*/
		float2  worldToScreen(const float3& world)
		{
			float4  worlds(world.x, world.y, world.z, 1);
			float4  screens;
			project(worlds, screens);
			return  float2(screens.x, screens.y);
		}

		/**
		*   窗口坐标转化为世界坐标
		*/
		float3  screenToWorld(const float2& screen)
		{
			float4  screens(screen.x, screen.y, 0, 1);
			float4  world;
			unProject(screens, world);
			return  float3(world.x, world.y, world.z);
		}

		float3  screenToWorld(float x, float y)
		{
			float4  screens(x, y, 0, 1);
			float4  world;
			unProject(screens, world);
			return  float3(world.x, world.y, world.z);
		}


		/**
		*   窗口坐标转化为世界坐标
		*/
		bool    unProject(const float4& screen, float4& world)
		{
			float4 v;
			v.x = screen.x;
			v.y = screen.y;
			v.z = screen.z;
			v.w = 1.0;

			// map from viewport to 0 - 1
			v.x = (v.x) / _viewSize.x;
			v.y = (_viewSize.y - v.y) / _viewSize.y;
			//v.y = (v.y - _viewPort.Y) / _viewPort.Height;

			// map to range -1 to 1
			v.x = v.x * 2.0f - 1.0f;
			v.y = v.y * 2.0f - 1.0f;
			v.z = v.z * 2.0f - 1.0f;

			CELL::matrix4  inverse = (_matProj * _matView * _matWorld).inverse();

			v = v * inverse;
			if (v.w == 0.0f)
			{
				return false;
			}
			world = v / v.w;
			return true;
		}

		Ray createRayFromScreen(int x, int y)
		{
			float4  minWorld;
			float4  maxWorld;

			float4  screen(float(x), float(y), 0, 1);
			float4  screen1(float(x), float(y), 1, 1);

			unProject(screen, minWorld);
			unProject(screen1, maxWorld);
			Ray     ray;
			ray.setOrigin(float3(minWorld.x, minWorld.y, minWorld.z));

			float3  dir(maxWorld.x - minWorld.x, maxWorld.y - minWorld.y, maxWorld.z - minWorld.z);
			ray.setDirection(normalize(dir));
			return  ray;
		}
		/**
		*   下面的函数的功能是将摄像机的观察方向绕某个方向轴旋转一定的角度
		*   改变观察者的位置,目标的位置不变化
		*/
		void    rotateView(float angle)
		{
			_dir = rotateY<float>(_dir, angle);
		}
	};

场景角色类(响应输入事件的角色)

	//场景中的角色类
	class Role
	{
	public:
		float3 _pos;//当前位置
		float3 _target;//目的位置
		float _speed;//速度
	public:
		Role()
		{
			_speed = 5;
		}

		//设置移动的目标点
		void setTarget(float3 target)
		{
			_target = target;
		}

		//更新位置
		void setPosition(float3 pos)
		{
			_pos = pos;
			_pos.y = 1;
		}

		void moveCheck(const float elasped)
		{
				//目标位置不能是当前位置
			if (_target==_pos)
			{
				return;
			}

			//获取当前位置与目标位置的偏移量
			float3 offset = _target - _pos;
			//获取移动方向
			float3 dir = normalize(offset);//单位向量

			if (distance(_target,_pos)>1)
			{
				float speed = elasped*_speed;//时间乘以速度
				//最新位置=当前位置+移动的偏移量
				_pos += float3(dir.x*speed, 0, dir.z*speed);
			}
			else
			{
				_target = _pos;
			}
		}

		void render(float fElapsed)
		{
			moveCheck(fElapsed);
		}
	};

事件响应代码()

		/*
			鼠标移动,含鼠标滚轮
		*/

		virtual void onMouseMove(int absx, int absy, int absz)
		{
			if (absz>0)
			{
				_camera._radius = _camera._radius*1.1f;//相机焦距变大,观察的物体缩小
			}
			else if (absz<0)
			{
				_camera._radius = _camera._radius*0.9f;//相机焦距变小,观察的物体变大
			}
			else if (_rightButtonDown)//按下右键不放,移动鼠标,旋转整个场景,相当于旋转摄像机
			{
				float2 curPos(absx,absy);
				float2 offset = curPos - _mousePos;
					   _mousePos = curPos;
					   _camera.rotateView(offset.x*0.1f);
					   _camera.update();
			}
		}

 

		/*
			鼠标按下 
		*/
		virtual void onMousePress(int absx, int absy, CELL::MouseButton id)
		{
			if (id==CELL::MouseButton::Left)//如果按下是是左键 则开始运动
			{
				//创建一条由物体当前位置到目标位置的射线(即以角色当前位置为起点,鼠标按下点为终点的向量)
				Ray ray = _camera.createRayFromScreen(absx,absy);

				//射线的起点
				float3 pos = ray.getOrigin();
				//获取起始点和结束点坐标值的比例系数
				float tm = abs((pos.y)/ray.getDirection().y);
				//目标点向量,射线的终点,也就是物体要运动到的终点
				float3 target = -ray.getPoint(tm);
				//设置当前角色的运动目的地
				_role.setTarget(float3(target.x,0,target.z));
			}
			else if (id==CELL::MouseButton::Right) //如果按下的是右键,右键保持现状
			{
				_mousePos = float2(absx,absy);
				_rightButtonDown = true;
			}
		}
      
        /**
        *   鼠标释放
        */
        virtual void    onMouseRelease(int /*absx*/, int /*absy*/, CELL::MouseButton id)
        {
            if( id == CELL::MouseButton::Right)
            {
                _rightButtonDown    =   false;
            }
        }

完整代码参考:http://download.csdn.net/detail/hb707934728/9853933



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值