Page 3 of 4

Posted: Wed Mar 31, 2010 9:21 pm
by freetimecoder
Hi,
I am currently trying to port this method to OpenGL. The Shader is working fine so far, but I have a problem with combining the different render passes.
Using the inbuild Materialtypes I can accomplish Multipasseffects easily:

Code: Select all

    // First Pass
    Node->setMaterialType(video::EMT_SOLID);
    Node->setMaterialTexture(0,driver->getTexture("Data/textures/tileable_concrete_wall.jpg"));
    Node->render();
 
    //Second Pass
    Node->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL);
    Node->setMaterialTexture(0,driver->getTexture("Data/textures/BigSpark.png"));
    Node->setMaterialTexture(1,driver->getTexture("Data/textures/metal_diamond.jpg"));
    Node->render();
Image

However, when using my Shader strange things happen. When using a CubeSceneNode it looks "quite" right:
Image
(Sand, Gras and Stone = 1. Pass | Earth and Snow = 2. Pass) Two Problems occur: The second pass has a black outline and sometimes when the camera gets closer to the cube the first pass is not rendered anymore, just the second.

When I use a mesh (e.g. a terrain) only the second pass is rendered, I never see the first pass:
Image

Shader code:
Vertex

Code: Select all

void main()
{
    gl_TexCoord[0] = gl_MultiTexCoord0;
    gl_Position = ftransform();
}
 
Pixel

Code: Select all

uniform sampler2D SplatMap;
uniform sampler2D ColRed;
uniform sampler2D ColGreen;
uniform sampler2D ColBlue;
 
void main(){
        vec4 SplatCol=texture2D(SplatMap,gl_TexCoord[0].xy);
        vec4 RedCol=texture2D(ColRed,gl_TexCoord[0].xy*10);
        vec4 GreenCol=texture2D(ColGreen,gl_TexCoord[0].xy*10);
        vec4 BlueCol=texture2D(ColBlue,gl_TexCoord[0].xy*10);
 
    gl_FragColor=(vec4(SplatCol.r*RedCol+SplatCol.g*GreenCol+SplatCol.b*BlueCol))*vec4(1,1,1,SplatCol.a);
}
 
Setting up the Shader:

Code: Select all

//Set up Cube or Mesh
    Node = mgr->addCubeSceneNode();//mgr->addMeshSceneNode(mgr->getMesh("Data/terrain.b3d"));
    Node->setMaterialFlag(video::EMF_LIGHTING,false);
    Node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS,true);
    Node->setScale(core::vector3df(5,5,5));
 
    video::IGPUProgrammingServices* gpu = mgr->getVideoDriver()->getGPUProgrammingServices();
 
    if (gpu)
    {
        ITerrainSplattingShader *callback = new ITerrainSplattingShader();
 
        ShaderMaterial1 = gpu->addHighLevelShaderMaterialFromFiles(
                "Data/shader/terrainsplatting.vert", "vertMain", video::EVST_VS_1_1,
                "Data/shader/terrainsplatting.frag", "pixelMain", video::EPST_PS_1_1,
                callback, video::EMT_TRANSPARENT_ALPHA_CHANNEL);
 
        callback->drop();
        Node->setMaterialType((video::E_MATERIAL_TYPE)ShaderMaterial1);
 
 
    }
Rendering:

Code: Select all

    // First Pass
    Node->setMaterialTexture(0,driver->getTexture("Data/textures/splat_1.tga"));
    Node->setMaterialTexture(1,driver->getTexture("Data/textures/Felsen.jpg"));
    Node->setMaterialTexture(2,driver->getTexture("Data/textures/Gras.jpg"));
    Node->setMaterialTexture(3,driver->getTexture("Data/textures/Sand.jpg"));
    Node->render();
 
    // Second Pass
    Node->setMaterialTexture(0,driver->getTexture("Data/textures/splat_2.tga"));
    Node->setMaterialTexture(1,driver->getTexture("Data/textures/Schnee.jpg"));
    Node->setMaterialTexture(2,driver->getTexture("Data/textures/Steppe.jpg"));
    Node->render();
It might have something to do with these lines (from the original project):

Code: Select all

         DWORD alpha, srcblend, destblend;
         device->GetRenderState(D3DRS_ALPHABLENDENABLE, &alpha);
         device->GetRenderState(D3DRS_SRCBLEND, &srcblend);
         device->GetRenderState(D3DRS_DESTBLEND, &destblend);
         device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
         device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
         device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); 
But since I want to use OpenGL I cannot use them and I don't know the equivalent for OpenGL.

Can anyone make sense out of this?

edit: Final Code here http://irrlicht.sourceforge.net/forum/v ... =9&t=38676

greetings

Posted: Fri Apr 02, 2010 11:54 pm
by kjkrum
@freetimecoder: That first snippet you posted looks like what I want to do. But I don't know where that code would go. Did you create your own scene node type and put that in the render() method?

Posted: Sat Apr 03, 2010 2:19 pm
by freetimecoder
Yes, I basically copied MasterD's CExtendedTerrainSceneNode and changed the render method.

Still, it does not work so well with own shaders and I have not yet found a solution. Inbuild materialtypes work well.

greetings

Posted: Sun Apr 04, 2010 4:25 pm
by netpipe
freetimecoder could you post a complete project to compile please. i'de really like to start playing with this. OGL ftw

Posted: Sun Apr 04, 2010 8:57 pm
by freetimecoder
Here you go:
IMultiPassSceneNode.h

Code: Select all

#ifndef IMULTIPASSSCENENODE_H_INCLUDED
#define IMULTIPASSSCENENODE_H_INCLUDED


class IMultiPassSceneNode : public scene::ISceneNode
{
private:
    scene::ISceneNode *Node;

public:
    IMultiPassSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id=-1);
    virtual void OnAnimate(u32 timeMs);
    virtual void OnRegisterSceneNode();
    virtual void render();
    const core::aabbox3d<f32>& getBoundingBox() const;

    void remove();
    void setPosition(const core::vector3df& newpos);
    void setRotation(const core::vector3df& rotation);
    void setScale(const core::vector3df& scale);
    ~IMultiPassSceneNode();
    scene::ESCENE_NODE_TYPE getType() const;
};


#endif // IMULTIPASSSCENENODE_H_INCLUDED
IMultiPassSceneNode.cpp

Code: Select all

#include "IMultiPassSceneNode.h"

IMultiPassSceneNode::IMultiPassSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id): scene::ISceneNode(parent, mgr, id){
    if(!parent)
        parent = mgr->getRootSceneNode();

    //Add whatever node you want
    Node = mgr->addCubeSceneNode();
    Node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS,true);
    Node->setScale(core::vector3df(5,5,5));
    setVisible(true);
}

void IMultiPassSceneNode::OnAnimate(u32 timeMs){
}

void IMultiPassSceneNode::OnRegisterSceneNode()
{
    if (IsVisible)
    {
         SceneManager->registerNodeForRendering(this);
         Node->setVisible(true);
         Node->OnRegisterSceneNode();
         Node->setVisible(false);
    }

}

void IMultiPassSceneNode::render(){
    Node->setVisible(true);

    //Change these settings to fit your needs

    // First Pass
    Node->setMaterialType(video::EMT_SOLID);
    Node->setMaterialTexture(0,driver->getTexture("texture1.jpg"));
    Node->render();

    //Second Pass
    Node->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL);
    Node->setMaterialTexture(0,driver->getTexture("Alphamap.png"));
    Node->setMaterialTexture(1,driver->getTexture("Color.jpg"));
    Node->render();

    Node->setVisible(false);
}

const core::aabbox3d<f32>& IMultiPassSceneNode::getBoundingBox() const{
	if(Node){
        return Node->getBoundingBox();
	}
	return core::aabbox3d<f32>(0,0,0,0,0,0);
}

void IMultiPassSceneNode::remove()
{
    if(Node)
        Node->remove();
    scene::ISceneNode::remove();
}

IMultiPassSceneNode::~IMultiPassSceneNode(){
}

void IMultiPassSceneNode::setPosition(const core::vector3df& newpos){
    RelativeTranslation = newpos;
    if(Node)
        Node->setPosition(newpos);
    updateAbsolutePosition();
}

void IMultiPassSceneNode::setRotation(const core::vector3df& rotation){
    RelativeRotation = rotation;
    if(Node){
        Node->setRotation(rotation);
    }
    updateAbsolutePosition();
}

void IMultiPassSceneNode::setScale(const core::vector3df& scale){
    RelativeScale = scale;
    if(Node)
        Node->setScale(scale);
    updateAbsolutePosition();
}

scene::ESCENE_NODE_TYPE IMultiPassSceneNode::getType() const{
    return scene::ESNT_UNKNOWN;
}
The OnRegisterSceneNode and render methods are the important ones.
I still haven't found a solution for shaders, though.

greetings

Posted: Wed Apr 14, 2010 12:42 am
by grunt
When I use jarheads shader and add a dynamic light, the terrain is unlit. If I comment the shader code out it is fine.

Posted: Sat Apr 17, 2010 10:53 pm
by grunt
any help on getting lighting and fog working again.

Posted: Sun Apr 18, 2010 12:25 pm
by freetimecoder
When using a custom shader, fog and lighting does not work anymore. You need to implement it yourself in the shader code.

greetings

Posted: Sun Apr 18, 2010 10:35 pm
by grunt
well ive located this.

http://xna-uk.net/blogs/randomchaos/arc ... ffuse.aspx

Would diffuse lighting be what I want for my terrain?

Posted: Mon Apr 19, 2010 8:15 am
by freetimecoder
I think so. You could also try to use a lightmap.

greetings

Posted: Tue May 04, 2010 7:50 am
by grunt
can somebody help me add a directional light to it. Tried to merge some of a per pixel shader into this and got this, but really dont know about shader programming.

Code: Select all

float4x4 matViewProjection : ViewProjection; 

float3 LightPos;
float4x4 mWorld;

sampler AlphaMap = sampler_state 
{ 
   ADDRESSU = WRAP; 
   ADDRESSV = WRAP; 
   ADDRESSW = WRAP; 
}; 

sampler TextureOne = sampler_state 
{ 
   MipFilter = LINEAR; 
   MinFilter = LINEAR; 
   MagFilter = LINEAR; 
   ADDRESSU = WRAP; 
   ADDRESSV = WRAP; 
   ADDRESSW = WRAP; 
}; 

sampler TextureTwo = sampler_state 
{ 
   MipFilter = LINEAR; 
   MinFilter = LINEAR; 
   MagFilter = LINEAR; 
   ADDRESSU = WRAP; 
   ADDRESSV = WRAP; 
   ADDRESSW = WRAP; 
}; 

sampler TextureThree = sampler_state 
{ 
   MipFilter = LINEAR; 
   MinFilter = LINEAR; 
   MagFilter = LINEAR; 
   ADDRESSU = WRAP; 
   ADDRESSV = WRAP; 
   ADDRESSW = WRAP; 
}; 

struct VS_INPUT 
{ 
   float4 Position : POSITION0; 
   float2 alphamap : TEXCOORD0; 
   float2 tex : TEXCOORD1; 
}; 

struct VS_OUTPUT 
{ 
   float4 Position : POSITION0; 
   float2 alphamap : TEXCOORD0; 
   float2 tex : TEXCOORD1; 
   float3 oLightDir : TEXCOORD2
   float3 oNormal : TEXCOORD3
}; 

struct PS_OUTPUT 
{ 
   float4 diffuse : COLOR0; 
   float3 LightDir : TEXCOORD2
   float3 Normal : TEXCOORD3
   float4 color : COLOR
}; 

VS_OUTPUT vs_main( VS_INPUT Input ) 
{ 
   VS_OUTPUT Output; 
   Output.Position = mul( Input.Position, matViewProjection ); 
   Output.alphamap = Input.alphamap; 
   Output.tex = Input.tex; 

   Output.oLightDir = normalize(LightPos-posWorld)
   Output.oNormal = normal

   return( Output ); 
} 

PS_OUTPUT ps_main(in VS_OUTPUT input) 
{ 
   float texScale = 1.0; 	
   PS_OUTPUT output = (PS_OUTPUT)0; 

   vector a = tex2D(AlphaMap, input.alphamap); 
   vector i = tex2D(TextureOne, mul(input.tex, texScale));
   vector j = tex2D(TextureTwo, mul(input.tex, texScale)); 
   vector k = tex2D(TextureThree, mul(input.tex, texScale)); 

   float4 oneminusx = 1.0 - a.x; 
   float4 oneminusy = 1.0 - a.y; 
   float4 oneminusz = 1.0 - a.z; 

   vector l = a.x * i + oneminusx * i; 
   vector m = a.y * j + oneminusy * l; 
   vector n = a.z * k + oneminusz * m; 

   oLightDir = normalize(LightPos-

   output.diffuse = n; 
   output.color.xyz *= dot(LightDir, Normal);
   return output; 
} 

technique Default_DirectX_Effect 
{ 
   pass Pass_0 
   { 
      VertexShader = compile vs_2_0 vs_main(); 
      PixelShader = compile ps_2_0 ps_main(); 
   } 
}

Posted: Sun May 09, 2010 7:49 am
by grunt
MasterD wrote:Are you submitting the textures in the correct order? Irrlicht transfers the textures 1 to 1, meaning TextureLayer[0].Texture will be the AlphaMap.

Additionally, the constant set within the shader (float texScale = 10.0; ) seamed to have no effect, try to put that declaration within the pixel shader function.

Here's the code I use, which has lighting using ambient lighting and one directional light. NOTE: I've changed the order of the textures, TextureLayer[4] is Alpha Map.

Code: Select all

float4x4 matViewProjection;
float3 fSunlightDir;
float3 fAmbientColor;
float3 fSunlightColor;

sampler2D TextureOne;
sampler2D TextureTwo;
sampler2D TextureThree;
sampler2D AlphaMap;

struct VS_INPUT
{
   float4 Position  : POSITION0;
   float3 Normal    : NORMAL0;
   float2 alphamap  : TEXCOORD0;
   float2 tex       : TEXCOORD1;
};

struct VS_OUTPUT
{
   float4 Position  : POSITION0;
   float2 alphamap  : TEXCOORD0;
   float2 tex       : TEXCOORD1;
   float3 Normal    : TEXCOORD2;
};

struct PS_OUTPUT
{
   float4 diffuse : COLOR0;
};

VS_OUTPUT vs_main( VS_INPUT Input )
{
   VS_OUTPUT Output;
   Output.Position = mul( Input.Position, matViewProjection );
   Output.alphamap  = Input.alphamap;
   Output.tex       = Input.tex;
   Output.Normal    = Input.Normal;

   return( Output );
}

PS_OUTPUT ps_main(in VS_OUTPUT input)
{
    float texScale = 40.0;

    float3 N = normalize(input.Normal);

    PS_OUTPUT output;// = (PS_OUTPUT)0;

    float3 a =  tex2D(AlphaMap,       input.alphamap);
    float3 c1 = tex2D(TextureOne,     input.tex);
    float3 c2 = tex2D(TextureTwo,     input.tex);
    float3 c3 = tex2D(TextureThree,   input.tex);

    float3 detail1 = tex2D(TextureOne,   input.tex * texScale);
    float3 detail2 = tex2D(TextureTwo,   input.tex * texScale);
    float3 detail3 = tex2D(TextureThree, input.tex * texScale);

    float d1 = (detail1.r + detail1.g + detail1.b) / 3;
    float d2 = (detail2.r + detail2.g + detail2.b) / 3;
    float d3 = (detail3.r + detail3.g + detail3.b) / 3;

    c1 = saturate(c1 + d1 - 0.5);
    c2 = saturate(c2 + d2 - 0.5);
    c3 = saturate(c3 + d3 - 0.5);

    float3 oneminusx = 1.0 - a.r;
    float3 oneminusy = 1.0 - a.g;
    float3 oneminusz = 1.0 - a.b;

    output.diffuse.rgb = a.r * c1.rgb;
    output.diffuse.rgb = a.g * c2.rgb + oneminusy * output.diffuse.rgb;
    output.diffuse.rgb = a.b * c3.rgb + oneminusz * output.diffuse.rgb;

    // Lighting
    output.diffuse.rgb = output.diffuse.rgb * 
        saturate((fAmbientColor + fSunlightColor*saturate(dot(N, fSunlightDir))));

// this term is only neccessary for multipass rendering, 
// will be ignored with standard rendering
    output.diffuse.a = saturate(a.r + a.g + a.b);


    return output;
}
[/size]

Edit: Just Realized that I'm responding to quite an old thread, sorry for that, would've made a new one, if I realized that earlier :)
I tried this one and all I get is all black terrain. I tried hard coding the values :

Code: Select all

float3 fSunlightDir = float3(0.7, 1, -0.8); 
float3 fAmbientColor = float3(255, 255, 255); 
float3 fSunlightColor = float3(255, 255, 255); 
If I comment out:

Code: Select all

output.diffuse.rgb = output.diffuse.rgb * 
        saturate((fAmbientColor + fSunlightColor*saturate(dot(N, fSunlightDir))));
It works just without the lighting.

Posted: Mon May 24, 2010 8:42 pm
by freetimecoder
Image

Yay! :D
OpenGL Multitexture, still have to do this and that, but it works. I will post code soon.

edit: Final Code here http://irrlicht.sourceforge.net/forum/v ... =9&t=38676

greetings

Posted: Tue May 25, 2010 3:24 am
by kjkrum
Looks wonderful! Can't wait to see the code.

Posted: Wed May 11, 2011 9:28 am
by Virror
Sorry to bump an old thread like this, but just have to say that the example project in this thread is very helpful!
Should be put on wiki.
Might help some more ppl : )