Help trying to get reflections to work

Game Engine, Players & Web Plug-in, Virtual Reality, support for other engines

Moderators: jesterKing, stiv

Post Reply
Posts: 53
Joined: Fri Oct 18, 2002 1:35 am
Location: Oceanside, California

Help trying to get reflections to work

Post by Sutabi »

Ok here is how I figured things, If I still am reading the game engine and tring to implent somthing I dont know how to do yet I fugred i'd try it outside of blender, using Ghost lib:
With that said I failed big time. I just cant seem to get reflection in opengl....I had someone that uses opengl help me outand well its really just a proplem with how I have ghost set up but not sure how to fix it... Can anyone help? as soon as I can get this the soon blender will have reflections in the game engine ^_^.

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <GHOST_C-api.h>
#include <GL/gl.h>
#include <GL/glu.h>
static GHOST_SystemHandle ghost_system;
static GHOST_WindowHandle win;
static GHOST_WindowHandle full_screen_window;
static GHOST_EventConsumerHandle consumer;
static GHOST_TimerTaskHandle timer;

static GLuint box;
static int exit_requested = 0;

static GLfloat xrot = 0.0;
static GLfloat yrot = 0.0;
static GLfloat zrot = 0.0;

// Light Parameters
static GLfloat	LightAmb[] = {0.7f, 0.7f, 0.7f, 1.0f};				// Ambient Light
static GLfloat	LightDif[] = {1.0f, 1.0f, 1.0f, 1.0f};				// Diffuse Light
static GLfloat	LightPos[] = {4.0f, 4.0f, 6.0f, 1.0f};				// Light Position

GLUquadricObj	*q;										// Quadratic For Drawing A Sphere

GLfloat		xrotspeed	=  0.0f;						// X Rotation Speed
GLfloat		yrotspeed	=  0.0f;						// Y Rotation Speed
GLfloat		zoom		= -7.0f;						// Depth Into The Screen
GLfloat		height		=  2.0f;						// Height Of Ball From Floor

void DrawObject(void) {
	glColor3f(1.0f, 1.0f, 1.0f);						// Set Color To White
	gluSphere(q, 0.35f, 32, 16);						// Draw First Sphere

	glColor4f(1.0f, 1.0f, 1.0f, 0.4f);					// Set Color To White With 40% Alpha
	glEnable(GL_BLEND);									// Enable Blending
	glBlendFunc(GL_SRC_ALPHA, GL_ONE);					// Set Blending Mode To Mix Based On SRC Alpha

	gluSphere(q, 0.35f, 32, 16);						// Draw Another Sphere Using New Texture
void DrawFloor(void)										// Draws The Floor
	glBegin(GL_QUADS);									// Begin Drawing A Quad
		glNormal3f(0.0, 1.0, 0.0);						// Normal Pointing Up
			glVertex3f(-2.0, 0.0, 2.0);					// Bottom Left Corner Of Floor
			glVertex3f(-2.0, 0.0,-2.0);					// Top Left Corner Of Floor
			glVertex3f( 2.0, 0.0,-2.0);					// Top Right Corner Of Floor

			glVertex3f( 2.0, 0.0, 2.0);					// Bottom Right Corner Of Floor
	glEnd();											// Done Drawing The Quad

int InitGL(GLvoid)										// All Setup For OpenGL Goes Here

	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
	glClearColor(0.2f, 0.5f, 1.0f, 1.0f);				// Background
	glClearDepth(1.0f);									// Depth Buffer Setup
	glClearStencil(0);									// Clear The Stencil Buffer To 0
	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
	glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations
	glEnable(GL_TEXTURE_2D);							// Enable 2D Texture Mapping

	glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmb);			// Set The Ambient Lighting For Light0
	glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDif);			// Set The Diffuse Lighting For Light0
	glLightfv(GL_LIGHT0, GL_POSITION, LightPos);		// Set The Position For Light0

	glEnable(GL_LIGHT0);								// Enable Light 0
	glEnable(GL_LIGHTING);								// Enable Lighting

	q = gluNewQuadric();								// Create A New Quadratic
	gluQuadricNormals(q, GL_SMOOTH);					// Generate Smooth Normals For The Quad

	return 1;										// Initialization Went OK

void DrawGLScene(void) {

	// Clip Plane Equations
	double eqr[] = {0.0f,-1.0f, 0.0f, 0.0f};			// Plane Equation To Use For The Reflected Objects

	// Clear Screen, Depth Buffer & Stencil Buffer

	glLoadIdentity();									// Reset The Modelview Matrix
	glTranslatef(0.0f, -0.6f, zoom);					// Zoom And Raise Camera Above The Floor (Up 0.6 Units)
	glColorMask(0,0,0,0);								// Set Color Mask
	glEnable(GL_STENCIL_TEST);							// Enable Stencil Buffer For "marking" The Floor
	glStencilFunc(GL_ALWAYS, 1, 1);						// Always Passes, 1 Bit Plane, 1 As Mask
	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);			// We Set The Stencil Buffer To 1 Where We Draw Any Polygon
														// Keep If Test Fails, Keep If Test Passes But Buffer Test Fails
														// Replace If Test Passes
	glDisable(GL_DEPTH_TEST);							// Disable Depth Testing
	DrawFloor();										// Draw The Floor (Draws To The Stencil Buffer)
														// We Only Want To Mark It In The Stencil Buffer
	glEnable(GL_DEPTH_TEST);							// Enable Depth Testing
	glColorMask(1,1,1,1);								// Set Color Mask to TRUE, TRUE, TRUE, TRUE
	glStencilFunc(GL_EQUAL, 1, 1);						// We Draw Only Where The Stencil Is 1
														// (I.E. Where The Floor Was Drawn)
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);				// Don't Change The Stencil Buffer
	glEnable(GL_CLIP_PLANE0);							// Enable Clip Plane For Removing Artifacts
														// (When The Object Crosses The Floor)
	glClipPlane(GL_CLIP_PLANE0, eqr);					// Equation For Reflected Objects
	glPushMatrix();										// Push The Matrix Onto The Stack
		glScalef(1.0f, -1.0f, 1.0f);					// Mirror Y Axis
		glLightfv(GL_LIGHT0, GL_POSITION, LightPos);	// Set Up Light0
		glTranslatef(0.0f, height, 0.0f);				// Position The Object
		glRotatef(xrot, 1.0f, 0.0f, 0.0f);				// Rotate Local Coordinate System On X Axis
		glRotatef(yrot, 0.0f, 1.0f, 0.0f);				// Rotate Local Coordinate System On Y Axis
		DrawObject();									// Draw The Sphere (Reflection)
	glPopMatrix();										// Pop The Matrix Off The Stack
	glDisable(GL_CLIP_PLANE0);							// Disable Clip Plane For Drawing The Floor
	glDisable(GL_STENCIL_TEST);							// We Don't Need The Stencil Buffer Any More (Disable)
	glLightfv(GL_LIGHT0, GL_POSITION, LightPos);		// Set Up Light0 Position
	glEnable(GL_BLEND);									// Enable Blending (Otherwise The Reflected Object Wont Show)
	glDisable(GL_LIGHTING);								// Since We Use Blending, We Disable Lighting
	glColor4f(1.0f, 1.0f, 1.0f, 0.8f);					// Set Color To White With 80% Alpha
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);	// Blending Based On Source Alpha And 1 Minus Dest Alpha
	DrawFloor();										// Draw The Floor To The Screen
	glEnable(GL_LIGHTING);								// Enable Lighting
	glDisable(GL_BLEND);								// Disable Blending
	glTranslatef(0.0f, height, 0.0f);					// Position The Ball At Proper Height
	glRotatef(xrot, 1.0f, 0.0f, 0.0f);					// Rotate On The X Axis
	glRotatef(yrot, 0.0f, 1.0f, 0.0f);					// Rotate On The Y Axis
	DrawObject();										// Draw The Ball
	xrot += xrotspeed;									// Update X Rotation Angle By xrotspeed
	yrot += yrotspeed;									// Update Y Rotation Angle By yrotspeed
	glFlush();											// Flush The GL Pipeline
	return 1;										// Everything Went OK										// Flush The GL Pipeline


 * This invalidates a window so that the WindowUpdate
 * event will be generated for the window
void invalidate_window(void) {
    if (GHOST_GetFullScreen(ghost_system)) 
    else {
        if (GHOST_ValidWindow(ghost_system, win)) 

 * the procedure to run when the timer goes off
void timer_proc(GHOST_TimerTaskHandle task, GHOST_TUns64 time) {

 * does the initial OpenGL setup of the main window
void setup_window(GHOST_WindowHandle win) {
    GHOST_RectangleHandle rect = NULL;
    GLfloat w, h, aspect;

    rect = GHOST_GetClientBounds(win);

    w = (GLfloat)GHOST_GetWidthRectangle(rect);
    h = (GLfloat)GHOST_GetHeightRectangle(rect);
    aspect = w / h;

    glViewport(0, 0, w, h);
    glFrustum(-aspect, aspect, -1.0, 1.0, 5.0, 60.0);
    glTranslatef(0.0, 0.0, -12.0);

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

 * this handles the events as they are generated by the GHOST system
int process_event(GHOST_EventHandle event, GHOST_TUserDataPtr data) {
    int handled = 0;
    GHOST_TEventKeyData *key_data = (GHOST_TEventKeyData *)GHOST_GetEventData(event);
    /* all the entries need to be in the switch to make the compiler shut up */
    switch (GHOST_GetEventType(event)) { 
        case GHOST_kEventUnknown:
        case GHOST_kEventCursorMove:
        case GHOST_kEventButtonDown:
        case GHOST_kEventButtonUp:
        case GHOST_kEventKeyUp:
        case GHOST_kEventWindowActivate:
        case GHOST_kEventWindowDeactivate:
        case GHOST_kEventWindowSize:
        case GHOST_kNumEventTypes:

        case GHOST_kEventWheel:
                GHOST_TEventWheelData *wheel = (GHOST_TEventWheelData *)GHOST_GetEventData(event);

                if (wheel->z > 0)
                    xrot += 2;
                    xrot -= 2;


        case GHOST_kEventWindowUpdate:
                GHOST_WindowHandle win_handle = GHOST_GetEventWindow(event);
                if (!GHOST_ValidWindow(ghost_system, win_handle))

        case GHOST_kEventQuit:
        case GHOST_kEventWindowClose:
            exit_requested = 1;
            handled = 1;

        case GHOST_kEventKeyDown:
            if (key_data) {
                if (key_data->key == GHOST_kKeyQ) {
                    exit_requested = 1;
                    handled = 1;
                } else if (key_data->key == GHOST_kKeyR) {


                } else if (key_data->key == GHOST_kKeyT) {
                    if (!timer)
                        timer = GHOST_InstallTimer(ghost_system, 0, 10, timer_proc, NULL);
                    else {
                        GHOST_RemoveTimer(ghost_system, timer);
                        timer = NULL;

                } else if (key_data->key == GHOST_kKeyF) {
                    if (GHOST_GetFullScreen(ghost_system)) {
                        full_screen_window = NULL;
                     } else {
                        GHOST_DisplaySetting setting;
                        setting.bpp = 16;
                        setting.frequency = 65;
                        setting.xPixels = 640;
                        setting.yPixels = 480;

                        full_screen_window = GHOST_BeginFullScreen(ghost_system, &setting, 0);
    return handled;

int main(int argc, char ** argv) {

    // create the system
    ghost_system = GHOST_CreateSystem();
    if (!ghost_system) {
        printf("Coun't not create the system, dying\n");

    // create the event consumer and add to the system
    consumer = GHOST_CreateEventConsumer(process_event, NULL);
    if (!consumer) {
        printf("Failed to create consumer\n");
    GHOST_AddEventConsumer(ghost_system, consumer);

    // make the main window
    win = GHOST_CreateWindow(ghost_system, "Realtime Reflection-or", 10, 64, 320, 200,
                GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, 0);
    if (!win) {
        printf("Couldn't not create window\n");

    /* the event loop */
    while(!exit_requested) {
       // could sleep if there are no events, but hey i'm cruel, heh.
       GHOST_ProcessEvents(ghost_system, 0);

    /* exit full screen if we are in it */
    if (GHOST_GetFullScreen(ghost_system)) 

    /* delete the timer */
    if (timer)
        GHOST_RemoveTimer(ghost_system, timer);

    /* clean it all up */
    if (GHOST_ValidWindow(ghost_system, win)) 
        GHOST_DisposeWindow(ghost_system, win);

    return 0;

Posts: 0
Joined: Tue Mar 04, 2003 7:55 pm

Post by Panther »

Hi Sutabi,

Unfortunately, I don't have an answer to your question, but the best person to speak to may be Erwin ( you can find him through this forum ).

On a side note...

It's good to see someone else who is willing to improve the GameEngine - So well done, and good luck ;-)

Personally, I think it would be nice to have real-time shadows in the GameEngine too !!!

Posts: 289
Joined: Wed Oct 16, 2002 2:38 am


Post by z3r0_d »

I am not sure, but could opengl think it can't have a stencil buffer or something?

(it is hard to read that there, now pasted into mvc6)

I don't have much of an idea (not having used stencil testing), but other than code problems which aren't ghost specific I have no more guesses

Posts: 289
Joined: Wed Oct 16, 2002 2:38 am

Post by z3r0_d »


I think the problem was that your spheres are being placed in the same spot.
It would probably be prefered that your draw code called the DrawObject function AFTER changing the matrix and blendmode settings so that your DrawObject function a) didn't have to b) would draw only one object c) this part of your code made sense.

I added a couple lines, this is the resulting DrawObject function

Code: Select all

void DrawObject(void) {
  glColor3f(1.0f, 0.5f, 0.5f);            // Set Color
  gluSphere(q, 0.35f, 32, 16);            // Draw First Sphere

// begin change
  glTranslatef(0.0f, -1.0f, 0.0f);
// end change

  glColor4f(1.0f, 1.0f, 1.0f, 0.4f);          // Set Color To White With 40% Alpha
  glEnable(GL_BLEND);                  // Enable Blending
  glBlendFunc(GL_SRC_ALPHA, GL_ONE);          // Set Blending Mode To Mix Based On SRC Alpha

  gluSphere(q, 0.35f, 32, 16);            // Draw Another Sphere Using New Texture
a hack, but it works (I also changed the height to .5f at the begining of the code)
(and I am using sdl not ghost)

image at ... orking.png


the method you use will work, but it will be limited to planar reflections.

still good to see someone working for improvement of the game engine

I am thinking (this second) about [realtime] reflection and refraction in this method:
render the scene without the water
using your render as a texture, render the refraction
render the reflections using a [precalculated?] cube environment map of the scene, and
also use a fresnel shader on the latter

Note that the last 3 steps are mostly combined into one using texture combination [extensions?]

it has been done
new thought:
why does it seem that so many people want technical improvements to the game engine that could quickly sacrifice the 'for the artist' nature that it was (and hopefully still is) intended to convey?

admittedly the game engine does have a learning curve, but it would be much steeper if the artist had to code the colisions and more themselves (after first deciding to use gameblender, then learning to code).

I think the improvements should be directed in this manner
*get it working
*fix bugs
*add features to improve speed
*and features to aide in the art (a partial-runtime mode?) of development
*add features to aide in runtime (graphics I guess, like

... looses thought

/steps off soapbox and presses the submit button

Post Reply