ARB_vertex_program and the fog coordinate

I’ve got a vertex program doing geomorphing for my terrain. I just wanted to enable the FFP fog, but it obviously doesn’t work as i’m using a vertex program. So i’m trying to replicate the FFP fog by the vertex program.

The spec. is unclear about how the fog coordinate is to be interpreted. On my Radeon 9700, it seems to expect a world space distance. For ex. if i set my fog mode to linear with a start distance of 1000 and an end distance of 2000, a vertex at a distance of 1500 will result in 50% fog. In consequence in my program i just feed in fogcoord.x the distance between the vertex and the camera, and fogging appears correctly.

Unfortunately the meaning seems to be different on NVidia cards. I haven’t tested a lot, just saw that no fog appeared on a GF4 Ti 4600 with latest drivers. I’m suspecting they need the foog coord to be in the [0-1] range as a percentage directly.

Do i need to implement two seperate shaders just to fix that ?

Y.

[This message has been edited by Ysaneya (edited 02-07-2004).]

I can confirm the difference in VP fog behaviour between NV and ATI cards. I’m also interested to know why and what should be done about it.

I believe the Nvidia driver is wrong. The ARB_vertex_program spec is pretty clear in saying the fog output of the vertex program is treated the same as the fog coordinate specificed if EXT_fog_coord is used. That spec is very clear about the interpretation of the coordinate. The third issue says “Since we’re now specifying a number which behaves like an eye-space distance, rather than a [0,1] quantity…”

I’d suggest reporting it as a bug to Nvidia. If they respond with a reasonable justification of why their driver does what it does, could you post it here? That should shed some light on the issue.

Originally posted by Ysaneya:
Do i need to implement two seperate shaders just to fix that ?
As a workaround you can set linear fog with a [0…1] range, for all cards.

I don’t see anything about fog coord clamping in the ARB_vp spec, so maybe that plays a role, too. Clamping doesn’t make much sense for EXP and EXP2 fog, but I can see how it could be needed for linear fog …

bump

I suspect I have found a bug in Catalyst 4.2, but as I’m not too experienced with vertex programs, I thought I’d ask before bothering ATI.

Question: Shouldn’t the following two ways of rendering be equivalent?
It appears I can’t use vertex.fogcoord as an input in ARB_vertex_program. I get a constant zero on R300 and outright “undefined” values on RV280. I can however use result.fogcoord as an output without any issues. This isn’t shown here.

Is there some enable or other required state I’ve missed?

Common init

struct Vertex
{
	float x,y;
	float fogcoord;
};

Vertex vert[3];

static const char vertex_program_code_f[]=
	"!!ARBvp1.0
"
	"OPTION ARB_position_invariant;"
	"MOV result.color,vertex.color;"
	"MOV result.fogcoord,vertex.fogcoord;"
	"END";

GLuint vertex_program_fogcoord=0;

void
init()
{
	//initialize fog parameters
	glFogf(GL_FOG_START,0.0f);
	glFogf(GL_FOG_END,1.0f);
	glFogi(GL_FOG_MODE,GL_LINEAR);
	glFogi(GL_FOG_COORDINATE_SOURCE_EXT,GL_FOG_COORDINATE_EXT);
	glEnable(GL_FOG);

	//initialize vertex array
	vert[0].x=-0.5f;	vert[0].y=-0.5f;	vert[0].fogcoord=0.0f;
	vert[1].x= 0.5f;	vert[1].y= 0.0f;	vert[1].fogcoord=0.5f;
	vert[2].x= 0.0f;	vert[2].y= 0.5f;	vert[2].fogcoord=1.0f;

	glVertexPointer(2,GL_FLOAT,sizeof(Vertex),&vert[0].x);
	glEnableClientState(GL_VERTEX_ARRAY);

	glFogCoordPointerEXT(GL_FLOAT,sizeof(Vertex),&vert[0].fogcoord);

	//initialize colors
	glClearColor(0.0f,0.0f,0.0f,0.0f);
	glFogfv(GL_FOG_COLOR,blue);
	glColor4fv(red);

	int gl_error=glGetError();
	printf("Last GL error is %d
",gl_error);
	glGenProgramsARB(1,&vertex_program_fogcoord);
	glBindProgramARB(GL_VERTEX_PROGRAM_ARB,vertex_program_fogcoord);
	glProgramStringARB(GL_VERTEX_PROGRAM_ARB,GL_PROGRAM_FORMAT_ASCII_ARB,
		strlen(vertex_program_code_f),
		vertex_program_code_f);

	int error_position=0;
	glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB,&error_position);
	printf("Vertex program error position=%d
",error_position);
	printf("Error string: %s
",(const char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB));
}

Fixed function version

glEnableClientState(GL_FOG_COORDINATE_ARRAY_EXT);
glDisable(GL_VERTEX_PROGRAM_ARB);
glLoadIdentity();
glDrawArrays(GL_TRIANGLES,0,3);

Vertex program version

glEnableClientState(GL_FOG_COORDINATE_ARRAY_EXT);
glBindProgramARB(GL_VERTEX_PROGRAM_ARB,vertex_program_fogcoord);
glEnable(GL_VERTEX_PROGRAM_ARB);
glLoadIdentity();
glDrawArrays(GL_TRIANGLES,0,3);

There are no errors reported by the GL. The triangle rendered with ARB_vp is flat red. The triangle rendered with fixed function vertex processing shows the expected red->blue color gradient.

so fog is the next mystery? on my gf3 when using a vertex program i could just do
MOV result.fogcoord, vertex.fogcoord;

and the fog appeared correctly.
when using a fragment program i did
OPTION ARB_fog_linear;

and again fog appeared correctly.
now when using that vertex program AND fragment program together -> no fog at all. i just noticed its the same on my radeon (though i never tested both programs on their own with this card).

when checking whats wrong btw. it seemed like the fogcoord was always zero
(MOV result.color, fragment.fogcoord.x

Originally posted by Jared:
[b]so fog is the next mystery? on my gf3 when using a vertex program i could just do
MOV result.fogcoord, vertex.fogcoord;

and the fog appeared correctly.[/b]
I’ve just swapped cards again. My Geforce 3 behaves as I expected, ie there’s fog.

when using a fragment program i did
OPTION ARB_fog_linear;
and again fog appeared correctly.

ARB_fragment_program has always worked correctly for me on R300. You don’t need to use the ARB_fog_* options. “fragment.fogcoord” behaves just like any other interpolated attribute, as it should.

now when using that vertex program AND fragment program together -> no fog at all. i just noticed its the same on my radeon (though i never tested both programs on their own with this card).
You have just confirmed my findings. Good
Try outputting some constant (or other attribute) to result.fogcoord from the vertex program. It will work fine, as stated. It’s the fogcoord input to the vertex program that’s broken.

[/b]
when checking whats wrong btw. it seemed like the fogcoord was always zero
(MOV result.color, fragment.fogcoord.x; )[/b]
Yes, on R300. I get different results on RV280 though. The fog coord seems to be garbled, the color gradient even starts at the wrong vertex and proceeds in the wrong direction. Going to test R200 in a few minutes.

Thanks. I think I’ll send a bug report then.

I’ve been working on fragment program / fog support in Mesa these days. It took some experimentation to figure it out myself.

In general, the vertex program should emit a fog coordinate (i.e. an eye-space Z distance), not a fog blend factor (in [0,1]).
The fog coordinate may just be vertex.fogcoord or it may be computed from the incoming vertex position.

Then in your fragment program you can either specify a fog option (i.e. “OPTION ARB_fog_linear;”) or use the incoming fragment.fogcoord.x value to compute your own fog blend factor and modify result.color accordingly.

I tested with NVIDIA’s 53.36 driver and GeForceFX 5200. Mesa produces identical results now. See Mesa’s progs/demos/arbfplight.c for an example.

-Brian

Brian,
Note how I set up my fog mode:

glFogf(GL_FOG_START,0.0f);
glFogf(GL_FOG_END,1.0f);
glFogi(GL_FOG_MODE,GL_LINEAR);

This is essentially an identity transform for the fogcoord, except for clamping - the per-vertex fogcoords in my sample code don’t need further clamping though.

Even though I just recently started working with ARB_vertex_program, I don’t have any problems with ARB_fragment_program. I’ve been using it for quite some time now. Fog coords work as expected in the fragment program (if they get there). So the issue is not using the interpolated fogcoord in fragment processing, nor is it computing a fogcoord in a vertex program. This is all working fine on ATI cards AFAICS.

The issue is that per-vertex fogcoords cannot be passed into the vertex program.
I’ve found two workarounds for ATI cards. You can pass the fogcoords in either as 1D texcoords or as generic vertex attribute #5 (which aliases to vertex.fogcoord if it aliases at all - it doesn’t alias with ATI drivers, which is perfectly allowed behaviour, of course). In both cases, I just MOV to result.fogcoord and everything starts working again.

PS: the bug report has already been sent.

I’m not sure this is an “input only” problem. My vertex program doesn’t use the fog input, it directly writes into the fog destination register the eye-space distance to the vertex. It works well on ATIs, but is broken (no fog) on a GF4 Ti with latest drivers. Note that i later tested on a GF3 with drivers a month or two older, and that it worked perfectly well. So it doesn’t happen on all NVidia cards.

Y.

holy… either that fog business is more complicated than rocket science or something is just weird.

passing on vertex.fogcoord isnt a good idea, for some reason its always 0. not touching it will produce a fogcoord in the fragment program. using that as color looks good at first. until you move and notice “hey, its completely static”. also, the fog seems to appear along a diagonal line from left/front to right/back. not to mention all the artefacts along the seems that made me wonder if screwed up the index buffers. then i saw the same artifacts on clipped triangles. if they arent completely visible they end up with no fogcoord.

doesnt matter, lets just use fragment.position.z, which (as far as i understood) shouldnt contain a constant 1 (and w should be 1/w which seems to ALWAYS equal 0??)

so what, then pass the z coord of the transformed vertex as fogcoord. looked well and updated correctly, though it still had artifacts like clipped triangles wouldnt be interpolated correctly. additionally, some other values (either texcoords or colors from a texture lookup) were completely off (probably my fault, lets double check the attributes).

another nice thing when displaying the fogcoord as color is that close to the geometry holes appear and show a flickering checkboard pattern.

in vertex program:

MOV result.texcoord.x, res.z;
MOV result.position, res;

in fragment program:
ADD f, fragment.fogcoord.x, -20;
MUL_SAT f, f, .016666;
MOV result.color, f;

result: http://festini.device-zero.de/depth.jpg