Ejemplo n.º 1
0
//----------------------------------------------------------------------------
void Node::GetVisibleSet(Culler& rCuller, Bool noCull)
{
	for (UInt i = 0; i < mEffects.GetQuantity(); i++)
	{
		// This is a global effect. Place a 'begin' marker in the visible
		// set to indicate the effect is active.
		rCuller.Insert(mEffects[i], NULL);
	}

	GetVisibleSetRenderObject(rCuller, noCull);

	// All RenderObjects in the subtree are added to the visible set. If
	// a global effect is active, the RenderObjects in the subtree will be
	// drawn using it.
	for (UInt i = 0; i < mChildren.GetQuantity(); i++)
	{
		Spatial* pChild = mChildren[i];
		if (pChild)
		{
			pChild->OnGetVisibleSet(rCuller, noCull);
		}
	}

	for (UInt i = 0; i < mEffects.GetQuantity(); i++)
	{
		// Place an 'end' marker in the visible set to indicate that the
		// global effect is inactive.
		rCuller.Insert(NULL, NULL);
	}
}
Ejemplo n.º 2
0
//----------------------------------------------------------------------------
void Node::GetVisibleSetRenderObject(Culler& rCuller, Bool noCull)
{
	const Camera* pCamera = rCuller.GetCamera();

	// Add this RenderObject if it's not culled. (Its bounding volume is
	// smaller or equal the bounding volume of this node).
	if (mspRenderObject && ((pCamera->GetLayerMask() & mLayerMask) != 0))
	{
		if (GetQuantity() == 0)
		{
			const Vector3F& rCamPos = rCuller.GetCamera()->GetLocation();
			Vector3F pos = mspRenderObjectWorldBound->GetCenter() - rCamPos;

			rCuller.Insert(mspRenderObject, &World, pos);
		}
		else
		{
			UInt savePlaneState = rCuller.GetPlaneState();
			if (noCull || rCuller.IsVisible(mspRenderObjectWorldBound, true))
			{
				const Vector3F& rCamPos = rCuller.GetCamera()->GetLocation();
				Vector3F pos = mspRenderObjectWorldBound->GetCenter() - rCamPos;

				rCuller.Insert(mspRenderObject, &World, pos);
			}

			rCuller.SetPlaneState(savePlaneState);
		}
	}
}
Ejemplo n.º 3
0
//----------------------------------------------------------------------------
void Renderable::GetVisibleSet (Culler& culler, bool)
{
	AdjustTransparent();

	const Camera *camera = culler.GetCamera();

	assertion(camera!=0, "camera must not be 0.");

	AVector cameraDir = camera->GetDVector();
	AVector diff = WorldBound.GetCenter() - camera->GetPosition();

	mEyeDistance = cameraDir.Dot(diff);

	culler.Insert(this);
}
Ejemplo n.º 4
0
//----------------------------------------------------------------------------
void Portal::GetVisibleSet (Culler& culler, bool noCull)
{
    // Visit only the adjacent region if the portal is open.
    if (!Open)
    {
        return;
    }

    // Traverse only through visible portals.
    if (!culler.IsVisible(mNumVertices, mWorldVertices, true))
    {
        return;
    }

    // It is possible that this portal is visited along a path of portals
    // from the current room containing the camera.  Such portals might
    // have a back-facing polygon relative to the camera.  It is not possible
    // to see through these, so cull them.
    const Camera* camera = culler.GetCamera();
    if (mWorldPlane.WhichSide(camera->GetPosition()) < 0)
    {
        return;
    }

    // Save the current frustum.
    float saveFrustum[6];
    const float* frustum = culler.GetFrustum();
    for (int j = 0; j < 6; ++j)
    {
        saveFrustum[j] = frustum[j];
    }

    // If the observer can see through the portal, the culler's frustum may
    // be reduced in size based on the portal geometry.
    float reducedFrustum[6];
    if (ReducedFrustum(culler, reducedFrustum))
    {
        // Use the reduced frustum for drawing the adjacent region.
        culler.SetFrustum(reducedFrustum);

        // Visit the adjacent region and any nonculled objects in it.
        AdjacentRegion->GetVisibleSet(culler, noCull);

        // Restore the previous frustum.
        culler.SetFrustum(saveFrustum);
    }
}
//----------------------------------------------------------------------------
void TerrainPage::GetVisibleSet (Culler& culler, bool noCull)
{
	TriMesh::GetVisibleSet(culler, noCull);

	for (int i=0; i<(int)mJunglers.size(); i++)
	{
		culler.Insert(mJunglers[i]);
	}
}
Ejemplo n.º 6
0
//----------------------------------------------------------------------------
void Spatial::OnGetVisibleSet (Culler& culler, bool noCull)
{
    if (Culling == CULL_ALWAYS)
    {
        return;
    }

    if (Culling == CULL_NEVER)
    {
        noCull = true;
    }

    unsigned int savePlaneState = culler.GetPlaneState();
    if (noCull || culler.IsVisible(WorldBound))
    {
        GetVisibleSet(culler, noCull);
    }
    culler.SetPlaneState(savePlaneState);
}
Ejemplo n.º 7
0
//----------------------------------------------------------------------------
void NodeSkybox::GetVisibleSet(Culler& rCuller, Bool noCull)
{
	const Float sqrtOfThree = 1.7320508F;
	const Camera* const pCamera = rCuller.GetCamera();
	Float scale = pCamera->GetDMax() * 0.25F * sqrtOfThree;
	World.SetTranslate(pCamera->GetLocation());
	World.SetUniformScale(scale);

	Node::UpdateWorldData(mAppTime, true);
	Node::GetVisibleSet(rCuller, noCull);
}
Ejemplo n.º 8
0
//----------------------------------------------------------------------------
void Particles::GetVisibleSet (Culler& culler, bool noCull)
{
    GenerateParticles(culler.GetCamera());
    TriMesh::GetVisibleSet(culler, noCull);
}
Ejemplo n.º 9
0
//----------------------------------------------------------------------------
bool Portal::ReducedFrustum (const Culler& culler,
                             float reducedFrustum[6])
{
    // The portal polygon is transformed into the camera coordinate system
    // and projected onto the near plane.  An axis-aligned bounding rectangle
    // is computed for the projected points and clipped against the left,
    // right, bottom, and top frustum planes.  The result is itself an
    // axis-aligned bounding rectangle that is used to define a "reduced
    // frustum" to be used for drawing what is visible through the portal
    // polygon.
    //
    // The algorithm must handle the situation when portal polygon vertices
    // are behind the observer.  Imagine standing in a room with a doorway
    // immediately to your left.  Part of the doorway frame is in front of
    // you (and visible) and part of it is behind you (and not visible).
    // A portal point is represented by P = E + d*D + u*U + r*R, where E is
    // the world location for the eye point, D is the camera's world direction
    // vector, U is the camera's world up vector, and R is the camera's world
    // right vector.  The camera coordinates for the portal point are (d,u,r).
    // If d > 0, P is in front of the eye point and has a projection onto the
    // near plane d = n.  If d < 0, P is behind the eye point and does not
    // have a projection onto the near plane.  If d = 0, P projects to
    // "infinity" on the near plane, a problematic case to deal with.
    //
    // To avoid dealing with d = 0, choose a small value e such that
    // 0 < e < n.  The portal polygon is clipped against the plane d = e,
    // keeping only that portion whose points satisfy d >= e.  The clipped
    // polygon always has a projection onto the near plane.  The axis-aligned
    // bounding box for this projection is computed; clipped against the
    // left, right, bottom, and top of the frustum; and the result used to
    // define the reduced frustum.  All this is designed for an inexact
    // culling of the objects in the adjacent room, so it is useful to avoid
    // preserving the topology of the portal polygon as it is clipped.
    // Instead, the portal polygon vertices with d > e are projected and
    // the intersection points of portal polygon edges with d = e are
    // computed and projected.  The axis-aligned bounding box is computed for
    // the projections, a process that does not require knowing the polygon
    // topology.  The algorithm is essentially the one used for clipping a
    // convex polygon against the view frustum in the software renderer.  The
    // polygon vertices are traversed in-order and the signs of the d values
    // are updated accordingly.  This avoids computing d-signs twice per
    // vertex.

    const Camera* camera = culler.GetCamera();
    const float* frustum = culler.GetFrustum();
    float rmin = +Mathf::MAX_REAL;  // left
    float rmax = -Mathf::MAX_REAL;  // right
    float umin = +Mathf::MAX_REAL;  // bottom
    float umax = -Mathf::MAX_REAL;  // top

    AVector diff;
    APoint vertexCam;
    int i;

    if (camera->IsPerspective())
    {
        const float epsilon = 1e-6f, invEpsilon = 1e+6f;
        int firstSign = 0, lastSign = 0;  // in {-1,0,1}
        bool signChange = false;
        APoint firstVertex = APoint::ORIGIN;
        APoint lastVertex = APoint::ORIGIN;
        float NdD, UdD, RdD, t;

        for (i = 0; i < mNumVertices; i++)
        {
            diff = mWorldVertices[i] - camera->GetPosition();
            vertexCam[0] = diff.Dot(camera->GetDVector());
            vertexCam[1] = diff.Dot(camera->GetUVector());
            vertexCam[2] = diff.Dot(camera->GetRVector());
            vertexCam[3] = 1.0f;

            if (vertexCam[0] > epsilon)
            {
                if (firstSign == 0)
                {
                    firstSign = 1;
                    firstVertex = vertexCam;
                }

                NdD = frustum[Camera::VF_DMIN]/vertexCam[0];
                UdD = vertexCam[1]*NdD;
                RdD = vertexCam[2]*NdD;

                if (UdD < umin)
                {
                    umin = UdD;
                }
                if (UdD > umax)
                {
                    umax = UdD;
                }

                if (RdD < rmin)
                {
                    rmin = RdD;
                }
                if (RdD > rmax)
                {
                    rmax = RdD;
                }

                if (lastSign < 0)
                {
                    signChange = true;
                }

                lastSign = 1;
            }
            else
            {
                if (firstSign == 0)
                {
                    firstSign = -1;
                    firstVertex = vertexCam;
                }

                if (lastSign > 0)
                {
                    signChange = true;
                }

                lastSign = -1;
            }

            if (signChange)
            {
                diff = vertexCam - lastVertex;
                t = (epsilon - lastVertex[0])/diff[0];
                NdD = frustum[Camera::VF_DMIN]*invEpsilon;
                UdD = (lastVertex[1] + t*diff[1])*NdD;
                RdD = (lastVertex[2] + t*diff[2])*NdD;

                if (UdD < umin)
                {
                    umin = UdD;
                }
                if (UdD > umax)
                {
                    umax = UdD;
                }

                if (RdD < rmin)
                {
                    rmin = RdD;
                }
                if (RdD > rmax)
                {
                    rmax = RdD;
                }

                signChange = false;
            }

            lastVertex = vertexCam;
        }

        if (firstSign*lastSign < 0)
        {
            // Process the last polygon edge.
            diff = firstVertex - lastVertex;
            t = (epsilon - lastVertex[0])/diff[0];
            UdD = (lastVertex[1] + t*diff[1])*invEpsilon;
            RdD = (lastVertex[2] + t*diff[2])*invEpsilon;

            if (UdD < umin)
            {
                umin = UdD;
            }
            if (UdD > umax)
            {
                umax = UdD;
            }

            if (RdD < rmin)
            {
                rmin = RdD;
            }
            if (RdD > rmax)
            {
                rmax = RdD;
            }
        }
    }
    else
    {
        for (i = 0; i < mNumVertices; i++)
        {
            diff = mWorldVertices[i] - camera->GetPosition();
            vertexCam[1] = diff.Dot(camera->GetUVector());
            vertexCam[2] = diff.Dot(camera->GetRVector());

            if (vertexCam[1] < umin)
            {
                umin = vertexCam[1];
            }
            if (vertexCam[1] > umax)
            {
                umax = vertexCam[1];
            }

            if (vertexCam[2] < rmin)
            {
                rmin = vertexCam[2];
            }
            if (vertexCam[2] > rmax)
            {
                rmax = vertexCam[2];
            }
        }
    }

    // Test whether the axis-aligned bounding rectangle is outside the current
    // frustum.  If it is, the adjoining room need not be visited.
    if (frustum[Camera::VF_RMIN] >= rmax ||
            frustum[Camera::VF_RMAX] <= rmin ||
            frustum[Camera::VF_UMIN] >= umax ||
            frustum[Camera::VF_UMAX] <= umin)
    {
        return false;
    }

    // The axis-aligned bounding rectangle intersects the current frustum.
    // Reduce the frustum for use in drawing the adjoining room.
    for (int j = 0; j < 6; ++j)
    {
        reducedFrustum[j] = frustum[j];
    }

    if (reducedFrustum[Camera::VF_RMIN] < rmin)
    {
        reducedFrustum[Camera::VF_RMIN] = rmin;
    }

    if (reducedFrustum[Camera::VF_RMAX] > rmax)
    {
        reducedFrustum[Camera::VF_RMAX] = rmax;
    }

    if (reducedFrustum[Camera::VF_UMIN] < umin)
    {
        reducedFrustum[Camera::VF_UMIN] = umin;
    }

    if (reducedFrustum[Camera::VF_UMAX] > umax)
    {
        reducedFrustum[Camera::VF_UMAX] = umax;
    }

    return true;
}
Ejemplo n.º 10
0
//----------------------------------------------------------------------------
void Visual::GetVisibleSet (Culler& culler, bool)
{
    culler.Insert(this);
}
Ejemplo n.º 11
0
//----------------------------------------------------------------------------
void BspNode::GetVisibleSet (Culler& culler, bool noCull)
{
    // Get visible Geometry in back-to-front order.  If a global effect is
    // active, the Geometry objects in the subtree will be drawn using it.
    SpatialPtr posChild = GetPositiveChild();
    SpatialPtr copChild = GetCoplanarChild();
    SpatialPtr negChild = GetNegativeChild();

    const Camera* camera = culler.GetCamera();
    int positionSide = mWorldPlane.WhichSide(camera->GetPosition());
    int frustumSide = culler.WhichSide(mWorldPlane);

    if (positionSide > 0)
    {
        // Camera origin on positive side of plane.

        if (frustumSide <= 0)
        {
            // The frustum is on the negative side of the plane or straddles
            // the plane.  In either case, the negative child is potentially
            // visible.
            if (negChild)
            {
                negChild->OnGetVisibleSet(culler, noCull);
            }
        }

        if (frustumSide == 0)
        {
            // The frustum straddles the plane.  The coplanar child is
            // potentially visible.
            if (copChild)
            {
                copChild->OnGetVisibleSet(culler, noCull);
            }
        }

        if (frustumSide >= 0)
        {
            // The frustum is on the positive side of the plane or straddles
            // the plane.  In either case, the positive child is potentially
            // visible.
            if (posChild)
            {
                posChild->OnGetVisibleSet(culler, noCull);
            }
        }
    }
    else if (positionSide < 0)
    {
        // Camera origin on negative side of plane.

        if (frustumSide >= 0)
        {
            // The frustum is on the positive side of the plane or straddles
            // the plane.  In either case, the positive child is potentially
            // visible.
            if (posChild)
            {
                posChild->OnGetVisibleSet(culler, noCull);
            }
        }

        if (frustumSide == 0)
        {
            // The frustum straddles the plane.  The coplanar child is
            // potentially visible.
            if (copChild)
            {
                copChild->OnGetVisibleSet(culler, noCull);
            }
        }

        if (frustumSide <= 0)
        {
            // The frustum is on the negative side of the plane or straddles
            // the plane.  In either case, the negative child is potentially
            // visible.
            if (negChild)
            {
                negChild->OnGetVisibleSet(culler, noCull);
            }
        }
    }
    else
    {
        // Camera origin on plane itself.  Both sides of the plane are
        // potentially visible as well as the plane itself.  Select the
        // first-to-be-drawn half space to be the one to which the camera
        // direction points.
        float NdD = mWorldPlane.GetNormal().Dot(camera->GetDVector());
        if (NdD >= 0.0f)
        {
            if (posChild)
            {
                posChild->OnGetVisibleSet(culler, noCull);
            }

            if (copChild)
            {
                copChild->OnGetVisibleSet(culler, noCull);
            }

            if (negChild)
            {
                negChild->OnGetVisibleSet(culler, noCull);
            }
        }
        else
        {
            if (negChild)
            {
                negChild->OnGetVisibleSet(culler, noCull);
            }

            if (copChild)
            {
                copChild->OnGetVisibleSet(culler, noCull);
            }

            if (posChild)
            {
                posChild->OnGetVisibleSet(culler, noCull);
            }
        }
    }
}
Ejemplo n.º 12
0
//----------------------------------------------------------------------------
void DlodNode::GetVisibleSet (Culler& culler, bool noCull)
{
    SelectLevelOfDetail(culler.GetCamera());
    SwitchNode::GetVisibleSet(culler, noCull);
}
Ejemplo n.º 13
0
//----------------------------------------------------------------------------
void NodeCamera::Draw(TArray<NodeCamera*>& rNodeCameras, Spatial* pRoot,
	Culler& rCuller, Renderer* pRenderer)
{
	WIRE_ASSERT(pRenderer && pRoot);
	if (!pRenderer || !pRoot)
	{
		return;
	}

	const UInt maxCameraCount = 64;
	if (rNodeCameras.GetQuantity() >= 64)
	{
		WIRE_ASSERT(false);
		return;
	}

	// cull all skyboxes attached to cameras in the scene
	Spatial::CullingMode tempCullingModes[maxCameraCount];
	for (UInt i = 0; i < rNodeCameras.GetQuantity(); i++)
	{
		NodeCamera* pNodeCamera = rNodeCameras[i];
		WIRE_ASSERT(pNodeCamera);
		Node* pSkybox = pNodeCamera->mspSkybox;
		if (pSkybox && pNodeCamera->IsEnabled())
		{
			tempCullingModes[i] = pSkybox->Culling;
			pSkybox->Culling = Spatial::CULL_ALWAYS;
		}
	}

	for (UInt i = 0; i < rNodeCameras.GetQuantity(); i++)
	{
		NodeCamera* pNodeCamera = rNodeCameras[i];
		WIRE_ASSERT(pNodeCamera && pNodeCamera->Get());
		if (!pNodeCamera->IsEnabled())
		{
			continue;
		}

		Camera* pCamera = pNodeCamera->Get();

		rCuller.SetCamera(pCamera);
		rCuller.ComputeVisibleSet(pRoot);

		Float left;
		Float right;
		Float top;
		Float bottom;
		pCamera->GetViewport(left, right, top, bottom);
		UInt width = pRenderer->GetWidth();
		UInt height = pRenderer->GetHeight();
		Vector4F rect;
		rect.X() = MathF::Round(left*width);
		rect.Y() = MathF::Round((1.0F-top)*height);
		rect.Z() = MathF::Round((right-left)*width);
		rect.W() = MathF::Round((top-bottom)*height);

		ColorRGBA clearColor = pRenderer->GetClearColor();
		switch (rNodeCameras[i]->mClearFlag)
		{
		case CF_ALL:
			pRenderer->SetClearColor(pNodeCamera->GetClearColor());
			pRenderer->ClearBuffers(true, true, rect);
			pRenderer->SetClearColor(clearColor);
			break;

		case CF_Z_ONLY:
			pRenderer->ClearBuffers(false, true, rect);
			break;

		case CF_NONE:		
			break;

		default:
			WIRE_ASSERT(false);
		}

		pRenderer->SetCamera(pCamera);
		pRenderer->Draw(rCuller.GetVisibleSets());

		Node* pSkybox = pNodeCamera->mspSkybox;
		if (pSkybox)
		{
			pSkybox->Culling = Spatial::CULL_NEVER;
			rCuller.ComputeVisibleSet(pSkybox);
			pRenderer->Draw(rCuller.GetVisibleSets());
			pSkybox->Culling = Spatial::CULL_ALWAYS;
		}
	}

	// restore culling mode of all skyboxes attached to cameras in the scene
	for (UInt i = 0; i < rNodeCameras.GetQuantity(); i++)
	{
		NodeCamera* pNodeCamera = rNodeCameras[i];
		WIRE_ASSERT(pNodeCamera);
		Node* pSkybox = pNodeCamera->mspSkybox;
		if (pSkybox && pNodeCamera->IsEnabled())
		{
			pSkybox->Culling = tempCullingModes[i];
		}
	}
}