
Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
NVIDIAのIsland11を改造して作っています。
題の通り物を水面に浮かべたいのですが、ゲルストナー波はHLSLで実装したので現状CPUから水面の動きを取得する方法がありません。しかし、波のパラメータはCPU側でも分かっているので、C++でも同じ計算を実装すれば目的を達成できます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct Wave | |
{ | |
Vec2 dir; | |
float amplitude; | |
float waveLength; | |
}; | |
struct ImmutableCB | |
{ | |
float waveSteepness; | |
float waveSpeed; | |
Wave waves[20]; | |
}; | |
static Vec3 CalcGerstnerWaveOffset(const ImmutableCB& cb, Vec3 location, float time) | |
{ | |
Vec3 sum = Vec3(0, 0, 0); | |
for (int i = 0; i < dimof(cb.waves); i++) | |
{ | |
const Wave& wave = cb.waves[i]; | |
float wi = 2 / wave.waveLength; | |
float rad = (dot(wave.dir, Vec2(location.x, location.z)) + time * cb.waveSpeed) * wi; | |
float sine = std::sin(rad); | |
float cosine = std::cos(rad); | |
sum.y += sine * wave.amplitude; | |
sum.x += wave.dir.x * cosine * cb.waveSteepness / (wi * dimof(cb.waves)); | |
sum.z += wave.dir.y * cosine * cb.waveSteepness / (wi * dimof(cb.waves)); | |
} | |
return sum; | |
} |
ほぼ機械的にHLSLからそのまま持ってきただけです。ImmutableCBはコンスタントバッファになる構造体で、GPUと共有する波のパラメータの集まりです。この波のパラメータは一度決定したら書き換えません。変化するのはtimeだけで、現在時刻だけ毎フレームC++とHLSLで同期すれば任意の地点の海水面の移動量が一意に決定します。
あとは、描画したいメッシュの座標をCalcGerstnerWaveOffsetにlocationとして渡せばVec3の移動量が取得できるので、それを足して描画すれば上のアニメーションが得られます。
更に、ここからキューブを波に沿って傾けることを考えてみます。

Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
HLSLでやったように微分して法線を得る事でもできそうですが、予想される結果として戦艦のような大きなものを局所的な法線で傾けるとおかしくなりそうです。今回は海面から任意の3点を取得してそれの属する平面の法線を使うことにします。これなら、大きな物体は3点をなるべく離れた場所に設定することで傾きすぎないようにするなどの調整ができます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Vec3 center = pos + CalcGerstnerWaveOffset(immutableCb, pos, terrainFrameCB.g_time); | |
Vec3 offsetXZ = pos + Vec3(1, 0, 1) + CalcGerstnerWaveOffset(immutableCb, pos + Vec3(1, 0, 1), terrainFrameCB.g_time); | |
Vec3 offsetNegX = pos + Vec3(-1, 0, 0) + CalcGerstnerWaveOffset(immutableCb, pos + Vec3(-1, 0, 0), terrainFrameCB.g_time); | |
Vec3 offsetNegZ = pos + Vec3(0, 0, -1) + CalcGerstnerWaveOffset(immutableCb, pos + Vec3(0, 0, -1), terrainFrameCB.g_time); | |
Vec3 normal = normalize(cross(offsetNegZ - offsetXZ, offsetNegX - offsetXZ)); | |
Vec3 rotAxis = normalize(cross(normal, Vec3(0, 1, 0))); | |
float rotRad = acos(dot(normal, Vec3(0, 1, 0))); | |
cube.Draw(MeshXAnimResult(), scale(5, 5, 5) * q2m(Quat(rotAxis, -rotRad)) * translate(center.x, center.y, center.z)); |
No comments:
Post a Comment