Some code for you (I was bored). The meat is in the function `random_direction'.
#include <iostream>
#include <cmath>
#include <ctime>
float const Pi = std::atan(1.0f) * 4.0f;
float uniform_random(float a, float b) {
return a + drand48() * (b - a);
}
struct Vector {
float x, y, z;
Vector(float x, float y, float z) : x(x), y(y), z(z) {
}
};
std::ostream &operator<<(std::ostream &os, Vector const &v) {
return os << '(' << v.x << ',' << v.y << ',' << v.z << ')';
}
Vector operator+(Vector const &v1, Vector const &v2) {
return Vector(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
}
Vector operator*(float s, Vector const &v) {
return Vector(s * v.x, s * v.y, s * v.z);
}
float dot(Vector const &v1, Vector const &v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
float length(Vector const &v) {
return std::sqrt(dot(v, v));
}
Vector cross_product(Vector const &v1, Vector const &v2) {
return Vector(v1.y * v2.z - v1.z * v2.y,
v1.z * v2.x - v1.x * v2.z,
v1.x * v2.y - v1.y * v2.x);
}
Vector normalize(Vector const &v) {
return (1.0f / length(v)) * v;
}
Vector random_direction(Vector direction, float spread) {
// Make an orthogonal basis whose third vector is along `direction'
Vector b3 = normalize(direction);
Vector different = (std::abs(b3.x) < 0.5f) ? Vector(1.0f, 0.0f, 0.0f) : Vector(0.0f, 1.0f, 0.0f);
Vector b1 = normalize(cross_product(b3, different));
Vector b2 = cross_product(b1, b3);
// Pick (x,y,z) randomly around (0,0,1)
float z = uniform_random(std::cos(spread * Pi), 1);
float r = std::sqrt(1.0f - z * z);
float theta = uniform_random(-Pi, +Pi);
float x = r * std::cos(theta);
float y = r * std::sin(theta);
// Construct the vector that has coordinates (x,y,z) in the basis formed by b1, b2, b3
return x * b1 + y * b2 + z * b3;
}
int main() {
srand48(std::time(0));
for (int i = 0; i < 10; ++i)
std::cout << random_direction(Vector(1.0f, 0.0f, 0.0f), 0.1f) << '\n';
}
Enjoy!