How to implement SLERP in GLSL/HLSL
Asked Answered
S

1

11

I'm attempting to SLERP from GLSL (HLSL would also be okay as I'm targeting Unity3D)

I've found this page: http://www.geeks3d.com/20140205/glsl-simple-morph-target-animation-opengl-glslhacker-demo

It contains the following listing:

#version 150
in vec4 gxl3d_Position;
in vec4 gxl3d_Attrib0;
in vec4 gxl3d_Attrib1;
out vec4 Vertex_Color;
uniform mat4 gxl3d_ModelViewProjectionMatrix;
uniform float time;

vec4 Slerp(vec4 p0, vec4 p1, float t)
{
  float dotp = dot(normalize(p0), normalize(p1));
  if ((dotp > 0.9999) || (dotp<-0.9999))
  {
    if (t<=0.5)
      return p0;
    return p1;
  }
  float theta = acos(dotp * 3.14159/180.0);
  vec4 P = ((p0*sin((1-t)*theta) + p1*sin(t*theta)) / sin(theta));
  P.w = 1;
  return P;
}

void main()
{
  vec4 P = Slerp(gxl3d_Position, gxl3d_Attrib1, time);
  gl_Position = gxl3d_ModelViewProjectionMatrix * P;
  Vertex_Color = gxl3d_Attrib0;
}

The maths can be found on the Wikipedia page for SLERP: http://en.wikipedia.org/wiki/Slerp

But I question the line

  float theta = acos(dotp * 3.14159/180.0);

That number is 2π/360, i.e. DEG2RAD And dotp, a.k.a cos(theta) is not an angle

i.e. it doesn't make sense to DEG2RAD it.

Isn’t the bracketing wrong?

float DEG2RAD = 3.14159/180.0;
float theta_rad = acos(dotp) * DEG2RAD;

And even then I doubt acos() returns degrees.

Can anyone provide a correct implementation of SLERP in GLSL?

Subservient answered 21/5, 2014 at 21:0 Comment(4)
Good question, shame no answer. I agree, the implementation you posted looks broken. acos definitely returns radians.Aufmann
Did you find a correct implementation for this?Canica
shadertoy.com/view/4sV3zt has a vec2 implementation that should generalize to vec3/vec4 easily. And indeed, acos takes a radians value, and returns a value in the interval [0, pi] - see e.g. khronos.org/registry/OpenGL-Refpages/gl4/html/acos.xhtmlChristen
instead of using the 'if ((dotp > 0.9999) || (dotp<-0.9999))' statement, you can use the clamp function at line 'float theta = acos(dotp);' in the following way: 'float theta = acos(clamp(dotp,-1,1));'Unwise
T
1

All that code seems fine. Just drop the " * 3.14159/180.0 " and let it be just:

float theta = acos(dotp);
Tweezers answered 21/8, 2018 at 22:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.