Improving the efficiency of frustum culling
- by DeadMG
I've got some code which performs frustum culling. However, this defines the "frustum" way too broadly- when I have ~10 objects on screen, the code returns 42 objects to be rendered. I've tried taking "slices" through the frustum to attempt to increase the accuracy of the technique, but it doesn't seem to have made much impact. I also significantly reduced the far plane, so that the objects are barely at the edge. Here's my code (where size is the size in screen space- the resolution of the client area of the window I'm rendering into). Any suggestions?
auto&& size = GetDimensions();
D3DVIEWPORT9 vp = { 0, 0, size.x, size.y, 0, 1 };
D3DCALL(device->SetViewport(&vp));
static const int slices = 10;
std::vector<Object*> result;
for(int i = 0; i < slices; i++) {
D3DXVECTOR3 WorldSpaceFrustrumPoints[8] = {
D3DXVECTOR3(0, size.y, static_cast<float>(i) / slices),
D3DXVECTOR3(size.x, 0, static_cast<float>(i) / slices),
D3DXVECTOR3(size.x, size.y, static_cast<float>(i) / slices),
D3DXVECTOR3(0, 0, static_cast<float>(i) / slices),
D3DXVECTOR3(0, 0, static_cast<float>(i + 1) / slices),
D3DXVECTOR3(size.x, 0, static_cast<float>(i + 1) / slices),
D3DXVECTOR3(size.x, size.y, static_cast<float>(i + 1) / slices),
D3DXVECTOR3(0, size.y, static_cast<float>(i + 1) / slices)
};
D3DXMATRIXA16 Identity;
D3DXMatrixIdentity(&Identity);
D3DXVec3UnprojectArray(
WorldSpaceFrustrumPoints,
sizeof(D3DXVECTOR3),
WorldSpaceFrustrumPoints,
sizeof(D3DXVECTOR3),
&vp,
&Projection,
&View,
&Identity,
8
);
Math::AABB Frustrum;
auto world_begin = std::begin(WorldSpaceFrustrumPoints);
auto world_end = std::end(WorldSpaceFrustrumPoints);
auto world_initial = WorldSpaceFrustrumPoints[0];
Frustrum.BottomLeftClosest.x = std::accumulate(world_begin, world_end, world_initial, [](D3DXVECTOR3 lhs, D3DXVECTOR3 rhs) { return lhs.x < rhs.x ? lhs : rhs; }).x;
Frustrum.BottomLeftClosest.y = std::accumulate(world_begin, world_end, world_initial, [](D3DXVECTOR3 lhs, D3DXVECTOR3 rhs) { return lhs.y < rhs.y ? lhs : rhs; }).y;
Frustrum.BottomLeftClosest.z = std::accumulate(world_begin, world_end, world_initial, [](D3DXVECTOR3 lhs, D3DXVECTOR3 rhs) { return lhs.z < rhs.z ? lhs : rhs; }).z;
Frustrum.TopRightFurthest.x = std::accumulate(world_begin, world_end, world_initial, [](D3DXVECTOR3 lhs, D3DXVECTOR3 rhs) { return lhs.x > rhs.x ? lhs : rhs; }).x;
Frustrum.TopRightFurthest.y = std::accumulate(world_begin, world_end, world_initial, [](D3DXVECTOR3 lhs, D3DXVECTOR3 rhs) { return lhs.y > rhs.y ? lhs : rhs; }).y;
Frustrum.TopRightFurthest.z = std::accumulate(world_begin, world_end, world_initial, [](D3DXVECTOR3 lhs, D3DXVECTOR3 rhs) { return lhs.z > rhs.z ? lhs : rhs; }).z;
auto slices_result = ObjectTree.collision(Frustrum);
result.insert(result.end(), slices_result.begin(), slices_result.end());
}
return result;