Exemple #1
0
void TreeStem::buildSegment(TreeGeneralParams generalParams, TreeSegment* prevSeg, int segIndex, 
							float splitAngle, float divergeAngle, float rotateYAngle, LevelContext& context)
{
	_Assert(segIndex < mLevelParams.curveRes);

	static int dbNumSegs[4];
	dbNumSegs[mLevelParams.level]++;
	ConsolePrint(L"current numSegs: (0-%d),(1-%d),(2-%d),(3-%d)\n", dbNumSegs[0], dbNumSegs[1], dbNumSegs[2], dbNumSegs[3]);

	int numSegs = mLevelParams.curveRes;
	float segLength = mLength / numSegs;

	TreeSegment* seg = New TreeSegment;

	float curveDelta = 0;
	if(segIndex != 0)
	{
		if(mLevelParams.curveBack == 0)
		{
			curveDelta = mLevelParams.curve / mLevelParams.curveRes;
		}
		else
		{
			if(segIndex < (mLevelParams.curveRes + 1) / 2)
				curveDelta = 2 * mLevelParams.curve / mLevelParams.curveRes;
			else
				curveDelta = -2 * mLevelParams.curveBack / mLevelParams.curveRes;
		}

		curveDelta += RandomVariation(0, mLevelParams.curveV) / mLevelParams.curveRes;
	}

	Vector3 basePos;
	if(prevSeg == NULL)
		basePos = Vector3::Zero;
	else
		basePos = Vector3(0, segLength, 0);

	seg->mPos = basePos;
	seg->mOrient = Quaternion(0, DEGREE_TO_RAD(divergeAngle), DEGREE_TO_RAD(curveDelta + splitAngle));
	seg->mSegIndex = segIndex;
	seg->mParent = prevSeg;
	seg->mStem = this;

	Quaternion parentOrientWorld;
	if(prevSeg)
	{
		prevSeg->mChildren.push_back(seg);
		parentOrientWorld = prevSeg->mOrientWorld;
	}
	else
	{
		mFirstSeg = seg;
		parentOrientWorld = mOrient;
	}

	// divergeAngle是绕世界的y轴旋转
	seg->mOrientWorld = Quaternion(0, DEGREE_TO_RAD(rotateYAngle), 0) * (parentOrientWorld * seg->mOrient);
	seg->mOrient = WorldRotationToLocal(parentOrientWorld.Difference(seg->mOrientWorld), parentOrientWorld);

	// create seg vb ...
	std::vector<float> segRadius;
	{
		float offset = (float)segIndex / numSegs;
		float offsetDelta = 1.0f / numSegs / mLevelParams.segSegsH;
		for(int i = 0; i <= mLevelParams.segSegsH; ++i)
		{
			segRadius.push_back(GetStemRadius(offset));
			offset += offsetDelta;
		}
	}

	bool closeTop = true;
	bool closeBottom = true;
	//if(segIndex == 0)
	//	closeBottom = true;
	//if(segIndex == numSegs - 1)
	//	closeTop = true;

	seg->mGeo = New TreeSegGeo(segLength, mLevelParams.segSegsW, mLevelParams.segSegsH, segRadius, 
 		Quaternion(0, 0, DEGREE_TO_RAD(curveDelta + splitAngle)), closeTop, closeBottom);
	seg->mGeo->CalculateNormals();
	seg->mGeo->BuildGeometry(XYZ_N);

	// branches
	if(seg->mStem->GetNumBranches() != 0 && mLevelParams.level < generalParams.levels - 1)
	{
		float baseOffset = 0;
		if(mLevelParams.level == 0)
		{
			float baseLength = generalParams.baseSize * mLength;
			baseOffset = baseLength - segIndex * segLength;
		}

		float offset = 0;
		if(baseOffset <= 0)
		{
			offset = mBranchInterval - context.branchDistError;
		}
		else if(baseOffset < segLength)
		{
			offset = baseOffset + mBranchInterval;
		}
		else
		{
			offset = segLength + mBranchInterval;
		}

		while(offset < segLength - 0.0001f)
		{
			TreeStem* branch = New TreeStem(mTree, mLevelParams.level + 1);
			branch->Build(seg, offset, generalParams, mTree->GetLevelParams(mLevelParams.level + 1), context);
			seg->mBranches.push_back(branch);

			offset += mBranchInterval;
		}

		context.branchDistError = segLength - (offset - mBranchInterval);
	}

	// splits
	if(segIndex == numSegs - 1)
		return;

	int numSplits = 0;
	if(mLevelParams.level == 0 && segIndex == 0)
	{
		numSplits = generalParams.baseSplits;
	}
	else
	{
		numSplits = (int)(mLevelParams.segSplits + context.splitError);
		context.splitError = mLevelParams.segSplits + context.splitError - numSplits;
	}

	if(numSplits < 1)		// no splits
	{
		buildSegment(generalParams, seg, segIndex + 1, 0, 0, 0, context);
	}
	else
	{			
		Vector3 vecUp = Vector3(0, 1, 0) * seg->mOrientWorld;
		float declination = VectorAngle(Vector3(0, 1, 0), vecUp);

		float splitAngleFactor = 1.0f;		// 调整此算法来使splitAngle随枝干的水平角度加成变化
		splitAngleFactor = fabs(declination - PI/2) / (PI/2);

		float childSplitAngle = max(0, splitAngleFactor * RandomVariation(mLevelParams.splitAngle, mLevelParams.splitAngleV));	

		for(int i = 0; i <= numSplits; ++i)
		{
			float childDivergeAngle = 0;
			float childRotateYAngle = 0;

			childDivergeAngle = ((float)i / (numSplits + 1)) * 360;
			if(mLevelParams.level == 0 && segIndex == 0)
			{
				childRotateYAngle = 0;
			}
			else
			{
				float rf = RandomFloat(0, 1.0f);
				int s = sign(RandomFloat(-1.0f, 1.0f));
				childRotateYAngle = s * (20 + 0.75f * (30 + fabs(declination - 90)) * pow(rf, 2));
			}

			buildSegment(generalParams, seg, segIndex + 1, childSplitAngle, childDivergeAngle, childRotateYAngle, context);
		}
	}
}