jaykumarark
jaykumarark

Reputation: 2449

Render circles along a 3d curves

I am trying to render circles around each point of a 3d curves. Basically trying to create a tube like structure for the curve. But the orientation of the circle is wrong as shown in the image. Below are my calculations for the Model matrix of the circle object after calculating the frenet frame. Where am I going wrong? For reference, green line is the tangent, blue is the normal and red is the binormal.

view 1 view 2

Frenet Frame Calculations:

glm::vec3 pointback = curve_points[i-1];
glm::vec3 pointmid = curve_points[i];
glm::vec3 pointforward = curve_points[i+1];

glm::vec3 forward_tangent_vector =  glm::vec3(glm::normalize(pointforward - pointmid)) ;
glm::vec3 backward_tangent_vector = glm::vec3(glm::normalize(pointmid - pointback)) ;

glm::vec3 second_order_tangent = glm::normalize(forward_tangent_vector - backward_tangent_vector);

glm::vec3 binormal = glm::normalize(glm::cross(forward_tangent_vector, second_order_tangent));

glm::vec3 normal = glm::normalize(glm::cross(binormal, forward_tangent_vector));

Model Matrix for Circle calculations

glm::mat3 tbn = glm::mat3(forward_tangent_vector,binormal,normal);

glm::vec3 normal_axis = glm::vec3(0, 1, 0);
//normal_axis = forward_tangent_vector;

glm::vec3 circleNormal = glm::normalize(tbn * normal_axis);
glm::vec3 rotationAxis = glm::cross(normal_axis, circleNormal);
float rotationAngle = glm::acos(glm::dot(normal_axis, circleNormal));

R = glm::rotate(R, glm::degrees(rotationAngle), rotationAxis);

T = glm::translate(T, pointmid);

glm::mat4 Model = T*R;

Upvotes: 4

Views: 1166

Answers (1)

Paul Houx
Paul Houx

Reputation: 2043

The easiest way to do this is by using Frenet-Serret frames, more commonly known as TBN frames or a TBN matrix. Here's how:

  1. Sample two points on the curve. Let's call them "current" and "next".
  2. Construct the Frenet frame as follows:

    vec3 T = normalize( next - current );
    vec3 B = normalize( cross( T, next + current ) );
    vec3 N = normalize( cross( B, T ) );
    
  3. Calculate your 2D circle, similar to this:

    float x = cos( angle );
    float y = sin( angle );
    
  4. Now, use the Frenet frame to calculate the proper orientation:

    vec3 tangent = T;
    vec3 normal = normalize( B * x + N * y );
    vec3 vertex = current + B * x + N * y; // note: not normalized!
    

An easy to follow explanation can be found here: http://www.blackpawn.com/texts/pqtorus/

Upvotes: 5

Related Questions