2D 高度图上的基本(假)光线投射
我正在尝试使用基本的光线投射来对 2D 高度图进行着色,该光线投射会检查光线在对其进行着色之前是否被拦截。但是它不起作用。
地图 :
光线投射给了我这个:
- 红色是光线拦截,但在预期位置之前(因此着色),
- 蓝色是光线在正确的位置进行拦截(因此突出显示或按原样),
- 黄色表示在 while 循环剪切之前没有光线交互。
结果在背向斜坡和大山(阴影)后面的区域应为红色,在朝阳斜坡上结果应为蓝色(重点)。不应该有任何黄色。因此,该图像表明,要么所有光线都击中了错误的位置,要么总是在其他地方相交,这是不可能的。我怀疑问题出在我的三角函数上。
Ray 类:
class Ray
{
public Vector2 Position;
public Vector2 Direction; // Think in XZ coordinates for these (they are on a perpendicular plane to the heightmap)
// Angle is angle from horizon (I think), and height is height above zero (arbitrary)
public float Angle, Height;
private TerrainUnit[,] Terrainmap;
private float U, V;
public Ray(ref TerrainUnit[,] Terrainmap, float height, float angle)
{
this.Terrainmap = Terrainmap;
this.Angle = angle;
this.Height = this.V = height;
// Create new straight vector
this.Direction = new Vector2(0, 1);
// Rotate it to the values determined by the angle
this.Direction = Vector2.Transform(Direction, Matrix.CreateRotationX(Angle));
//this.Direction = new Vector2((float)Math.Sin(angle), -(float)Math.Cos(angle));
// Find the horizontal distance of the origin-destination triangle
this.U = V / (float)Math.Tan(Angle);
// Bleh just initialize the vector to something
this.Position = new Vector2(U, V);
}
public void CastTo(int x, int y)
{
// Get the height of the target terrain unit
float H = (float)Terrainmap[x, y].Height;
// Find where the ray would have to be to intersect that terrain unit based on its angle and height
Position = new Vector2(x - U, H + V);
float Z = 1000 * (float)Terrainmap[0, y].Height;
// As long as the ray is not below the terrain and not past the destination point
while (Position.Y > Z && Position.X <= x)
{
// If the ray has passed into terrain bounds update Z every step
if (Position.X > 0) Z = 1000 * (float)Terrainmap[(int)Position.X, y].Height;
Position.X += Direction.X;
Position.Y += Direction.Y;
}
Terrainmap[x, y].TypeColor = Color.Yellow;
if ((int)Position.X == x) Terrainmap[x, y].TypeColor = Color.Blue;
else Terrainmap[x, y].TypeColor = Color.Red;
}
}
投射每条光线的函数以及我如何调用它:
if (lighting) CastSunRays(1f, MathHelper.PiOver4);
private void CastSunRays(float height, float angle)
{
Ray ray = new Ray(ref Terrainmap, height, angle);
for (int x = 0; x < Width; x++)
for (int y = 0; y < Height; y++)
ray.CastTo(x, y);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我最终使用了一种更简单的方法,即 Bresenham 直线算法 来找到截取点;我想这比我尝试的方式更快、更高效。
I ended up using a much simpler approach with Bresenham's Line Algorithm to find the intercept point; I imagine it's much faster and more efficient than the way I was trying to do it would have been.
我的猜测是,当您的
Direction
向量应用于Position
时,它超出了之前的下限 (Position.Y > -1
)有机会撞击地面 (Position.Y <= Terrainmap[(int)Position.X, y].Height
)。您可以尝试降低下限,或重新排序
if
/while
测试。另一个问题可能是方向向量与您的高度范围相比太大。两个相邻像素之间的距离为1,而整个高度差范围包含在范围(-1,1)内。从光线投射器的角度来看,这给出了一个非常平坦的表面。当
Direction
向量应用于Position
向量时,在长度上采取相对较小的步长,在高度上采取相对较大的步长。My guess is that when your
Direction
vector is applied toPosition
, it oversteps the lower limit (Position.Y > -1
) before it has a chance to hit the surface (Position.Y <= Terrainmap[(int)Position.X, y].Height
).You could try to decrease the lower limit, or re-order your
if
/while
tests.Another problem might be that the
Direction
Vector is too large in comparison to your height-range. The distance between two neighboring pixels is 1, while the whole range of height differences is contained in the range (-1,1). This gives a very flat surface from the ray-casters point of view. When theDirection
vector is applied to thePosition
vector is takes a relatively small step over the length, and a relatively large step over the height.我还使用了 Bresenham 直线算法,并将计算时间减少到 1/10!可以在我的 GitHub 项目 TextureGenerator-Online 中查看示例。地形工具使用这种方法。
请参阅 setTerrainShadow() rel="nofollow noreferrer">tex_terrain.js。
I also used Bresenham's line algorithm and decreased calculation time to 1/10! Example can be viewed at my GitHub project TextureGenerator-Online. The terrain tool uses this approach.
See function
setTerrainShadow()
at tex_terrain.js.