Wpf 确定一个三维对象是否被另一个三维对象隐藏
我在Viewport3D中有一些GeometryModel3D球,其中一些球是可见的,一些球被蓝色立方体隐藏。 (尽管下面的图像是二维的,但让我们假设所有对象都是三维的) 我想确定哪些红球可以看到,哪些是隐藏的 我该怎么做Wpf 确定一个三维对象是否被另一个三维对象隐藏,wpf,3d,Wpf,3d,我在Viewport3D中有一些GeometryModel3D球,其中一些球是可见的,一些球被蓝色立方体隐藏。 (尽管下面的图像是二维的,但让我们假设所有对象都是三维的) 我想确定哪些红球可以看到,哪些是隐藏的 我该怎么做 此问题也称为,尽管您对计算被遮挡的基本体感兴趣。根据场景的条件,解决此问题的暴力方法(假设使用透视投影)是以下伪代码: occludedSpheresCount = 0 spheres = {Set of spheres} cubes = {Set of cubes} nor
此问题也称为,尽管您对计算被遮挡的基本体感兴趣。根据场景的条件,解决此问题的暴力方法(假设使用透视投影)是以下伪代码:
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
这种方法的唯一缺点是在以下情况下:
+--------------+--------------+
| -|- |
| / | \ |
| | | | |
| \ | / |
| -|- |
+--------------+--------------+
or
interception here
|
v
+----------+--+--------------+
| | -|- |
| /| | \ |
| | | | | |
| \| | / |
| | -|- |
+----------+--+--------------+
+--------------+--------------+
| -|- |
| / | \ |
| | | | |
| \ | / |
| -|- |
+--------------+--------------+
或
这里拦截
|
v
+----------+--+--------------+
| | -|- |
| /| | \ |
| | | | | |
| \| | / |
| | -|- |
+----------+--+--------------+
在这种情况下,当两个或多个多维数据集区域被拦截(可以在第一个循环中完成)时,您必须构建一组规范化多维数据集(set{set{cube1,cube2},set{cube3,cube4},…}
),并且争用测试将更加复杂。但我不知道你的程序中是否允许(多维数据集拦截)
这个算法是
O(n^2)
,因为这是一个蛮力方法,希望这能给你一个最终解决方案的提示,如果你想寻找一个更有效的更一般的解决方案,请使用类似于的东西你想知道球是否部分隐藏吗?或者你需要对它们进行二进制测试?h3nr1x-如果它只是部分隐藏,我认为它不是隐藏的。球体基本体是以对{center,radius}的形式存储还是以模型网格的形式存储(如果你以模型网格的形式存储它们,你是否存储它们的中心和半径)?立方体基本体是否存储为边界框?您使用的是正交投影还是透视投影?(我需要详细说明解决方案的信息)感谢h3nr1x-我使用MeshGeometry3Ds。如果有帮助的话,我可以存储它们的中心和半径,我正在使用PerspectiveCamera。谢谢h3nr1x,我没有成功地将您的伪代码转换为c#,WPF,所以我不知道这是否是正确的答案。
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
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);
}
+--------------+--------------+
| -|- |
| / | \ |
| | | | |
| \ | / |
| -|- |
+--------------+--------------+
or
interception here
|
v
+----------+--+--------------+
| | -|- |
| /| | \ |
| | | | | |
| \| | / |
| | -|- |
+----------+--+--------------+