Archived

This topic is now archived and is closed to further replies.

how to render objects with different effects?

This topic is 5009 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

Say I have my scene manager rendering all objects by getting the vertices etc into geometry chunks and sending them to the renderer, the renderer then gets the effect ID from the objects material propertiy (which has texture layers, alpha values etc) and renders that object with the shader linked to that effect. Say one objects geometry chunk stores vertices, normals and texcoords and the effect is to just render it using a diffuse texture with basic lighting. Now if I want to render the same object with a different effect, like bump mapping, where would I get the extra data for the geometry chunk? or would the shader be able to generate this data?

Share this post


Link to post
Share on other sites
I havn''t done any bumpmapping so I don''t know what data you need... but I guess that the best choice is to have as much as posible pre-calculated so you don''t need to do it in run-time wich I think will lower the FPS..

altough you could have both.. if the GeometryChunk that is going to be renderd doesn''t have the stuff it needs then calculate, else use it..

Share this post


Link to post
Share on other sites
You could solve it by putting redundant stream components in your geometry chunk, e.g. (very simple example)



struct GeometryChunk
{
float *positions;
float *texcoords;
float *tangents;
float *binormals;
float *normals;
};



Then, you always have the potential to store whatever data you need, at the cost of storing a couple extra pointers each chunk.
First off you just fill out what you need, so probably positions and texcoords and normals, then, if you want to change to an effect that requires the extra data, you can generate it and stick it in the extra field. However, as McZ said doing as much of this as pre-computation would be better, so you might want to bite the memory usage or figure some other clever scheme (like you *know* you will be switching to an effect requiring the extra data, so store it anyway).

-Mezz

Share this post


Link to post
Share on other sites
Mezz: thats the sort of implementation i have just now, just it''s my lack of ecperience in knowing what i need, my engine is only coming up for release 0.1 though lol

Share this post


Link to post
Share on other sites
I had a similar (actually...exactly the same :S) problem a while back when I was developing this section of my own engine. I wanted maximum flexibility, so that future shaders and effects wouldn't have to rely on out-dated variables. An example: if you 'store' 4 different texture pointers per geometry chunk, and you later need 6 possible textures for some new crazy per-pixel shadow and occlusion shader, it's going to be some work...so what I did was build a hash-table type object to manage 'properties', which are objects with a name (in a hash table) and a dword value. This way a shader can declare what properties geometry chunk's should have and the engine will be able to check if these requirements are met... Here's the basic code for a 'property list':


/**
* XPropertyList
*
* an object to encapsulate a property list. a property
* list is a O(1) look-up table for u32 values with ascii
* names
*
*/

class EngineMode XPropertyList
{
public:

/**
* UtProperty
*
* a utility class to manage a single property,
* including the releasing of the property at
* the end of this chunk's lifetime
*
*/

class EngineMode UtProperty
{
public:

/**
* destructor
*
*/

~UtProperty();


/*! the property value */
u32 Value;

/*! the property data type */
EPropertyType Type;

/*! the type descriptor of this object */
char TypeID[ 16 ];
};


/*! the iterator for this object */
typedef core::XHashTable<UtProperty*>::UtIterator UtIterator;

protected:

/*! the hash table of properties */
core::XHashTable< UtProperty* > Properties;

public:


/**
* destructor
*
*/

virtual ~XPropertyList();


/**
* checks if a property exists
*
* Property: the property name to search for
*
* /ret: true if the property exists, false otherwise
*/

bool propertyExists( core::XHashString Property ) const;


/**
* sets a property value
*
* Property: the property name to set
* Value: the u32 value to set the property to
* Type: the property type
* TypeID: the property type identifier
*/

void setProperty( core::XHashString Property, u32 Value, EPropertyType Type = Property_Value, const char* TypeID = NULL );

/**
* gets a property value
*
* ! will throw an error if the property does not exist
*
* Property: the property name to get
*
* /ret: the u32 value associated with the property
*/

u32 getProperty( core::XHashString Property ) const;


/**
* retrieves the first property iterator
*
* /ret: the first property iterator
*/

UtIterator getFront() { return Properties.getFront(); }

/**
* retrieves the NULL property iterator
*
* /ret: the NULL property iterator
*/

UtIterator getNull() { return Properties.getNull(); }


/**
* gets a property type
*
* ! will throw an error if the property does not exist
*
* Property: the property name to get
*
* /ret: the property type
*/

EPropertyType getPropertyType( core::XHashString Property ) const;

/**
* gets a property type id
*
* ! will throw an error if the property does not exist
*
* Property: the property name to retrieve the type id
*
* /ret: the property type
*/

char* getPropertyTypeID( core::XHashString Property );
};

/**
* destructor
*
*/

XPropertyList :: UtProperty :: ~UtProperty()
{
// this is utility code to clean up any allocated memory

// that this property is using (and is why we have the Type variable


switch( Type )
{
case Property_COMObj:
{
((IUnknown*) Value)->Release();
}
break;

case Property_SharedObj:
{
((ISharedObj*) Value)->drop();
}
break;
}
}

/**
* destructor
*
*/

XPropertyList :: ~XPropertyList()
{
UtIterator it = Properties.getFront();

while( it.isValid() )
{
char* property = ConvertHashToString( it.getHashID() );

SafeDeleteC( (*it) );

it++;
}


Properties.destroyTable();
}

/**
* checks if a property exists
*
* Property: the property name to search for
*
* /ret: true if the property exists, false otherwise
*/

bool XPropertyList :: propertyExists( core::XHashString Property ) const
{
return Properties.exists( Property );
}

/**
* sets a property value
*
* Property: the property name to set
* Value: the u32 value to set the property to
* Type: the property type
* TypeID: the property type identifier
*/

void XPropertyList :: setProperty( core::XHashString Property, u32 Value, EPropertyType Type, const char* TypeID )
{
UtProperty* Prop;

if( !Properties.exists( Property ) )
{
Prop = Properties[ Property ] = new UtProperty;
}
else
{
Prop = *Properties.get( Property );
}


Prop->Value = Value;
Prop->Type = Type;

if( TypeID != NULL )
{
strcpy( Prop->TypeID, TypeID );
}
else
{
Prop->TypeID[0] = '\0';
}
}

/**
* gets a property value
*
* ! will throw an error if the property does not exist
*
* Property: the property name to get
*
* /ret: the u32 value associated with the property
*/

u32 XPropertyList :: getProperty( core::XHashString Property ) const
{
UtProperty* const * ptr = Properties.get( Property );

verify( Assert_Error, ptr != NULL, "invalid property requested; property does not exist in property list" );


return (*ptr)->Value;
}

/**
* gets a property type
*
* ! will throw an error if the property does not exist
*
* Property: the property name to get
*
* /ret: the property type
*/

EPropertyType XPropertyList :: getPropertyType( core::XHashString Property ) const
{
UtProperty* const * ptr = Properties.get( Property );

verify( Assert_Error, ptr != NULL, "invalid property requested; property does not exist in property list" );


return (*ptr)->Type;
}

/**
* gets a property type id
*
* ! will throw an error if the property does not exist
*
* Property: the property name to retrieve the type id
*
* /ret: the property type
*/

char* XPropertyList :: getPropertyTypeID( core::XHashString Property )
{
UtProperty** ptr = Properties.get( Property );

verify( Assert_Error, ptr != NULL, "invalid property requested; property does not exist in property list" );


return (*ptr)->TypeID;
}


And to just give you an idea of how geometry chunks work in my engine, here's the declaration for my geometry chunk class (which contains all renderable data for a single pass of a single object):


/**
* XGeometryChunk
*
* manages a geometry chunk and all properties associated with
* the chunk
*
*/

class EngineMode XGeometryChunk : public core::ISharedObj, public XPropertyList
{
public:

/**
* default constructor
*
*/

XGeometryChunk();

/**
* destructor
*
*/

~XGeometryChunk();


/**
* copies this object attempting to keep the same members as this chunk.
* if you need to modify data, copy that data into a new array or all
* geometry chunks will reflect the update at random !
*
* /ret: the fresh instanced copy of this object; be sure to 'grab' this object !
*/

XGeometryChunk* createChunkInstance();


/*! the geometry chunk name */
core::XHashString ChunkName;

/*! the number of vertices in the chunk */
u32 VertexCount;

/*! the number of indices in the chunk */
u32 IndexCount;

/*! flag indicating whether the data itself has changed */
bool DataUpdate;

/*! the geometry chunk's sorting ID */
class XSortingID* SortingID;

/*! the shader for this geometry chunk */
class XShaderI* Shader;

/*! the effect for this geometry chunk */
XEffect* Effect;

/*! the local blending term for this geometry chunk */
XEffect::UtBlendTerm* LocalColorTerm;

/*! the global blending term for this geometry chunk (the first level up) */
XEffect::UtBlendTerm* GlobalColorTerm;

/*! the render stage to render this geometry chunk */
ERenderStage RenderStage;

/*! flag indicating whether this geometry chunk is not the first pass */
bool MultiPass;

/*! flag indicating whether this geometry chunk is transparent or not */
bool Transparent;
};


The actual variables in the geometry chunk are required-by-the-engine administrative variables. All stream data is stored in the inherited property list. Hope this gives you some ideas!

[EDIT]:
An advantage to this technique is that if a shader needs to calculate and store some chunk-specific data (such as an environment map for the chunk, or a time variable, or anything at all), it only needs to set that property in the chunk, and if anything can use it, it can check for it, and access it. Here's some sample code from one of my shader's that fills a geometry chunk with data needed by the shader (vertex buffer, index buffer, etc.)


if( !Chunk.propertyExists( "vertexBuffer" ) )
{
buffer = allocateVertexBuffer( VertexBufferMgr );


buffer->createBuffer( ChunkName + XHashString( "vertexBuffer" ).getValue(), vertexSize * vertexCount );


XAccessor myAccessor( buffer->accessBuffer(), vertexSize * vertexCount );


vector3* positions = (vector3*) UtSharedArray(Chunk.getProperty( ".position.xyz" ));
u32* colors = (u32*) UtSharedArray(Chunk.getProperty( ".color.diffuse" ));
XPair<float>* texCoords = (XPair<float>*) UtSharedArray(Chunk.getProperty( ".texCoord2D.set0" ));


for( u32 k = 0; k < vertexCount; k ++ )
{
myAccessor.addComponent( positions[k] );
myAccessor.addComponent( colors[k] );

myAccessor.addComponent( &texCoords[k], sizeof( texCoords[k] ) );
}


Chunk.setProperty( "vertexBuffer", (u32) buffer, Property_SharedObj );
}


Chris Pergrossi
My Realm | "Good Morning, Dave"

[edited by - c t o a n on April 1, 2004 8:11:43 AM]

Share this post


Link to post
Share on other sites