Game Development Community

WIP: Glow/bloom

by Manoel Neto · in Torque Game Engine · 01/24/2006 (7:58 am) · 16 replies

Just kidding, but I couldn't resist after we got this up and running in TGE 1.4:

Normal setting (the one we'll use in-game - it sets a mood without offending):
img234.imageshack.us/img234/3176/weakglow7xt.th.jpg

Very strong setting (looks awesome but can give you headaches after a while):
img234.imageshack.us/img234/9606/strongglow2sl.th.jpg

Those both are unmodified screenshots (only scaled down). Yes, that's split screen. That bloom effect is the result of an extra effect we added to ScreenFXMgr (awesome resource), and runs 100% on fixed-function. It works on GUIs as well.

I'll try to make that into a resource (it's kinda complicated, because it's interwined with several other changes, so it might take a while).

#1
01/24/2006 (8:01 am)
Wow... that looks pretty sweet, nice job!
#2
01/24/2006 (8:16 am)
Manoel, I'd die for that resource :) Hope you find the time to release it ...
#3
01/24/2006 (9:20 am)
Yeah those kinds of bloom effects are avaliable to most DX7 generation video cards. Nice to see it being done in TGE :)
#4
04/19/2006 (10:36 am)
That looks great Manoel, thanks for mentioning the ScreenFXMgr resource I don't think I've played with that yet.
#5
04/19/2006 (12:01 pm)
Awesome :) would love to have this in our game which is based on historical gladiator fights... the sand + arena would like nice with such nice bloom... *drool*
#6
04/19/2006 (12:21 pm)
That would be a great resoruce Manoel
#7
04/20/2006 (9:32 am)
I'm unsure about posting the glow as a resource.

The DRL-resource for the Torque Lighting Kit also implements a bloom effect, and while I find our blur routine cleaner and more accurate, the DRL resource's bloom has two major advantages, which made us use it instead of our own in our new project:

- It accurately bleeds only the overbright colors, doing some black OpenGL voodoo I couldn't do myself (our glow bleeds in both directions).

- It runs much, much faster than our own.

But maybe the other changes to the screenFXMgr might be useful for someone. We de-coupled it from the sceneGraph, and made each GUITsCtrl have it's own screenFXManager instance, so effects can be toggled on/off for each individual control. Based on this, we made a small GuiTSCtrl derived control which renders nothing, and it can thus apply it's special effects to any GUI controls behind it, so you can add the bloom effect to menus, as example.
#8
04/20/2006 (9:45 am)
Perhaps release the resource as a work-in-progress and let others to inspect what you're been doing to maybe give you an idea on how to improve it? If you're not using it and you think *someone* could use it then why not :)
#9
04/20/2006 (9:56 am)
I would be interested in it as well. :)
#10
04/21/2006 (10:01 am)
Aaargh, gadnabit, I thought this was the updated water resource for a minute when I saw your name back there Manoel! 8)

he he he

Screenshots look great by the way......
#11
04/30/2006 (10:28 am)
Looking good Manoel--TSE has seemless terrain and shading effects if you didn't already know.
#12
04/30/2006 (3:13 pm)
Wow good stuff keep up the good work. when should we be expecting it up for download?
#13
04/30/2006 (8:11 pm)
@Talon: I was just kidding. I got a TSE license too.

@T:
Not sure when, got some other stuff eating my time right now.
#14
05/01/2006 (5:24 am)
I am currently trying to implement a generic shader class, so we can avoid possible identifier conflicts etc.
I am new to cg and at this point I had to extract the cg-specific vars and 2 functions used in bumpmapped interiors and water upgrade resources. I'm not sure if this can work, but I am trying. To keep TGE's code clean I created 2 new files (core/shaders.cc and core/shaders.h). If anyone has an idea how to do it in a good and TGE-friendly way, let me know :) I think generic shader implementation would be a boost here ;)

core/shaders.h
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

#ifndef _SHADERS_H_
#define _SHADERS_H_

class CgShader
{
	private:
		bool			cg_enable;
		TextureHandle	normalHandle;
		CGcontext		cgContext;			// A Context To Hold Our Cg Program
		CGprogram		cgVertexProgram,	// Our Cg Vertex Program
						cgFragProgram;		// Our Cg Fragment Program
		CGprofile		cgVertexProfile,	// The Profile To Use For Our Vertex Shader
						cgFragProfile;		// The Profile To Use For Our Frag Shader


		CGparameter		position,
						VertexColor,color,
						modelViewMatrix,
						KdParam;			// The Parameters Needed For Our Shader(s)

	public:
		CGerrorCallbackFunc cgErrorCallBack(void);
		int initShader(const char *program);
};

#endif // _SHADERS_H_

core/shaders.cc
//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

#include "sceneGraph/sceneGraph.h"
#include "dgl/dgl.h"
#include "dgl/materialPropertyMap.h"
#include "cg/cg.h"
#include "cg/cgGL.h"
#include "core/shaders.h"

int CgShader::initShader(const char *program)
{	
	cg_enable = true;

	Con::printf("initShader started");

	// Search for a valid Frag shader profile in this order:
	//
	// CG_PROFILE_ARBFP1 - GL_ARB_fragment_program
	// CG_PROFILE_FP30   - GL_NV_fragment_program
	// CG_PROFILE_FP20   - NV_texture_shader & NV_register_combiners
	//
	
	if( cgGLIsProfileSupported(CG_PROFILE_ARBFP1) )
        cgFragProfile = CG_PROFILE_ARBFP1;
    else if( cgGLIsProfileSupported(CG_PROFILE_FP30) )
        cgFragProfile  = CG_PROFILE_FP30;
	else if( cgGLIsProfileSupported(CG_PROFILE_FP20) )
        cgFragProfile  = CG_PROFILE_FP20;
    else
    {
           Con::errorf("#######CG ERROR:Failed to initialize Frag shader! Hardware doesn't "
			        "support any of the Frag shading extensions!");
		return -1;
    }

	Con::printf("CG: found frag profile...");

	cgContext = cgCreateContext();
    
	
	// Load And Compile The Frag Shader From File
   cgFragProgram = cgCreateProgramFromFile( cgContext,
										         CG_SOURCE,
										         program,
												 cgFragProfile,
										         NULL, 
										         NULL);
 
		cgGLLoadProgram(cgFragProgram);

   // Might Need these later
  //  cgGLSetStateMatrixParameter(cgGetNamedParameter(cgVertexProgram, "ModelViewProj"),
  //                              CG_GL_MODELVIEW_PROJECTION_MATRIX,
  //                              CG_GL_MATRIX_IDENTITY);
  //  cgGLSetStateMatrixParameter(cgGetNamedParameter(cgVertexProgram, "ModelView"),
  //                              CG_GL_MODELVIEW_MATRIX,
  //                              CG_GL_MATRIX_IDENTITY);
  //  cgGLSetStateMatrixParameter(cgGetNamedParameter(cgVertexProgram, "ModelViewIT"),
  //                              CG_GL_MODELVIEW_MATRIX,
  //                              CG_GL_MATRIX_INVERSE_TRANSPOSE);
    
	
		Con::printf("Shader initialized!");
		return 0;

}

//CG ERROR CALLBACK
CGerrorCallbackFunc CgShader::cgErrorCallBack(void)
{
	CGerror LastError = cgGetError();
	if (LastError)
		Con::errorf("#######CG ERROR: %s\n%s",cgGetErrorString(LastError),cgGetLastListing(cgContext)); 
	
	return 0;
}

If you have any suggestions, please feel free to share them :)
#15
05/01/2006 (7:35 am)
The way I'm handling the GLSL port is by giving each class its own InitShader function so I can load all of the necessary uniforms in the function instead of having to bind the uniforms in the rendering loop. Just makes the code more readable.

Also, I added two new functions to dgl, dglLoadGLSLVertexShaderFromFile and dglLoadGLSLFragmentShaderFromFile. So, a general InitShader function would look like this:

if(!dglDoesSupportFragmentShader())
   return;

if(GLSLProgram == NULL)
{
   GLSLVertexShader = dglLoadGLSLVertexShaderFromFile("GLSL/test.vert");
   GLSLFragmentShader = dglLoadGLSLFragmentShaderFromFile("GLSL/test.frag");
   GLSLProgram = glCreateProgramObjectARB();
   
   glAttachObjectARB(GLSLProgram, GLSLVertexShader);
   glAttachObjectARB(GLSLProgram, GLSLFragmentShader);
   glLinkProgramARB(GLSLProgram);

   bTexLoc = glGetUniformLocationARB(GLSLProgram, "BaseTexture");
   nMapLoc = glGetUniformLocationARB(GLSLProgram, "NormalMap");
}

glUseProgramObjectARB(GLSLProgram);
glUniform1iARB(bTexLoc, 0);
glUniform1iARB(nMapLoc, 1);
#16
05/01/2006 (8:35 am)
OMG!!!! This is awesome!!!!