float polygon_sides_length(float sides_count) { return 2.0 * sin(M_PI / sides_count); } /* Returns intersection ratio between the radius edge at theta and the polygon edge. * Start first corners at theta == 0. */ float circle_to_polygon_radius(float sides_count, float theta) { /* From Graphics Gems from CryENGINE 3 (Siggraph 2013) by Tiago Sousa (slide 36). */ float side_angle = M_2PI / sides_count; float halfside_angle = side_angle * 0.5; theta += halfside_angle; return cos(side_angle * 0.5) / cos(theta - side_angle * floor((sides_count * theta + M_PI) / M_2PI)); } /* Remap input angle to have homogenous spacing of points along a polygon edge. * Expect theta to be in [0..2pi] range. */ float circle_to_polygon_angle(float sides_count, float theta) { float side_angle = M_2PI / sides_count; float side = floor(theta / side_angle); float halfside_angle = side_angle * 0.5; /* Length of segment from center to the middle of polygon side. */ float adjacent = circle_to_polygon_radius(sides_count, halfside_angle); /* This is the relative position of the sample on the polygon half side. */ float local_theta = theta - side * side_angle; float ratio = (local_theta - halfside_angle) / halfside_angle; float halfside_len = polygon_sides_length(sides_count) * 0.5; float oposite = ratio * halfside_len; /* NOTE: atan(y_over_x) has output range [-M_PI_2..M_PI_2]. */ float final_local_theta = halfside_angle + atan(oposite / adjacent); return side * side_angle + final_local_theta; }