A voxel world.

はじめに 編集

さて、ボクセルの世界を動きまわれるようになったので、ボクセルを追加、削除または変更したくなります。 ひとつめのチュートリアルでは、 シンプルな set()関数を実装して、任意のボクセルの内容を変更できるようにしました。 しかし、このトリックは、見ているのがどのブロックかを正確に判別するためのもので、より具体的にいえば、そのブロックのどの面を見ているかを判別します。

Unprojecting coordinates 編集

object selectionチュートリアルで見てきたように、ウィンドウ内の任意のピクセルの深度値を取得することができ、そして元のオブジェクト座標にその座標をunprojectできます。 現在のウィンドウの幅と高さ、 wwwh、およびビュー行列と投影行列を考えて、これを中心にあるピクセルに対して次のように行います:

glReadPixels(ww / 2, wh / 2, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);

glm::vec4 viewport = glm::vec4(0, 0, ww, wh);
glm::vec3 wincoord = glm::vec3(ww / 2, wh / 2, depth);
glm::vec3 objcoord = glm::unProject(wincoord, view, projection, viewport);

int x = floorf(objcoord).x;
int y = floorf(objcoord).y;
int z = floorf(objcoord).z;

objcoordは中心ピクセルの座標を保持しますが、シンプルに浮動小数点値を切り捨てて最も近い整数にしてボクセルの座標を取得します。 ユーザーが現在どのボクセルを見ているかを明確にするために、その周りに bounding boxを描画することができます。 ワールドとの相互作用を許可するために、マウスボタンの1つがクリックされたときに呼び出されるコールバック関数を登録することができ、そして適切なチャンクに set()を使用することで、現在選択されているボクセルを変更することができます。 set()関数はチャンクをchangedとしてマークし、次のフレームがレンダリングされるとき、これが自動的にVBOを更新して変更を反映します。

既存のボクセルを変更したり削除することはうまくいっていますが、新しいボクセルを追加することもあります。 ボクセルを追加する場合はかなり論理的で、現在選択されているボクセルの隣に、どの面を見ているかに応じて追加されます。 これを行う1つの方法は、私たちは常にボクセルの表面上の点を見ることになるので、X、Y、Z座標のいずれかが常に正確に整数値を有するべきであることを認識することです。 実際には、これが本当に問題になることはありませんが、x、y、zのどれが整数値に 最も近いかを確認することができます。 x座標が最も近い場合、2つの面のいずれかがx方向に向いていることがわかります。 x座標がカメラのX座標よりも小さい場合、正のx方向に向く面を見ていることがわかり、そしてX座標がさらに小さい場合は、他の面を見ていることになります。 なので、新しいボクセルの座標を決定するために、まず最も近い整数の距離をみちびきだす関数を定義します:

float dti(float val) {
  return fabsf(val - roundf(val));
}

その後、それを次のように使用します:

int nx = x;
int ny = y;
int nz = z;

if(dti(objcoord.x) < dti(objcoord.y))
  if(dti(objcoord.x) < dti{objcoord.z))
    if(lookat.x > 0)
      nx--;
    else
      nx++;
  else
    if(lookat.z > 0)
      nz--;
    else
      nz++;
else
  if(dti(objcoord.y) < dti{objcoord.z))
    if(lookat.y > 0)
      ny--;
    else
      ny++;
  else
    if(lookat.z > 0)
      nz--;
    else
      nz++;

この方法には非常に遠く離れているボクセルでもうまく機能するという利点があります。 欠点は、時々、丸め誤差に起因して間違ったボクセルを選択することです。 この方法のもう一つのプロパティでは、部分的に透明なテクスチャを通してボクセルを見る場合、そして透明ピクセルがフラグメントシェーダでは破棄され、テクスチャの不透明な部分の一部を正確に指していない場合、部分的に透明なボクセルの背後に見えるボクセルを選択することになります。 あなたが求めるものによっては、これは機能でもありバグでもあります。

レイキャスティング 編集

もうひとつのテクニックは、カメラから始まってあなたが見ている方向に進む直線を想像することです。 その線に沿って、ボクセルにあたるまで進むことができます。

この方法の利点は、よりいっそう正確だということです。 すべてのボクセルを不透明なものとして扱うので、部分的に透明なボクセルは見通すことができません。 欠点は、多くの計算を必要とすることで、計算量は見ているボクセルが遠くにあるほど増加します。 最大距離を制限して、近くボクセルだけを選択することが最善の方法です。