Sign in to follow this  

Fake flat surface reflections

This topic is 4176 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been wanting to add this for a while, but I can't seem to get the math together to do what I want. Basically, I just want to use a low quality blurry texture to represent the ceiling (or the ceiling and all four walls), and render this as a secondary texture on the floor. If anyone reading this played Half Life 2, this was happening in the first building area you enter, where you have to enter the metal-fence-looking queue. You could see the ceiling lights on the floor. Just a texture that moved about when you look at it from different perspectives. I'm guessing I need to do some type of bounce from the camera, off of the normal of the surface, to the object surface being reflected. But nothing I try seems to work the way I want it to. I drew this up quickly to explain what I expect I need to do, or at least simulate: Free Image Hosting at www.ImageShack.us I have my texture loaded and my vertex shader technique is ready for me to start typing, but I'm not sure what to try. Can anyone recommend a tutorial or some type of online reading material? I would really appreciate any information. Thanks.

Share this post


Link to post
Share on other sites
Just render the ceiling (and walls if you have to) to a texture with inverted up axis. Then project this texture on to the floor (you may even perturb the texcoords on the floor judiciously in a fragment program or in a vertex program with a tesselated mesh to simulate a bumpy surface). You can find implementation details in this article.

Share this post


Link to post
Share on other sites
Well, this is a top-down third person view, so I don't actually have a ceiling to reflect. Just literally a texture that I've manually created. From what I understood, it doesn't look like that operation will work quite the same way. It looks like it relies on the reflection texture to be from the perspective of the camera.

But it was still educational, so thanks. I still need a little help figuring out how to render using, as he puts it, "projective texturing", with a pre-generated texture. I believe it could be similarly accomplished with the camera matrices.

Thanks again :)

Share this post


Link to post
Share on other sites
I'm having a hard time visualizing the problem, could you post a screenshot from your game?

Share this post


Link to post
Share on other sites
Well.... if I understand correctly, you have a 3rd person view, so you don't have geometry for the ceiling, but you want to pretend there is so it may be reflected.

That's why you called the "fake" flat surface reflections.

You plan to make use of a "flat" ceiling texture (or collection of textures)

You can do that - the equation becomes nothing more than a position raytrace of each corner of the viewing frustrum (as you've shown) brush up on the maths and you'll be fine.

You may want to (if you're already using a 3d renderer) make use of its capabilities and just "mirror" (no really, mathematically) the coordinates of flat 3d geometry of the ceiling below the floor plane.

At his point you can blend the result over a stenciled section of the scene, or can render to texture and use it slightly differently if you're wanting to do blurry, noisy, or distorted floor reflections (probably advisable for quality)

Hopefully this pushes you in the right direction.

-Michael g.

Share this post


Link to post
Share on other sites
Half Life 2 simply used pre-rendered cubemaps for environment reflections. The level builders placed points in the level where the environment was rendered into a low resolution cubemap. The game then used this cubemap as the specular component by choosing the closest cubemap to a surface (or material) and doing a cubemap lookup based on the reflection vector.

So you need to render the environment that you want reflected at various sample points (and the environment could be different then what you render in the game since this can be a preprocess) and do simple cubic environment mapping. If you decide to do this I'd highly recommend using glossmaps (where the reflection is modulated by the glossmap to allow varying reflectivity).

Share this post


Link to post
Share on other sites
Quote:
Original post by blue_knight
Half Life 2 simply used pre-rendered cubemaps for environment reflections. The level builders placed points in the level where the environment was rendered into a low resolution cubemap. The game then used this cubemap as the specular component by choosing the closest cubemap to a surface (or material) and doing a cubemap lookup based on the reflection vector.

So you need to render the environment that you want reflected at various sample points (and the environment could be different then what you render in the game since this can be a preprocess) and do simple cubic environment mapping. If you decide to do this I'd highly recommend using glossmaps (where the reflection is modulated by the glossmap to allow varying reflectivity).


:(
Environment mapped cubemapping for flat reflections is a bad idea...
(I've never seen it done well, anyway...)

-Michael g.

Share this post


Link to post
Share on other sites
I could get the result I want by throwing a flat quad down under the floor, just as far down from the floor as the ceiling would be up, then making the floor mesh blend by modulating over that quad.

Imagine a glass floor, where another opaque floor is about five feet down under it. The glass floor would not be entirely transparent. If you were drunk, you might think that the glass floor is just a very shiny opaque floor, and that the secondary floor (which is under it) is the ceiling being reflected.

The only input to this calculation is the 5-feet, which represents how far the reflected object is from the surface. I just figured there was a way to accomplish this same effect by generating secondary texture coordinates for the floor in the vertex shader.

I still appreciate the information. Thanks.

Share this post


Link to post
Share on other sites
stupid question, but can't you just add a ceiling quad? and then reflect it normally?

It will be backface-culled so it wont be obstructing the camera, and reflections will be accurate - so unless you have a good reason for not adding an extra pair of triangles per room, I see no point not doing it the "right" way. :)

Share this post


Link to post
Share on other sites
Quote:
Environment mapped cubemapping for flat reflections


can indeed be done easily.. its basically just dependent on calculating a reflection vector in the vertex shadoer and projecting your cubemap in the pixel shader.

Share this post


Link to post
Share on other sites
Quote:
Original post by Rasmadrak
stupid question, but can't you just add a ceiling quad? and then reflect it normally?

I want to do a straight multi-texture render rather than using secondary render target surfaces AND multi-texture renders, or stencil buffers. With the simplified system, I can make any flat surface reflect, rather than just the floor. The reflections would be fake, but they could be used anywhere and everywhere at once, with virtually no performance costs.

I did manage to pull off a hack for the floor.

vector pos = vertex_pos * worldmatrix;
pos += camera_forward_vector * arbitrary_multiplier;
reflect_tex_coords.x = pos.x * arbitrary_divisor;
reflect_tex_coords.y = pos.z * arbitrary_divisor;

It's definitely a hack, and not correct. I simply shoved the texture coordinates away from the camera by a certain amount. But just using the camera's forward vector is incorrect. The amount that the texture needs to be pushed away would depend a lot on the angle. When the camera is looking at the surface from the side (parallel), the coordinates would need to be pushed very far away. But that's where my math falls short. Figuring out how to calculate this distance based on the angle of the vector and surface.

The fact that I used the world space vertex positions (pos.x and pos.z) to generate textures coordinates is also a hack that would only work for surfaces facing up. I'm not sure how to do this with unknown surface directions. All I have to work with in the shader is the vertex normal and vertex coordinates. I would need to get the 2D locations of vertices on the plane of the vertex normal (hence, the 2D location of a vertex on normals facing straight up [x=0,y=1,z=0] would be pos.x and pos.z). But I don't think this is even possible to calculate without puting more data into the stream.

If anyone can help, feel free to kick me back into the right lane.

Share this post


Link to post
Share on other sites
With todays polygon pushing power, I think you're kind of shooting yourself in the foot by faking it... :/

Share this post


Link to post
Share on other sites
I'm already using that power for important gameplay effects.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kest
I could get the result I want by throwing a flat quad down under the floor, just as far down from the floor as the ceiling would be up, then making the floor mesh blend by modulating over that quad.

Imagine a glass floor, where another opaque floor is about five feet down under it. The glass floor would not be entirely transparent. If you were drunk, you might think that the glass floor is just a very shiny opaque floor, and that the secondary floor (which is under it) is the ceiling being reflected.

The only input to this calculation is the 5-feet, which represents how far the reflected object is from the surface. I just figured there was a way to accomplish this same effect by generating secondary texture coordinates for the floor in the vertex shader.

I still appreciate the information. Thanks.


This is exactly what I think you should do... Except you need to also reflect the walls (if there's any chance they would be reflected)
That's the other problem with just generating texture coordinates - you probably aren't setting one texture for the entire level's ceiling - it's probably tiled, but there are nooks and crannys (corners) where a plain faked tiled texture won't do justly.

Here's a list of what [Sanders] gave as the steps for stenciled reflections:

1) turn off all pixel shaders, textures, light etcetera
2) render [floorplane] to stencil buffer
3) enable stuff from (1)
4) flip geometry over the [floor] plane
5) enable clipplane over the [floorplane]
6) render geometry with testcil test (only render where stencil buffer is set to 1 in step (2))
7) undo (4) and (5)
8) render [floorplane] (blended)
9) render geometry again

If you wish to get distorted or blurred reflections, you'd be better off doing it similarly to how HL2 did it: http://www2.ati.com/developer/gdc/D3DTutorial10_Half-Life2_Shading.pdf
See page 92 (Water) - 96 for how they did reflective and refractive water (and use the reflective idea)

Anyway, now you can actually implement one of these ideas if you like!

hth,
-Michael g.

Share this post


Link to post
Share on other sites
Planar projective texturing is really quite simple. It may sound scary, but it is not. If you know what vectors are, and you can do a little algebra, you can very easily sketch out on paper the scenario. Do it from the side. Draw a line representing your imaginary ceiling. Draw a line that represents your floor. Then draw another line that represents the reflection of the ceiling. Then pick an arbitrary point for your camera. Next, pick an arbitrary point on the ceiling, and cast it straight down to the reflected ceiling. Now, from that reflected point, draw a ray to the camera (the direction the camera is looking does not matter). Now, where that ray intersects the floor is the point you need to find. But you already know the y coordinate of that point, you only need to figure out the x and z. So then using a parameterization of the ray, where the parameter, p, is zero at the reflected point and one at the camera, solve for p when y=0 (or whatever your floor's y position is). Then simply solve for x and z using that value of p. From that you can then transform the (x,z) pair into texture space. Of course, you wouldn't do this exact procedure. You want to do the inverse. But the procedure is the same, except reversed. Draw it out on paper from the side!

Share this post


Link to post
Share on other sites
I managed to calculate the texture offsets correctly for up-facing surfaces. I don't know why I didn't realize it before, but all that needs to be done is a generic ray-intersect test (where most of the values are already known). Here's what I did, without optimization shortcuts:

1. Use the vertex position and normal to represent a plane
[ p.pos = v.pos; p.normal = v.normal ]

2. Push the plane into the opposite direction of the vertex normal (down for the floor), multiplied by the distance to the reflected object (the height to the ceiling from the floor).
[ p.pos -= p.normal * distance ]

3. Intersect this plane from the vertex, with the direction of the ray being a vector in the view * projection matrix which happens to still equal the forward vector of the camera.
[ ray_dir = float3( ViewProj._13, ViewProj._23, ViewProj._33 ) ]
[ push_dist = dot( p.normal, p.pos - v.pos ) / dot( p.normal, ray_dir ) ]

4. This is where I still need help. Push the texture coordinates away from the surface using push_dist.
[ reflected_pos = v.pos + ray_dir * push_dist ]
[ tex_coords.x = reflected_pos.x * modifier ]
[ tex_coords.y = reflected_pos.z * modifier ]

Modifier represents the scale of the reflection texture coordinates, and can be set to any value. But the other parts of step #4 I do not like. As I mentioned above, I'm specifically using reflected_pos.x and reflected_pos.z straight from the vector to generate the texture coordinates, and this will only work on surfaces that point up. IE, it's hard coded specifically for floor surface normals. I need to figure out how to generate these for any surface.

It all comes down to one question. If given a plane normal and a 3D world-space coordinate, is it possible to convert the 3D coordinates to 2D coordinates on the plane? IE, if starting at location 0,0,0, the 2D values would roll across only the X and Y directions of the plane normal until it lands on the 3D coordinate. What would the X and Y coordinates be when it lands? Is it possible to find those values?

That's all that's stopping me from wrapping this up completely. It already looks really cool on the floors, though.

Thanks again for the help.

Share this post


Link to post
Share on other sites
Do you just need to reflect the view frustum?

First intersect each edge (ignoring edges on the far and near clip planes) of the frustum with the floor (call these pairs of position and direction FloorRay) using the formula found Here[1].

Next, use the formula Here[2] to reflect each of the 4 FloorRay direction vectors (call these reflected directions paired with FloorRays' positions ReflectedRays).

Then, intersect each ReflectedRays with the ceiling to find which ceiling position should be mapped to the 4 floor positions.

Finally, you just need to do basic linear interpolation to map those ceiling points to texture coordinates so that the texture is properly aligned.


In case the site isn't available for whatever reason, the formulas are:
[1]The plane has normal PlaneNormal and goes through PlanePoint
The line goes through point LinePoint in the direction LineDir.
Distance = (PlaneNormal dot (PlanePoint - LinePoint)) / (PlaneNormal dot LineDir)
The intersection point is then LinePoint + Distance * LineDir

[2] ReflectedVec = IncomingRayDir - 2 NormalVec * (IncomingRayDir dot NormalVec)

[Edited by - Extrarius on August 11, 2006 2:10:26 PM]

Share this post


Link to post
Share on other sites

This topic is 4176 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this