Exemplo n.º 1
0
    // ------------------------------------------------------------------------
    void ShadowCaster::generateShadowVolume(EdgeData* edgeData, 
        const HardwareIndexBufferSharedPtr& indexBuffer, size_t& indexBufferUsedSize, 
        const Light* light, ShadowRenderableList& shadowRenderables, unsigned long flags)
    {
        // Edge groups should be 1:1 with shadow renderables
        assert(edgeData->edgeGroups.size() == shadowRenderables.size());

        Light::LightTypes lightType = light->getType();

        // Whether to use the McGuire method, a triangle fan covering all silhouette
        // This won't work properly with multiple separate edge groups (should be one fan per group, not implemented)
        // or when light position is too close to light cap bound.
        bool useMcGuire = edgeData->edgeGroups.size() <= 1 && 
            (lightType == Light::LT_DIRECTIONAL || isBoundOkForMcGuire(getLightCapBounds(), light->getDerivedPosition()));
        EdgeData::EdgeGroupList::const_iterator egi, egiend;
        ShadowRenderableList::const_iterator si;

        // pre-count the size of index data we need since it makes a big perf difference
        // to GL in particular if we lock a smaller area of the index buffer
        size_t preCountIndexes = 0;

        si = shadowRenderables.begin();
        egiend = edgeData->edgeGroups.end();
        for (egi = edgeData->edgeGroups.begin(); egi != egiend; ++egi, ++si)
        {
            const EdgeData::EdgeGroup& eg = *egi;
            bool  firstDarkCapTri = true;

            EdgeData::EdgeList::const_iterator i, iend;
            iend = eg.edges.end();
            for (i = eg.edges.begin(); i != iend; ++i)
            {
                const EdgeData::Edge& edge = *i;

                // Silhouette edge, when two tris has opposite light facing, or
                // degenerate edge where only tri 1 is valid and the tri light facing
                char lightFacing = edgeData->triangleLightFacings[edge.triIndex[0]];
                if ((edge.degenerate && lightFacing) ||
                    (!edge.degenerate && (lightFacing != edgeData->triangleLightFacings[edge.triIndex[1]])))
                {

                    preCountIndexes += 3;

                    // Are we extruding to infinity?
                    if (!(lightType == Light::LT_DIRECTIONAL &&
                        flags & SRF_EXTRUDE_TO_INFINITY))
                    {
                        preCountIndexes += 3;
                    }

                    if(useMcGuire)
                    {
                        // Do dark cap tri
                        // Use McGuire et al method, a triangle fan covering all silhouette
                        // edges and one point (taken from the initial tri)
                        if (flags & SRF_INCLUDE_DARK_CAP)
                        {
                            if (firstDarkCapTri)
                            {
                                firstDarkCapTri = false;
                            }
                            else
                            {
                                preCountIndexes += 3;
                            }
                        }
                    }
                }

            }

            if(useMcGuire)
            {
                // Do light cap
                if (flags & SRF_INCLUDE_LIGHT_CAP) 
                {
                    // Iterate over the triangles which are using this vertex set
                    EdgeData::TriangleList::const_iterator ti, tiend;
                    EdgeData::TriangleLightFacingList::const_iterator lfi;
                    ti = edgeData->triangles.begin() + eg.triStart;
                    tiend = ti + eg.triCount;
                    lfi = edgeData->triangleLightFacings.begin() + eg.triStart;
                    for ( ; ti != tiend; ++ti, ++lfi)
                    {
                        assert(ti->vertexSet == eg.vertexSet);
                        // Check it's light facing
                        if (*lfi)
                        {
                            preCountIndexes += 3;
                        }
                    }

                }
            }
            else
            {
                // Do both caps
                int increment = ((flags & SRF_INCLUDE_DARK_CAP) ? 3 : 0) + ((flags & SRF_INCLUDE_LIGHT_CAP) ? 3 : 0);
                if(increment != 0)
                {
                    // Iterate over the triangles which are using this vertex set
                    EdgeData::TriangleList::const_iterator ti, tiend;
                    EdgeData::TriangleLightFacingList::const_iterator lfi;
                    ti = edgeData->triangles.begin() + eg.triStart;
                    tiend = ti + eg.triCount;
                    lfi = edgeData->triangleLightFacings.begin() + eg.triStart;
                    for ( ; ti != tiend; ++ti, ++lfi)
                    {
                        assert(ti->vertexSet == eg.vertexSet);
                        // Check it's light facing
                        if (*lfi)
                            preCountIndexes += increment;
                    }
                }
            }
        }
        // End pre-count
        
        //Check if index buffer is to small 
        if (preCountIndexes > indexBuffer->getNumIndexes())
        {
            LogManager::getSingleton().logWarning(
                "shadow index buffer size to small. Auto increasing buffer size to" +
                StringConverter::toString(sizeof(unsigned short) * preCountIndexes));

            SceneManager* pManager = Root::getSingleton()._getCurrentSceneManager();
            if (pManager)
            {
                pManager->setShadowIndexBufferSize(preCountIndexes);
            }
            
            //Check that the index buffer size has actually increased
            if (preCountIndexes > indexBuffer->getNumIndexes())
            {
                //increasing index buffer size has failed
                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                    "Lock request out of bounds.",
                    "ShadowCaster::generateShadowVolume");
            }
        }
        else if(indexBufferUsedSize + preCountIndexes > indexBuffer->getNumIndexes())
        {
            indexBufferUsedSize = 0;
        }

        // Lock index buffer for writing, just enough length as we need
        HardwareBufferLockGuard indexLock(indexBuffer,
            sizeof(unsigned short) * indexBufferUsedSize, sizeof(unsigned short) * preCountIndexes,
            indexBufferUsedSize == 0 ? HardwareBuffer::HBL_DISCARD : HardwareBuffer::HBL_NO_OVERWRITE);
        unsigned short* pIdx = static_cast<unsigned short*>(indexLock.pData);
        size_t numIndices = indexBufferUsedSize;
        
        // Iterate over the groups and form renderables for each based on their
        // lightFacing
        si = shadowRenderables.begin();
        egiend = edgeData->edgeGroups.end();
        for (egi = edgeData->edgeGroups.begin(); egi != egiend; ++egi, ++si)
        {
            const EdgeData::EdgeGroup& eg = *egi;
            // Initialise the index start for this shadow renderable
            IndexData* indexData = (*si)->getRenderOperationForUpdate()->indexData;

            if (indexData->indexBuffer != indexBuffer)
            {
                (*si)->rebindIndexBuffer(indexBuffer);
                indexData = (*si)->getRenderOperationForUpdate()->indexData;
            }

            indexData->indexStart = numIndices;
            // original number of verts (without extruded copy)
            size_t originalVertexCount = eg.vertexData->vertexCount;
            bool  firstDarkCapTri = true;
            unsigned short darkCapStart = 0;

            EdgeData::EdgeList::const_iterator i, iend;
            iend = eg.edges.end();
            for (i = eg.edges.begin(); i != iend; ++i)
            {
                const EdgeData::Edge& edge = *i;

                // Silhouette edge, when two tris has opposite light facing, or
                // degenerate edge where only tri 1 is valid and the tri light facing
                char lightFacing = edgeData->triangleLightFacings[edge.triIndex[0]];
                if ((edge.degenerate && lightFacing) ||
                    (!edge.degenerate && (lightFacing != edgeData->triangleLightFacings[edge.triIndex[1]])))
                {
                    size_t v0 = edge.vertIndex[0];
                    size_t v1 = edge.vertIndex[1];
                    if (!lightFacing)
                    {
                        // Inverse edge indexes when t1 is light away
                        std::swap(v0, v1);
                    }

                    /* Note edge(v0, v1) run anticlockwise along the edge from
                    the light facing tri so to point shadow volume tris outward,
                    light cap indexes have to be backwards

                    We emit 2 tris if light is a point light, 1 if light 
                    is directional, because directional lights cause all
                    points to converge to a single point at infinity.

                    First side tri = near1, near0, far0
                    Second tri = far0, far1, near1

                    'far' indexes are 'near' index + originalVertexCount
                    because 'far' verts are in the second half of the 
                    buffer
                    */
                    assert(v1 < 65536 && v0 < 65536 && (v0 + originalVertexCount) < 65536 &&
                        "Vertex count exceeds 16-bit index limit!");
                    *pIdx++ = static_cast<unsigned short>(v1);
                    *pIdx++ = static_cast<unsigned short>(v0);
                    *pIdx++ = static_cast<unsigned short>(v0 + originalVertexCount);
                    numIndices += 3;

                    // Are we extruding to infinity?
                    if (!(lightType == Light::LT_DIRECTIONAL &&
                        flags & SRF_EXTRUDE_TO_INFINITY))
                    {
                        // additional tri to make quad
                        *pIdx++ = static_cast<unsigned short>(v0 + originalVertexCount);
                        *pIdx++ = static_cast<unsigned short>(v1 + originalVertexCount);
                        *pIdx++ = static_cast<unsigned short>(v1);
                        numIndices += 3;
                    }

                    if(useMcGuire)
                    {
                        // Do dark cap tri
                        // Use McGuire et al method, a triangle fan covering all silhouette
                        // edges and one point (taken from the initial tri)
                        if (flags & SRF_INCLUDE_DARK_CAP)
                        {
                            if (firstDarkCapTri)
                            {
                                darkCapStart = static_cast<unsigned short>(v0 + originalVertexCount);
                                firstDarkCapTri = false;
                            }
                            else
                            {
                                *pIdx++ = darkCapStart;
                                *pIdx++ = static_cast<unsigned short>(v1 + originalVertexCount);
                                *pIdx++ = static_cast<unsigned short>(v0 + originalVertexCount);
                                numIndices += 3;
                            }

                        }
                    }
                }

            }

            if(!useMcGuire)
            {
                // Do dark cap
                if (flags & SRF_INCLUDE_DARK_CAP) 
                {
                    // Iterate over the triangles which are using this vertex set
                    EdgeData::TriangleList::const_iterator ti, tiend;
                    EdgeData::TriangleLightFacingList::const_iterator lfi;
                    ti = edgeData->triangles.begin() + eg.triStart;
                    tiend = ti + eg.triCount;
                    lfi = edgeData->triangleLightFacings.begin() + eg.triStart;
                    for ( ; ti != tiend; ++ti, ++lfi)
                    {
                        const EdgeData::Triangle& t = *ti;
                        assert(t.vertexSet == eg.vertexSet);
                        // Check it's light facing
                        if (*lfi)
                        {
                            assert(t.vertIndex[0] < 65536 && t.vertIndex[1] < 65536 &&
                                t.vertIndex[2] < 65536 && 
                                "16-bit index limit exceeded!");
                            *pIdx++ = static_cast<unsigned short>(t.vertIndex[1] + originalVertexCount);
                            *pIdx++ = static_cast<unsigned short>(t.vertIndex[0] + originalVertexCount);
                            *pIdx++ = static_cast<unsigned short>(t.vertIndex[2] + originalVertexCount);
                            numIndices += 3;
                        }
                    }

                }
            }

            // Do light cap
            if (flags & SRF_INCLUDE_LIGHT_CAP) 
            {
                // separate light cap?
                if ((*si)->isLightCapSeparate())
                {
                    // update index count for this shadow renderable
                    indexData->indexCount = numIndices - indexData->indexStart;

                    // get light cap index data for update
                    indexData = (*si)->getLightCapRenderable()->getRenderOperationForUpdate()->indexData;
                    // start indexes after the current total
                    indexData->indexStart = numIndices;
                }

                // Iterate over the triangles which are using this vertex set
                EdgeData::TriangleList::const_iterator ti, tiend;
                EdgeData::TriangleLightFacingList::const_iterator lfi;
                ti = edgeData->triangles.begin() + eg.triStart;
                tiend = ti + eg.triCount;
                lfi = edgeData->triangleLightFacings.begin() + eg.triStart;
                for ( ; ti != tiend; ++ti, ++lfi)
                {
                    const EdgeData::Triangle& t = *ti;
                    assert(t.vertexSet == eg.vertexSet);
                    // Check it's light facing
                    if (*lfi)
                    {
                        assert(t.vertIndex[0] < 65536 && t.vertIndex[1] < 65536 &&
                            t.vertIndex[2] < 65536 && 
                            "16-bit index limit exceeded!");
                        *pIdx++ = static_cast<unsigned short>(t.vertIndex[0]);
                        *pIdx++ = static_cast<unsigned short>(t.vertIndex[1]);
                        *pIdx++ = static_cast<unsigned short>(t.vertIndex[2]);
                        numIndices += 3;
                    }
                }

            }

            // update index count for current index data (either this shadow renderable or its light cap)
            indexData->indexCount = numIndices - indexData->indexStart;

        }

        // In debug mode, check we didn't overrun the index buffer
        assert(numIndices == indexBufferUsedSize + preCountIndexes);
        assert(numIndices <= indexBuffer->getNumIndexes() &&
            "Index buffer overrun while generating shadow volume!! "
            "You must increase the size of the shadow index buffer.");

        indexBufferUsedSize = numIndices;
    }
	//---------------------------------------------------------------------
	void TangentSpaceCalc::extendBuffers(VertexSplits& vertexSplits)
	{
		if (!vertexSplits.empty())
		{
			// ok, need to increase the vertex buffer size, and alter some indexes

			// vertex buffers first
			VertexBufferBinding* newBindings = HardwareBufferManager::getSingleton().createVertexBufferBinding();
			const VertexBufferBinding::VertexBufferBindingMap& bindmap = 
				mVData->vertexBufferBinding->getBindings();
			for (VertexBufferBinding::VertexBufferBindingMap::const_iterator i = 
				bindmap.begin(); i != bindmap.end(); ++i)
			{
				HardwareVertexBufferSharedPtr srcbuf = i->second;
				// Derive vertex count from buffer not vertex data, in case using
				// the vertexStart option in vertex data
				size_t newVertexCount = srcbuf->getNumVertices() + vertexSplits.size();
				// Create new buffer & bind
				HardwareVertexBufferSharedPtr newBuf = 
					HardwareBufferManager::getSingleton().createVertexBuffer(
					srcbuf->getVertexSize(), newVertexCount, srcbuf->getUsage(), 
					srcbuf->hasShadowBuffer());
				newBindings->setBinding(i->first, newBuf);

				// Copy existing contents (again, entire buffer, not just elements referenced)
				newBuf->copyData(*(srcbuf.get()), 0, 0, srcbuf->getNumVertices() * srcbuf->getVertexSize(), true);

				// Split vertices, read / write from new buffer
				char* pBase = static_cast<char*>(newBuf->lock(HardwareBuffer::HBL_NORMAL));
				for (VertexSplits::iterator spliti = vertexSplits.begin(); 
					spliti != vertexSplits.end(); ++spliti)
				{
					const char* pSrcBase = pBase + spliti->first * newBuf->getVertexSize();
					char* pDstBase = pBase + spliti->second * newBuf->getVertexSize();
					memcpy(pDstBase, pSrcBase, newBuf->getVertexSize());
				}
				newBuf->unlock();

			}

			// Update vertex data
			// Increase vertex count according to num splits
			mVData->vertexCount += vertexSplits.size();
			// Flip bindings over to new buffers (old buffers released)
			HardwareBufferManager::getSingleton().destroyVertexBufferBinding(mVData->vertexBufferBinding);
			mVData->vertexBufferBinding = newBindings;

			// If vertex size requires 32bit index buffer
			if (mVData->vertexCount > 65536)
			{
				for (size_t i = 0; i < mIDataList.size(); ++i)
				{
					// check index size
					IndexData* idata = mIDataList[i];
					HardwareIndexBufferSharedPtr srcbuf = idata->indexBuffer;
					if (srcbuf->getType() == HardwareIndexBuffer::IT_16BIT)
					{
						size_t indexCount = srcbuf->getNumIndexes();

						// convert index buffer to 32bit.
						HardwareIndexBufferSharedPtr newBuf =
							HardwareBufferManager::getSingleton().createIndexBuffer(
							HardwareIndexBuffer::IT_32BIT, indexCount,
							srcbuf->getUsage(), srcbuf->hasShadowBuffer());

						uint16* pSrcBase = static_cast<uint16*>(srcbuf->lock(HardwareBuffer::HBL_NORMAL));
						uint32* pBase = static_cast<uint32*>(newBuf->lock(HardwareBuffer::HBL_NORMAL));

						size_t j = 0;
						while (j < indexCount)
						{
							*pBase++ = *pSrcBase++;
							++j;
						}

						srcbuf->unlock();
						newBuf->unlock();

						// assign new index buffer.
						idata->indexBuffer = newBuf;
					}
				}
			}
		}

	}
Exemplo n.º 3
0
    // ------------------------------------------------------------------------
    void ShadowCaster::generateShadowVolume(EdgeData* edgeData, 
        const HardwareIndexBufferSharedPtr& indexBuffer, const Light* light,
        ShadowRenderableList& shadowRenderables, unsigned long flags)
    {
        // Edge groups should be 1:1 with shadow renderables
        assert(edgeData->edgeGroups.size() == shadowRenderables.size());

        EdgeData::EdgeGroupList::const_iterator egi, egiend;
        ShadowRenderableList::const_iterator si;

        Light::LightTypes lightType = light->getType();

        // Lock index buffer for writing
        unsigned short* pIdx = static_cast<unsigned short*>(
            indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
        size_t numIndices = 0;

        // Iterate over the groups and form renderables for each based on their
        // lightFacing
        si = shadowRenderables.begin();
        egiend = edgeData->edgeGroups.end();
        for (egi = edgeData->edgeGroups.begin(); egi != egiend; ++egi, ++si)
        {
            const EdgeData::EdgeGroup& eg = *egi;
            // Initialise the index start for this shadow renderable
            IndexData* indexData = (*si)->getRenderOperationForUpdate()->indexData;
            indexData->indexStart = numIndices;
            // original number of verts (without extruded copy)
            size_t originalVertexCount = eg.vertexData->vertexCount;
            bool  firstDarkCapTri = true;
            unsigned short darkCapStart;

            EdgeData::EdgeList::const_iterator i, iend;
            iend = eg.edges.end();
            for (i = eg.edges.begin(); i != iend; ++i)
            {
                const EdgeData::Edge& edge = *i;

                // Silhouette edge, when two tris has opposite light facing, or
                // degenerate edge where only tri 1 is valid and the tri light facing
                char lightFacing = edgeData->triangleLightFacings[edge.triIndex[0]];
                if ((edge.degenerate && lightFacing) ||
                    (!edge.degenerate && (lightFacing != edgeData->triangleLightFacings[edge.triIndex[1]])))
                {
                    size_t v0 = edge.vertIndex[0];
                    size_t v1 = edge.vertIndex[1];
                    if (!lightFacing)
                    {
                        // Inverse edge indexes when t1 is light away
                        std::swap(v0, v1);
                    }

                    /* Note edge(v0, v1) run anticlockwise along the edge from
                    the light facing tri so to point shadow volume tris outward,
                    light cap indexes have to be backwards

                    We emit 2 tris if light is a point light, 1 if light 
                    is directional, because directional lights cause all
                    points to converge to a single point at infinity.

                    First side tri = near1, near0, far0
                    Second tri = far0, far1, near1

                    'far' indexes are 'near' index + originalVertexCount
                    because 'far' verts are in the second half of the 
                    buffer
                    */
                    *pIdx++ = v1;
                    *pIdx++ = v0;
                    *pIdx++ = v0 + originalVertexCount;
                    numIndices += 3;

                    // Are we extruding to infinity?
                    if (!(lightType == Light::LT_DIRECTIONAL &&
                        flags & SRF_EXTRUDE_TO_INFINITY))
                    {
                        // additional tri to make quad
                        *pIdx++ = v0 + originalVertexCount;
                        *pIdx++ = v1 + originalVertexCount;
                        *pIdx++ = v1;
                        numIndices += 3;
                    }

                    // Do dark cap tri
                    // Use McGuire et al method, a triangle fan covering all silhouette
                    // edges and one point (taken from the initial tri)
                    if (flags & SRF_INCLUDE_DARK_CAP)
                    {
                        if (firstDarkCapTri)
                        {
                            darkCapStart = v0 + originalVertexCount;
                            firstDarkCapTri = false;
                        }
                        else
                        {
                            *pIdx++ = darkCapStart;
                            *pIdx++ = v1 + originalVertexCount;
                            *pIdx++ = v0 + originalVertexCount;
                            numIndices += 3;
                        }

                    }
                }

            }

            // Do light cap
            if (flags & SRF_INCLUDE_LIGHT_CAP) 
            {
                // separate light cap?
                if ((*si)->isLightCapSeparate())
                {
                    // update index count for this shadow renderable
                    indexData->indexCount = numIndices - indexData->indexStart;

                    // get light cap index data for update
                    indexData = (*si)->getLightCapRenderable()->getRenderOperationForUpdate()->indexData;
                    // start indexes after the current total
                    indexData->indexStart = numIndices;
                }

                // Iterate over the triangles which are using this vertex set
                EdgeData::TriangleList::const_iterator ti, tiend;
                EdgeData::TriangleLightFacingList::const_iterator lfi;
                ti = edgeData->triangles.begin() + eg.triStart;
                tiend = ti + eg.triCount;
                lfi = edgeData->triangleLightFacings.begin() + eg.triStart;
                for ( ; ti != tiend; ++ti, ++lfi)
                {
                    const EdgeData::Triangle& t = *ti;
                    assert(t.vertexSet == eg.vertexSet);
                    // Check it's light facing
                    if (*lfi)
                    {
                        *pIdx++ = t.vertIndex[0];
                        *pIdx++ = t.vertIndex[1];
                        *pIdx++ = t.vertIndex[2];
                        numIndices += 3;
                    }
                }

            }

            // update index count for current index data (either this shadow renderable or its light cap)
            indexData->indexCount = numIndices - indexData->indexStart;

        }


        // Unlock index buffer
        indexBuffer->unlock();

		// In debug mode, check we didn't overrun the index buffer
		assert(numIndices <= indexBuffer->getNumIndexes() &&
            "Index buffer overrun while generating shadow volume!! "
			"You must increase the size of the shadow index buffer.");

    }