我在这里设置了一种反射矢量模拟器:https://jsfiddle.net/ahvonenj/1re5n8jg/
我正在使用Vectorious进行矢量计算和对象。
我正在从画布中间向鼠标光标投射光线。我可以成功地检测到墙壁的光线交叉点和墙壁上的交叉点(红点)。我也能够得到墙的中点(蓝点)。我认为当我对中间点矢量进行标准化时,这就是墙的法线。
这是听取鼠标移动,投射光线,获取交叉点并试图计算反射向量的部分(我已经添加了一些关于反射向量的实际计算和我认为我正在计算的评论):
Global.$canvas.addEventListener('mousemove', function(e)
{
var ctx = Global.ctx;
var rect = canvas.getBoundingClientRect();
Global.Mouse = new Vector([e.clientX - rect.left, e.clientY - rect.top]);
var v1 = Vector.subtract(Global.Mouse, Global.Canvas.Center).normalize();
var mag = Vector.subtract(Global.Canvas.Center, Global.Mouse).magnitude();
var ray = Vector.scale(v1, mag * 3).add(Global.Canvas.Center);
ctx.clearRect(0, 0, 600, 600);
ctx.beginPath();
for(var i = 0; i < Global.Canvas.Walls.length; i++)
{
var wall = Global.Canvas.Walls[i];
if(rayIntersectsWith(wall, [Global.Canvas.Center, ray]))
{
// x_1' - x_0 = v - 2(v dot ñ)ñ
// Where ñ = Normal of the wall
// and v = Vector from center to the point of intersection with the wall
// http://mathworld.wolfram.com/Reflection.html
// This is the point on wall where the intersection happens
var point = rayIntersectionPoint(wall, [Global.Canvas.Center, ray])
// This is the full ray cast from center towards the mouse
var d = ray;
// This (probably) is the vector from center to the intersection point on the wall
var v = Vector.subtract(point, Global.Canvas.Center);
// This represents the wall vector, or a middle of the wall (blue dot on wall)
var wallVector = Vector.add(wall[0], wall[1]).scale(0.5);
// This is supposed to be the normal of the wall
var wallNormal = Vector.normalize(wallVector);
// This is supposed to be the 2(v dot ñ) part of the equation
var v_dot_n = Vector.dot(v, wallNormal) * 2;
// This is supposed to be the v_dot_n * ñ of the equation
var v_dot_n_scaled_by_n = Vector.scale(wallNormal, v_dot_n);
// This is supposed to be the v - v_dot_n_scale_by_n part of the equation
var dot_vector = Vector.subtract(v, v_dot_n_scaled_by_n);
console.log('w1', wall[0].x, wall[0].y, ", w2", wall[1].x, wall[1].y)
var bounceVector = dot_vector
console.log(wallVector.x, wallVector.y, wallVector.magnitude())
console.log(wallNormal.x, wallNormal.y, wallNormal.magnitude())
ctx.beginPath();
ctx.arc(wallVector.x, wallVector.y, Global.isecRadius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'blue';
ctx.fill();
ctx.lineWidth = 0;
ctx.strokeStyle = 'blue';
ctx.beginPath();
ctx.arc(dot_vector.x, dot_vector.y, Global.isecRadius * 1.5, 0, 2 * Math.PI, false);
ctx.fillStyle = 'blue';
ctx.fill();
ctx.lineWidth = 0;
ctx.strokeStyle = 'blue';
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = '#00FF00';
ctx.moveTo(wall[0].x, wall[0].y);
ctx.lineTo(wall[1].x, wall[1].y);
ctx.stroke();
console.log(bounceVector.x, bounceVector.y)
ctx.beginPath();
ctx.arc(bounceVector.x, bounceVector.y, Global.isecRadius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'red';
ctx.fill();
ctx.lineWidth = 0;
ctx.strokeStyle = 'red';
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = '#000000';
ctx.moveTo(point.x, point.y);
ctx.lineTo(bounceVector.x, bounceVector.y);
ctx.stroke();
ctx.beginPath();
ctx.arc(point.x, point.y, Global.isecRadius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'red';
ctx.fill();
ctx.lineWidth = 0;
ctx.strokeStyle = 'red';
}
}
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = '#000000';
ctx.moveTo(Global.Canvas.Center.x, Global.Canvas.Center.y);
ctx.lineTo(ray.x, ray.y);
ctx.stroke();
});
我的计算基于此处找到的公式:http://mathworld.wolfram.com/Reflection.html
但是如果你尝试小提琴,你会注意到反射计算几乎不适用于倾斜的墙壁,目前根本不适用于外墙,所以这是我需要帮助的地方。
等式如下:
x_1'- x_0 = v - 2(v·ñ)ñ.
其中x_1' - x_0是从墙的交叉点到它应该指向的位置的反射向量。可能与v。
的长度相同v是从x_1到墙的交点的向量,因此在我的代码中它被命名为v并从中心到墙交叉点。
是墙的法线。
其余的等式也应该在我的代码中注释,并且我希望相应地命名变量。
我对从等式中的v中减去的东西感到有些困惑。 vdotñ返回一个标量,然后再乘以2.但是ñ是一个向量,所以2(v点ñ)必须表示缩放矢量ñ标量值为2(v点ñ)?
最好的猜测我已经能够通过调试得出这个结论,即墙壁法线很可能是正确计算的。
答案 0 :(得分:0)
我自己的Geom图书馆。
// v1, v2 are Vec
// reflected vec for line hitting this
// argument line is the line to be reflected
// retVec is the returned resulting vector.
reflectAsVec : function(line, retVec = new Vec()){ // returns a vector...
v2.x = this.p2.x - this.p1.x;
v2.y = this.p2.y - this.p1.y;
v1.x = line.p2.x - line.p1.x;
v1.y = line.p2.y - line.p1.y;
var len = v1.dot(v2.norm()) * 2;
retVec.x = v2.x * len - v1.x;
retVec.y = v2.y * len - v1.y;
return retVec;
},
this
是一条带有两个点p1,p2的线,用于定义两端。请注意,v2针对计算反射vec的最后两行进行了标准化。
函数v2.norm()
将Vec转换为标准化向量,如下所示
// u is a number
norm : function(){ // normalises this to be a unit length.
u = Math.hypot(this.x,this.y);
this.x /= u;
this.y /= u;
return this; // returns this
},
适用于v1.dot(vec)
dot : function(vec){ // get the dot product of this and {avec}
return this.x * vec.x + this.y * vec.y; // returns number
},
获得反射矢量后,您可以从截距点和反射矢量创建反射线。