4 Replies - 1370 Views - Last Post: 11 November 2016 - 06:49 AM

#1 EzraSidran  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 28-October 16

C# XNA 4.0 3D Terrain

Posted 28 October 2016 - 10:18 AM

I'm looking for some example XNA 4.0 code for creating a 3D map utilizing a heightmap with multiple terrain textures. Preferably not a hex map but a grid.

I understand XNA is pretty much dead but there seems to be some people at this site that can still answer questions. I've looked at Reimer's stuff but it's too dated.
Is This A Good Question/Topic? 0
  • +

Replies To: C# XNA 4.0 3D Terrain

#2 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 5831
  • View blog
  • Posts: 19,880
  • Joined: 05-May 12

Re: C# XNA 4.0 3D Terrain

Posted 29 October 2016 - 04:51 AM

This post sounds amazingly like a gimme-the-codez.
Was This Post Helpful? 0
  • +
  • -

#3 EzraSidran  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 28-October 16

Re: C# XNA 4.0 3D Terrain

Posted 29 October 2016 - 06:30 AM

View PostSkydiver, on 29 October 2016 - 04:51 AM, said:

This post sounds amazingly like a gimme-the-codez.


Actually, I've written something similar about 5 years ago but it was just one texture stretched over a large height map. I suppose I could modify it. But, I've seen some stuff utilizing tessellation that looked great but no examples of how it was done.
Was This Post Helpful? 0
  • +
  • -

#4 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 792
  • View blog
  • Posts: 1,886
  • Joined: 24-April 12

Re: C# XNA 4.0 3D Terrain

Posted 11 November 2016 - 05:32 AM

Sorry that I missed your post until now. It's like 2 weeks later. But I have some tutorials on 3D terrain. But it sounds like you may have already figured that stuff out. It's drawing of the terrain and collision detection and I think the random terrain generation stuff is in there as well. All of that has XNA 4.0 (I think it was) Visual Studio project files with all the code and assets and everything with working examples. I converted a few projects over to MonoGame, but I don't think any of that stuff ever got converted. Not sure.

There's also my blog here where I just kind of discuss the whole thing at a high level.

None of this specifically addresses your question about multi-texture terrains. I've never done that. But if I had to make an educated guess, I would say that is entirely done in HLSL in your shader by first making it accept multiple terrain textures and then writing in an algorithm on how to use them. I don't think any of the built in shaders in XNA, like BasicEffect for example, can handle this. You could also make terrain height a parameter on the shader and use that to determine which texture is used like Reimer did.

http://www.riemers.n...titexturing.php

Or you could have another map that matches the height map that allows you to blend multiple textures based on the gray scale of that map. There are probably countless ways you could do it, but I think most of them will involve an understanding of HLSL.

If you're new to HLSL, I would encourage you to go through my HLSL tutorial series. The HLSL stuff applies to DirectX and is not a bad place to start learning GLSL for OpenGL, but it just so happens that I wrote the series from an XNA standpoint. None of it talks directly about how HLSL could be used for terrains, but it's so generalized that it might help you understand how it could be used for terrains. It's basically walking you through recreating BasicEffect from scratch using HLSL. At the end, you have a shader that is basically the same shader as BasicEffect except that you should then understand it and how to modify it to make it into whatever shader you can imagine. It's very fundamental shader stuff that could apply to a terrain shader or anything else.

I'm kind of off in the world of OpenGL now and not really doing XNA anymore, but I used to do XNA tutorials as much as possible. Sorry that I don't have anything specific on terrain multi-texturing, but maybe with Reimer's multi-texture terrain shader and my stuff you can piece something together. It should mostly just be a matter of selecting which texture to use based on height or some other parameter and blending the colors of the two textures by sampling them and multiplying their pixel colors in the pixel shader.

I think the tessellation stuff is just for the shape of the terrain and making more geometrical detail in the terrain at lower cost, although honestly I've never really looked into this. Terrain with tessellation shaders is on my "to-do" list but it's way down the list just because the list is so long right now. I don't know how much of the basics you know on terrain, but I would definitely recommend getting that down first. Most of my stuff is basic terrain 101. Beyond that there are algorithms like ROAM and such to build bigger terrains more efficiently that build off the same basic principle. And then now of course there is tessellation terrains, which I know little to nothing about. But I imagine, that like everything else will build off the basics.

Edit: Oh wow! Look at that! I not only did a MonoGame example, I actually did a basic HLSL terrain example although it was probably to implement blur rather than to implement multi-texturing. But it's maybe a jumping off point that could be compared to Reimer's shader.

You might also want to check out my terrain example and ocean examples. There I implement a bit more with actual grass texture, trees, and water. Most of it needs some work, but it's a good starting off point. The trees for example use overlapping quads. Today most games will use models for trees, but the still actually use this technique for trees in the distance since it's far cheaper and you can't tell the difference at a distance. So, it's a Level Of Detail thing. Not to mention you're still likely to see this technique for grass and weed models as well as the tree branches on modern tree models, or something similar.

Taking my HLSL terrain example and modifying it to use Reimer's shader here, might give you what you want. I doubt anything has changed with HLSL over the years enough to make this invalid although it doesn't get into any of the more advanced terrain ideas like tessellation. Much of the writing you're likely to find on tessellation terrains is likely to be written for DirectX or OpenGL. So, having a solid foundation in the basics from XNA will help tremendously before going that route.
//----------------------------------------------------
//--                                                --
//--             www.riemers.net                 --
//--         Series 4: Advanced terrain             --
//--                 Shader code                    --
//--                                                --
//----------------------------------------------------

//------- Constants --------
float4x4 xView;
float4x4 xProjection;
float4x4 xWorld;
float3 xLightDirection;
float xAmbient;
bool xEnableLighting;

//------- Texture Samplers --------
Texture xTexture;

sampler TextureSampler = sampler_state { texture = <xTexture> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};Texture xTexture0;

sampler TextureSampler0 = sampler_state { texture = <xTexture0> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = wrap; AddressV = wrap;};Texture xTexture1;

sampler TextureSampler1 = sampler_state { texture = <xTexture1> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = wrap; AddressV = wrap;};Texture xTexture2;

sampler TextureSampler2 = sampler_state { texture = <xTexture2> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};Texture xTexture3;

sampler TextureSampler3 = sampler_state { texture = <xTexture3> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};
//------- Technique: Textured --------
struct TVertexToPixel
{
float4 Position     : POSITION;
float4 Color        : COLOR0;
float LightingFactor: TEXCOORD0;
float2 TextureCoords: TEXCOORD1;
};

struct TPixelToFrame
{
float4 Color : COLOR0;
};

TVertexToPixel TexturedVS( float4 inPos : POSITION, float3 inNormal: NORMAL, float2 inTexCoords: TEXCOORD0)
{
    TVertexToPixel Output = (TVertexToPixel)0;
    float4x4 preViewProjection = mul (xView, xProjection);
    float4x4 preWorldViewProjection = mul (xWorld, preViewProjection);

    Output.Position = mul(inPos, preWorldViewProjection);
    Output.TextureCoords = inTexCoords;

    float3 Normal = normalize(mul(normalize(inNormal), xWorld));
    Output.LightingFactor = 1;
    if (xEnableLighting)
        Output.LightingFactor = saturate(dot(Normal, -xLightDirection));

    return Output;
}

TPixelToFrame TexturedPS(TVertexToPixel PSIn)
{
    TPixelToFrame Output = (TPixelToFrame)0;

    Output.Color = tex2D(TextureSampler, PSIn.TextureCoords);
    Output.Color.rgb *= saturate(PSIn.LightingFactor + xAmbient);

    return Output;
}

technique Textured_2_0
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 TexturedVS();
        PixelShader = compile ps_2_0 TexturedPS();
    }
}

technique Textured
{
    pass Pass0
    {
        VertexShader = compile vs_1_1 TexturedVS();
        PixelShader = compile ps_1_1 TexturedPS();
    }
}

//------- Technique: Multitextured --------
struct MTVertexToPixel
{
    float4 Position         : POSITION;    
    float4 Color            : COLOR0;
    float3 Normal            : TEXCOORD0;
    float2 TextureCoords    : TEXCOORD1;
    float4 LightDirection    : TEXCOORD2;
    float4 TextureWeights    : TEXCOORD3;
};

struct MTPixelToFrame
{
    float4 Color : COLOR0;
};

MTVertexToPixel MultiTexturedVS( float4 inPos : POSITION, float3 inNormal: NORMAL, float2 inTexCoords: TEXCOORD0, float4 inTexWeights: TEXCOORD1)
{    
    MTVertexToPixel Output = (MTVertexToPixel)0;
    float4x4 preViewProjection = mul (xView, xProjection);
    float4x4 preWorldViewProjection = mul (xWorld, preViewProjection);
    
    Output.Position = mul(inPos, preWorldViewProjection);
    Output.Normal = mul(normalize(inNormal), xWorld);
    Output.TextureCoords = inTexCoords;
    Output.LightDirection.xyz = -xLightDirection;
    Output.LightDirection.w = 1;    
    Output.TextureWeights = inTexWeights;
    
    return Output;    
}

MTPixelToFrame MultiTexturedPS(MTVertexToPixel PSIn)
{
    MTPixelToFrame Output = (MTPixelToFrame)0;        
    
    float lightingFactor = 1;
    if (xEnableLighting)
        lightingFactor = saturate(saturate(dot(PSIn.Normal, PSIn.LightDirection)) + xAmbient);
        
    Output.Color = tex2D(TextureSampler0, PSIn.TextureCoords)*PSIn.TextureWeights.x;
    Output.Color += tex2D(TextureSampler1, PSIn.TextureCoords)*PSIn.TextureWeights.y;
    Output.Color += tex2D(TextureSampler2, PSIn.TextureCoords)*PSIn.TextureWeights.z;
    Output.Color += tex2D(TextureSampler3, PSIn.TextureCoords)*PSIn.TextureWeights.w;    
        
    Output.Color *= lightingFactor;
    
    return Output;
}

technique MultiTextured
{
    pass Pass0
    {
        VertexShader = compile vs_1_1 MultiTexturedVS();
        PixelShader = compile ps_2_0 MultiTexturedPS();
    }
}


This post has been edited by BBeck: 11 November 2016 - 05:56 AM

Was This Post Helpful? 1
  • +
  • -

#5 EzraSidran  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 28-October 16

Re: C# XNA 4.0 3D Terrain

Posted 11 November 2016 - 06:49 AM

First, many thanks for the reply!
Second, I don't know how my numerous Google searches did not turn up your work.
Third, this is the project that I'm working on: General Staff. I have a heightmap and a terrain value (let's say 0- 7) for each point on the map. In 3D I would want to use the appropriate terrain texture (obviously, not based on height but from a lookup table). There may be more than one texture per terrain to keep it visually interesting.
Fourth, I seem to remember (I haven't used XNA for about 5 years) that was some kind of limitation on the number of textures in a 3D map (I think it was 4). But, they may have just been the Sunburn engine that I was also using.

Again, many thanks for the help!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1