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