FireMonkey で、波の干渉を視覚化する

By: Chikako Yonezawa

Abstract: この記事では、Delphi XE2 および FireMonkey を使用して、波の干渉を視覚化するために 3次元メッシュをどのように生成するかを解説します。

    前提条件!

この記事は、以前の記事 “FireMonkey でカスタムメッシュを生成することにより、数学関数を視覚化する” を基にして構築しています。

    波の関数

この記事で使用する波の関数:

         f(x,y) = A*sin(1/L*r-v*t)

式内の項目:

  • (x,y) = 観測点
  • A = 振幅
  • L = 波の長さ
  • r = 波の中心と観測点間の距離
  • v = 波の伝播速度
  • t = 時間

この関数を Delphi で表記すると次のようになります。

function f(x,y : Double) : Double;
begin
  f := Amplitude*Sin(1/Length*Sqrt(Sqr(x-PosX)+Sqr(y-PosY))-Speed*t);
end;

注意: この関数は、単に平衡状態を与えていることに注意してください。完全に始動のシナリオ、および、時間と距離で波が消えてしまう事実を無視しています。

以下のスクリーンショットは 1 つの波を表現しています。

Hide image
Click to see full-sized image

互いに干渉する 2 つの波の場合:

Hide image
Click to see full-sized image

そして、それが 4 つの波になった場合:

Hide image
Click to see full-sized image

    メッシュを生成する

メッシュを生成するために、以前の記事からコードを参照し、時間のパラメータを与えて少し変更します。

procedure TForm1.GenerateWave(t : Double);
  function f(x,y : Double) : Double;
  var
    i : Integer;
  begin
    Result := 0;
    for i:=0 to 3 do
      with Wave[i] do
        if Enabled then
          Result := Result+Amplitude*Sin(1/Length*Sqrt(Sqr(x-PosX)+Sqr(y-PosY))-Speed*t);
  end;
const
  MaxX = 30;
  MaxZ = 30;
var
  u, v : Double;
  px, py, pz : array [0..3] of Double;
  d : Double;
  NP, NI : Integer;
  BMP : TBitmap;
  k : Integer;
begin
  d := 0.5;
  NP := 0;
  NI := 0;

  Mesh1.Data.VertexBuffer.Length := Round(2*MaxX*2*MaxZ/d/d)*4;
  Mesh1.Data.IndexBuffer.Length := Round(2*MaxX*2*MaxZ/d/d)*6;

  BMP := TBitmap.Create(1,360);
  for k := 0 to 359 do
    BMP.Pixels[0,k] := CorrectColor(HSLtoRGB(k/360,0.75,0.5));

  u := -MaxX;
  while u < MaxX do begin
    v := -MaxZ;
    while v < MaxZ do begin
      px[0] := u;
      pz[0] := v;
      py[0] := f(px[0],pz[0]);

      px[1] := u+d;
      pz[1] := v;
      py[1] := f(px[1],pz[1]);

      px[2] := u+d;
      pz[2] := v+d;
      py[2] := f(px[2],pz[2]);

      px[3] := u;
      pz[3] := v+d;
      py[3] := f(px[3],pz[3]);

      with Mesh1.Data do begin
        // Set the points
        with VertexBuffer do begin
          Vertices[NP+0] := Point3D(px[0],py[0],pz[0]);
          Vertices[NP+1] := Point3D(px[1],py[1],pz[1]);
          Vertices[NP+2] := Point3D(px[2],py[2],pz[2]);
          Vertices[NP+3] := Point3D(px[3],py[3],pz[3]);
        end;

        // Map the colors
        with VertexBuffer do begin
          TexCoord0[NP+0] := PointF(0,(py[0]+35)/45);
          TexCoord0[NP+1] := PointF(0,(py[1]+35)/45);
          TexCoord0[NP+2] := PointF(0,(py[2]+35)/45);
          TexCoord0[NP+3] := PointF(0,(py[3]+35)/45);
        end;

        // Map the triangles
        IndexBuffer[NI+0] := NP+1;
        IndexBuffer[NI+1] := NP+2;
        IndexBuffer[NI+2] := NP+3;
        IndexBuffer[NI+3] := NP+3;
        IndexBuffer[NI+4] := NP+0;
        IndexBuffer[NI+5] := NP+1;
      end;

      NP := NP+4;
      NI := NI+6;
      v := v+d;
    end;
    u := u+d;
  end;

  Mesh1.Material.Texture := BMP;
end;

    メッシュのアニメーション化

上記のコードは、任意の時間 t で、4 つの波の間の相互作用の "スナップショット" を生成します。

波をアニメーション化するには、時間をインクリメントするためにタイマーを使用し、メッシュを繰り返し再生成するだけです。

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  GenerateWave(t);
  t := t+0.1;
end;

波は、このレコード型で表現されます。

type
  TWave = record
    Enabled : Boolean;
    Amplitude : Double;
    Length : Double;
    PosX : Double;
    PosY : Double;
    Speed : Double;
  end;

この記事に付属しているデモプロジェクトでは、始動する 4 つの波を宣言しました。

var
  Wave : array [0..3] of TWave = ((Enabled: False; Amplitude: 1; Length: 1; PosX: -20; PosY: -20; Speed: 1),
                                  (Enabled: False; Amplitude: 1; Length: 1; PosX: +20; PosY: -20; Speed: 1),
                                  (Enabled: False; Amplitude: 1; Length: 1; PosX: +20; PosY: +20; Speed: 1),
                                  (Enabled: False; Amplitude: 1; Length: 1; PosX: -20; PosY: +20; Speed: 1));

4 つの波のすべてが、その起点が座標系に分散しているのを除き、同じプロパティを持っていることに注意してください。具体的にそれらは (-20,-20), (+20,-20), (+20,+20), (-20,+20) に位置づけられています。

    デモアプリケーション

CodeCentral にこのデモアプリケーション のプロジェクト一式があります。

    お問い合わせ

embarcadero.com で aohlson へフィードバック等、メールでお気軽にご相談ください。

Server Response from: ETNASC04