Caustics

Well, I’m not sure if this should go in the advanced section or not, as I feel like I’m a beginner to opengl.

I’m trying to render an underwater scene, I currently have a terrain - using a heightmap, particles in the water - GL_POINTS, and a pipe with a leak and bubbles - more particles - coming out of it.

It is written in C++ using MFC and I’m using Visual Studio .Net Environment. I’m hoping to implement Caustics, I found this http://www.opengl.org/developers/code/mjktips/caustics/ on your website but can’t quite get my head around the code. I was wondering/hoping that somebody might help me with this, by explainig the code found on the website mentioned. Or if someone has done this already then could they let me know how.

I have an nVidia Geforce 3 graphics card, if this would make any difference at all.

Thanks

jotch.

I’m the Angus Dorbie that Mark’s text mentions.

The idea is quite simple, you have an animated pattern that represents the refracted underwater light contribution. This was borrowed from a guy called Jos Stam who has written papers on this stuff, we don’t need to worry about the details because Jos provided some cool textures that Mark & I used.

To apply this in an OpenGL scene today you simply apply it to the scene as a second texture. Using multitexture with a GL_MODULATE function makes this very simple, the only tricky part is generating the texture coordinates that are required to apply the pattern over the scene, again this is simple because OpenGL provides a mechanism called texgen for this. You simply enable texgen for s & t coordinates and provide suitable plane equations. Then you cycle through the animated texture images over time to get the full effect.

So conceptually it’s simple, you modulate the scene by an additional texture representing an animated caustic pattern.

If you have additional questions let me know, there really are only 2 OpenGL implementations stages; using multitexture and applying texgen.

I’ve blended textures before, and I’ve downloaded the code on the mentioned text. Haven’t run it though as I would rather understand it than watch it.

It seems quite complicated to me, do you end up drawing everything twice?
How do you load the textures that you used?
I already have textures loaded into my scene but haven’t clue where to start with that winRAR (caustics.tar.gz) file?
And what exactly does the floor.rgb file do? Is it relevent to what I want?

Is it similar to the detail texturing on the heightmap examples - gametutorials.com - where the texture is overlayed on the objects(heightmap) and then cycled through binding a different texture each time?

Any ideas on how I would set up a class that could be called for every object that would do this?? Or do you have a really simple way of performing what I desire my renderscene to produce??

any help is gratefully appreciated,

jotch.

PS try and make it simple enough so that a child could understand as i get confused easily. thanks.

[This message has been edited by jotch (edited 03-24-2003).]

Has anyone else done this sort of thing??

What format are the ‘cool textures’ that are supplied in the .tar.gz file?? I can’t seem to load them.

Still don’t have much of a clue where to start?? You make it sound really easy, but I’ve never coded this kind of thing before.

Anymore help is appreciated.

jotch

File formats aren’t really on-topic for OpenGL discussions. A .tar.gz archive can be uncompressed on most UNIX boxes (and on Windows boxes that have Cygwin installed) using “tar xvfz filename.tar.gz”

The basic idea of faking caustics this way is, as dorbie says, very simple. You just use multitexturing in GL_MODULATE mode to multiply LIGHT * COLOR with CAUSTICS_ANIMATION. You don’t even need to generate a second set of texture coordinates, because you can use TexGen for that, where the S and T coordinate vectors could typically be perpendicular to the (infinite) light vector.

If you don’t know how to use multitexture, or how to use TexGen, I recommend the OpenGL specification document, available in PDF format from the front page of this site. There are also tutorials on nehe.gamedev.net that go into a bit of detail.

Thanks, that’s kinda what I needed to hear.

Sorry for the trouble.

jotch

How would one stop caustic appearing on the underside if objects in the water ?

Originally posted by pocketmoon:
[b]How would one stop caustic appearing on the underside if objects in the water ?

[/b]

By multiplying (eg GL_MODULATE) the texture by the light contribution. It would give better results if only the diffuse part of lighting was used to modulate the texture, but unless you render your model in multipass or unless you use a pixel shader (be it ARB_texture_env_combine or ARB_fragment_shader) you won’t be able to dissociate the diffuse contribution of OpenGL’s lighting.

http://opengl.nutty.org/effects/index.html

Something similar here… I also did the trick of modulating the caustic texture with a dot of ship normal and upwards vector. I didn’t actually have any proper lighting in it.

The shadow mapping is truly horrendous tho… I must do it properly one day.

Doesn’t run correctly on drivers 43.03 on GF3’s for some reason… Works fine, but big black squares over the terrain.

Source is there for perusal…

Nutty

http://www.lysator.liu.se/~kand/caustics/

-SirKnight

The light contribution should be from above, and that’s the light that’s modulated by the caustics. It’s the L.N of the light contribution that means there’s no illumination underneath, not that there’s no modulation. You just need to take care that you modulate the appropriate directional illumination contribution.

This is not multipass any more, you can easily accomplish this using multitexture in a single pass.

Originally posted by dorbie:
This is not multipass any more, you can easily accomplish this using multitexture in a single pass.

But how do you dissociate the L.N contribution from others (especially ambient) ? Without setting a nul material ambient, I don’t see how it is possible (except with “custom” lightings such as per-pixel lighting).

You don’t want ambient to come in together with diffuse as the fragment color; you want ambient to come in somewhere else (such as in a texture environment constant color) and add it at some later stage.

If you don’t do specular, you could also just send ambient as the separate color and have the color add at the end take care of it.

With fragment programs, this of course becomes very straightforward.

Ok, so with EXT_separate_specular_color and set a nul ambient, you need some kind of ARB_texture_env_crossbar and certainly ARB_texture_env_add.
Fortunately, most of todays graphics cards support all of those extensions.

Thanks,

Okay, this is extremely advanced stuff, but i don’t want to ask in the beginner section as when you ask the question there it doesn’t get the answer quickly, but if i don’t understand the answer will somebody explain it really simply with an example, that they can knock up quickly or has done. Nutty’s example is good, but i haven’t a clue what’s going on as the code is just that, code in code form.

I’ve got the texture mapped to the terrain but anything else in the water doesn’t get touched. It’s based on the detail texture demos on www.gametutorials.com, and i just loop the detail texture with the caustic texture.

Now, how do i set up the coordinates of the texture so that it maps onto everything else in the water??

Say i have a really simple cube made up of 6 quads that are textured, and i want the same size caustics on that cube as are on the terrain?

The terrain does this:
void SetTextureCoord(float x, float y){
float u = (float)x / (float)MAP_SIZE;
float v = -(float)z / (float)MAP_SIZE;
glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);
glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);
}

how do i change this so that the caustics can be applied to a simple quad??
does u & v bcome the corner points to where my quad is drawn??

sorry if this is really simple but i’m not this advanced and need things spelling to me rather than going straight over my head.

thanks

jotch

if anyones willing to look at my code then i’ll quite happily email it to them :slight_smile:

OK, you need texgen.

Basically you need to texgen in eye space and load the eye translation component of the viewing transformation onto the texture matrix stack (inverse eye position actually).

This effectively gives you world space texgen where moving objects and everything else in the world appears to swim through caustics that are fixed in space.

OpenGL functions you need to do all this:

glMatrixMode
glTexGen
glEnable
glTranslate

and possibly matrix pushes & pops.

I did something similar here:
http://www.sgi.com/software/performer/brew/aqua.html

Although my code does the texgen in object space so it’s the wrong thing because whenever you change the modelview matrix for object animation you need to change the texture matrix. Texgen in eye space is much easier.

thanks for the amazingly quick response.

I’ll give it a go, and see what happens, I’ll probably post again soon, :-S

jotch

Hey, you don’t have to load anything into the texture matrix, just specify the eye planes before the camera transform and you’re set. Or was it after? I think it’s before but the point is that the contents of the modelview matrix matter when setting up the eye linear texgen, so it has to be done in the right place which depends on the result you’re trying to achieve.

If you got confused, sorry, you can just read the first sentence and ignore the rest.

-Ilkka

Originally posted by pocketmoon:
[b]How would one stop caustic appearing on the underside if objects in the water ?

[/b]

hi
i’ve tried to figure it out from the other
answers, but unfortunately i didn’t succed.
I’ve based my effect on the ideas from Mark
Kilkgard and Angus Dorbie.
I also have the problem of the caustics being
projected from up and down.
I do a 2-pass rendering, and here’s the code
which setup the texgen and the caustics.

void preFrame(vgCommon *handle, void *udata)
{
//to cycle through the caustics texture
static float lastTime=0.0;

//Planes equations for the s&t text coord gneration
GLfloat sPlane[4] = { 0.003, 0.0, 0.0, 0.0 };
GLfloat tPlane[4] = { 0.0, 0.003, 0.0, 0.0 };

//get the struct from the void pointer argument
causticsData *data = (causticsData *)udata;

/* Compute s&t text coord */
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGenfv(GL_S, GL_OBJECT_PLANE, sPlane);
glTexGenfv(GL_T, GL_OBJECT_PLANE, tPlane);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);

//setup depth Mask and func
glDepthMask(GL_FALSE);
glDepthFunc(GL_EQUAL);

//disable lighting
glDisable(GL_LIGHTING);

/* Setup blending*/
glEnable(GL_BLEND);
glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);

/* Make all the objects in the scene having the same texture*/
pfEnable(PFEN_TEXTURE);
pfApplyTEnv(data->tenv);
pfOverride(PFSTATE_ENTEXTURE | PFSTATE_TEXTURE | PFSTATE_TEXENV, PF_ON);
pfApplyTex(data->tex[data->texindice]);

//cycle through the caustics texture array
if (vgGetTime()-lastTime>0.1)
{
lastTime = vgGetTime();
data->texindice++;

if(data->texindice>=32)
    data->texindice=0;

}

}

btw, i don’t have access to the vertex level
of my objects, that’s why i don’t use multi-texturing.
or dot product.
There is some Vega and perfomer code, but the
translation should be obvious for you folks

Lighting is essential, for this to work correctly. If you illuminate the model from above and have no ambient then it look correct.

If you still want ambient illumination, or additional lights from other directions then you make sure that they are not modulated by the caustic texture. Only the direct illumination term from above should be modulated by the caustic texture.