Skip to content

Instantly share code, notes, and snippets.

@Robadob
Last active October 19, 2016 09:55
Show Gist options
  • Save Robadob/481a8a2b0dd3f74865b3ab7218dde7e0 to your computer and use it in GitHub Desktop.
Save Robadob/481a8a2b0dd3f74865b3ab7218dde7e0 to your computer and use it in GitHub Desktop.
3D Rotation inside a vertex shader, where the models remains upright
#version 430
//gl_InstanceID //attribute in uint agent_index;
in vec3 _vertex;
out vec3 u_normal;
uniform mat4 _modelViewMat;
uniform mat4 _projectionMat;
uniform samplerBuffer _texBuf; //Position
uniform samplerBuffer _texBuf2; //Direction
uniform vec3 _color;
out vec3 o_color;
void main(){
//Grab model offset from textures
vec3 loc_data = texelFetch(_texBuf, gl_InstanceID).xyz;//vec3(gl_InstanceID,0,0);//
vec3 dir_data = texelFetch(_texBuf2, gl_InstanceID).xyz;//vec3(gl_InstanceID,0,0);//
float locLen = length(_vertex);//Calc distance from rotation pt, so we can use it later
//Init our axis
vec3 look = vec3(1,0,0);//Model looks down X axis to begin
vec3 up = vec3(0,1,0);
vec3 right = cross(look,up);
vec3 point = _vertex;
//Vector currently points (1,0,0)
//We want to rotate that to point to loc_data
//And then stabilise the Up vector (to remove roll)
//Calculate rotation angle
vec3 rotTarget = normalize(vec3(dir_data.x,0,dir_data.z));
if(rotTarget!=vec3(0)&&rotTarget!=look&&rotTarget!=-look)
{
float yaw = acos(dot(look,rotTarget));
//Rotate about UP
float cosL = cos(yaw);
float sinL = sin(yaw);
vec3 u = normalize(cross(look,rotTarget));//vec3(0,1,0);
mat3 rm = mat3(
(cosL + (u.x*u.x*(1-cosL))), ((u.x*u.y*(1-cosL))-(u.z*sinL)), ((u.x*u.z*(1-cosL))+(u.y*sinL)),
((u.y*u.x*(1-cosL))+(u.z*sinL)), (cosL + (u.y*u.y*(1-cosL))), ((u.y*u.z*(1-cosL))-(u.x*sinL)),
((u.z*u.x*(1-cosL))-(u.y*sinL)), ((u.z*u.y*(1-cosL))+(u.x*sinL)), (cosL + (u.z*u.z*(1-cosL)))
);
right = rm*right;
//Apply rotation matrix
point = rm*point;
}
rotTarget = normalize(vec3(dir_data.x,dir_data.y,0));
if(rotTarget!=vec3(0)&&rotTarget!=look&&rotTarget!=-look)
{
//This is the angle
float pitch = acos(dot(look,rotTarget));
float cosL = cos(pitch);
float sinL = sin(pitch);
vec3 u =normalize(right);
u=(dir_data.y>0)?u:-u;
mat3 rm = mat3(
(cosL + (u.x*u.x*(1-cosL))), ((u.x*u.y*(1-cosL))-(u.z*sinL)), ((u.x*u.z*(1-cosL))+(u.y*sinL)),
((u.y*u.x*(1-cosL))+(u.z*sinL)), (cosL + (u.y*u.y*(1-cosL))), ((u.y*u.z*(1-cosL))-(u.x*sinL)),
((u.z*u.x*(1-cosL))-(u.y*sinL)), ((u.z*u.y*(1-cosL))+(u.x*sinL)), (cosL + (u.z*u.z*(1-cosL)))
);
point = rm*point;
//If upside down (rotation if 90-270 degrees)
if(cosL<0)
{
float roll=3.14159;
float cosL = cos(roll);
float sinL = sin(roll);
up=rm*up;
u =normalize(cross(right,up));
rm = mat3(
(cosL + (u.x*u.x*(1-cosL))), ((u.x*u.y*(1-cosL))-(u.z*sinL)), ((u.x*u.z*(1-cosL))+(u.y*sinL)),
((u.y*u.x*(1-cosL))+(u.z*sinL)), (cosL + (u.y*u.y*(1-cosL))), ((u.y*u.z*(1-cosL))-(u.x*sinL)),
((u.z*u.x*(1-cosL))-(u.y*sinL)), ((u.z*u.y*(1-cosL))+(u.x*sinL)), (cosL + (u.z*u.z*(1-cosL)))
);
point = rm*point;
}
}
//Output vert loc to be interpolated for shader to calc norm
vec3 t_position = point + loc_data;
u_normal = vec4(_modelViewMat * vec4(t_position,1.0)).xyz;
gl_Position = _projectionMat * _modelViewMat * vec4(t_position,1.0);
o_color = _color;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment