I am getting more confused. My biggest problem is I am trying to design my engine in such a way that it is open to have new effects added. Yet I do not know what to expect when I try more advanced things.
Unlike everyone else, I do not have hardcoded material attributes. I have a system where an effect class creates a material by querying the effect interface for variables.
It works.
Now I am trying to implement a "RenderMethod" class that will be a member of each object getting rendered to describe what
effect to use
material to use
technique to use
passes to apply
etc.
This render method class is obtained from the renderable object by the render queue. The render queue communicates between the renderable object and the effect manager, binding input layout, binding effect, setting effect variables, etc.
Two problems:
I am unsure if the material is going to change per pass or per frame.
I am unsure if transforms will change per pass or frame.
I am unsure if the vertex buffers I bind will change per pass or per frame.
Edit: well, actually someone told the vertex buffers and input layout can change per pass, in another post.
Can someone list the things that are liable to change per pass?
If vertex buffers are going to change per pass, I am at a complete loss on how I can track which vertex buffers to bind on what pass. There are no comparison methods for any of the built in directx stuff for input layout or vertex buffers. I'd have to create some way of knowing what buffer contains what and what pass can use which one. Its harder then it sounds.
Right now, I just rely on the author knowing what the vertex buffers contain and knowing what vertex data the effect uses. My renderbale object is capable of creating one hardcoded input layout. To dynmaically create an inout layout is going to drive me nutts.
I'd love it if someone knowledgable could take a look at my system. It's small and I can put it up on my ftp site. Hell, I'd pay them for good suggestions. Getting this basic framework to where I am happy with it is taking months and I haven' even done anything but render a few lit and textured cubes :(
Short of that here are some snippets:
//----------------------------------------------------------------------------
void TestApp::Render()
{
//--------
// TODO - Alot of the following should belong in a renderqueue class
// These steps only need take place once per frame
// Bind the view and projection matrices from the camera
m_effectManager->BindCamera(m_camera);
// Bind the lights
// NOTE - No lights yet in this project
// These can be skipped for polygon sets that use the same shape as the previous rendered polygon sets
// Bind the input format
// NOTE - I haven't written a renderqueue yet to do this, so the input layout is bound once in InitResources()
// Bind vertex and index buffers
m_polygonSet->BindBuffers();
// These steps can be skipped when no transform or other non-tweable effect parameters have changed
// Update the effect's world matrix variable
// These steps can be skipped for polygon sets that use the same material
// Bind the effect variables
m_effectManager->BindMaterial(m_polygonSet->GetMaterial());
// These steps need always take place
// Apply pass
//
// TODO - Later, the renderable object should have a render method class that contains information
// about what passes to apply, what vertex buffers to use for each, and material to use
// for now, the effect only has 1 pass.
m_effectManager->ApplyPass(m_polygonSet->GetMaterial().GetEffectName(),
m_polygonSet->GetMaterial().GetTechniqueName(),
0);
// Draw
m_device->DrawIndexed(m_polygonSet->GetNumIndices(), 0, 0);
}
#ifndef TEXTUREMANAGER_H
#define TEXTUREMANAGER_H
// EngineX Includes
#include "Texture.h"
// DirectX Includes
#include <d3dx10.h>
#include <d3d10.h>
// Standard Includes
#include <string>
#include <map>
class TextureManager
{
public:
/**
* Constructor
*
* @param device - an intialized Direct3D device to use
*/
TextureManager(ID3D10Device & device);
/**
* Deconstructor
*/
~TextureManager();
/**
* Creates a texture from a file
*/
void CreateTextureFromFile(const std::string & textureName, const std::string & filePath);
/**
* Sets an effect variable to use a texture
*/
void SetTextureEffectVariable(const std::string & textureName,
ID3D10EffectShaderResourceVariable * effectVariable);
protected:
private:
ID3D10Device & m_device;
/**
* Map of textures where the name of the texture is the key and a pointer to a texture is the value
* I use a pointers to textures here, because there should only be one instance of a given texture,
* so copying and passing by value is not permitted */
typedef std::map<std::string, Texture *> TextureMap;
TextureMap m_textures;
};
#endif // TEXTUREMANAGER_H
#ifndef TEXTURE_H
#define TEXTURE_H
// Common Lib Includes
#include "BaseException.h"
// DirectX Includes
#include <d3d10.h>
#include <d3dx10.h>
// Standard Includes
#include <string>
//------------------------------------------------------------------------------------------
/**
* Wrapper around the Direct3D texture resource
*/
class Texture
{
public:
/**
* Constructor
*
* @param device - Direct3D device
* @param filePath - Path to the texture file to load
*
* @throws BaseException - if the texture cannot be loaded
*/
Texture(ID3D10Device & device, const std::string & filePath);
/**
* Deconstructor
*/
~Texture();
/**
* Sets an effect variable to use this texture
*/
void SetTextureEffectVariable(ID3D10EffectShaderResourceVariable * effectVariable);
private:
/**
* Copy Constructor
*
* You cannot copy this class, there should only be one instance of a particular texture
* in video memory. There are ways to get an manupulate data and create a new resource
* from it, which might be added later.
*/
Texture(const Texture & rhs);
ID3D10Device & m_device;
ID3D10ShaderResourceView * m_texture;
bool m_transparent;
unsigned m_width;
unsigned m_height;
};
#endif
#ifndef EFFECTMANAGER_H
#define EFFECTMANAGER_H
// EngineX Includes
#include "Graphics/Textures/TextureManager.h"
#include "Effect.h"
#include "Material.h"
#include "Graphics/3D/PolygonSet3D.h"
#include "Graphics/Cameras/BaseCamera.h"
// DirectX Includes
#include <d3dx10.h>
#include <d3d10.h>
// Standard Includes
#include <string>
#include <map>
//----------------------------------------------------------------------------
/**
* Manages the DirectX effects, which contain techniques for rendering
*/
class EffectManager
{
public:
/**
* Constructor
*
* @param device - an intialized Direct3D device to use
* @param effectsDirectory - Directory that contains the .fx and .fxh files for the DirectX effects
*/
EffectManager(ID3D10Device & device, TextureManager & textureManager, const std::string & effectDirectory);
/**
* Deconstructor
*/
~EffectManager();
/**
* Creates an effect from a file
*/
void CreateEffectFromFile(const std::string & effectName, const std::string & filePath);
/**
* Removes a loaded effect
*/
void RemoveEffect(const std::string & effectName);
/**
* Gets a Material from an effect
*/
const Material & GetMaterial(const std::string & effectName) const;
/**
* Gets the input description of a pass which must be verified with the description of the vertex buffers
* that will be bound during rendering of that pass
*/
const D3D10_PASS_DESC GetPassDesc(const std::string effectName,
const std::string techniqueName,
const unsigned passIndex) const;
/**
* Binds the camera's view and projection matrices to the effect
*/
void BindCamera(BaseCamera * camera);
/**
* Binds material attributes to the effect variables
*/
void BindMaterial(const Material & material);
/**
* Applys a technique pass
*/
void ApplyPass(std::string effectName, std::string techniqueName, unsigned passIndex);
private:
ID3D10Device & m_device;
TextureManager & m_textureManager;
const std::string m_effectDirectory;
ID3D10EffectPool * m_effectPool;
// Shared effect variables
ID3D10EffectMatrixVariable * m_effectVariable_view;
ID3D10EffectMatrixVariable * m_effectVariable_projection;
typedef struct AmbientLight
{
AmbientLight()
:
m_effectVariable_intensity(0),
m_effectVariable_color(0)
{}
ID3D10EffectVectorVariable * m_effectVariable_intensity;
ID3D10EffectVectorVariable * m_effectVariable_color;
};
AmbientLight m_ambientLight;
typedef struct DirectionalLight
{
DirectionalLight()
:
m_effectVariable_enabled(0),
m_effectVariable_direction(0),
m_effectVariable_color(0)
{}
ID3D10EffectScalarVariable * m_effectVariable_enabled;
ID3D10EffectVectorVariable * m_effectVariable_direction;
ID3D10EffectVectorVariable * m_effectVariable_color;
};
DirectionalLight m_directionalLights[8];
// Child effects
typedef std::map<std::string, Effect *> EffectMap;
EffectMap m_effects;
};
#endif // EFFECTMANAGER_H
#ifndef EFFECT_H
#define EFFECT_H
// EngineX Includes
#include "Graphics/Effects/Material.h"
#include "Graphics/Textures/TextureManager.h"
#include "Graphics/3D/PolygonSet3D.h"
// Common Lib Includes
#include "BaseException.h"
// DirectX Includes
#include <d3d10.h>
#include <d3dx10.h>
// Standard Includes
#include <string>
//----------------------------------------------------------------------------
/**
*
*/
class Effect
{
public:
/**
* Constructor
*/
Effect(ID3D10Device & device,
ID3D10EffectPool & effectPool,
TextureManager & textureManager,
const std::string & effectName,
const std::string & filePath);
/**
* Deconstructor
*/
~Effect();
/**
* Gets the description of a pass within a technique
*/
const D3D10_PASS_DESC GetPassDesc(const std::string & techniqueName, unsigned index) const;
/**
* Applies the state contained in a pass to the DirectX device
*/
void ApplyPass(const std::string techniqueName, unsigned passIndex);
/**
* Sets the world matrix effect variable
*/
void SetWorldMatrix(const D3DXMATRIX & worldMatrix);
/**
* Gets the current material.
*/
const Material & GetMaterial() const;
/**
* Sets the current material
* Sets tweakable effect parameters to those values contained within the material.
*/
void SetMaterial(const Material & material);
private:
/**
* Updates tweakable parameters by obtaining the values from a supplied material
*/
void UpdateMatrices(const Material & material);
void UpdateFloats(const Material & material);
void UpdateTextures(const Material & material);
/** Reference to the D3D graphics device */
ID3D10Device & m_device;
/** Reference to the texture manager from which texturesd will be obtained */
TextureManager & m_textureManager;
/** Each Effect creates and maintains its own copy of a DirectX effect interface */
ID3D10Effect * m_effect;
/** Current Material */
Material m_material;
// Non- Tweakable effect parameters
//
// These values are communicated directly through the public interface to this class
ID3D10EffectMatrixVariable * m_worldMatrix;
// Tweakable effect parameters
//
// These values are encapsulated by a material and communicated to the effect through the material
typedef std::map<std::string, ID3D10EffectMatrixVariable *> EffectMatrixVariables;
EffectMatrixVariables m_effectMatrixVariables;
typedef std::map<std::string, ID3D10EffectScalarVariable *> EffectFloatVariables;
EffectFloatVariables m_effectFloatVariables;
typedef std::map<std::string, ID3D10EffectShaderResourceVariable *> EffectTextureVariables;
EffectTextureVariables m_effectTextureVariables;
};
#endif // EFFECT_H
#ifndef MATERIAL_H
#define MATERIAL_H
// EngineX Includes
#include "Graphics\3D\Vertices3D.h"
// Common Lib Includes
#include "BaseException.h"
// DirectX Includes
#include <d3d10.h>
#include <d3dx10.h>
// Standard Includes
#include <string>
#include <map>
class Effect;
//----------------------------------------------------------------------------
/**
* Material
*
* Dynamic container of variables used by an Effect.
*
* A Material first has to be created by an Effect in order to allocate the differant
* types of attributes the Effect uses. It can then be obtained from and given back to
* the Effect, which will use the attributes of the Material to set the variables of
* the Effect.
*/
class Material
{
public:
friend class Effect;
/**
* Copy Constructor
*/
Material(const Material & rhs);
/**
* Deconstructor
*/
~Material();
/**
* Assignment Operator
*/
Material & operator = (const Material & rhs);
/**
* Get the name of the effect that created this material and to which this material provides attributes to
*/
const std::string & GetEffectName() const;
/**
* Get the name of the effect's technique that will render this material
*/
const std::string & GetTechniqueName() const;
/**
* Gets an existing matrix attribute
*
* @param variableName - Name of the matrix effect variable as it appears in the effect that created this material
*
* @return - The current value that will be used to set the matrix effect variable
**/
const D3DXMATRIX & GetMatrix(const std::string & variableName) const;
/**
* Sets an existing matrix attribute
*
* @param variableName - Name of the matrix effect variable as it appears in the effect that created this material
* @param value - The current value that will be used to set the matrix effect variable
*/
void SetMatrix(const std::string & variableName, const D3DXMATRIX & value);
/**
* Gets an existing float attribute
*
* @param variableName - Name of the float effect variable as it appears in the effect that created this material
*
* @return - The current value that will be used to set the float effect variable
**/
const float GetFloat(const std::string & varibaleName) const;
/**
* Sets an existing float attribute
*
* @param variableName - Name of the float effect variable as it appears in the effect that created this material
* @param value - The current value that will be used to set the float effect variable
*/
void SetFloat(const std::string & variableName, const float value);
/**
* Gets an existing texture name attribute
*
* @param variableName - Name of the texture effect variable as it appears in the effect that created this material
*
* @return - The current name of the texture, as it appears in the TextureManager, that will be used to set the
* texture effect variable
**/
const std::string GetTextureName(const std::string & variableName) const;
/**
* Sets an existing texture name attribute
*
* @param variableName - Name of the texture effect variable as it appears in the effect that created this material
* @param textureName - The name of the texture, as it appears in the TextureManager, that will be used to set the
* texture effect variable
*/
void SetTextureName(const std::string & variableName, const std::string & textureName);
private:
/**
* Constructor
*/
Material(const std::string & effectName, const std::string & techniqueName);
/**
* Creates an unitialized matrix attribute
*
* @param variableName - Name of the matrix effect variable as it appears in the effect that created this material
*/
void CreateMatrix(const std::string & variableName);
/**
* Creates an unitialized float attribute
*
* @param variableName - Name of the float effect variable as it appears in the effect that created this material
*/
void CreateFloat(const std::string & variableName);
/**
* Creates an unitialized texture name attribute
*
* @param variableName - Name of the texture effect variable as it appears in the effect that created this material
*/
void CreateTextureName(const std::string & variableName);
/** Name of the effect that created this material and to whom it provides attributes to */
std::string m_effectName;
/** Name of the effect's technique that will be used to render this material */
std::string m_techniqueName;
/**
* Material attribute value data structure
*
* Each attribute is first created by the effect that creates the material.
* However, the attributes are not initialized by the effect, but are initialized
* after the material has been created. This data structure adds a flag to the
* attribute value to determine if it has been initialized.
*/
template <class T>
struct Attribute
{
bool m_initialized;
T m_value;
};
/**
* Map of matrix attributes
*
* key - matrix variable name as it appears in the DirectX effect
* value - Attribute structure containing the matrix
*/
typedef std::map<std::string, Attribute<D3DXMATRIX> > Matrices;
Matrices m_matrices;
/**
* Map of float attributes
*
* key - float variable name as it appears in the DirectX effect
* value - Attribute structure containing the float
*/
typedef std::map<std::string, Attribute<float> > Floats;
Floats m_floats;
/**
* Map of the texture name attributes
*
* key - texture variable name as it appears in the DirectX effect
* value - Attribute structure containing the texture name as it appears in the texture manager
*/
typedef std::map<std::string, Attribute<std::string> > TextureNames;
TextureNames m_textureNames;
};
#endif
#ifndef POLYGONSET3D_H
#define POLYGONSET3D_H
// EngineX Includes
#include "Graphics\3D\Transformable.h"
#include "Graphics\3D\Vertices3D.h"
#include "Graphics\Effects\Material.h"
// DirectX Includes
#include <d3d10.h>
#include <d3dx10.h>
// Standard Includes
#include <vector>
//------------------------------------------------------------------------------------------
/**
* A set of polygons that are typically rendered as one group of triangles sharing the
* same transform, material, and shader.
*/
class PolygonSet3D : public Transformable
{
public:
/**
* Describes the vertex buffers this object will use
*/
typedef std::vector<D3D10_INPUT_ELEMENT_DESC> InputDesc;
/**
* Constructor
*/
PolygonSet3D::PolygonSet3D(ID3D10Device & device,
std::vector<Position> positions,
std::vector<Normal> normals,
std::vector<UV> texCoords,
std::vector<Index> indices,
const Material & material);
/**
* Deconstructor
*/
~PolygonSet3D();
/**
* Gets the description of the vertex buffers that will be bound to render this object
*/
const InputDesc & GetInputDesc() const;
/**
* Gets the number of indices in the index buffer
*/
const unsigned GetNumIndices() const;
/**
* Gets the material
*/
const Material & GetMaterial();
/**
* Sets the material
*/
void SetMaterial(const Material & material);
/**
* Binds the vertex and index buffers for rendering
*/
void BindBuffers();
private:
ID3D10Device & m_device;
typedef std::vector<ID3D10Buffer *> VertexBuffers;
VertexBuffers m_vertexBuffers;
typedef std::vector<unsigned> Strides;
Strides m_strides;
InputDesc m_inputDesc;
unsigned m_numVertices;
ID3D10Buffer * m_indexBuffer;
unsigned m_numIndices;
Material m_material;
};
#endif // POLYGONSET3D_H
#ifndef TRANSFORMABLE_H
#define TRANSFORMABLE_H
// DirectX Includes
#include <d3dx10.h>
//--------------------------------------------------------------------------------
class Transformable
{
public:
/**
* Constructor
*/
Transformable();
/**
* Deconstructor
*/
virtual ~Transformable();
/**
* Updates and obtains the current transform matrix
*/
virtual const D3DXMATRIX & GetTransform();
/**
* Moves the the object
*
* @param distance - number of units to move the object in the given direction
* @param direction - direction vector in which to move the object
* @pram objectSpace - If true, then the direction is in object space, otherwise the direction is in world space
*/
virtual void ApplyTranslation(const float distance, const D3DXVECTOR3 & direction, const bool objectSpace = false);
/**
* Rotates the object
*
* @param angle - radians to rotate clockwise when looking down the axis toward the origin in object space
* @param objectAxis - specifies the axis to rotate around
*/
virtual void ApplyRotation(const float angle, const D3DXVECTOR3 & objectAxis);
/**
* Get the object's current postion
*/
virtual const D3DXVECTOR3 & GetPosition() const;
/**
* Sets the object's postion
*/
virtual void SetPosition(const D3DXVECTOR3 & position);
/**
* Get the object's current orientation
*/
virtual const D3DXQUATERNION & GetOrientation() const;
/**
* Sets the object's orientation
*/
virtual void SetOrientation(const D3DXQUATERNION & orientation);
/**
* Gets the object's scaling factor
*/
virtual const float GetScale() const;
/**
* Sets the object's scaling factor
*/
virtual void SetScale(float scale);
/**
* Set the 3D object's orientation using an interpolated rotation from the
* current orientation to a specified orientation, given a rotation speed
*
* @param target_orientation - orientation of the object at speed = 1
* @param speed - How far along the interpolated curve to rotate. A number between 0 and 1,
* where 0 rotates to the current orientation and 1 rotates to the target orientation
*/
virtual void Slerp(const D3DXQUATERNION & target_orientation, float speed);
protected:
/**
* Updates the transform matrix to reflect the object's current position, orientation, and scale
*/
virtual void Update();
/**
* Transforms an axis from object space to world space
*/
D3DXVECTOR3 ObjectAxisToWorld(const D3DXVECTOR3 & objectAxis);
/**
* The position, orientation, and scale in matrix form
*/
D3DXMATRIX m_transform;
/**
* Seperate components of the total transform
*
* These are seperate components change when the various methods are called
* The transform matrix is updated when needed, to reflect those changes
*/
D3DXVECTOR3 m_position;
D3DXQUATERNION m_orientation;
float m_scale;
/**
* Whether or not the transform matrix needs to be updated to reflect changes
* to position, orientation, or scale.
*/
bool m_needUpdated;
private:
};
#endif
#ifndef RENDERMETHOD_H
#define RENDERMETHOD_H
//------------------------------------------------------------------------------------------
class PassDescription
{
// ????????????????????????
};
//------------------------------------------------------------------------------------------
class RenderMethod
{
public:
private:
std::string effectName;
std::string techniqueName;
std::vector<PassDesc> PassDescriptions;
PassDescriptions m_passDescriptions;
};
#endif
As you can see, effectName, technqiqueName, Material, world matrix, and the like appear a few places they shouldn't. I am hoping to sort all this out with the render method class and updating the portion that will become the renderqueue.
I am trying to seperate things while keeping it as open ended as I can. Unfortunatly, my brain cannot keep track of all these relationships!
I've poored through other peoples engines, but they have half the problems I have, because they set in stone all thier effect varibale names, what uses them , etc. If you always render an object the same way everything is easy! I don't forsee rendering things the same way. I want to be able to add effects, shadows, and all the advanced trimmings down the road with minimal effort.
[Edited by - brekehan on January 24, 2009 4:59:02 AM]