public double[] MakeFromX(FVector XAxis) { double[] mt = new double[9]; FVector NewX = XAxis.GetSafeNormal(); // try to use up if possible FVector UpVector = new FVector(0, 0, 1.0);// (Math.Abs(NewX.Z) < (1.0 - KINDA_SMALL_NUMBER)) ? FVector(0, 0, 1.f) : FVector(1.f, 0, 0); FVector NewY = (UpVector.CrossProduct(NewX)).GetSafeNormal(); FVector NewZ = NewX.CrossProduct(NewY); //FRotator Rotator = new FRotator(Math.Atan2(NewX.Z, Math.Sqrt(NewX.X * NewX.X + NewX.Y * NewX.Y)) * 180.0 / PI, // Math.Atan2(XAxis.Y, XAxis.X) * 180.0 / PI, // 0); //const FVector SYAxis = FRotationMatrix(Rotator).GetScaledAxis(EAxis::Y); //Rotator.Roll = FMath::Atan2(ZAxis | SYAxis, YAxis | SYAxis) * 180.f / PI; mt[0] = NewX.X; mt[1] = NewX.Y; mt[2] = NewX.Z; mt[3] = NewY.X; mt[4] = NewY.Y; mt[5] = NewY.Z; mt[6] = NewZ.X; mt[7] = NewZ.Y; mt[8] = NewZ.Z; return(mt); }
/// <summary> /// Returns a random unit vector, uniformly distributed, within the specified cone. /// </summary> /// <param name="dir">The center direction of the cone</param> /// <param name="horizontalConeHalfAngleRad">Horizontal half-angle of cone, in radians.</param> /// <param name="verticalConeHalfAngleRad">Vertical half-angle of cone, in radians.</param> /// <returns>Normalized vector within the specified cone.</returns> public FVector VRandCone(FVector dir, float horizontalConeHalfAngleRad, float verticalConeHalfAngleRad) { if ((verticalConeHalfAngleRad > 0.0f) && (horizontalConeHalfAngleRad > 0.0f)) { float randU = FRand(); float randV = FRand(); // Get spherical coords that have an even distribution over the unit sphere // Method described at http://mathworld.wolfram.com/SpherePointPicking.html float theta = 2.0f * FMath.PI * randU; float phi = FMath.Acos((2.0f * randV) - 1.0f); // restrict phi to [0, ConeHalfAngleRad] // where ConeHalfAngleRad is now a function of Theta // (specifically, radius of an ellipse as a function of angle) // function is ellipse function (x/a)^2 + (y/b)^2 = 1, converted to polar coords float coneHalfAngleRad = FMath.Square(FMath.Cos(theta) / verticalConeHalfAngleRad) + FMath.Square(FMath.Sin(theta) / horizontalConeHalfAngleRad); coneHalfAngleRad = FMath.Sqrt(1.0f / coneHalfAngleRad); // clamp to make a cone instead of a sphere phi = FMath.Fmod(phi, coneHalfAngleRad); // get axes we need to rotate around FMatrix dirMat = FMatrix.CreateRotation(dir.Rotation()); // note the axis translation, since we want the variation to be around X FVector dirZ = dirMat.GetUnitAxis(EAxis.X); FVector dirY = dirMat.GetUnitAxis(EAxis.Y); FVector result = dir.RotateAngleAxis(phi * 180.0f / FMath.PI, dirY); result = result.RotateAngleAxis(theta * 180.0f / FMath.PI, dirZ); // ensure it's a unit vector (might not have been passed in that way) result = result.GetSafeNormal(); return(result); } else { return(dir.GetSafeNormal()); } }
/// <summary> /// Returns a random unit vector, uniformly distributed, within the specified cone. /// </summary> /// <param name="dir">The center direction of the cone</param> /// <param name="coneHalfAngleRad">Half-angle of cone, in radians.</param> /// <returns>Normalized vector within the specified cone.</returns> public FVector VRandCone(FVector dir, float coneHalfAngleRad) { if (coneHalfAngleRad > 0.0f) { float randU = FRand(); float randV = FRand(); // Get spherical coords that have an even distribution over the unit sphere // Method described at http://mathworld.wolfram.com/SpherePointPicking.html float theta = 2.0f * FMath.PI * randU; float phi = FMath.Acos((2.0f * randV) - 1.0f); // restrict phi to [0, ConeHalfAngleRad] // this gives an even distribution of points on the surface of the cone // centered at the origin, pointing upward (z), with the desired angle phi = FMath.Fmod(phi, coneHalfAngleRad); // get axes we need to rotate around FMatrix dirMat = FMatrix.CreateRotation(dir.Rotation()); // note the axis translation, since we want the variation to be around X FVector dirZ = dirMat.GetUnitAxis(EAxis.X); FVector dirY = dirMat.GetUnitAxis(EAxis.Y); FVector result = dir.RotateAngleAxis(phi * 180.0f / FMath.PI, dirY); result = result.RotateAngleAxis(theta * 180.0f / FMath.PI, dirZ); // ensure it's a unit vector (might not have been passed in that way) result = result.GetSafeNormal(); return(result); } else { return(dir.GetSafeNormal()); } }