Dot product in Cg?

Started by
7 comments, last by phresnel 15 years, 4 months ago
I have the following test in a fragment shader:

float2 test1 = (1,1);
float2 test2 = (1,15);
float res    = dot(test1, test2);
	
if (res == 16) {
  color = (0.0,0.0,0.0,0.0);
} else {
  color = (1.0,1.0,1.0,1.0);	
	
}	

But it outputs black instead of white, why!?
Advertisement
test1.x * test2.x + test1.y * test2.y   1    *    1    +    1    *   15     =    16


so res = 16 so the color is set to 0,0,0,0 which is black
Sorry I of course mean that it prints WHITE, which it still does.
I have also tried:

float res = test1.x*test2.x+test1.y*test2.y;

but it still prints white.
This is weird indeed, and it is not the first time I get problems with if statements in CG.

I would say, always try to avoid if statements in a shader. Do it mathematically if possible.

EDIT: Or it might be because of a shader imprecision. Try something like:
if (res > 15.9 && res < 16.1)
The problem is that I have written a function that at some point does the dot product and that function currently does not give the correct result.

I have written the same function in matlab and it gives the correct result, but for some reason it does not work in Cg:

float sineWave(float4 wave_spec, float2 pos, float2 direction, float time, float k){		// Currently testing with hardcoded values.	float amplitude = 1.0;	float freq      = 1.0;	float speed     = 10.0;			float frac = (sin(dot(direction,pos)*freq+time*speed)+1)/2;	float res = 2*amplitude*pow(frac,k);		return res;}


I have a feeling that its the dot product that gives the problem (since a very simple use of this as previously described does not give the correct result), but I have no idea on how to debug/see the returned value.



EDIT: I have now tried:


	float2 test1 = (1,1);	float2 test2 = (1,15);	float res = dot(test1, test2);		if (res > 25 && res < 35) {		// Black		color = (0.0,0.0,0.0,0.0);	} else {			// White		color = (1.0,1.0,1.0,1.0);		}	


and now it prints black, so the dotproduct of test1 and test2 is somewhere in-between ]25;35[ which of course still makes no sense what so ever.
I couldn't get it to work until I changed the code to:

	vec2 test1 = vec2(1.0,1.0);	vec2 test2 = vec2(1.0,15.0);	float res  = dot(test1, test2);		if(res == 16.0)	{		gl_FragColor = vec4 (0,1,0,1);	}else{		gl_FragColor = vec4 (1,0,0,1);	}


was getting all kinds of warnings trying to compile the original version of that
You code is invalid. It should be

if (res == 16.0) {  color = vec4(0.0,0.0,0.0,0.0);} else {  color = vec4(1.0,1.0,1.0,1.0);		}


notice I added vec4 in
color = (0.0,0.0,0.0,0.0);
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
You are right, though its before the if statement that the problem occurs and its float2/float4 in Cg and not vec2/vec4. Here is how it worked out:


float2 test1 = float2(1,1);    //Notice the use of float2 on RHSfloat2 test2 = float2(1,15);   //Notice the use of float2 on RHS	float res = dot(test1, test2);if (res == 16) {		// Black	color = float4(0.0,0.0,0.0,0.0);} else {	// White	color = float4(1.0,1.0,1.0,1.0);		}	
I am not sure if Cg takes the precision of floating point numbers automatically into account, but I bet it doesn't. Surely, google won't be silent. But as a general device:


  • Never use the equality operator ('==') on floating point numbers (that includes floats, double, long double, in C/C++)

  • Floating point numbers *are* imprecise, as compared to integers (which is the reason why often business software works entirely on integer numbers, using floats there could decide about the next million € loss)

  • E.g. 'float x = (1/y) * y' will generally not yield the same as 'float x = y;', and a serious compiler won't make that optimisation, because it would violate IEEE floating point laws (unless you explicitly set a flag to do it anyway)



Wikipedia explains the reasons for this, especially here.

There exist different workarounds to this, but the canonical beginners' workaround is something like:
const float epsilon = 0.00001;...float x = ...;float y = ...;if (x > y-epsilon && x < y+epsilon) {   ...}


Actually, a proper definition of epsilon is not very easy to beginners, so something like the above is a good start. Make it smaller or higher on purpose.

In Ray Tracing, this can be really annoying, as there is often no difference between "Hitpoint on surface" or "Hitpoint directly above it", so there more complicated solutions then the above, because the epsilon sometimes should depend on the actual size of the floats, but I don't want to go into too much detail for now.

Later, you might consult "What every Scientist should now about Floating-Point Arithmetic", which is a gem and should be standard lecture for every graphics programmer (though I myself haven't read it completely yet).

This topic is closed to new replies.

Advertisement