I'm trying to port the zeroZshadow's Fur shader (http://irrlicht.sourceforge.net/forum/v ... hp?t=31295 originally written in 2008 in GLSL, based itself on http://www.xbdev.net/directx3dx/specialX/Fur/index.php in HLSL) in CG that is now fully and officially supported by irrlicht.
BUT... here is the problem: I think there's some issues with EMT_ONETEXTURE_BLEND because I can't see the whole model...
As stated somewhere else on the forum and in the examples I already tryied to set the EMF_BLEND_OPERATION flag to the material.
here are the tests I've made using EMT_SOLID as material shader flag
- you can see it produces "instanced copies" BEHIND the model and not AROUND as you would expect from fur
- it turned out that passing matrices variable from irrlicht (wolrd, view, normals and other stuff) is better because otherwise you can't see anything (so using shaders global constants is wrong)
- as stated in a topic on this forum, passing texture to shader was done before by casting the texture reference to float but now it has been fixed so I just pass the reference
http://www.mediafire.com/?nnfdbzo4vr4fjxt
main.cpp
Code: Select all
#include "global.h"
#include "shader.h"
bool InitIrrlicht();
int main()
{
//Startup irrlicht
if(!InitIrrlicht())
return 0;
//Setup Camera
//smgr->addCameraSceneNodeFPS();
ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS(0, 100.0f, 0.5f);
cam->setPosition(vector3df(0.0f, 100.0f, -100.0f));
//Create CFurSceneNode
IAnimatedMesh* meshFur = smgr->addHillPlaneMesh("plane", core::dimension2d<irr::f32>(10,10), core::dimension2d<irr::u32>(10,10));
CFurSceneNode* nodeFur = new CFurSceneNode(meshFur, smgr->getRootSceneNode(), smgr, 666);
if (nodeFur)
{
nodeFur->setName("nodeFur");
nodeFur->setMaterialFlag(EMF_LIGHTING, false);
nodeFur->setMaterialFlag(EMF_BLEND_OPERATION,true);
nodeFur->setMaterialType((E_MATERIAL_TYPE)EMT_FUR);
nodeFur->setPosition( vector3df( 0, -50, 100) );
nodeFur->setLayers(10);
nodeFur->setFurLength(0.3f);
nodeFur->setMaterialTexture( 1, driver->getTexture("../res/FurTexColor.jpg") ); //FurTexture
nodeFur->setMaterialTexture( 0, driver->getTexture("../res/Fur.tga") ); //FurAlpha
}
while(device->run())if (device->isWindowActive())
{
driver->beginScene(true, true, SColor(255, 255, 128, 64));
smgr->drawAll();
driver->endScene();
}
device->drop();
return 0;
}
bool InitIrrlicht()
{
//*************************starting irrlicht********************************
device = createDevice(EDT_DIRECT3D9, dimension2d<u32>(800, 600), 32, false, false, false);
if(!device)
return 0;
device->setWindowCaption(L"Fur Demo - by zeroZshadow");
driver = device->getVideoDriver();
smgr = device->getSceneManager();
gpu = driver->getGPUProgrammingServices();
driver->setTextureCreationFlag(ETCF_CREATE_MIP_MAPS,false);
smgr->setAmbientLight(SColor(0,146,75,56));
InitShaders();
return 1;
}
Code: Select all
#include "shader.h"
#include <irrlicht.h>
void MyShaderCallBack::OnSetConstants(video::IMaterialRendererServices* services, s32 userData)
{
// set inverted world matrix
// if we are using highlevel shaders (the user can select this when
// starting the program), we must set the constants by name.
float fUVScale = 1.0f;
vector3df vGravity = vector3df(0.0, 0.0f, 0.0f);
services->setVertexShaderConstant("fFurLength", &fFurLength, 1);
services->setVertexShaderConstant("fMaxLength", &fMaxLength, 1);
services->setVertexShaderConstant("fUVScale", &fUVScale, 1);
services->setVertexShaderConstant("fLayer", &fLayer, 1);
services->setVertexShaderConstant("vGravity", reinterpret_cast<f32*>(&vGravity), 3);
//vLightDir
vector3df vLightDir = vector3df(0.8f, 0.8f, 0.8f);
services->setPixelShaderConstant("vLightDir", reinterpret_cast<f32*>(&vLightDir), 3);
//vAmbient
SColorf vAmbient = smgr->getAmbientLight().toSColor();
services->setPixelShaderConstant("vAmbient", reinterpret_cast<f32*>(&vAmbient), 4);
//Set Textures
int texVar = 1;
services->setPixelShaderConstant("FurTexture", &texVar, 1);
texVar = 0;
services->setPixelShaderConstant("ColourTexture", &texVar, 1);
//mWorld
matrix4 mWorld = driver->getTransform(video::ETS_WORLD);
services->setVertexShaderConstant("mWorld", mWorld.pointer(), 16);
//mWorldViewProj
matrix4 mWorldViewProj;
mWorldViewProj = driver->getTransform(video::ETS_PROJECTION);
mWorldViewProj *= driver->getTransform(video::ETS_VIEW);
mWorldViewProj *= driver->getTransform(video::ETS_WORLD);
services->setVertexShaderConstant("mWorldViewProj", mWorldViewProj.pointer(), 16);
}
void InitShaders()
{
ShaderCB = new MyShaderCallBack();
blShader=true;
if (!driver->queryFeature(video::EVDF_PIXEL_SHADER_1_3) &&
!driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1))
{
device->getLogger()->log("WARNING: Pixel shaders disabled "\
"because of missing driver/hardware support.");
blShader=false;
}
if (!driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
!driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1))
{
device->getLogger()->log("WARNING: Vertex shaders disabled "\
"because of missing driver/hardware support.");
blShader=false;
}
EMT_FUR = 0;
if(blShader)
{
/*EMT_FUR = gpu->addHighLevelShaderMaterialFromFiles(
"../res/fur.vert", "main", video::EVST_VS_1_1,
"../res/fur.frag", "main", video::EPST_PS_1_3,
ShaderCB, video::EMT_ONETEXTURE_BLEND
);*/
const video::E_GPU_SHADING_LANGUAGE shadingLanguage = video::EGSL_CG;
EMT_FUR = gpu->addHighLevelShaderMaterialFromFiles(
"../res/fur.hlsl", "vertexMain", video::EVST_VS_1_1,
"../res/fur.hlsl", "pixelMain", video::EPST_PS_1_3,
ShaderCB, video::EMT_ONETEXTURE_BLEND, 0, shadingLanguage);
}
else EMT_FUR = EMT_SOLID;
}
CFurSceneNode::~CFurSceneNode()
{
}
void CFurSceneNode::OnRegisterSceneNode()
{
if(blShader){
//printf("shader\n");
SceneManager->registerNodeForRendering(this, irr::scene::ESNRP_SOLID);
SceneManager->registerNodeForRendering(this, irr::scene::ESNRP_SHADOW);
}
else{
SceneManager->registerNodeForRendering(nodeSelf);
}
}
void CFurSceneNode::render()
{
f32 CurrentLength = 0.0f;
f32 CurrentLayer = 0.0f;
ShaderCB->fMaxLength = fFurLength + ( fFurLength * (1 / iLayers));
if(smgr->getSceneNodeRenderPass() == ESNRP_SOLID)
{
ShaderCB->fLayer = 0.0f;
ShaderCB->fFurLength = 0.0f;
nodeSelf->render();
}
else
{
for(float i= 1.0f; i < iLayers; i++)
{
//calc value's
CurrentLayer = i / iLayers;
CurrentLength = fFurLength * CurrentLayer;
//set value's
ShaderCB->fLayer = CurrentLayer;
ShaderCB->fFurLength = CurrentLength;
//render child
nodeSelf->render();
}
}
}
void CFurSceneNode::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
{
nodeSelf->setMaterialFlag(flag,newvalue);
ISceneNode::setMaterialFlag(flag,newvalue);
}
SMaterial& CFurSceneNode::getMaterial(u32 i)
{
return nodeSelf->getMaterial(i);
}
u32 CFurSceneNode::getMaterialCount() const
{
return nodeSelf->getMaterialCount();
}
const aabbox3d<f32>& CFurSceneNode::getBoundingBox() const
{
return nodeSelf->getBoundingBox();
}
void CFurSceneNode::setMaterialTexture(u32 textureLayer, video::ITexture* texture)
{
nodeSelf->setMaterialTexture(textureLayer,texture);
}
void CFurSceneNode::setAnimationSpeed(f32 speed)
{
nodeSelf->setAnimationSpeed(speed);
}
void CFurSceneNode::setFrameLoop(u32 first, u32 last)
{
nodeSelf->setFrameLoop(first, last);
}
f32 CFurSceneNode::getFrameNr()
{
return nodeSelf->getFrameNr();
}
void CFurSceneNode::setLayers(u32 Layer)
{
if(Layer)
iLayers = Layer;
}
void CFurSceneNode::setFurLength(f32 Length)
{
fFurLength = Length;
}
//Custom Functions
void CFurSceneNode::Init()
{
//create childnode
nodeSelf = device->getSceneManager()->addAnimatedMeshSceneNode(meshSelf, this);
getMaterial(0).MaterialTypeParam = pack_textureBlendFunc(EBF_SRC_ALPHA, EBF_ONE_MINUS_SRC_ALPHA, EMFN_MODULATE_2X );
fFurLength = 0.0f;
iLayers = 1;
}
IAnimatedMeshSceneNode* CFurSceneNode::getNode(){return nodeSelf;}
Code: Select all
float fFurLength = 0;
float fUVScale = 1.0f;
float fLayer = 0; // 0 to 1 for the level
float3 vGravity = float3(0,-2.0,0);
float4 vLightDir = float4(0.8,0.8,1,0);
//------------------------------------
sampler2D FurTexture;
sampler2D TextureSampler;
//------------------------------------
// transformations
float4x4 worldViewProj : WORLDVIEWPROJ;
float4x4 matWorld : WORLD;
float4x4 mWorldViewProj; // World * View * Projection transformation
float4x4 mWorld; // Inverted world matrix
//------------------------------------
struct vertexInput {
float3 position : POSITION;
float3 normal : NORMAL;
float2 texCoordDiffuse : TEXCOORD0;
};
struct vertexOutput {
float4 HPOS : POSITION;
float2 T0 : TEXCOORD0; // fur alpha
float3 normal : TEXCOORD1;
};
vertexOutput vertexMain(vertexInput IN)
{
vertexOutput OUT = (vertexOutput)0;
//** MAIN LINE ** MAIN LINE ** MAIN LINE ** MAIN LINE ** MAIN LINE **//
//This single line is responsible for creating the layers! This is it! Nothing
//more nothing less!
float3 P = IN.position.xyz + (IN.normal * fFurLength);
//Modify our normal so it faces the correct direction for lighting if we
//want any lighting
//float3 normal = normalize(mul(float4(IN.normal,1.0), matWorld));
float3 normal = normalize(mul(float4(IN.normal,1.0), mWorld));
// Couple of lines to give a swaying effect!
// Additional Gravit/Force Code
//vGravity = mul(float4(vGravity, 1.0), matWorld);
float3 ovGravity = mul(float4(vGravity, 1.0), mWorld);
float k = pow(fLayer, 3.0); // We use the pow function, so that only the tips of the hairs bend
// As layer goes from 0 to 1, so by using pow(..) function is still
// goes form 0 to 1, but it increases faster! exponentially
P = P + ovGravity*k;
// End Gravity Force Addit Code
OUT.T0 = IN.texCoordDiffuse * fUVScale; // Pass long texture data
// UVScale?? Well we scale the fur texture alpha coords so this effects the fur thickness
// thinness, sort of stretches or shrinks the fur over the object!
//OUT.HPOS = mul(float4(P, 1.0f), worldViewProj); // Output Vertice Position Data
OUT.HPOS = mul(float4(P, 1.0f), mWorldViewProj); // Output Vertice Position Data
OUT.normal = normal; // Output Normal
return OUT;
}
//----------------------------------- ( ps 1.3 )
float4 pixelMain( vertexOutput IN): COLOR
{
float4 FurColour = tex2D( FurTexture, IN.T0 ); // Fur Texture - alpha is VERY IMPORTANT!
float4 FinalColour = FurColour;
//--------------------------
//Basic Directional Lighting
float4 ambient = {0.3, 0.3, 0.3, 0.0};
ambient = ambient * FinalColour;
float4 diffuse = FinalColour;
FinalColour = ambient + diffuse * dot(vLightDir, IN.normal);
//End Basic Lighting Code
//--------------------------
FinalColour.a = FurColour.a;
//FinalColour.a = 1.0;
return FinalColour; // fur colour only!
//return FinalColour; // Use texture colour
//return float4(0,0,0,0); // Use for totally invisible! Can't see
}