Shader Base Material
Shader Base Material
When using my own shader, is is accurate to think that I could use only the EMT_SOLID or EMT_TRANSPARENT_ADD_COLOR(or variation of transparent) as the 'base' material in order to have the system sort / render correctly?
for example, using EMT_DETAIL_MAP would be the same as using EMT_SOLID and would be in the non-transparent rendering pass where as the EMT_TRANSPARENT_ADD_COLOR would give the same output (since the shader outputs all of the pixels) but would be in the transparent pass for rendering performing transparency? (simply set the alpha of the pixel to 0)
or do i have to clip pixels in the shader to get transparency?
for example, using EMT_DETAIL_MAP would be the same as using EMT_SOLID and would be in the non-transparent rendering pass where as the EMT_TRANSPARENT_ADD_COLOR would give the same output (since the shader outputs all of the pixels) but would be in the transparent pass for rendering performing transparency? (simply set the alpha of the pixel to 0)
or do i have to clip pixels in the shader to get transparency?
Re: Shader Base Material
Phew, one of the confusing parts...
In Irrlicht trunk this has been unified so base material affects 4 variables in COpenGLSLMaterialRenderer. And aside from those nothing should really be different anymore (Irrlicht 1.9 was very different, this is our first step in getting toward shader-materials...). Those are Alpha, FixedBlending and Blending and AlphaTest. And they are set like this:
So that's the part that really matter from base-materials. And you are right - EMT_DETAIL_MAP and EMT_SOLID are the same in Irrlicht trunk.
What they are (I think... struggling a bit myself each time):
Alpha: Enables blending with blend function GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
FixedBlending: Enables blending with blend function GL_ONE, GL_ONE_MINUS_SRC_COLOR
Blending: Enables blending with function parameters from SMaterial:: MaterialTypeParam which you can set with pack_textureBlendFunc
AlphaTest: No real blending, but some sharp color clipping. Transparent when alpha < 128, otherwise solid.
edit: I mentioned OpenGL names here - D3D should be similar.
In Irrlicht trunk this has been unified so base material affects 4 variables in COpenGLSLMaterialRenderer. And aside from those nothing should really be different anymore (Irrlicht 1.9 was very different, this is our first step in getting toward shader-materials...). Those are Alpha, FixedBlending and Blending and AlphaTest. And they are set like this:
Code: Select all
case EMT_TRANSPARENT_VERTEX_ALPHA:
case EMT_TRANSPARENT_ALPHA_CHANNEL:
case EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA:
case EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA:
Alpha = true;
break;
case EMT_TRANSPARENT_ADD_COLOR:
case EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR:
case EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR:
FixedBlending = true;
break;
case EMT_ONETEXTURE_BLEND:
Blending = true;
break;
case EMT_TRANSPARENT_ALPHA_CHANNEL_REF:
AlphaTest = true;
break;
default:
AlphaTest = false; Alpha = false; FixedBlending = false; Blending = false;
What they are (I think... struggling a bit myself each time):
Alpha: Enables blending with blend function GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
FixedBlending: Enables blending with blend function GL_ONE, GL_ONE_MINUS_SRC_COLOR
Blending: Enables blending with function parameters from SMaterial:: MaterialTypeParam which you can set with pack_textureBlendFunc
AlphaTest: No real blending, but some sharp color clipping. Transparent when alpha < 128, otherwise solid.
edit: I mentioned OpenGL names here - D3D should be similar.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Shader Base Material
Ah right. Not enough confusion. This was about setting the variables for the low-level drivers.
But when it comes to transparency there are certainly 2 more things to care about.
First is z-write handling:
For shaders z-writing is enabled as soon as Alpha, FixedBlender or Blending are used OR SMaterial::isAlphaBlendOperation is true (it uses needsTransparentRenderPass function to decide).
Second is that transparent nodes are sorted back to front when using the scenemanager for rendering. Which happens as soon as a node is in one of the transparent render passes. Where it is put either by using registerNodeForRendering with ESNRP_TRANSPARENT or ESNRP_TRANSPARENT_EFFECT. Or (and that's the usual case) with ESNRP_AUTOMATIC and then needsTransparentRenderPass is checked again for the material used in that pass. Note that you kinda get another sorting from renderpasses themself - as they draw in a certain order (like ESNRP_TRANSPARENT before ESNRP_TRANSPARENT_EFFECT). In theory each node-type decides itself where it registers itself, but in Irrlicht trunk they should by now all use IDriver::needsTransparentRenderPass for this decision (in Irrlicht 1.9 it was a bit of a mess).
And minor note: there is no per polygon sorting so far. One day...
But when it comes to transparency there are certainly 2 more things to care about.
First is z-write handling:
For shaders z-writing is enabled as soon as Alpha, FixedBlender or Blending are used OR SMaterial::isAlphaBlendOperation is true (it uses needsTransparentRenderPass function to decide).
Second is that transparent nodes are sorted back to front when using the scenemanager for rendering. Which happens as soon as a node is in one of the transparent render passes. Where it is put either by using registerNodeForRendering with ESNRP_TRANSPARENT or ESNRP_TRANSPARENT_EFFECT. Or (and that's the usual case) with ESNRP_AUTOMATIC and then needsTransparentRenderPass is checked again for the material used in that pass. Note that you kinda get another sorting from renderpasses themself - as they draw in a certain order (like ESNRP_TRANSPARENT before ESNRP_TRANSPARENT_EFFECT). In theory each node-type decides itself where it registers itself, but in Irrlicht trunk they should by now all use IDriver::needsTransparentRenderPass for this decision (in Irrlicht 1.9 it was a bit of a mess).
And minor note: there is no per polygon sorting so far. One day...
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Shader Base Material
perfect. I solved my issue. thanks for the help.
are there any examples of using multiple shaders on one scenenode?
last but not least, is the overridematerial useful for something like when selecting an object it would be nice to have a shader that runs to show it selected. (i currently use debuginfo but would rather have my own shader run.
are there any examples of using multiple shaders on one scenenode?
last but not least, is the overridematerial useful for something like when selecting an object it would be nice to have a shader that runs to show it selected. (i currently use debuginfo but would rather have my own shader run.
Re: Shader Base Material
You mean switching shaders? No examples probably. Depends a bit on the situation what I do. Sometimes I push all node materials to a stack - change materials - render - pop old node materials back.
If not all nodes are involved then I might remember nodes and material-indices involved in my stack in some struct, like:
So let's say I want to backup all nodes involved in shadows it's:
More ways to do it I guess.
Needing more variables to pass to shader than SMaterial offers is unfortunately always pretty hard.
For stuff like highlighting I generally try to find some unused variable in the material and abuse it. MaterialTypeParam is often unused. Even wrote me some helper struct where I can use floats bytewise in case I need a few more bytes.
I rarely need extra floats - so I get 4 bytes out of each float that way.
Also sometimes not all colors are needed etc.
Override material has other use-cases. Thought I have to admit not having more variables is annoying (there's some reason - as material switches tend to have some costs).
If not all nodes are involved then I might remember nodes and material-indices involved in my stack in some struct, like:
Code: Select all
struct SMaterialBackup
{
SMaterialBackup(const irr::video::SMaterial& m, irr::u32 idx, irr::scene::ISceneNode* n)
: material(m), materialIdx(idx), node(n)
{}
irr::video::SMaterial material;
irr::u32 materialIdx;
irr::scene::ISceneNode* node;
};
std::vector<SMaterialBackup> backupMaterials;
Code: Select all
for ( auto node : shadowNodeArray )
{
for ( irr::u32 i=0; i< node->getMaterialCount(); ++i )
backupMaterials.push_back(SMaterialBackup(node->getMaterial(i), i, node));
}
// then modify materials in some way before rendering
smgr->drawAll();
// restore materials
for ( auto& backup : backupMaterials )
{
backup.node->getMaterial(backup.materialIdx) = backup.material;
}
Needing more variables to pass to shader than SMaterial offers is unfortunately always pretty hard.
For stuff like highlighting I generally try to find some unused variable in the material and abuse it. MaterialTypeParam is often unused. Even wrote me some helper struct where I can use floats bytewise in case I need a few more bytes.
Code: Select all
union UMaterialTypeParam
{
UMaterialTypeParam(irr::f32 f) : value(f) {}
irr::f32 value;
struct
{
irr::u8 reserved1;
irr::u8 reserved2;
irr::u8 reserved3;
EColHighlight highlight;
};
};
// now this switches only one byte of MaterialTypeParam in a SMaterial variable called mat
UMaterialTypeParam mtp(mat.MaterialTypeParam); // initalize with old f32 value
materialTypeParam.highlight = xxx; // set the highlighting byte
mat.MaterialTypeParam = materialTypeParam.value; // now we got the change f32 value
Also sometimes not all colors are needed etc.
Override material has other use-cases. Thought I have to admit not having more variables is annoying (there's some reason - as material switches tend to have some costs).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Shader Base Material
seems we think alike. I am doing something similar to what you have but on a per object case. basically I have a shadermanager that creates shaders and then use node->setmaterialType() as needed inside the game objects. (curently have a base shadertype in each obejct but can set the current shader as anything, always reverting back tot he base shader when desired)
I might be confusing myself though, because I see that the scennodes have the ability to have multiple materials. I had assumed you could assign different sahders and the system would automatically make multiple renderpasses to apply each one in turn. I will have to study into that more. Not sure how that works since some functions seem to be entire scenenode
//! Sets the material type of all materials in this scene node to a new material type.
/** \param newType New type of material to be set. */
void setMaterialType(video::E_MATERIAL_TYPE newType)
but then we have a materialcount also....... I'll have to study it I think.....
I might be confusing myself though, because I see that the scennodes have the ability to have multiple materials. I had assumed you could assign different sahders and the system would automatically make multiple renderpasses to apply each one in turn. I will have to study into that more. Not sure how that works since some functions seem to be entire scenenode
//! Sets the material type of all materials in this scene node to a new material type.
/** \param newType New type of material to be set. */
void setMaterialType(video::E_MATERIAL_TYPE newType)
but then we have a materialcount also....... I'll have to study it I think.....
Re: Shader Base Material
maybe I am doing it wrong. I dont use the material variables at all in the shader, I send them all through the onsetconstants() function.
for example , one of my lit shaders with 8 textures.
(the whole stringtoFloat() and such is just my own nonsense for having exposed variables for the scripting language)
(also, IGE_ADD_VARIABLE just prevents some typeing for me)
#define IGE_VARIABLE_SETGET(x,y,z) private: x m_##y = z; public : virtual void set##y(x v) { m_##y = v; } virtual x get##y() { return m_##y; }
if there is a better way to do this PLEASE teach me
again, if there is a better way please feel free to teach me!
how would I access a material variable inside the shader?
for example , one of my lit shaders with 8 textures.
(the whole stringtoFloat() and such is just my own nonsense for having exposed variables for the scripting language)
(also, IGE_ADD_VARIABLE just prevents some typeing for me)
#define IGE_VARIABLE_SETGET(x,y,z) private: x m_##y = z; public : virtual void set##y(x v) { m_##y = v; } virtual x get##y() { return m_##y; }
if there is a better way to do this PLEASE teach me

Code: Select all
class IGE_ShaderCallback : public IShaderConstantSetCallBack
{
private:
IGE_VARIABLE_SETGET(bool, FirstUpdate, true);
IGE_VARIABLE_GET(IGE_Object*, Object, nullptr);
// vertex constants
IGE_VARIABLE_SETGET(s32, WorldViewProjID, -1);
IGE_VARIABLE_SETGET(s32, TransWorldID, -1);
IGE_VARIABLE_SETGET(s32, InvWorldID, -1);
IGE_VARIABLE_SETGET(s32, AmbientLightID, -1);
IGE_VARIABLE_SETGET(s32, CameraPositionID, -1);
IGE_VARIABLE_SETGET(s32, TimeID, -1);
IGE_VARIABLE_SETGET(s32, LightPositionID, -1);
IGE_VARIABLE_SETGET(s32, LightDiffuseID, -1);
IGE_VARIABLE_SETGET(s32, LightSpecularID, -1);
IGE_VARIABLE_SETGET(s32, LightAttenuationID, -1);
IGE_VARIABLE_SETGET(s32, LightRadiusID, -1);
IGE_VARIABLE_SETGET(s32, FogColorID, -1);
IGE_VARIABLE_SETGET(s32, FogStartID, -1);
IGE_VARIABLE_SETGET(s32, FogEndID, -1);
IGE_VARIABLE_SETGET(s32, FogDensityID, -1);
// fragment constants
IGE_VARIABLE_SETGET(s32, Texture0ID, -1);
IGE_VARIABLE_SETGET(s32, Texture1ID, -1);
IGE_VARIABLE_SETGET(s32, Texture2ID, -1);
IGE_VARIABLE_SETGET(s32, Texture3ID, -1);
IGE_VARIABLE_SETGET(s32, Texture4ID, -1);
IGE_VARIABLE_SETGET(s32, Texture5ID, -1);
IGE_VARIABLE_SETGET(s32, Texture6ID, -1);
IGE_VARIABLE_SETGET(s32, Texture7ID, -1);
public:
IGE_ShaderCallback(IGE_Object* obj) : IShaderConstantSetCallBack(), m_Object(obj) { }
virtual stringc getDirectory(stringc dirname) { return m_Object == nullptr ? IGE_DEFAULT_STRING : m_Object->getDirectory(dirname); }
virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{
// get shader constants id.
if (m_FirstUpdate)
{
m_WorldViewProjID = services->getVertexShaderConstantID("mWorldViewProj");
m_TransWorldID = services->getVertexShaderConstantID("mTransWorld");
m_InvWorldID = services->getVertexShaderConstantID("mInvWorld");
m_AmbientLightID = services->getVertexShaderConstantID("mAmbientLight");
m_CameraPositionID = services->getVertexShaderConstantID("mCameraPosition");
m_TimeID = services->getVertexShaderConstantID("mTime");
m_LightPositionID = services->getVertexShaderConstantID("mLightPosition");
m_LightDiffuseID = services->getVertexShaderConstantID("mLightDiffuse");
m_LightSpecularID = services->getVertexShaderConstantID("mLightSpecular");
m_LightAttenuationID = services->getVertexShaderConstantID("mLightAttenuation");
m_LightRadiusID = services->getVertexShaderConstantID("mLightRadius");
m_FogColorID = services->getVertexShaderConstantID("mFogColor");
m_FogStartID = services->getVertexShaderConstantID("mFogStart");
m_FogEndID = services->getVertexShaderConstantID("mFogEnd");
m_FogDensityID = services->getVertexShaderConstantID("mFogDensity");
m_Texture0ID = services->getPixelShaderConstantID("Texture0");
m_Texture1ID = services->getPixelShaderConstantID("Texture1");
m_Texture2ID = services->getPixelShaderConstantID("Texture2");
m_Texture3ID = services->getPixelShaderConstantID("Texture3");
m_Texture4ID = services->getPixelShaderConstantID("Texture4");
m_Texture5ID = services->getPixelShaderConstantID("Texture5");
m_Texture6ID = services->getPixelShaderConstantID("Texture6");
m_Texture7ID = services->getPixelShaderConstantID("Texture7");
//printf("texture IDs = %d %d %d %d %d\n", m_Texture0ID, m_Texture1ID, m_Texture2ID, m_Texture3ID, m_Texture4ID);
return;
}
// vertex shader constants
// set inverted world matrix
video::IVideoDriver* driver = services->getVideoDriver();
// set clip matrix
core::matrix4 worldViewProj;
worldViewProj = driver->getTransform(video::ETS_PROJECTION);
worldViewProj *= driver->getTransform(video::ETS_VIEW);
worldViewProj *= driver->getTransform(video::ETS_WORLD);
services->setVertexShaderConstant(m_WorldViewProjID, worldViewProj.pointer(), 16);
// set world matrixes
core::matrix4 world = driver->getTransform(video::ETS_WORLD);
world = world.getTransposed();
services->setVertexShaderConstant(m_TransWorldID, world.pointer(), 16);
core::matrix4 invWorld = driver->getTransform(video::ETS_WORLD);
invWorld.makeInverse();
services->setVertexShaderConstant(m_InvWorldID, invWorld.pointer(), 16);
// set the ambient light
SColorf c = m_Object->getSmgr()->getAmbientLight();
services->setVertexShaderConstant(m_AmbientLightID, reinterpret_cast<f32*>(&c), 4);
//printf("ambient light = %s\n", SColorfToStringc(c).c_str());
SColor c2 = m_Object->getLevel()->getFogColor();
SColorf c3(c2);
services->setVertexShaderConstant(m_FogColorID, reinterpret_cast<f32*>(&c3), 4);
float fs = m_Object->getLevel()->getFogStart();
services->setVertexShaderConstant(m_FogStartID, reinterpret_cast<f32*>(&fs), 1);
float fe = m_Object->getLevel()->getFogEnd();
services->setVertexShaderConstant(m_FogEndID, reinterpret_cast<f32*>(&fe), 1);
float fd = m_Object->getLevel()->getFogDensity();
services->setVertexShaderConstant(m_FogDensityID, reinterpret_cast<f32*>(&fd), 1);
// set the camera position
vector3df p = m_Object->getSmgr()->getActiveCamera()->getPosition();
float cp[4];
p.getAs4Values(cp);
services->setVertexShaderConstant(m_CameraPositionID, cp, 4);
vector3df lightPos = vector3df(0, 0, 0);
SColorf lightDiffuse = SColorf(0, 0, 0, 0);
SColorf lightSpecular = SColorf(0, 0, 0, 0);
vector3df lightAttenuation = vector3df(0.03f, 0.03f, 0.03f);
float lightRadius = 300;
float l[4];
float att[4];
IGE_Object* theLight = m_Object->getLevel()->getObjectManager()->getObjectPointerByName("Light", true);
if (theLight)
{
lightPos = theLight->getAbsolutePosition();
lightDiffuse = stringcToSColorf(theLight->getVariable("Diffuse"));
lightSpecular = stringcToSColorf(theLight->getVariable("Specular"));
lightRadius = stringcToFloat(theLight->getVariable("Radius"));
lightAttenuation = stringcToVector3df(theLight->getVariable("Attenuation"));
}
else
{
theLight = m_Object->getLevel()->getObjectManager()->getObjectPointerByName("IGEO_CAMERALIGHT", true);
if (theLight)
{
lightPos = theLight->getAbsolutePosition();
lightDiffuse = stringcToSColorf(theLight->getVariable("Diffuse"));
lightSpecular = stringcToSColorf(theLight->getVariable("Specular"));
lightRadius = stringcToFloat(theLight->getVariable("Radius"));
lightAttenuation = stringcToVector3df(theLight->getVariable("Attenuation"));
}
}
lightPos.getAs4Values(l);
services->setVertexShaderConstant(m_LightPositionID, l, 4);
services->setVertexShaderConstant(m_LightDiffuseID, reinterpret_cast<f32*>(&lightDiffuse), 4);
services->setVertexShaderConstant(m_LightSpecularID, reinterpret_cast<f32*>(&lightSpecular), 4);
services->setVertexShaderConstant(m_LightRadiusID, reinterpret_cast<f32*>(&lightRadius), 1);
lightAttenuation.normalize();
lightAttenuation.getAs4Values(att);
services->setVertexShaderConstant(m_LightAttenuationID, att, 4);
// set the time
float time = (f32)m_Object->getDevice()->getTimer()->getTime() / 1000.0f;
services->setVertexShaderConstant(m_TimeID, (const irr::f32*)&time, 1);
//printf("time = %f\n", time);
// set texture, for textures you can use both an int and a float setPixelShaderConstant interfaces (You need it only for an OpenGL driver).
s32 TextureLayerID = 0;
services->setPixelShaderConstant(m_Texture0ID, &TextureLayerID, 1);
TextureLayerID = 1;
services->setPixelShaderConstant(m_Texture1ID, &TextureLayerID, 1);
TextureLayerID = 2;
services->setPixelShaderConstant(m_Texture2ID, &TextureLayerID, 1);
TextureLayerID = 3;
services->setPixelShaderConstant(m_Texture3ID, &TextureLayerID, 1);
TextureLayerID = 4;
services->setPixelShaderConstant(m_Texture4ID, &TextureLayerID, 1);
TextureLayerID = 5;
services->setPixelShaderConstant(m_Texture5ID, &TextureLayerID, 1);
TextureLayerID = 6;
services->setPixelShaderConstant(m_Texture6ID, &TextureLayerID, 1);
TextureLayerID = 7;
services->setPixelShaderConstant(m_Texture7ID, &TextureLayerID, 1);
}
};
again, if there is a better way please feel free to teach me!
how would I access a material variable inside the shader?
Re: Shader Base Material
Code: Select all
#version 120
//////////////////////////////////////////////////////////////////////////////////
// uniforms are passed to the shader from the IShaderConstantSetCallBack
//////////////////////////////////////////////////////////////////////////////////
uniform mat4 mWorldViewProj; //
uniform mat4 mTransWorld; //
uniform mat4 mInvWorld; //
uniform vec4 mAmbientLight; // ambient light value from IGE_Level instance
uniform vec4 mCameraPosition; // current active camera position
uniform float mTime; // time
// vertex uniforms for testing a single light
uniform vec3 mLightPosition; // a single light position
uniform vec4 mLightDiffuse; // a single light
uniform vec4 mLightSpecular; // a single light
uniform vec4 mLightAttenuation; // a single light
uniform float mLightRadius; // a single light
uniform vec4 mFogColor; // fog color
uniform float mFogStart; //
uniform float mFogEnd; //
uniform float mFogDensity; //
//////////////////////////////////////////////////////////////////////////////////
// varying values are set in the vertex shader but available in the pixel shader
// allows passing info from the vertex to the pixel shader
//////////////////////////////////////////////////////////////////////////////////
varying vec3 pNormal; // the normal of the fragment
varying vec4 pAmbientLight; // pass through to pixel shader
varying vec4 pCameraPosition; // pass through to pixel shader
varying float pTime; // pass through to pixel shader
varying vec3 pLightPosition; // pass through to pixel shader
varying vec4 pLightDiffuse; // pass through to pixel shader
varying vec4 pLightSpecular; // pass through to pixel shader
varying vec4 pLightAttenuation; // pass through to pixel shader
varying float pLightRadius; // pass through to pixel shader
varying vec4 pFogColor; // pass through to pixel shader
varying float pFogStart; // pass through to pixel shader
varying float pFogEnd; // pass through to pixel shader
varying float pFogDensity; // pass through to pixel shader
// calculated in the vertex shader and passed to the pixel shader
varying vec4 pWorldPosition; // vertex position in world coordinates
void main (void)
{
// remember these so that the pixel shader can access them if desired
pAmbientLight = mAmbientLight;
pCameraPosition = mCameraPosition;
pTime = mTime;
pNormal = normalize(gl_Normal);
pLightPosition = mLightPosition;
pLightDiffuse = mLightDiffuse;
pLightSpecular = mLightSpecular;
pLightAttenuation = mLightAttenuation;
pLightRadius = mLightRadius;
pFogColor = mFogColor;
pFogStart = mFogStart;
pFogEnd = mFogEnd;
pFogDensity = mFogDensity;
// calculate these
gl_Position = mWorldViewProj * gl_Vertex; // vertex position in screen coordinates?
pWorldPosition = gl_Vertex * mTransWorld; // vertex position in world coordinates
gl_FrontColor = gl_BackColor = vec4(1.0f,1.0f,1.0f,1.0f); // not sure why we do this here
gl_TexCoord[0] = gl_MultiTexCoord0; // texture coord
}
// these are built in GLSL variables accessible in the pixel shader listed here as reference so i remember they are available if needed
/*
vec4 gl_FragCoord read-only current fragment window relative coordinate. z is 0-1 and assigned to gl_FragDepth if no other value is assigned.
bool gl_FrontFacing true if the fragment belongs to a front facing geometric primitive.
int gl_PointCoord fragment position within a point (point rasterization only)in the range 0.0 to 1.0
vec4 gl_FragColor the colour of the fragment
vec4 gl_FragData data associated with the fragment
*/
Re: Shader Base Material
Code: Select all
#version 120
///////////////////////////////////////////////////////////////////////////////////
// bind all 8 textures in case we want to use them
// how to access the textures vec4 col0 = texture2D(Texture0, vec2(gl_TexCoord[0]));
///////////////////////////////////////////////////////////////////////////////////
uniform sampler2D Texture0;
uniform sampler2D Texture1;
uniform sampler2D Texture2;
uniform sampler2D Texture3;
uniform sampler2D Texture4;
uniform sampler2D Texture5;
uniform sampler2D Texture6;
uniform sampler2D Texture7;
//////////////////////////////////////////////////////////////////////////////////
// varying values are set in the vertex shader but available in the pixel shader
// allows passing info from the vertex to the pixel shader
//////////////////////////////////////////////////////////////////////////////////
varying vec4 pAmbientLight; // pass through to pixel shader
varying vec4 pCameraPosition; // pass through to pixel shader
varying float pTime; // pass through to pixel shader
varying vec3 pLightPosition; // pass through to pixel shader
varying vec4 pLightDiffuse; // pass through to pixel shader
varying vec4 pLightSpecular; // pass through to pixel shader
varying vec4 pLightAttenuation; // pass through to pixel shader
varying float pLightRadius; // pass through to pixel shader
varying vec4 pWorldPosition; // vertex position in world coordinates
varying vec3 pNormal; // the normal of the fragment
varying vec4 pFogColor; // pass through to pixel shader
varying float pFogStart; // pass through to pixel shader
varying float pFogEnd; // pass through to pixel shader
varying float pFogDensity; // pass through to pixel shader
// FOG
float getFogFactor(float fogCoordinate)
{
float result = 0.0;
float fogLength = pFogEnd - pFogStart;
result = (pFogEnd - fogCoordinate) / fogLength;
result = 1.0 - clamp(result, 0.0, 1.0);
return result;
}
/////
/// POINT LIGHT and AMBIENT
vec4 Light_Point( vec4 pos, vec3 nrm, vec3 light, vec4 lcolor, vec3 att )
{
vec4 diffuse;
// get the direction from the fragment to the light, normalize it and then get the distance between them
vec3 lDir = vec3(light.xyz - pos.xyz);
float distance = length(lDir);
lDir = normalize(lDir);
// simple attenuation formula to approximate light drop off over distance
float intensity = 1 - ((distance - pLightRadius) / pLightRadius);
// keep in the 0 to 1 range
intensity = clamp(intensity,0.0f,1.0f);
// the diffuse color should be falloff value * the light color * ambient light
diffuse += dot(lDir, nrm) * lcolor * intensity;
diffuse += pAmbientLight;
// light alpha is always 1
diffuse.a = 1.0;
// return the lighted pixel color
return diffuse;
}
// the program entry point
void main()
{
vec3 vNormalized = normalize(pNormal);
vec4 vTexColor = vec4(0.0);
vec2 vTexCoord = gl_TexCoord[0].st;
vec2 vTexCoord2 = gl_TexCoord[0].st * 500;
// path texture
vec4 PathTexColor = texture2D(Texture5, vTexCoord);
// default base colors mized
vec4 TexColor0 = texture2D(Texture0, vTexCoord2) * .3;
vec4 TexColor1 = texture2D(Texture1, vTexCoord2) * .3;
// mixed rocks, grass etc based on path texture colors
vec4 TexColor2 = texture2D(Texture2, vTexCoord2) * PathTexColor.r;
vec4 TexColor3 = texture2D(Texture3, vTexCoord2) * PathTexColor.b;
vec4 TexColor4 = texture2D(Texture4, vTexCoord2) * PathTexColor.g;
// combine them all togther
vec4 vFinalTexColor = TexColor2 + TexColor3+ TexColor4;
// mix in the point lighting if desired
#if(1)
vec4 pointlight = Light_Point(pWorldPosition, pNormal, pLightPosition, pLightDiffuse, pLightAttenuation.xyz);
vFinalTexColor = vFinalTexColor * pointlight;
#endif
#if(1)
float fogCoordinate = length(pCameraPosition - pWorldPosition);
vFinalTexColor = mix(vFinalTexColor, pFogColor, getFogFactor(fogCoordinate));
#endif
clamp(vFinalTexColor.r,0.0f,1.0f);
clamp(vFinalTexColor.g,0.0f,1.0f);
clamp(vFinalTexColor.b,0.0f,1.0f);
vFinalTexColor.a = 1.0f;
// output the final color
gl_FragColor = vFinalTexColor;
}
}
Re: Shader Base Material
Nope, that's 1 material per meshbuffer. You can have different meshbuffers in a mesh - and each needs it's own material.Seven wrote: Fri Aug 05, 2022 9:53 pm I might be confusing myself though, because I see that the scennodes have the ability to have multiple materials. I had assumed you could assign different sahders and the system would automatically make multiple renderpasses to apply each one in turn.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Shader Base Material
Accessing material variables in shaders: You copy them in OnSetMaterial to your shader class. Then in OnSetConstants you can pass them on.
The problem with OnSetConstants is that it's one for all nodes. Unless you create a shader-material per node. Or you figure out some way to access the node in OnSetConstants. Which I think is probably not possible right now (it's a bit tricky as that low-level it doesn't have the concept of nodes, but only drawCall with a material). Thought maybe SceneManager could have the concept of currently rendered node (not sure if it helps).
The problem with OnSetConstants is that it's one for all nodes. Unless you create a shader-material per node. Or you figure out some way to access the node in OnSetConstants. Which I think is probably not possible right now (it's a bit tricky as that low-level it doesn't have the concept of nodes, but only drawCall with a material). Thought maybe SceneManager could have the concept of currently rendered node (not sure if it helps).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Shader Base Material
gotcha. It seems we still think alike so I feel I am on the right track. I create a shader instance for each object and then store the object instance inside the shader class so that I have access to the scenenode (as well as the lights, fog etc... though the object and into the level instance). I will have to devise a method to reach each meshbuffer although that shouldnt be too difficult when I get to that level.
for now I want to create shaders for all material types so that I can start my deferred rendering studies. Once I have the forward rendering done using my own shaders, I should be able to switch between forward / deferred at runtime which is my final goal.
for now I want to create shaders for all material types so that I can start my deferred rendering studies. Once I have the forward rendering done using my own shaders, I should be able to switch between forward / deferred at runtime which is my final goal.
Re: Shader Base Material
Hm, I never tried just creating one shader instance per object, so I can't really tell if that is a good idea or not. The constant material changes this causes might have some overhead? Just guessing - never tried it that way. In my irr-playground-micha repository (see sig) I got a few files called profile* which can be useful to test the effect stuff has on speed. Thought you probably have your own tests ;-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Re: Shader Base Material
thanks for all the help! I now have things working as desired.
in the shader system I have, I currently have to paste the lighting and fog code into each shader. is it possible to use a #include statement inside the shaders for irrlicht so i can have a single lighting / fog file?
in the shader system I have, I currently have to paste the lighting and fog code into each shader. is it possible to use a #include statement inside the shaders for irrlicht so i can have a single lighting / fog file?
Re: Shader Base Material
You need your own pre-processor for this. XEffects (https://github.com/monstrobishi/xeffect ... ter/Source) has one with CPreShader.cpp/.h . That one doesn't have include yet, but I've added a function for that which looks somewhat like following (not tested right now if I forgot something, but I think aside from STL it only uses getFileContent from those XEffect files ... which could probably be optimized, not sure why that reads stuff per line, but won't matter much).
Note that I kept the same style as XEffects - everything in our own pre-processor uses 2 ##, so for example ##include to distinguish it from the pre-processor which the shader compiler itself runs. Also as I run resolveIncludes it doesn't care about defines (so you can't define out the include).
Hm, I see I also rewrote comment-stripping a bit. Mainly to keep line-numbers intact, didn't like how it removed them as shader-compiler then gave wrong lines on errors. And only makes sense if you use rest of that pre-processor as it's just an easy way to prevent accidentally using commented out defines later:
Code: Select all
static void resolveIncludes(std::string& shaderProgram, const std::string& includePath)
{
std::string::size_type includePos = 0;
const std::string includeLabel("##include");
while ((includePos = shaderProgram.find(includeLabel, includePos)) != std::string::npos)
{
std::string::size_type posStartStr = shaderProgram.find("\"", includePos + includeLabel.size());
if (posStartStr == std::string::npos)
{
Logger::log("Shader preprocessor: ##include statement not followed by \".");
return;
}
++posStartStr;
std::string::size_type posEndStr = shaderProgram.find("\"", posStartStr);
if (posEndStr == std::string::npos)
{
Logger::log("Shader preprocessor: ##include statement missing closing \".");
return;
}
std::string includeFilename = includePath + shaderProgram.substr(posStartStr, posEndStr - posStartStr);
std::string includeContent = getFileContent(includeFilename.c_str());
if (includeContent.empty())
Logger::log("Shader preprocessor: ##include returned empty string"); // Could be OK, but usually isn't. getFileContent will deliver errors.
else
stripComments(includeContent);
shaderProgram = shaderProgram.substr(0, includePos) + includeContent + shaderProgram.substr(posEndStr + 1, std::string::npos);
// Not skipping over includeContent as it might have further includes. Means: infinite recursive includes can happen (and can't be avoided with defines as those are handled later). Just don't make shader too complicated.
}
}
Hm, I see I also rewrote comment-stripping a bit. Mainly to keep line-numbers intact, didn't like how it removed them as shader-compiler then gave wrong lines on errors. And only makes sense if you use rest of that pre-processor as it's just an easy way to prevent accidentally using commented out defines later:
Code: Select all
static void stripComments(std::string &shaderProgram)
{
// Strip all comments, they get in the way.
// Note they are replaced by whitespace which does not affect line-numbers.
// (the reason error-line-numbers are still wrong sometimes is because of nvidia's compiler messing it up)
std::string::size_type currentSearchPos = 0;
// c++ style comments //
while ((currentSearchPos = shaderProgram.find("//", currentSearchPos)) != std::string::npos)
{
std::string::size_type findEnd = shaderProgram.find('\n', currentSearchPos+2);
if (findEnd == std::string::npos) // no eol, so go until eof
findEnd = shaderProgram.size();
for (size_t i = currentSearchPos; i < findEnd; ++i)
shaderProgram[i] = ' ';
}
// c style comments /* */
currentSearchPos = 0;
while ((currentSearchPos = shaderProgram.find("/*", currentSearchPos)) != std::string::npos)
{
std::string::size_type findEnd = shaderProgram.find("*/", currentSearchPos+2);
if (findEnd == std::string::npos) // no end of commment - use eol
findEnd = shaderProgram.size();
else
findEnd += 2; // overwrite ending-chars as well
for (size_t i = currentSearchPos; i < findEnd; ++i)
shaderProgram[i] = ' ';
}
}
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm