Skip to content

Instantly share code, notes, and snippets.

@nkint
Created December 12, 2016 11:32
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nkint/7449c893fb7d6b5fa83118b8474d7dcb to your computer and use it in GitHub Desktop.
Save nkint/7449c893fb7d6b5fa83118b8474d7dcb to your computer and use it in GitHub Desktop.
Rotate mesh points towards a direction vector with vertex shader
// quaternion code from https://github.com/stackgl/gl-quat
// rotation from https://twistedpairdevelopment.wordpress.com/2013/02/11/rotating-a-vector-by-a-quaternion-in-glsl/
precision mediump float;
uniform mat4 projection, view;
uniform vec3 translate;
uniform vec3 scale;
attribute vec3 normal;
attribute vec3 position;
varying vec3 vNormal;
varying vec4 vPosition;
float PI = 3.1415926535897932384626433832795;
vec4 setAxisAngle (vec3 axis, float rad) {
rad = rad * 0.5;
float s = sin(rad);
return vec4(s * axis[0], s * axis[1], s * axis[2], cos(rad));
}
vec3 xUnitVec3 = vec3(1.0, 0.0, 0.0);
vec3 yUnitVec3 = vec3(0.0, 1.0, 0.0);
vec4 rotationTo (vec3 a, vec3 b) {
float vecDot = dot(a, b);
vec3 tmpvec3 = vec3(0);
if (vecDot < -0.999999) {
tmpvec3 = cross(xUnitVec3, a);
if (length(tmpvec3) < 0.000001) {
tmpvec3 = cross(yUnitVec3, a);
}
tmpvec3 = normalize(tmpvec3);
return setAxisAngle(tmpvec3, PI);
} else if (vecDot > 0.999999) {
return vec4(0,0,0,1);
} else {
tmpvec3 = cross(a, b);
vec4 _out = vec4(tmpvec3[0], tmpvec3[1], tmpvec3[2], 1.0 + vecDot);
return normalize(_out);
}
}
vec4 multQuat(vec4 q1, vec4 q2) {
return vec4(
q1.w * q2.x + q1.x * q2.w + q1.z * q2.y - q1.y * q2.z,
q1.w * q2.y + q1.y * q2.w + q1.x * q2.z - q1.z * q2.x,
q1.w * q2.z + q1.z * q2.w + q1.y * q2.x - q1.x * q2.y,
q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
);
}
vec3 rotateVector( vec4 quat, vec3 vec ) {
// https://twistedpairdevelopment.wordpress.com/2013/02/11/rotating-a-vector-by-a-quaternion-in-glsl/
vec4 qv = multQuat( quat, vec4(vec, 0.0) );
return multQuat( qv, vec4(-quat.x, -quat.y, -quat.z, quat.w) ).xyz;
}
void main () {
vec3 dir = translate - vec3(0.0, 0.0, 0.0);
vec3 forward = vec3(0.0, 0.0, 1.0);
vec4 quaternion1 = rotationTo(dir, forward);
vec3 positionScaled = (position * scale);
vec3 positionRotated = rotateVector(quaternion1, positionScaled);
vec3 modelPosition = positionRotated + translate;
gl_Position = projection * view * vec4(modelPosition, 1.0);
vNormal = normal;
vPosition = view * vec4(modelPosition, 1.0);
vPosition.z -= view[3].z;
}
@patricknelson
Copy link

patricknelson commented Jan 24, 2018

Thanks so much for distilling this! Saved me a ton of time/effort condensing all the functions to operate on quaternions in my Cg/HLSL. You're awesome! This was so helpful that I wanted to share the slightly modified version with an example that could be used in Unity as well. Check it out: https://gist.github.com/patricknelson/f4dcaedda9eea5f5cf2c359f68aa35fd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment