How to use vertex colors to put different textures on mesh?

The place for artists, modellers, level designers et al to discuss their approaches for creating content for OGRE.
gamekill
Gnoblar
Posts: 15
Joined: Thu May 11, 2006 6:50 pm

How to use vertex colors to put different textures on mesh?

Post by gamekill »

Hi guys,

I made a simple terrain in 3DS Max 8, and used the Vertex Paint modifier to make some regions green and others red. My intent is to display a grass.jpg texture where the vertices are green, and a rock.jpg texture where the vertices are red. But different from using two texture sub-channels, I also want the transition between grass and rock to be smooth, so I set the intermediate vertices to 60% green and 40% red. I managed to use this vertex color variation and accomplish my goal using Composite materials. But the Ogre Exporter tells me it will only export Standard or Multi/Sub Materials. Problem is, I can't accomplish this with Standard or Sub/Multi. Anyone know how to do this?

The pictures show what I accomplished with Composite materials. I simply used a base grass material and set the Opacity map to VertexColor, and "green". And then added a 1st Composite Material, rock, with the Opacity Map set to VertexColor too, but "red". The mesh itself contains only ONE material sub-channel, and ONE UV mapping (all terrain stretched across the UV Map).

Image

Image

Please help me use this kind of technique into Ogre!
Any tips are really appreciated...

THANKS!!!!!!!!!

:shock: :D :D :shock: :P
User avatar
haffax
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 4823
Joined: Fri Jun 18, 2004 1:40 pm
Location: Berlin, Germany
x 8

Post by haffax »

Use a shader that does alpha blending based on vertex colour. You have to look into shader programming for this I am afraid. Maybe fxcompose or rendermonkey have an example shader for this, but I don't know.

Anyway, this is a simplier shading project. Good for a start into this topic.
team-pantheon programmer
creators of Rastullahs Lockenpracht
User avatar
ChocoboInbreeder
Kobold
Posts: 38
Joined: Thu Jun 30, 2005 10:55 pm
Location: Boston, MA

Post by ChocoboInbreeder »

Unless I'm misunderstanding the question, you can already do this in Ogre using blend_diffuse_alpha or blend_diffuse_colour as the colour_op_ex operation parameter for a multitextured material. You'd of course have to change the blending to correspond to the vertex color's alpha channel or the combined rgb value (i.e. a vertex alpha of 0.6 corresponding to blending 60% of the second texture and 40% of the first. It wouldn't work with your current example of red and green being used separately as the blending parameters unless you used a shader.).

For example the material could look like this:

Code: Select all

material vertex_blend_mat
{
    technique
    {
        pass
        {
            texture_unit 
            {
                texture rock.jpg
                colour_op_ex source1 src_texture src_current // replace
            }

            texture_unit
            {
                texture grass.jpg
                colour_op_ex blend_diffuse_alpha src_texture src_current
            }
        }
    }
}
This is how many games handle texture blending for terrain. See:
http://www.delphi3d.net/articles/viewar ... aintex.htm
and
Image
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 67

Post by sinbad »

Note that the fixed function approach using blend_diffuse_alpha and blend_diffuse_colour only allows you to blend 3 textures; a base texture, one texture based on vertex alpha, and one texture based on vertex colour (ie all 3 colour channels combined). If you want to use the red/green/blue channels separately you'll have to write it as a shader instead.
gamekill
Gnoblar
Posts: 15
Joined: Thu May 11, 2006 6:50 pm

Post by gamekill »

Ok guys, I THINK I am getting to understand this, I just need a BIT more help:

First of all, Sinbad, thanks for the heads up. I believe 3 textures is gonna be enough for now, so I will try to use this technique instead of trying to write the shader. But I need help understanding it (even though I went through Computer Science college and work closely with my coder, I am no programmer I am the 3D artist and content creator).

You guys told me to use this:
-------------------------------------------------------------------------
material vertex_blend_mat
{
technique
{
pass
{
texture_unit
{
texture rock.jpg
colour_op_ex source1 src_texture src_current // replace
}

texture_unit
{
texture grass.jpg
colour_op_ex blend_diffuse_alpha src_texture src_current
}
}
}
}
-------------------------------------------------------------------

So please tell me if I understand it right:

Is this the base texture?
texture_unit
{
texture rock.jpg
colour_op_ex source1 src_texture src_current
}


Also, is this the first additional blended texture?
texture_unit
{
texture grass.jpg
colour_op_ex blend_diffuse_alpha src_texture src_current
}

If so, how would the second additional blended texture be called for? Like say, thickergrass.jpg?

And what should I set the vertices at in 3DMax? I mean, if this technique won't allow me to use rgb variation, what are the parameters it uses? Should I set alpha BLACK (zero) where I don't want grass.jpg to be displayed, WHITE (100%) where I only want grass.jpg to be displayed and GRAY (50%) where I want both rock.jpg and grass.jpg to be blended equally? Is that it?

What about the second additional texture thickergrass.jpg, how should I set the vertex Colors to adjust its opacity?

ALSO, could you please explain what would src_texture and src_current mean?

Thank you a TON for the help, this is one of the last doubts I have as far as texturing our game in Ogre is concerned!

Waiting for any reply...

:D :shock: :D :) :D
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 67

Post by sinbad »

Use the 'code' tags to format out code BTW ;)

You need to add this to do the 3rd layer:

Code: Select all

texture_unit
{
    texture thickergrass.jpg
    colour_op_ex blend_diffuse_colour src_texture src_current
} 
In this case, rock is always rendered everywhere to begin with. Then, based on the alpha component of the vertex colour (vertex colours are RGBA), the grass will be brought in. Higher alpha, more grass.jpg. Then for the final unit, the RGB components of the vertex colour are used to introduce thickergrass.jpg - brighter = more of it (might as well make it a grey shade of some sort).

The meaning of these blend functions and sources etc is in the manual.
gamekill
Gnoblar
Posts: 15
Joined: Thu May 11, 2006 6:50 pm

Post by gamekill »

Ok I think I got the hand of this.

I wrote my own .material file like this:

Code: Select all

material engine_terreno_vertexpaint
{
    technique
    {
        pass
        {
	ambient 0.588 0.588 0.588
	diffuse 0.588 0.588 0.588
	emissive 0.0 0.0 0.0
	    texture_unit
            {
                texture enginegramasuja.png
		colour_op_ex source1 src_texture src_current
            }
	    texture_unit
            {
                texture engine_subida.png
		colour_op_ex blend_diffuse_alpha src_texture src_current 
            }
	    texture_unit
	    {
		texture engine_torretelhado.png
		colour_op_ex blend_diffuse_colour src_texture src_current
	    } 
        }
    }
}

But I can't test it because I can't use my exported meshes from Max! I get lockups when trying to open any object from Max that has Vertex Paint modifiers... even very simple meshes. Is it a known problem?
I add two VertexPaint modifiers to the stack, I set both to "Color by Vertex", the first one (bottom) to Channel-> Vertex Alpha, and the second one (top) to Channel-> Vertex Color. On both modifiers I paint some vertexes black and other white... then I use the Exporter and check "Export Vertex Color". Seems to export ok but won't load on viewers (Cegui or ShowMesh)...

:cry: :? :shock: :x :shock: [/code]
Nudel
Halfling
Posts: 79
Joined: Thu Mar 23, 2006 4:14 pm
Location: Vienna

Post by Nudel »

sinbad wrote:Note that the fixed function approach using blend_diffuse_alpha and blend_diffuse_colour only allows you to blend 3 textures; a base texture, one texture based on vertex alpha, and one texture based on vertex colour (ie all 3 colour channels combined). If you want to use the red/green/blue channels separately you'll have to write it as a shader instead.
Im trying to write such a shader, but i couldnt even manage to get the vertex colour.

This is the cg program:

Code: Select all

//------------------------------------
struct vertexInput {
    float3 position				: POSITION;
    float3 normal				: NORMAL;
    float4 texCoord				: TEXCOORD0;
    float4 vColor				: COLOR0;
};

struct vertexOutput {
    float4 position			: POSITION;
    float4 texCoord			: TEXCOORD0;
    float4 vColor			: COLOR;
};


//------------------------------------
vertexOutput VS_TransformAndTexture(vertexInput IN) 
{
    vertexOutput OUT;
    IN.position = IN.position + normalize(IN.normal)*0.1;
    OUT.position = mul( float4(IN.position.xyz , 1.0) , worldViewProj);
    OUT.texCoord = IN.texCoord;
    
    OUT.vColor = IN.vColor +0.5;
    
    return OUT;
}

//-----------------------------------
float4 PS_Textured( vertexOutput IN): COLOR
{
  return IN.vColor;
}
The result is a grey mesh (due to +0.5 to the vertex colours value)
Is "float4 vColor : COLOR0;" not the correct way to get the meshs vertex colour?
By the way, where can i get a reference with all possible input and output parameters(like TEXCOORD0)?

Thanks for any help.
User avatar
haffax
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 4823
Joined: Fri Jun 18, 2004 1:40 pm
Location: Berlin, Germany
x 8

Post by haffax »

You forgot to write how the results you want differ from what you get.
team-pantheon programmer
creators of Rastullahs Lockenpracht
Nudel
Halfling
Posts: 79
Joined: Thu Mar 23, 2006 4:14 pm
Location: Vienna

Post by Nudel »

sorry. :)

This is what i want it to look like. (flat shaded though)
Image

And this is how it looks like in fx composer:
Image

The mesh has been exported as .x and includes the vertex colour information.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 67

Post by sinbad »

Are you sure it really includes the vertex colour information? Since this is .x rather than an OGRE format you can't be using one of our exporters.
Nudel
Halfling
Posts: 79
Joined: Thu Mar 23, 2006 4:14 pm
Location: Vienna

Post by Nudel »

In the .x file, theres a section called "MeshVertexColors" in this format:
"0;0.097814;0.097814;0.097814;1.000000;;,"
with 2601 entries.
Im not sure, but the first value seems to be the vertex number and the other 4 the rgba values. The rgb values range from 0 to 1, a is allways 1.
Since this is .x rather than an OGRE format you can't be using one of our exporters.
At the beginning i wanted to use ofusion to try out the shaders but ofusion crashes along with 3dsmax if the shader isnt 100% correct so i switched to nvidias fx composer and had to export the mesh as .x in order to use it there. Ill port the shader to ogre later, to see if it works in ofusion.
Nudel
Halfling
Posts: 79
Joined: Thu Mar 23, 2006 4:14 pm
Location: Vienna

Post by Nudel »

Ah well, i didnt find out why it didnt work in fx composer but it works in ofusion now. :)
Only with 3 textures though. I also wanted to apply a forth texture to black areas by multiplying the 4.texture with the inverse of each colour value instead(or in addition) of using the alpha channel, but that returned an "too much arithmetic operations" error.

Code: Select all

void vp_vcolor(
	float3 iPosition		: POSITION,
	float3 iNormal			: NORMAL,
	float4 iColor			: COLOR,
	float2 iTexCoord01		: TEXCOORD0,
	float2 iTexCoord02		: TEXCOORD1,
	float2 iTexCoord03		: TEXCOORD2,
	//float2 iTexCoord04		: TEXCOORD3,
	
	out float4 oPosition	: POSITION,
	out float4 oColor		: COLOR,
	out float2 oTexCoord01	: TEXCOORD0,
	out float2 oTexCoord02	: TEXCOORD1,
	out float2 oTexCoord03	: TEXCOORD2,
	//out float2 oTexCoord04	: TEXCOORD3,
	
	uniform float4x4 worldViewProj
	)
{
	oPosition = mul(float4(iPosition.xyz, 1.0), worldViewProj);
	oColor = iColor;
	
	oTexCoord01 = iTexCoord01;
	oTexCoord02 = iTexCoord02;
	oTexCoord03 = iTexCoord03;
	//oTexCoord04 = iTexCoord04;
}

//-----------------------------------
void fp_vcolor(
	float4 iPosition		: POSITION,
	float4 iColor			: COLOR,
	float2 iTexCoord01		: TEXCOORD0,
	float2 iTexCoord02		: TEXCOORD1,
	float2 iTexCoord03		: TEXCOORD2,
	//float2 iTexCoord04		: TEXCOORD3,
	
	out float4 oColor		: COLOR,
	
	uniform sampler2D texture01,
	uniform sampler2D texture02,
	uniform sampler2D texture03
	//uniform sampler2D texture04
	)
{
	//Multiplying by the inverse of each colour value to apply a texture to black areas.
	//oColor = tex2D(texture01, iTexCoord01)*(1-iColor.r)*(1-iColor.g)*(1-iColor.b);
	//Apply textures according to red, green and blue values.
	oColor = tex2D(texture01, iTexCoord01)*iColor.r;
	oColor = oColor +  tex2D(texture02, iTexCoord02)*iColor.g;
	oColor = oColor +  tex2D(texture03, iTexCoord03)*iColor.b;
	
}