void P3DStemModelTube::ApplyAxisVariation (P3DMathRNG *RNG, P3DStemModelTubeInstance *Instance) const { float Angle1; float Angle2; float SinAngle1; float CosAngle1; P3DQuaternionf Q; unsigned int SegIndex; if (RNG == 0) { return; } for (SegIndex = 0; SegIndex < (AxisResolution - 1); SegIndex++) { Angle1 = RNG->UniformFloat(0,P3DMATH_PI * 2.0f); Angle2 = RNG->UniformFloat(-AxisVariation,AxisVariation) * P3DMATH_PI; P3DMath::SinCosf(&SinAngle1,&CosAngle1,Angle1); Q.FromAxisAndAngle(CosAngle1,0.0f,SinAngle1,Angle2); Instance->SetSegOrientation(SegIndex,Q.q); } }
void P3DBranchingAlgBase::CalcBranchOrientationInCircleShape (P3DQuaternionf *Orientation, float X, float Z, P3DMathRNG *RNG) const { P3DQuaternionf Rotation1Quat; P3DQuaternionf Rotation2Quat; P3DQuaternionf DeclinationQuat; P3DQuaternionf TempQuat; float DeclinationAngle; float XAxisVsPointAngle = P3DMath::ATan2(X,Z); Rotation1Quat.FromAxisAndAngle(0.0f,1.0f,0.0f,XAxisVsPointAngle); Rotation2Quat.FromAxisAndAngle(0.0f,1.0f,0.0f,Rotation); float SquaredRadius = Spread * Spread * 0.25f; float NormDistance; if (!P3DMATH_ALMOST_ZERO(SquaredRadius)) { NormDistance = P3DMath::Sqrtf((X * X + Z * Z) / (Spread * Spread * 0.25f)); } else { NormDistance = 0.0f; } if (RNG != 0) { NormDistance += RNG->UniformFloat(-DeclFactorV,DeclFactorV); } DeclinationAngle = P3DMath::Clampf (-P3DMATH_PI * 0.5,P3DMATH_PI * 0.5, NormDistance * DeclFactor * P3DMATH_PI * 0.5); DeclinationQuat.FromAxisAndAngle(1.0f,0.0f,0.0f,DeclinationAngle); P3DQuaternionf::CrossProduct(TempQuat.q,Rotation1Quat.q,DeclinationQuat.q); P3DQuaternionf::CrossProduct(Orientation->q,TempQuat.q,Rotation2Quat.q); }
void P3DBranchingAlgStd::CreateBranches (P3DBranchingFactory *Factory, const P3DStemModelInstance *Parent, P3DMathRNG *RNG) { unsigned int BranchCount; float OffsetStep; float CurrRevAngle; float BranchRegionLength; CurrRevAngle = StartRevAngle; BranchRegionLength = Parent->GetLength() * (MaxOffset - MinOffset); if (BranchRegionLength <= 0.0f) { return; } if (RNG != 0) { BranchCount = (int)(BranchRegionLength * (Density + RNG->UniformFloat(-DensityV,DensityV) * Density)); } else { BranchCount = (int)(BranchRegionLength * Density); } BranchCount /= Multiplicity; if (BranchCount < MinNumber) { BranchCount = MinNumber; } if (MaxLimitEnabled && BranchCount > MaxNumber) { BranchCount = MaxNumber; } if (BranchCount > 0) { P3DQuaternionf orientation; P3DQuaternionf decl; P3DQuaternionf rev; P3DQuaternionf Rot; P3DQuaternionf TempRot; float MultRevAngleStep; OffsetStep = (MaxOffset - MinOffset) / (BranchCount + 1); P3DVector3f CurrOffset(0.0f,MinOffset + OffsetStep,0.0f); MultRevAngleStep = (2.0f * P3DMATH_PI) / Multiplicity; for (unsigned int i = 0; i < BranchCount; i++) { float BaseDeclination; for (unsigned int MultIndex = 0; MultIndex < Multiplicity; MultIndex++) { BaseDeclination = DeclinationCurve.GetValue(CurrOffset.Y()); if (RNG != 0) { BaseDeclination += RNG->UniformFloat(-DeclinationV,DeclinationV) * BaseDeclination; } decl.FromAxisAndAngle(0.0f,0.0f,-1.0f,P3DMATH_DEG2RAD(180.0f * BaseDeclination)); rev.FromAxisAndAngle(0.0f,1.0f,0.0f,CurrRevAngle + MultRevAngleStep * MultIndex); Rot.FromAxisAndAngle(0.0f,1.0f,0.0f,Rotation); P3DQuaternionf::CrossProduct(TempRot.q,rev.q,decl.q); P3DQuaternionf::CrossProduct(orientation.q,TempRot.q,Rot.q); Factory->GenerateBranch(&CurrOffset,&orientation); } if (RNG != 0) { CurrRevAngle += RevAngle + (RevAngle * RNG->UniformFloat(-RevAngleV,RevAngleV)); } else { CurrRevAngle += RevAngle; } CurrOffset.Y() += OffsetStep; } } }
P3DStemModelInstance *P3DStemModelTube::CreateInstance (P3DMathRNG *rng, const P3DStemModelInstance *parent, float offset, const P3DQuaternionf *orientation) const { P3DStemModelTubeInstance *Instance; if (parent == 0) { float InstanceLength; InstanceLength = Length; if (rng != 0) { InstanceLength += rng->UniformFloat(-LengthV,LengthV) * InstanceLength; } if (orientation != 0) { P3DMatrix4x4f WorldTransform; orientation->ToMatrix(WorldTransform.m); Instance = new P3DStemModelTubeInstance ( InstanceLength, AxisResolution, ProfileScaleBase, &ProfileScaleCurve, ProfileResolution, UMode, UScale, VMode, VScale, &WorldTransform); } else { Instance = new P3DStemModelTubeInstance ( InstanceLength, AxisResolution, ProfileScaleBase, &ProfileScaleCurve, ProfileResolution, UMode, UScale, VMode, VScale, 0); } } else { P3DMatrix4x4f ParentTransform; P3DMatrix4x4f WorldTransform; P3DQuaternionf ParentOrientation; P3DQuaternionf InstanceOrientation; P3DVector3f ParentAxisPos; P3DMatrix4x4f TempTransform; P3DMatrix4x4f TempTransform2; P3DMatrix4x4f TranslateTransform; float InstanceLength; parent->GetAxisOrientationAt(ParentOrientation.q,offset); parent->GetAxisPointAt(ParentAxisPos.v,offset); parent->GetWorldTransform(ParentTransform.m); P3DQuaternionf::CrossProduct(InstanceOrientation.q, ParentOrientation.q, orientation->q); InstanceOrientation.ToMatrix(TempTransform2.m); P3DMatrix4x4f::MakeTranslation(TranslateTransform.m, ParentAxisPos.X(), ParentAxisPos.Y(), ParentAxisPos.Z()); P3DMatrix4x4f::MultMatrix(TempTransform.m, TranslateTransform.m, TempTransform2.m); P3DMatrix4x4f::MultMatrix(WorldTransform.m, ParentTransform.m, TempTransform.m); InstanceLength = parent->GetLength() * Length * LengthOffsetInfluenceCurve.GetValue(offset); if (rng != 0) { InstanceLength += rng->UniformFloat(-LengthV,LengthV) * InstanceLength; } Instance = new P3DStemModelTubeInstance ( InstanceLength, AxisResolution, parent->GetMinRadiusAt(offset) * ProfileScaleBase, &ProfileScaleCurve, ProfileResolution, UMode, UScale, VMode, VScale, &WorldTransform); } ApplyAxisVariation(rng,Instance); ApplyPhototropism(Instance); return(Instance); }
/* * CurrOrientation is in parent seg space * DestVector is in parent seg space */ static void ApplyPhototropismToSegment (P3DQuaternionf *NewOrientation, const float *CurrOrientation, const float *DestVector, float Factor) { // Find branch direction after applying phototopism effect P3DVector3f SegmentY; SegmentY.Set(0.0f,1.0f,0.0); P3DQuaternionf::RotateVector(SegmentY.v,CurrOrientation); float CosA = P3DVector3f::ScalarProduct(DestVector,SegmentY.v); if (CosA >= 1.0f) { NewOrientation->Set(CurrOrientation); return; // nothing to do, SegmentY already points in DestVector direction } float Angle = P3DMath::ACosf(CosA); P3DVector3f Axis; if (Angle >= P3DMATH_PI) { Axis.Set(0.0f,0.0f,1.0f); } else { P3DVector3f::CrossProduct(Axis.v,SegmentY.v,DestVector); Axis.Normalize(); } P3DQuaternionf Rotation; Rotation.FromAxisAndAngle(Axis.X(),Axis.Y(),Axis.Z(),Angle * Factor); P3DQuaternionf::RotateVector(SegmentY.v,Rotation.q); // Now find transformation from parent branch to SegmentY // CosA = P3DVector3f::ScalarProduct(SegmentY,(0,1,0)); CosA = SegmentY.Y(); if (CosA >= 1.0f) { NewOrientation->MakeIdentity(); } else if (CosA <= -1.0f) { // P3Quaternion::FromAxisAndAngle((0,0,1),PI); NewOrientation->Set(0.0f,0.0f,1.0f,0.0f); } else { //Axis = P3DVector3f::CrossProduct(Axis.v,(0,1,0),SegmentY); Axis.Set(SegmentY.Z(),0.0f,-SegmentY.X()); Axis.Normalize(); NewOrientation->FromAxisAndAngle(Axis.X(),Axis.Y(),Axis.Z(),P3DMath::ACosf(CosA)); } }
void P3DCanvas3D::OnChar (wxKeyEvent &event) { bool CameraChanged; int KeyCode; CameraChanged = true; KeyCode = event.GetKeyCode(); if (P3DApp::GetApp()->GetCameraControlPrefs()->EmulateNumpad) { if (event.CmdDown() && KeyCode >= '0' && KeyCode <= '9') { KeyCode = NumPadEmulationKeyMap[KeyCode - '0']; } } if (KeyCode == WXK_NUMPAD1 || KeyCode == WXK_NUMPAD_END) { P3DQuaternionf Rotation; camera.SetCenter(0.0f,0.0f,0.0f); if (event.ShiftDown()) { Rotation.FromAxisAndAngle(0.0f,1.0f,0.0f,P3DMATH_PI); camera.SetDirection(Rotation.q[0], Rotation.q[1], Rotation.q[2], Rotation.q[3]); } else { camera.SetDirection(0.0f,0.0f,0.0f,1.0f); } } else if (KeyCode == WXK_NUMPAD7 || KeyCode == WXK_NUMPAD_HOME) { P3DQuaternionf Rotation; if (event.ShiftDown()) { Rotation.FromAxisAndAngle(-1.0f,0.0f,0.0f,P3DMATH_PI / 2); } else { Rotation.FromAxisAndAngle(1.0f,0.0f,0.0f,P3DMATH_PI / 2); } camera.SetCenter(0.0f,0.0f,0.0f); camera.SetDirection(Rotation.q[0], Rotation.q[1], Rotation.q[2], Rotation.q[3]); } else if (KeyCode == WXK_NUMPAD3 || KeyCode == WXK_NUMPAD_PAGEDOWN) { P3DQuaternionf Rotation; if (event.ShiftDown()) { Rotation.FromAxisAndAngle(0.0f,1.0f,0.0f,P3DMATH_PI / 2); } else { Rotation.FromAxisAndAngle(0.0f,-1.0f,0.0f,P3DMATH_PI / 2); } camera.SetCenter(0.0f,0.0f,0.0f); camera.SetDirection(Rotation.q[0], Rotation.q[1], Rotation.q[2], Rotation.q[3]); } else if (KeyCode == WXK_NUMPAD4 || KeyCode == WXK_NUMPAD_LEFT) { camera.RotateWS(P3DMATH_PI / 12.0f,0.0f,1.0f,0.0f); } else if (KeyCode == WXK_NUMPAD6 || KeyCode == WXK_NUMPAD_RIGHT) { camera.RotateWS(P3DMATH_PI / 12.0f,0.0f,-1.0f,0.0f); } else if (KeyCode == WXK_NUMPAD8 || KeyCode == WXK_NUMPAD_UP) { camera.RotateCS(P3DMATH_PI / 12.0f,1.0f,0.0f,0.0f); } else if (KeyCode == WXK_NUMPAD2 || KeyCode == WXK_NUMPAD_DOWN) { camera.RotateCS(P3DMATH_PI / 12.0f,-1.0f,0.0f,0.0f); } else if (KeyCode == WXK_NUMPAD_ADD || KeyCode == '+' || KeyCode == '=') { ZoomFactor *= 0.75f; } else if (KeyCode == WXK_NUMPAD_SUBTRACT || KeyCode == '-') { ZoomFactor *= 4.0f / 3.0f; } else if (KeyCode == WXK_NUMPAD5 || KeyCode == WXK_NUMPAD_BEGIN) { OrthoCamera = !OrthoCamera; } else { CameraChanged = false; event.Skip(); } if (CameraChanged) { P3DApp::GetApp()->InvalidateCamera(); Refresh(); } }