Jump to content
  • Advertisement
Sign in to follow this  

[C++, DX9] Heightmap texture blending

This topic is 2974 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've made heightmap but having problems making texture blending.
I have grayscale image for heights, which I load with C++ code and modify depending on data in image (Vertex Shader 2.0 doesn't support texture lookup so I can't do it in shader). Then I have second grayscale image which holds data what texture to use in each quad of my heightmap (0 being grass, 1 being sand and etc).

Here is my shader:

struct heightmapInput{
float4 Position : POSITION;
float3 Normal : NORMAL;
float3 Tex0 : TEXCOORD0;

struct heightmapOutput{
float4 Position : POSITION;
float2 Texcoord : TEXCOORD0;
float3 Normal : TEXCOORD1;
float3 ViewDirection : TEXCOORD2;
float3 LightDirection : TEXCOORD3;

//grayscale texture which holds data which tile to use
//(0 being grass, 1 being sand and etc)
//so limit is 256 different textures
texture mapTex;
sampler2D mapTexSampler = sampler_state{
Texture = <mapTex>;
AddressU = CLAMP;
AddressV = CLAMP;

//first tile (grass)
texture tile0;
sampler2D tile0s = sampler_state{Texture = <tile0>; AddressU = Mirror; AddressV = Mirror; MIPFILTER = LINEAR; MINFILTER = LINEAR; MAGFILTER = LINEAR;};

//second tile (sand)
texture tile1;
sampler2D tile1s = sampler_state{Texture = <tile1>; AddressU = Mirror; AddressV = Mirror; MIPFILTER = LINEAR; MINFILTER = LINEAR; MAGFILTER = LINEAR;};

heightmapOutput HeightmapVS(heightmapInput Input){
float4x4 WorldViewProjection = mul(gWorld, gViewProj);
float3 ObjectPosition = mul(Input.Position, gWorld);

heightmapOutput Output;
Output.Normal = mul(Input.Normal, gWorld);
Output.Position = mul(Input.Position, WorldViewProjection);

Output.ViewDirection = EyePosition - ObjectPosition;
Output.LightDirection = LightPosition - ObjectPosition;
Output.Texcoord = Input.Tex0;

return Output;

float4 HeightmapPS(heightmapOutput Input) : COLOR0{
float3 tiles[2];
float2 coord = Input.Texcoord;

//get tile data from texture, so we'll know what texture to use in this quad
float index = tex2D(mapTexSampler, coord).r * 255.0f;

//get Texture Coordinates in current quad
coord = frac(coord * 128); //my heightmap is 128x128 size

tiles[0] = tex2D(tile0s, coord); //texture1
tiles[1] = tex2D(tile1s, coord); //texture2

float3 color = tiles[index];

return float4(color, 1);

technique Heightmap{
pass p0{
VertexShader = compile vs_2_0 HeightmapVS();
PixelShader = compile ps_2_0 HeightmapPS();

Result of this shader:

Maybe anyone could help me to make blending?

Thanks in advance.

Share this post

Link to post
Share on other sites
The problem is you have no information on how to do the blend. Do you want each tile on a border to bleed out? Or do you want sand to stay within the border and for grass to blend into it.

A common solution to this in most tile engines is to either define blend tiles from one type to another. For instance if you wanted to blend road on top you would have one tarmac tile, then 8 other tiles defining how to blend in each direction into grass.

Share this post

Link to post
Share on other sites
Well I'd prefer sand to go over grass.
I though of using x and y coordinates as alpha value, but I didn't fit within Pixel Shader 2 arithmetic instruction slots.
Do you think it'll work with extra 8 textures for alpha blend?

Share this post

Link to post
Share on other sites
Even then imagine if you are rendering a tile and you have 8 other different tiles around it - how is it going to look when you are sampling all 9 textures and trying to blend them? Not to mention the 9 texture lookups to render every tile even one with no different neighbours.

If I was doing it I'd probably go for a multiple passes approach. Identify all tiles which do not need blending and render just those (either using stencil or selective drawcalls whatever is easier with your approach).

Then you need to render the blended tiles. One option would be to generate a whole bunch of tiles offline (grass into sand x8, tarmac into grass x8, etc) and select those and render them as opaque tiles. They could then be rendered in the first pass.

Alternatively if you are set on blending automatically then you could use the 9 lookups approach here but at least it wouldn't cost as much because you've already rendered the solid areas.

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!