确定3D对象是否被另一个3D对象隐藏

时间:2012-07-09 13:07:59

标签: wpf 3d

我在Viewport3D中有一些GeometryModel3D球,其中一些是可见的,其中一些被蓝色立方体隐藏。 (下图中的图像是2d,假设所有对象都是3D)

我想确定哪些红球可以看到,哪些是隐藏的。

我该怎么做?

enter image description here

1 个答案:

答案 0 :(得分:0)

此问题也称为Occlusion Culling,尽管您对计算被遮挡的基元感兴趣。鉴于您的场景条件,解决此问题的蛮力方法(假设您正在使用透视投影)是以下伪代码:

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

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

获取projectionMatrix的方法是使用以下代码(从here中提取):

    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
     +----------+--+--------------+
     |          | -|-             | 
     |         /|  |  \           |
     |        | |  |   |          |
     |         \|  |  /           |
     |          | -|-             |  
     +----------+--+--------------+

其中两个截取立方体遮挡了球体,在这种情况下,当两个或多个立方体区域截取时,您必须构建一组规范化立方体(Set{ Set{ cube1, cube2}, Set{cube3, cube4}, ... })(可以在第一个循环中完成)并且争用测试会更复杂。不知道你的程序是否允许(立方体拦截)

这个算法是O(n^2),因为它是一种蛮力的方法,希望这可以给你一个明确的解决方案的提示,如果你正在寻找一个有效的更通用的解决方案,请使用类似{{{ 3}}