Irrlicht 源码学习笔记 【position2d.h】 【vector2d.h】


之所以把这两个东西放在一篇笔记里面

是因为 position2d 和 vector2d 很多地方是相同的

因为 2D向量 和 2D点 的表示是可以互相转换的   ——   都是 (x, y)

只是点(position2d) 更偏重于表示,只有一些简单的运算

而 向量(vector2d) 除了表示之外,同时有比较多的计算规则


3D向量除了多一个维度之外, 运算方法和2D有所不同 而且更多一些运算

比如 向量叉乘对于 2D 向量是没有意义的,对于3D向量才有意义,可以用来求两向量的法向量

所以这个还是再单独开一篇笔记写吧!

(  看来没有人注意到我 3D 图形学已经忘得差不多的事实原因吧...   (  ̄へ ̄  )    )



【position2d】


先来看比较简单的 position2d 模板

 X 和 Y 的类型可以由使用者自行定义

这个聪明的办法, 比较容易让一套代码却使用不同精度的运算类型

于是可以直接 typedef position2d<int> position2di;      

                         typedef position2d<float> position2df

( 毕竟方脑壳的博主以前都是酱紫写的 class POINTF, class POINTI, 然后分别再写实现...  )


三个构造函数

0. 无参构造函数, X 和 Y 初始化为 0 

1. 传入 X, Y两个值, 分别对 X 和 Y 进行赋值

2. 传入另一个同类型的点 other , 使用 other 的 X 和 Y 分别对当前 X Y 赋值


position2d 中重载了一些常用的运算符

实现都很简单,和 2D 向量基本上是一样的,就不加赘述了

要注意一下的是返回值的问题

( 比如 博主一开始学 C 语言的时候就知道赋值运算符是有返回值的 )

( 但是第一次写重载的时候还是忘的死死地... )


 "==" 和 "!=" 的返回值是 bool 型这个应该是忘不掉的               ( 毕竟忘了这个就不剩啥了 )


 "+=" , "-=" 和 "=" 的返回值是自身的引用  即: return *this;     ( 所以 C 里面可以这样写 : a = b = 0; )


 "+" 和 "-" 返回值是一个新的 position2d                                     ( 这样才可以实现 a = b + c )


另外,代码里面有一处错误 —— 加法运算符里将 "+" 写成了 "-", 大家注意一下就好了

position2d<T> operator+(const position2d<T>& other) const
{
	return position2d<T>(X+other.X, Y+other.Y); // REVISED - 原代码"return position2d<T>(X-other.X, Y-other.Y);" 中, 加法错写为减法
}




【 vector2d】


向量里面很多运算是很基本的,和 position2d很相像
而且向量的知识在我大天朝只是高中的内容, 所以大多数的计算方法对于我们来说还是很简单的

(  不少老外读研究生的时候 两位数的乘法还会算错有木有?  )

所以一些简单的部分就一笔带过了


vector2d里面对乘法的重载就是向量的缩放,即分别对 X 和 Y 乘上一个值

除法亦然,但是除法好像没有检测除数是否为 0 ,这也不一定算是一个BUG

因为过度的检测会消耗宝贵的运算时间,而且对于内部使用的代码,可以保持一定的信任

vector2d<T> operator*(const vector2d<T>& other) const { return vector2d<T>(X * other.X, Y * other.Y);	}
vector2d<T>& operator*=(const vector2d<T>& other)	{ X*=other.X; Y*=other.Y; return *this; }
vector2d<T> operator*(const T v) const { return vector2d<T>(X * v, Y * v);	}
vector2d<T>& operator*=(const T v) { X*=v; Y*=v; return *this; }

vector2d<T> operator/(const vector2d<T>& other) const { return vector2d<T>(X / other.X, Y / other.Y);	}
vector2d<T>& operator/=(const vector2d<T>& other)	{ X/=other.X; Y/=other.Y; return *this; }
vector2d<T> operator/(const T v) const { return vector2d<T>(X / v, Y / v);	}
vector2d<T>& operator/=(const T v) { X/=v; Y/=v; return *this; }


getLength() 用以获取向量的模长,返回一个 64位浮点数, 也就是一个double, 和 sqrt() 的返回值类型是一致的

// 返回向量的模长
f64 getLength() const { return sqrt(X*X + Y*Y); }


dotProduct() 返回向量的点积

( 别问我什么是点积,博主不识数 )

// 返回与另一向量的点积结果
T dotProduct(const vector2d<T>& other) const
{
	return X*other.X + Y*other.Y;
}


getDistanceFrom() 将向量看作一个二维点, 求两个点之间的距离

( 别问我怎么求距离,博主连数都不识! )

// 返回两个点之间的距离 - 这个函数里, 向量被看作一个二维空间上的点
f64 getDistanceFrom(const vector2d<T>& other) const
{
	f64 vx = X - other.X; f64 vy = Y - other.Y;
	return sqrt(vx*vx + vy*vy);
}


normalize() 将当前向量单位化, 即是方向不变,长度变为 1

( 别问我怎么单位化, 你忘了博主不识数的么? )

// 单位化一个向量
void normalize()
{
	f64 len = getLenght();
	X /= len;
	Y /= len;
}




这些都是最简单的向量运算规则

稍微复杂一点的是向量的旋转,要用到一些三角函数的知识

 vector2d 中对旋转后的向量坐标是酱紫算的 :set(X*cs - Y*sn, X*sn + Y*cs);

在线性代数里,2D向量旋转也可以用 (二维向量 × 二维矩阵) 的方法来计算


先使用从三角函数推到向量旋转的公式 ( 博主装B,前方高能,选择性绕行  (゚Д゚*)ノ   )

 装B buff 开始   

将向量 a = (xa, ya) 绕原点逆时针旋转 β 角度, 得到向量 b = (xb, yb)

( 假设向量 a 长度为 L ,向量 a 与 x 轴正半轴夹角为 α )


存在等量关系       xa = L * cosα            ya = L * sinα


xb = L * cos(α + β)

     = L * ( cosα * cosβ - sinα * sinβ )

     = L * cosα * cosβ - L * sinα * sinβ     ( 下一步等量替换 )

     = xa * cosβ - ya * sinβ


yb = L * sin(α + β)

      = L * ( sinα * cosβ + cosα * sinβ )

      = L * sinα * cosβ + L * cosα * sinβ    ( 下一步等量替换 )

      = ya * cosβ + xa * sinβ


所以运算结果和 模长L 以及 向量 a 原来的角度都无关

看看是不是和 vector2d 中的运算方法是一样的?

 装B buff 结束   

void rotateBy(f64 degrees, const vector2d<T>& center)
{
	degrees *=gradPI2; // 将角度转换为弧度
	T cs = (T)cos(degrees);
	T sn = (T)sin(degrees);

	X -= center.X; // 将 center作为圆心
	Y -= center.Y;

	set( X * cs - Y * sn, X * sn + Y * cs );  // 旋转后向量的运算

	X += center.X;
	Y += center.Y;
}

首先 C 和 C++ 中计算 sine 和 cosine 使用的是弧度制

所以要先将角度转换为弧度


源码中为什么要先 减去 center 的坐标,运算完之后再加回来呢?

是因为旋转公式是围绕原点 (0, 0) 旋转的

所以先减去 center 之后再围绕 (0, 0) 旋转,然后在 加 center 就相当于围绕 center 旋转了


如果使用线性代数中的矩阵来表示的话就很简单了 ( 可以说是一个公式了 )

对于2D向量来说,向量就是一个 1×2 的矩阵, 旋转矩阵是一个 2×2 的矩阵

[ x, y ]  ×  |  cosβ      sinβ  |      =      [  x * cosβ - y * sinβ ,  x * sinβ + y * cosβ  ]

                  |  -sinβ    cosβ  |



游戏编程对程序员数学是有一定要求的 ( 根据做的内容和使用的工具而异 )

点和向量的使用是游戏数学中最基础也是最简单的部分

其实博主的数学也不是很好,大家多多交流学习吧!



( 今晚突然好想看星空, 贴一张星空吧   Ծ‸ Ծ   )




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值