Created
December 12, 2016 11:32
-
-
Save nkint/7449c893fb7d6b5fa83118b8474d7dcb to your computer and use it in GitHub Desktop.
Rotate mesh points towards a direction vector with vertex shader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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