Dark Bit Factory & Gravity
PROGRAMMING => Freebasic => Topic started by: ScottyBrosious on June 29, 2007
-
Could someone please show me how to use
OpenGL's Stencil buffer for doing reflections?
A small example program would be very helpful
not only to me but for other that come to this site just like
so many other programs before help is sometimes needed in codeing things up.
Thanks
Scotty B.
-
hi scotty the best thing to do when wanting to do a new effect is to have a goggle for it thats what i do then if its in c try a port to fb its quite easy then if you have trouble post up your broken code and we can try to help ;)
-
Amen :)
-
I'd love to help, but there's no such thing as a 'small stencil buffer example'. It's pretty complicated stuff and would take a good while to make a sample unless you'd already got some working code.
NeHe have great OpenGL samples, reflections are dealt with here
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=26 (http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=26)
Jim
-
This is a very very crude example and it doesn't even use the stencil buffer but might give you a little bit of an idea how that sort of reflections work:
option explicit
'$include once: 'GL/glfw.bi'
#include "fbgfx.bi"
type vertex
as single x,y,z
as single r,g,b
end type
type object
as integer num_verts
as vertex pointer vertex_list
end type
sub initialise_opengl(byval wwidth as integer,byval height as integer)
screen 19,32,2,GFX_OPENGL
glMatrixMode GL_PROJECTION '' Select The Projection Matrix
glLoadIdentity '' Reset The Projection Matrix
gluPerspective 45.0, wwidth/height, 1.0, 64000.0 '' Calculate The Aspect Ratio Of The Window
gldepthrange(0.0,1.0)
glMatrixMode GL_MODELVIEW '' Select The Modelview Matrix
glLoadIdentity '' Reset The Projection Matrix
glShadeModel(GL_SMOOTH) '' Enables Smooth Color Shading
glClearColor(0.0, 0.0, 0.0, 0.0) '' This Will Clear The Background Color To Black
glClearDepth(1.0)
glDepthFunc(GL_LESS)
glenable(gl_depth_test)
glcullface(gl_front)
glenable(gl_cull_face)
gldisable(gl_lighting)
glfrontface(gl_cw)
end sub
cube_data:
data 36
data -1,-1,-1,-1,-1,1,-1,1,1
data -1,1,1,-1,1,-1,-1,-1,-1
data -1,-1,1,1,-1,1,1,1,1
data 1,1,1,-1,1,1,-1,-1,1
data 1,-1,1,1,-1,-1,1,1,-1
data 1,1,-1,1,1,1,1,-1,1
data 1,-1,-1,-1,-1,-1,-1,1,-1
data -1,1,-1,1,1,-1,1,-1,-1
data -1,1,-1,-1,1,1,1,1,1
data 1,1,1,1,1,-1,-1,1,-1
data 1,-1,-1,1,-1,1,-1,-1,1
data -1,-1,1,-1,-1,-1,1,-1,-1
function create_cube()as object pointer
dim as object pointer cube=callocate(len(object))
dim as integer i
restore cube_data
read cube->num_verts
cube->vertex_list=callocate(len(vertex)*cube->num_verts)
for i=0 to cube->num_verts-1
read cube->vertex_list[i]->x,cube->vertex_list[i]->y,cube->vertex_list[i]->z
cube->vertex_list[i]->r=rnd
cube->vertex_list[i]->g=rnd
cube->vertex_list[i]->b=rnd
next
return cube
end function
'draw an object, if reflection=-1 then it is drawn upsidedown below the alpha plane
sub draw_object(object as object pointer,x as single,y as single,z as single,reflection as single=1.0)
'in a reflection the winding of tris is reversed
if reflection=-1.0 then
glcullface(gl_back)
else
glcullface(gl_front)
end if
glloadidentity()
gltranslatef(x,y*reflection,z)
dim as integer i
dim as vertex pointer current_vertex
glbegin(gl_triangles)
for i=0 to object->num_verts-1
current_vertex=@object->vertex_list[i]
glcolor3f(current_vertex->r,current_vertex->g,current_vertex->b)
glvertex3f(current_vertex->x,current_vertex->y*reflection,current_vertex->z)
next
glend()
end sub
'draw an alpha blended quad
sub draw_alpha_plane()
glloadidentity()
glcullface(gl_front)
glenable(gl_blend)
glblendfunc(gl_src_alpha,gl_one_minus_src_alpha)
glbegin(gl_quads)
glcolor4f(.4,.4,1.0,0.9)
glvertex3f(-30.0,0.0,-30.0)
glvertex3f(-30.0,0.0, 30.0)
glvertex3f( 30.0,0.0, 30.0)
glvertex3f( 30.0,0.0,-30.0)
glend()
gldisable(gl_blend)
end sub
sub main()
initialise_opengl(640,480)
'make 2 cubes and give them coordinates
dim cube1 as object pointer=create_cube()
dim as single x1=0.0,y1=4.9,z1=-10.0,vy1=0.0
dim cube2 as object pointer=create_cube()
dim as single x2=5.0,y2=2.5,z2=-7.0,vy2=0.0
'setup the camera
dim as single h
glMatrixMode GL_PROJECTION
gltranslatef(0.0,-1.0,0.0)
glMatrixMode GL_MODELVIEW
do
'draw cubes (the ones in the reflection... -1)
draw_object(cube1,x1,y1,z1,-1)
draw_object(cube2,x2,y2,z2,-1)
'draw the surface they're reflected on
draw_alpha_plane()
'draw the actual cubes
draw_object(cube1,x1,y1,z1)
draw_object(cube2,x2,y2,z2)
'control the cubes bouncing
vy1+=.006
y1-=vy1
if y1<1.0 then
y1=2.0-y1
vy1=-vy1
end if
vy2+=.006
y2-=vy2
if y2<1.0 then
y2=2.0-y2
vy2=-vy2
end if
'control the camera
glMatrixMode GL_PROJECTION
gltranslatef(0.2,-0.06*sin(h),0.0)
glrotatef(1.0,0.0,1.0,0.0)
glMatrixMode GL_MODELVIEW
h+=0.05
flip
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
sleep 10
loop while inkey$=""
end sub
main
In this case I am really cheating and it can't handle the objects being rotated or anything but reflections are basically the same objects drawn (sort of the other way round, left becomes right or up becomes down) on the other side of the reflective plane. The stencil buffer can be used with this process to mask the areas of the screen where the reflection would be seen.
-
Another thing I should've mentioned is that instead of positioning the objects on the other side of the reflection plane it's possible to position the camera on the other side looking back through and render from there instead of repositioning all the objects. How you do that though depends on how you're doing your geometry.
-
I've been thinking a little more about this (or reflections in general).
There are a few ways to achieve this type of reflection effect, either by reflecting all or most of the geometry to the other side of the plane or by having reversed copies of the geometry there. It could also be renderd into a texture for blurring or other effects. That's all ok for fairly limited planar reflections.
Another method of doing reflections is cubemapping with each side of the cube being rendered to with a camera pointing out in the direction of each face of the cube and then mapping that onto an object using some vector reflection calcs at every vertex to find the vector for the cubemap coords.
Maybe some sort of sphere mapping could also be used in a similar way, I'm not really sure.
Are there any other methods? (other than my dodgy way of rendering from a camera placed inside the object pointing back at the main camera with a wide angle)
-
thats some cool reflection ideas and im coming up for learning reflections so i might try them out cheers.
-
I'm trying to think back to doing the dot3 mapping and wondering if that could be combined with reflective cubemapping (with fixed function, I imagine it'd be possible with shaders).
-
I'm coming to the conclusion, probably not. Btw, what are 4d texture coords?
-
The 3rd coordinate (r) is reserved for 3d textures.
The 4th coordinate is used to calculate a second perspective correction on the texture (apparently for lighting, or if the original texture wasn't linear in the first place).
Jim
-
Thanks Jim, been thinking about it from a software point of view now and for cubemapping I reckon that triangles to be drawn would have to be chopped up where different faces of the cube are mapped onto different areas of each single tri which would be pretty cool and I might give it a go but if I was to use normal mapping it'd be a slightly different story and I'd have to work out which cubemap texture to use for every pixel, anyone know if I'm on the right track or know anything about how it would be dealt with with shaders as in can a shader be set up to read from a cubemap just given a vector or do you have to do that stuff yourself in glsl?