Viewport3D に GeometryModel3D ボールがいくつかあります。そのうちのいくつかは表示され、いくつかは青い立方体によって隠されています。(下の画像は 2D ですが、すべてのオブジェクトが 3D であると仮定します)
どの赤いボールが見えるか、どれが隠れているかを判断したいと思います。
これどうやってするの ?
この問題はオクルージョン カリングとしても知られていますが、オクルージョンされたプリミティブを数えることに関心があります。シーンの条件を考えると、この問題を解決するためのブルート フォース アプローチ (透視投影を使用している場合) は、次の疑似コードです。
occludedSpheresCount = 0
spheres = {Set of spheres}
cubes = {Set of cubes}
normalizedCubes = {}
# First, build the set of normalized cubes (it means,
# take the cubes that are free in space and transform their
# coordinates to values between [-1, -1, -1] and [1, 1, 1], they are the same
# cubes but now the coordinates are laying in that range
# To do that, use the
射影行列
projectionMatrix = GetProjectionMatrix(perspectiveCamera)
for each cube in cubes do
Rect3D boundingBox = cube.Bounds()
Rect3D normalizedBBox = projectionMatrix.transform(boundingBox)
cubes_normalized.add(normalizedBBox)
end for
# Now search every sphere, normalize it's bounding box
# and check if it's been occluded by some normalized cube
for each sphere in spheres do
Rect3D sphereBBox = sphere.Bounds()
Rect3D normalizedSphere = projectionMatrix.transform(sphereBBox)
for each normalizedCube in normalizedCubes do
x0 = normalizedCube.Location.X - (normalizedCube.Location.SizeX / 2)
y0 = normalizedCube.Location.Y - (normalizedCube.Location.SizeY / 2)
z0 = normalizedCube.Location.Z - (normalizedCube.Location.SizeZ / 2)
xf = normalizedCube.Location.X + (normalizedCube.Location.SizeX / 2)
yf = normalizedCube.Location.Y + (normalizedCube.Location.SizeY / 2)
sx0 <- normalizedSphere.Location.X - (normalizedSphere.Location.SizeX / 2)
sy0 <- normalizedSphere.Location.X - (normalizedSphere.Location.SizeY / 2)
sz0 <- normalizedSphere.Location.X - (normalizedSphere.Location.SizeZ / 2)
sxf <- normalizedSphere.Location.X + (normalizedSphere.Location.SizeX / 2)
syf <- normalizedSphere.Location.X + (normalizedSphere.Location.SizeY / 2)
# First, let's check that the normalized-sphere is behind the
# normalized-cube, to do that, let's compare their z-front values
if z0 > sz0 then
# Now that we know that the sphere is behind the frontface of the cube
# lets check if it is fully contained inside the
# the normalized-cube, in that case, it is occluded
if sx0 >= x0 and sxf <= xf and sy0 >= y0 and syf >= yf then
occludedSpheresCount++
# Here you can even avoid rendering the sphere altogether
end if
end if
end for
end for
projectMatrix を取得する方法は、次のコードを使用することです (ここから抽出)。
private static Matrix3D GetProjectionMatrix(PerspectiveCamera camera, double aspectRatio)
{
// This math is identical to what you find documented for
// D3DXMatrixPerspectiveFovRH with the exception that in
// WPF the camera's horizontal rather the vertical
// field-of-view is specified.
double hFoV = MathUtils.DegreesToRadians(camera.FieldOfView);
double zn = camera.NearPlaneDistance;
double zf = camera.FarPlaneDistance;
double xScale = 1 / Math.Tan(hFoV / 2);
double yScale = aspectRatio * xScale;
double m33 = (zf == double.PositiveInfinity) ? -1 : (zf / (zn - zf));
double m43 = zn * m33;
return new Matrix3D(
xScale, 0, 0, 0,
0, yScale, 0, 0,
0, 0, m33, -1,
0, 0, m43, 0);
}
この方法の唯一の欠点は、次の場合です。
+-------------+--------------+ | | -|- | | | / | \ | | | | | | | | | | | | | \ | / | | | -|- | +-------------+--------------+ また ここでインターセプト | | v +----------+--+--------------+ | | | | -|- | | | /| | | \ | | | | | | | | | | | | | | | \| | | / | | | | | -|- | +----------+--+--------------+
Set{ Set{ cube1, cube2}, Set{cube3, cube4}, ... }
2 つのインターセプト キューブが球体を遮る場合、 2 つ以上のキューブ エリアがインターセプトし (最初のループで実行できます)、競合テストがより多くの場合、正規化されたキューブのセットのセット ( ) を構築する必要があります。繁雑。ただし、それ(キューブのインターセプト)がプログラムで許可されているかどうかはわかりません
このアルゴリズムはO(n^2)
力ずくのアプローチであるためです。これが決定的な解決策のヒントになることを願っています。効率的でより一般的な解決策を探している場合は、階層型 Z バッファリングのようなものを使用してください。