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); } } }