Example #1
0
File: sphere.c Project: paud/d2x-xl
int TesselateSphereTri (tOOF_triangle *pDest, tOOF_triangle *pSrc, int nFaces)
{
	int	i;

for (i = 0; i < nFaces; i++, pDest += 6, pSrc++)
	SplitTriangle (pDest, pSrc);
return 1;
}
void Terrain::ForceSplit(Node* T)
{
	// Recursion Call to force split bases
	if(T->BaseNeighbour != NULL)						
	{		
		if(T->BaseNeighbour->BaseNeighbour != T)
	  	{			
			ForceSplit(T->BaseNeighbour);
		}
		SplitTriangle(T);
		SplitTriangle(T->BaseNeighbour);		
		T->LeftChild->RightNeighbour = T->BaseNeighbour->RightChild;
		T->RightChild->LeftNeighbour = T->BaseNeighbour->LeftChild;
		T->BaseNeighbour->LeftChild->RightNeighbour = T->RightChild;
		T->BaseNeighbour->RightChild->LeftNeighbour = T->LeftChild;
    }
    else
    {
        SplitTriangle(T);
		T->LeftChild->RightNeighbour = NULL;
		T->RightChild->LeftNeighbour = NULL;
    }
}
Example #3
0
_Use_decl_annotations_
bool KdTreeCompiler2::FindBestSplit(uint32_t trianglesRoot, uint32_t numTriangles,
    uint32_t* splitAxis, float* splitValue, _In_ const float min[3], _In_ const float max[3],
    uint32_t* frontRoot, uint32_t* frontCount, float frontMin[3], float frontMax[3],
    uint32_t* backRoot, uint32_t* backCount, float backMin[3], float backMax[3])
{
    if (numTriangles < 10)
    {
        return false;
    }

    uint32_t axis;
    float bestSplit = 0.0f;
    uint32_t bestAxis = 0;
    int32_t bestScore = INT32_MAX;

    // Find best split
    for (axis = 0; axis < 3; ++axis)
    {
        int32_t score = 0;
        float value = (min[axis] + max[axis]) * 0.5f;

        uint32_t tri = trianglesRoot;
        while (tri != UINT32_MAX)
        {
            KdCompilerTriangle* t = &_compilerTriangles[tri];
            score += (t->Centroid[axis] >= value) ? 1 : -1;
            tri = t->Next;
        }

        score = abs(score);
        if (score < bestScore)
        {
            bestScore = score;
            bestSplit = value;
            bestAxis = axis;
        }
    }

    if (bestScore == (int32_t)numTriangles)
    {
        return false;
    }

    *splitAxis = bestAxis;
    *splitValue = bestSplit;

    uint32_t front = UINT32_MAX, back = UINT32_MAX;
    uint32_t nFront = 0, nBack = 0;

    // Now actually split the triangles
    uint32_t tri = trianglesRoot;
    while (tri != UINT32_MAX)
    {
        KdCompilerTriangle* t = &_compilerTriangles[tri];
        uint32_t nextTri = t->Next;

        // Remove node
        t->Next = UINT32_MAX;

        if (t->Min[bestAxis] > bestSplit)
        {
            // insert in front
            if (front == UINT32_MAX)
            {
                front = tri;
                memcpy_s(frontMin, sizeof(t->Min), t->Min, sizeof(t->Min));
                memcpy_s(frontMax, sizeof(t->Max), t->Max, sizeof(t->Max));
            }
            else
            {
                t->Next = front;
                front = tri;
                for (axis = 0; axis < 3; ++axis)
                {
                    frontMin[axis] = std::min(frontMin[axis], t->Min[axis]);
                    frontMax[axis] = std::max(frontMax[axis], t->Max[axis]);
                }
            }

            ++nFront;
        }
        else if (t->Max[bestAxis] < bestSplit)
        {
            // insert in back
            if (back == UINT32_MAX)
            {
                back = tri;
                memcpy_s(backMin, sizeof(t->Min), t->Min, sizeof(t->Min));
                memcpy_s(backMax, sizeof(t->Max), t->Max, sizeof(t->Max));
            }
            else
            {
                t->Next = back;
                back = tri;
                for (axis = 0; axis < 3; ++axis)
                {
                    backMin[axis] = std::min(backMin[axis], t->Min[axis]);
                    backMax[axis] = std::max(backMax[axis], t->Max[axis]);
                }
            }

            ++nBack;
        }
        else
        {
            // TODO: split triangle
            SplitTriangle(tri, bestAxis, bestSplit, &front, &back);
        }

        tri = nextTri;
    }

    *frontRoot = front;
    *frontCount = nFront;
    *backRoot = back;
    *backCount = nBack;

    return true;
}
Example #4
0
_Use_decl_annotations_
bool BspCompiler::FindBestSplit(Triangle** triangles, uint32_t count, const Triangle** splitTriangle, Triangle** front, uint32_t* frontCount, Triangle** back, uint32_t* backCount)
{
    const Triangle* candidate = nullptr;
    int32_t score = 0;

#if defined(PARALLEL_BSP)
    if (count > 1000)
    {
        // Divide up workload and spin up multiple SplitTriangleTasks

        uint32_t numGroups = std::min((int)(count / 1000), 16);
        std::vector<std::shared_ptr<FindBestSplitPacket>> packets(numGroups + 1);
        std::vector<HANDLE> threads(numGroups + 1);

        for (uint32_t i = 0; i < packets.size(); ++i)
        {
            packets[i].reset(new FindBestSplitPacket);
        }

        uint32_t countPerGroup = count / numGroups;
        uint32_t countDispatched = 0;

        const Triangle* start = *triangles;
        for (uint32_t i = 0; i < numGroups; ++i)
        {
            auto& packet = packets[i];
            packet->start = start;
            packet->head = *triangles;
            packet->count = count;
            packet->numTriangles = countPerGroup;
            threads[i] = CreateThread(nullptr, 0, FindBestSplitTaskThreadProc, packet.get(), 0, nullptr);

            for (uint32_t j = 0; j < countPerGroup; ++j)
            {
                start = start->Next;
            }

            countDispatched += countPerGroup;
        }

        if (countDispatched < count)
        {
            auto& packet = packets[numGroups];
            packet->start = start;
            packet->head = *triangles;
            packet->count = count;
            packet->numTriangles = count - countDispatched;
            threads[numGroups] = CreateThread(nullptr, 0, FindBestSplitTaskThreadProc, packet.get(), 0, nullptr);
            ++numGroups;
        }

        WaitForMultipleObjects(numGroups, threads.data(), TRUE, INFINITE);

        for (uint32_t i = 0; i < numGroups; ++i)
        {
            CloseHandle(threads[i]);
        }

        // aggregate best
        const Triangle* best = nullptr;
        int32_t bestScore = 0;

        for (uint32_t i = 0; i < numGroups; ++i)
        {
            if (packets[i]->result)
            {
                if (best == nullptr || packets[i]->candidateScore < bestScore)
                {
                    best = packets[i]->candidateTriangle;
                    bestScore = packets[i]->candidateScore;
                }
            }
        }

        if (best == nullptr)
        {
            return false;
        }

        candidate = best;
        score = bestScore;
    }
    else
#endif
    {
        FindBestSplitPacket packet;
        packet.head = *triangles;
        packet.count = count;
        packet.start = *triangles;
        packet.numTriangles = count;
        FindBestSplitTask(&packet);
        if (!packet.result)
        {
            return false;
        }

        candidate = packet.candidateTriangle;
        score = packet.candidateScore;
    }

    *splitTriangle = candidate;
    const XMFLOAT4& plane = candidate->Plane;

    (*frontCount) = 0;
    (*backCount) = 0;

    Triangle* t = *triangles;
    while (t != nullptr)
    {
        Triangle* next = t->Next;

        if (t == candidate)
        {
            // self. insert in front
            PUSH(front, t);
            ++(*frontCount);
        }
        else
        {
            float d0 = DistToPlane(plane, t->v0.Position);
            float d1 = DistToPlane(plane, t->v1.Position);
            float d2 = DistToPlane(plane, t->v2.Position);

            if (ABS(d0) < epsilon && ABS(d1) < epsilon && ABS(d2) < epsilon)
            {
                XMVECTOR tplane = XMLoadFloat4(&t->Plane);

                // coplanar case
                if (XMVectorGetX(XMVector3Dot(XMLoadFloat4(&plane), tplane)) > 0)
                {
                    // same facing direction
                    PUSH(front, t);
                    ++(*frontCount);
                }
                else
                {
                     PUSH(back, t);
                    ++(*backCount);
                }
            }
            else if (d0 > -epsilon && d1 > -epsilon && d2 > -epsilon)
            {
                // front of plane
                PUSH(front, t);
                ++(*frontCount);
            }
            else if (d0 < epsilon && d1 < epsilon && d2 < epsilon)
            {
                // fully behind plane
                PUSH(back, t);
                ++(*backCount);
            }
            else
            {
                // intersect
                SplitTriangle(t, plane, front, back);
            }
        }

        t = next;
    }

    return true;
}
Example #5
0
cBSPTree::cBSPTree(std::vector<cTriangle>& tris, std::string name, eBSPHeuristic heuristic)
	:mName(name)
	,mHeuristic(heuristic)
	,mBoundingBox(cCoord3(0.0f))
{
	if(!tris.empty()){
		mBoundingBox.Reset(tris.back().GetVertex(0));
	}
	//SplitTriangle(cTriangle(cCoord3(0.0f, 2.0f, 0.0f),cCoord3(0.0f, 0.0f, 0.0f),cCoord3(2.0f, 0.0f, 0.0f),cCoord3(0.0f, 0.0f, 1.0f)), cPlane3(cCoord3::XAxis(), 1.0f));
	for (const cTriangle& t: tris)
	{
		mTris.push_back(t);
		mBoundingBox.ExpandToFit(t.GetVertex(0));
		mBoundingBox.ExpandToFit(t.GetVertex(1));
		mBoundingBox.ExpandToFit(t.GetVertex(2));
	}
	mBoundingBox.ExpandToFit(mBoundingBox.LowerCorner()-0.1f*cCoord3::Ones());
	mBoundingBox.ExpandToFit(mBoundingBox.UpperCorner()+0.1f*cCoord3::Ones());
	std::vector<cTriNodeIndexPair> in_progress;
	std::vector<int> index_stack;
	mNodeVec.reserve(mTris.size());
	in_progress.reserve(mTris.size());
	index_stack.reserve(static_cast<size_t>(std::log(mTris.size())+1));
	std::sort(mTris.begin(), mTris.end(), cTrianglePerimeterComparator());
	int count = 0;
	cCoord3 com;
	for (const cTriangle& tri: mTris)
	{
		com += tri.GetVertex(0);
		com += tri.GetVertex(1);
		com += tri.GetVertex(2);
		in_progress.emplace_back(count, 0);
		count++;
	}
	com /= static_cast<float>(count*3);
	index_stack.push_back(0);
	mNodeVec.push_back(cBSPNode(mTris.back(),-1, 0));
	in_progress.back().mParentNode--;
	int total_splits = 0;
	int max_depth = 0;
	while (index_stack.size()>0)
	{
		
		int parent_node = index_stack.back();
		index_stack.pop_back();
		int front_index = static_cast<int>(mNodeVec.size());
		int back_index = front_index + 1;
		float best_front_metric = 0.0f;
		float best_back_metric = 0.0f;
		int best_front_index = -1;
		int best_back_index = -1;
		int num_front_nodes = 0;
		int num_back_nodes = 0;
		int num_split = 0;
		int num_coplanar = 0;
		cCoord3 center;
		float avg_over = 0.0f;
		cCoord3 orientation;
		//PreProcessNodes(mTris,in_progress,parent_node);
		for (int i = 0 ; i < static_cast<int>(in_progress.size()); ++i)
		{
			if(in_progress.at(i).mParentNode != parent_node) continue;
			
			const int tri_index = in_progress.at(i).mTriIndex;
			cBSPNode::eClassification in_out = mNodeVec.at(parent_node).ClassifyTriangle(mTris.at(tri_index));
			const float area = mTris.at(tri_index).Area();
			if(area <  0.0001f) continue;
			float metric = 0.0;
			const float normal_dot = mTris.at(tri_index).GetNormal().dot(mNodeVec.at(parent_node).GetNormal());
			if(mHeuristic == BSP_COPLANAR){
				metric = std::abs(normal_dot);
			}
			else if(mHeuristic == BSP_ORTHOGONAL){
				metric = normal_dot;
			}
			else if(mHeuristic == BSP_AREA){
				metric = area* (1 +  std::abs(normal_dot));
			}
			//const cCoord3 mean_loc = mTris.at(tri_index).MeanLocation();
			//float axis_align = 1.0f - std::abs(mTris.at(tri_index).GetNormal().x);
			//axis_align = GreaterOf(axis_align, 1.0f -  std::abs(mTris.at(tri_index).GetNormal().y));
			//axis_align = GreaterOf(axis_align, 1.0f -  std::abs(mTris.at(tri_index).GetNormal().z));

			//const float dist = -0.0f*(mean_pos/3.0f - center).length();
			if(in_out == cBSPNode::BSP_COPLANAR){
				if(mTris.at(tri_index).GetNormal().dot(mNodeVec.at(parent_node).GetNormal()) <= 0.0){
					in_out = cBSPNode::BSP_BACK;
					float perim1 = std::sqrt(mTris.at(tri_index).Area());
					float normal_length = mNodeVec.at(parent_node).GetNormal().length();
					float ratio = mTris.at(tri_index).GetNormal().dot(mNodeVec.at(parent_node).GetNormal());
					p4::Log::Warn("coplanar triangles with different normals. area = %f, normal_len = %f, ratio: %f",perim1,normal_length, ratio);
					mNodeVec.at(parent_node).ClassifyTriangle(mTris.at(tri_index));
					//mNodeVec.at(parent_node).AddTriangle(mTris.at(tri_index));
					//num_coplanar++;
				}
				else{
					mNodeVec.at(parent_node).AddTriangle(mTris.at(tri_index));
					num_coplanar++;
				}
				//p4::Log::Debug("passing over coplanar tri %d", tri_index);
			}
			if(in_out == cBSPNode::BSP_FRONT){
				num_front_nodes++;
				//p4::Log::Debug("found front tri");
				
				if( metric > best_front_metric ){
					best_front_metric = metric; 
					best_front_index = i;
				}
				in_progress.at(i).mParentNode = front_index;
			}
			else if(in_out == cBSPNode::BSP_BACK){
				num_back_nodes++;
				//p4::Log::Debug("found back tri");
				if( metric > best_back_metric ){
					best_back_metric = metric; 
					best_back_index = i;
				}
				in_progress.at(i).mParentNode = back_index;
			}
			
			else if(in_out == cBSPNode::BSP_SPLIT){
				//p4::Log::Debug("splitting tri %d", tri_index);
				std::vector<cTriangle> split = SplitTriangle(mTris.at(tri_index), mNodeVec.at(parent_node).GetDividingPlane());
				
				// replace our current triangle
				mTris.at(tri_index) = split.at(0);
				// and then add two more
				if(split.size() > 1){
					mTris.emplace_back(split.at(1));
					in_progress.emplace_back(static_cast<int>(mTris.size()-1), parent_node);
				}
				if(split.size() > 2){
					mTris.emplace_back(split.at(2));
					in_progress.emplace_back(static_cast<int>(mTris.size()-1), parent_node);
				}
				//rewind the index to process this one again
				i--;
				num_split ++;
			}
		}
		p4::Log::TMI("Processed for node %d, depth %d, front: %d, back: %d, split: %d, coplanar %d",
			parent_node, mNodeVec.at(parent_node).GetDepth(), num_front_nodes, num_back_nodes, num_split, num_coplanar);
		// okay, classified all the triangles: now create 0-2 nodes
		if(best_front_index >= 0){
			const cCoord3 nrml = mTris.at(best_front_index).GetNormal();
			mNodeVec.push_back(cBSPNode(mTris.at(best_front_index),parent_node,mNodeVec.at(parent_node).GetDepth()+1));
			int new_front_index = static_cast<int>(mNodeVec.size()-1);
			mNodeVec.at(parent_node).SetFrontNodeIndex(new_front_index);
			P4_ASSERT(new_front_index == front_index);
			//TODO:watch out here...
			in_progress.at(best_front_index).mParentNode = parent_node;
			index_stack.push_back(new_front_index);
			p4::Log::TMI("created new front node %d, child of %d, depth %d", new_front_index, parent_node, mNodeVec.at(new_front_index).GetDepth());
			P4_ASSERT(mNodeVec.at(parent_node).GetDepth() >= 0);
			if(mNodeVec.at(new_front_index).GetDepth() > max_depth){
				max_depth = mNodeVec.at(new_front_index).GetDepth();
			}
		}
		if(best_back_index >= 0){
			const cCoord3 nrml = mTris.at(best_back_index).GetNormal();
			mNodeVec.push_back(cBSPNode(mTris.at(best_back_index),parent_node,mNodeVec.at(parent_node).GetDepth()+1 ));
			int new_back_index = static_cast<int>(mNodeVec.size()-1);
			mNodeVec.at(parent_node).SetBackNodeIndex(new_back_index);
			if(new_back_index != back_index){
				for (cTriNodeIndexPair& tri_index: in_progress)
				{
					if(tri_index.mParentNode == back_index){
						tri_index.mParentNode = new_back_index;
					}
				}
			}
			in_progress.at(best_back_index).mParentNode = parent_node;
			index_stack.push_back(new_back_index);
			p4::Log::TMI("created new back node %d, child of %d, depth %d", new_back_index, parent_node, mNodeVec.at(new_back_index).GetDepth());
			P4_ASSERT(mNodeVec.at(parent_node).GetDepth() >= 0);
			if(mNodeVec.at(new_back_index).GetDepth() > max_depth){
				max_depth = mNodeVec.at(new_back_index).GetDepth();
			}
		}
		total_splits += num_split;
	}
	p4::Log::Info("Finished BSP creation: %d nodes (%dkB), max depth = %d, splits = %d", mNodeVec.size(),(mNodeVec.size()*sizeof(cBSPNode)-1)/1024+1, max_depth, total_splits);


}