2011-07-24 14 views
2

基本的には、非常に基本的なレイキャスティングシステムを使用して2次元高さマップをシェードすることです。基本的にレイを遮るべきかどうかをチェックするだけです。しかし、それは正しく動作していないと私はこれで数時間前に私の頭を叩いていたので、私はそれがあなたがそれを裏返すために傷つけることができないと思ったので、それを見たり、私の頭を包み込むことは決してありません。2D Heightmapの基本(偽)レイキャスティング

私はこのようなマップを持っている: Map

をさらにレイキャスティングは、(それだけでデバッグ色だ覚えておいてくれ、これを与えている、赤い線傍受ですが、意図した位置の前に(そう)、シェーディング、青になります(ハイライトまたはそのままの状態)、黄色はその点がwhileループカットアウトの前にレイの相互作用を全く持たないことを意味します)。 Badx2

結果は、斜面や大きな山(陰影)の後ろのエリア、太陽に面する斜面(ハイライト)の青い部分に赤色で表示されます。黄色はないはずです。したがって、この画像は、すべての光線が間違った場所に当たっているか、光線が目標に到達する前にどこか他の場所で常に交差していることを示します。これは不可能です。

この時点で私は問題が私の三叉であると大いに疑う。

はここでレイクラスです:ちょうど形式としても

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); 
    } 
+0

setTerrainShadow()人々が何をしたい推測有するスタックオーバーフローにここに答えを得るための建設的な方法ではないことに注意してください。 –

+0

フェアポイント、メインポストが編集されました。 – Maltor

答えて

2

私は、より簡単な方法でBresenham's Line Algorithmを使ってインターセプトポイントを見つけました。私はそれがやろうとしていた方法よりずっと高速で効率的だと思います。

0

私の推測あなたのDirectionベクトルがPositionに適用されるとき、それはchancを持つ前に下限(Position.Y > -1)を上回ります表面にぶつかるe(Position.Y <= Terrainmap[(int)Position.X, y].Height)。

下限を下げるか、if/whileのテストを再注文してください。

もう1つの問題は、Directionベクトルが高さの範囲と比較して大きすぎることです。隣接する2つのピクセル間の距離は1であり、高さの差の全範囲は範囲(-1,1)に含まれる。これは、レイキャスターの観点からは、非常にの平坦な表面を与える。 DirectionベクターがPositionベクターに適用される場合、その長さに渡って比較的小さなステップを要し、高さにわたって比較的大きなステップを要する。

+0

ヒントをありがとう。あなたの考えを念頭に置いてCastTo関数を書き直しましたが、それでも正しく動作していません。すべてのピクセルはレイ・インタラクションを取得しますが、すべてのレイはピクセルに達する前に明らかに交差しています(赤色)。だから私はこの時点で私のトリグに問題があると思う。 – Maltor

0

@マルター:私は実際にあなた自身の答えをコメントしたかったが、私の評判は現在できていない。

私はまた、bresenhamのラインアプローチを使用し、計算時間を1/10に短縮しました!

その実行例は、私のgithubプロジェクトTextureGenerator-Onlineで見ることができます。 地形ツールはこのアプローチを使用します。

Terrain tool

参照機能tex_terrain.js