GLSL and HLSL Differences

Anyone happen to know if there are any differences between the way HLSL and GLSL handle basic mathematical operations?
For example, is the order or precedence in which calculations are carried out different, of do floating-point numbers have different precisions in the two languages?

I’m trying to convert some HLSL shaders to GLSL, and, though the Shader appears to work (in as much as no errors are generated) I’m not getting quite the results I expected.


I’m more familiar with Cg/HLSL than with GLSL (which I’ve only used on a handful of occasions) so I can’t directly answer your question. That said, I do know that automatic conversion utilities exist. If you haven’t already tried that route, you might have some luck comparing your hand-translated code vs. auto-translated code, tedious as it may be.

Good luck!

That’s a good point!

I’ve tried AMDs HLSL to GLSL conversion tool, but it seems to generate a huge amount of virtually unreadable code (unreadable to my inexperienced eye, at least). I may try giving it another go, however, and see if I can extract any useful information.

Thanks for the suggestion,


Do you have a simple example translation handy? I’d be interested in seeing some output, without having to do any work that is ;-).

Main differences are matrices operators. For example, in GLSL ‘*’ operator between matrices, is the standar linear algebra matrix multiplication, while in HLSL is a component wise multiplication. Another difference, is (IIRC) by default, HLSL matrices are row major, while in GLSL are column major, so the order of matrix multiplications should be reversed (Remember that A * B * C = C’ * B’ * A’, being A’ the transpose of A and so on) Check this and tell us :slight_smile:

P.D: an example of what code doest work in GLSL (and the translated part) will be useful to us to debug the problem.

It’s getting a bit more complicated, actually

I’ve managed install XP on my MacBook Pro and run the original HLSL shader in the program it was designed for, vvvv. On one of my computers (a PowerMac G5), duplicating the settings across into my GLSL version of the shader from vvvv produced a similar result (apart from the right side of the image being black). Whereas running exactly the same file, with identical settings, in the same Mac application (Quartz Composer) on the MacBook Pro produced a completely different result. I’ve posted screenshots on my blog of the original shader output from vvvv, and my GLSL/Quartz Composer version on the Intel and PPC-powered Macs.

Here is the Fragment Shader code I came up with:

= = = = = = = = = = = = = = = =


// Color 1 color UIName ‘Color 1’
uniform vec4 c1;
// Color 2 color UIName ‘Color 2’
uniform vec4 c2;
// Linear Amount -1000.0 > 1000.0 UIName ‘Linear’
uniform float Lamn;
// Linear Power -1000.0 > 1000.0 UIName ‘Linear Power’
uniform float Lpow;
// Radial Amount -1000.0 > 1000.0 UIName ‘Radial’
uniform float Ramn;
// Radial Pow -1000.0 > 1000.0 UIName ‘Radial Pow’
uniform float Rpow;
// Radial2 Amount 0.0 > 1000.0 UIName ‘Radial2’
uniform float R2amn;
// Radial2 Pow -1000.0 > 1000.0 UIName ‘Radial2 Pow’
uniform float R2pow;
// Pinwheel Amount 0.0 > 1000.0 UIName ‘Pinwheel’
uniform float Pamn;
// Pinwheel Pow 0.0 > 1000.0 UIName ‘Pinwheel Pow’
uniform float Ppow;
// Multiplier -1000.0 > 1000.0 UIName ‘Multiplier’
uniform float Multiplier;
// Phase 0.0 > 1.0 UIName ‘Phase’
uniform float Phase;
// Linear Pow switch UIName ‘Linear Pow enabled’
uniform bool LPe;
// Linear Pow switch UIName ‘Pinwheel Pow enabled’
uniform bool PPe;
//Declare a 2D texture as a uniform variable
uniform sampler2D texture;


void main()
vec4 col;
vec2 p1;
vec2 p2 = gl_TexCoord[0].xy;
vec2 p3 = vec2(0.0,1.0);
vec4 v;
float val,l,r,r2,p = 0.0;
v.xy = p1; = p2;
v -= 0.5;
// linear
if (LPe) l = pow(l,Lpow);
// radial
r = distance(p1+0.5,p2);
// Radial 2
r2 = dot(v,v);
// pinwheel
p = 2.3873atan(0.5-p2.x,0.5-p2.y); // 2.3873 ?
if (PPe) p = pow(p,Ppow);
// sum
val = ((l
val = fract(val+Phase);
val -= 0.5;
val *= -1.0;
val += 0.5;
val *= 2.0;
col = mix(c1,c2,val);
gl_FragColor = col;

= = = = = = = = = = = = = = = = = = = =

It looks like there are two separate issues here, one to do with my GLSL conversion, and another possibly to do with differences in Quartz Composer running on different processor architectures. The second issue is obviously beyond the scope of this forum, but I wonder if anyone can spot any weirdies in my GLSL code that might cause things to behave in an odd manner.

Incidentally, I claim no credit at all for writing the gradient-generating code, which was written by Ernst Hot, and downloaded from
…I just converted it (or attempted to).

Cheers guys,


When converting between HLSL you need to switch the parameters for the arctangent

HLSL atan2(x,y) == GLSL atan(y,x)


Hi -NiCo-

Ooops, yes. I did do that earlier, actually, after your reply to my previous post. I’ve copy-pasted this bit of code from the original HLSL so many times, I forgot to reverse the atan parameters on this occasion. Having said that, the result looks very similar with the parameters switched.

Cheers again,


Ah, I see…

Apart from the fact that you didn’t initialize the p1 variable before using it (I guess the default is zero, but it’s best to make sure) the code looks good.

Did you initialize the uniforms to the correct values?

And where’s your vertex shader code?


Hi again -NiCo-

ah… the uninitialised p1 vec2…
I initialised it to vec2(0.0,0.0) which seems to have helped, well spotted!

That’s done it! On my MacBook pro, at least, I now get the same results with identical settings in vvvv in XP and my GLSL code in Quartz Composer under MacOS X. The only obvious difference is that the image is flipped vertically. I guess HLSL coordinates start at bottom-left, rather than top-left.
Anyway, great stuff! I will try it on the G5 as soon as I get home.

I’ve just realised that, although some vvvv-specific code in the HLSL shader suggested quite large ranges for some of the parameters (-1000 to 1000 or 0 to 1000), it turns out that the usable range of these variables is much narrower than I had thought. This explains why I was unable to duplicate the screenshot from the vvvv site- the controls I had hooked-up to the Shader lack the precision to make fine alterations to the parameters when they’re set to such a large range. Perhaps I need another control setup to pre-multiply the parameters outside the shader for finer or courser control…

Thanks again for your help and suggestions. This gives me some hope that I might be able to get more complex Vertex-Shader-based HLSL effect to work as GLSL shaders in Quartz Composer.


Incidentally, the Vertex Shader code is very simple:

void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_FrontColor = gl_Color;
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;

Hiya, sorry for not replying specifically to your post earlier. This looks like useful info, and there’s a good chance it will come in very handy when I tackle some more complex HLSL Vertex Shaders. I’ll keep you informed on my progress!



I wasn’t sure if I should revive this thread or to start a new one. I’ve posted it here, but may start a new thread at some later point.

Anyone know if there’s a GLSL equivalent to the HLSL ‘lit’ function?
The function is defined as returning

"…a lighting coefficient vector (ambient, diffuse, specular, 1) where:

ambient = 1.
diffuse = ((n • l) < 0) ? 0 : n • l.
specular = ((n • l) < 0) || ((n • h) < 0) ? 0 : ((n • h) * m).
Where the vector n is the normal vector, l is the direction to light and h is the half vector."

Also, anyone happen to know what the ‘mul’ function in HLSL is equivalent to in GLSL? I can’t work out if it’s the same as using the ‘*’ operator. The code I’m trying to convert seem to use ‘mul’ to multiply different kinds of variables, float3s, float4x4 matrices… If I replace the mul function with a simple *, will this be equivalent, or am I going to have to make use of GLSLs matrix multiplication matrixCompMult function? Will these work if the matrices don’t match in terms of number of rows/columns?


matrixCompMult performs a component-wise multiplication of the matrices which is not what you want. The * operator should give you the correct result. When performing matrix operations the sizes always need to match.

You’ll probably have to implement the lit-function yourself, just look for a description of the lit-implementation in the documentation/inet.


Thanks once again -NiCo-!

I will report back on my progress.


Sorry to keep bugging you all on this HLSL/GLSL thing. Just wondering if anyone can give me another little push in the right direction by letting me know, or hazarding a guess, as to what the equivalent to these HLSL variables might be in GLSL.


They’re all float4x4s (equivalent to GLSL mat4s). and I’m guessing they correspond fairly exactly with the standard GLSL mat4 uniforms
but I can’t quite work out which is which.

Sorry for once again reviving this thread, and for asking silly questions.



OpenGL has no concept of a “view” matrix. The local-to-world and world-to-view transforms are always considered one matrix: the GL_MODELVIEW matrix.

As such, there is no equivalent to WORLD or VIEW. Or VIEWPROJECTION. Only WORLDVIEW and WORLDVIEWPROJECTION (and PROJECTION) have OpenGL equivalents.


thanks for getting back to me Korval. This is obviously going to be more complicated than I thought, in that case. I clearly need to do a bit more background-reading on this whole area. I was naively hoping that since the two languages are substantially similar, I could get away with just converting the variable-types and replacing the odd function with an equivalent GLSL version. This pretty-much worked for the first Pixel Shader I tackled, but it looks like there’s going to be a bit more to it when it comes to working with vertex shaders…



Hi again.
Apologies for waking this thread from it’s peaceful slumber, but having done a bit of background reading, I just wanted to check something.

Am I right in inferring that:

is equivalent to
GLSL gl_ModelViewMatrix

is equivalent to
GLSL gl_ModelViewProjectionMatrix

Sorry to be dense here…


AFAIK, yes. Another fine example of Microsoft’s copy and mutilate mentality. Modeling, Viewing, and Projection are the transforms. Object, World, Eye, and Clip are the coordinate spaces you’re transforming between.

Hi Dark Photon,

thanks for getting back to me.
I’m glad I had that right, anyway…



I know what you mean about M$- I used to work in webdesign, years ago, so I’m well aware of all the hacks you have to make to standards-compliant code to make it work with MicroSoft software. They are getting better in that regard though, apparently…