Sign in to follow this  
Paul7

Terrain / DirectX rendering issues

Recommended Posts

Ive just recently started a terrain implementation using a brute force height map method and have encountered a few problems. 1. From the screenshot you can see that the terrain behind certain areas is showing through as though there is a problem with the Zbuffer? DirectX is initialised as follows:
    if( NULL == ( gD3dObject=Direct3DCreate9(D3D_SDK_VERSION) ) )
        return E_FAIL;

        D3DDISPLAYMODE d3ddm;
    if( FAILED( gD3dObject->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
        return E_FAIL;


    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	d3dpp.EnableAutoDepthStencil = TRUE;
	d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

	    if( FAILED( gD3dObject->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_HARDWARE_VERTEXPROCESSING,
                                      &d3dpp, &gDevice ) ) )
    {
		        return E_FAIL;
    }
	gDevice->SetRenderState( D3DRS_ZENABLE, TRUE);

The Zbuffer is then cleared before rendering each frame using gDevice->Clear( 0, NULL, D3DCLEAR_TARGET| D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 ); 2. In many areas this pattern is visible in the terrain. Is this to do with the way is which it is split up into triangles? Would a diamond shape be better?

Share this post


Link to post
Share on other sites
I'm not sure why (1) is happening. Try colouring bits of your terrain differently and work out if that really is a part of the terrain that's behind showing through, or whether something else is happening.

As for (2), the problem is that colours in-between vertices are generally linearly interpolated (estimated based on the colours at the vertices) rather than being calculated in full.

Suppose that the terrain should be highlighted at x = 1.5, but in shadow at x = 1 and at x = 2. Now, if a single polygon stretches from x = 1 to x = 2 all of it's _vertices_ are in shadow and the highlight is missed.

A diamond-shaped primitive would be difficult to implement and probably wouldn't fix the problem.

You *could* decrease the size of your triangles, but that would be expensive and would only reduce the problem.

If it really bothers you, you could use some form of per-pixel lighting (research: DOTPRODUCT3), where only the vertex normals are interpolated, and the colours are then calculated in full.

You could reduce the problem by using softer lighting - the artifact wouldn't show up as badly if you had several light sources, or some ambient light so the difference between light / shadow isn't so great. Similarly, less sharply changing terrain would mask the problem.

Share this post


Link to post
Share on other sites
Hi Paul7,

First off, Problem number 1 looks exactly like Z-buffer inaccuracy.

It's really easy to check - just change your Z-buffer format to 32 bit (it's at 16 bits now). This would increase accuracy, and if the problem goes away, you know what it was.

(if it is that indeed, you could leave the buffer at 32 bits, which would cost you some in performance, or you could modify the Projection Matrix near and far to make the accuracy better).

As for question two, that looks extremely similar to a problem I've been having with my own terrain engine - only I was getting dark quad patters arround my terrain. heres a link to a post on devimg.net with some screenshots:

http://www.devimg.net/?View=345

I ended up giving up on this subject, but if you ever do find a solution, I'd love to hear it - might help me.

Good luck.

Share this post


Link to post
Share on other sites
Make sure that zfar/znear (of your perspective projection) is not too large (ie, znear too close to camera) as that can stuff up your zbuffer precision for large z.

I have this text file I got off the web but can't remember where so I'll just copy it here...


--------------------------------------------------------------------------------

> I took the time to derive a formula for the precision of a zbuffer:
>
> zerror(znear, zfar, z, n) = z^2 * (1 / znear - 1 / zfar) / (2^n -1)
>
> where:
> znear is the location of the near clip plane
> zfar is the location of the far clip plane
> z is is the "distance" from the camera
> n is the number of bits in the z buffer.
>
> Notice, that the error in a zbuffer varies depending on how far away you
> are. Less error near the camera, more error as we get farther away. That
is
> why we need z in this formula. Here is an example of how to interpret the
> results:
>
> zerror(1,1000,50,16) = .0381
>
> What this means is that if you have a 16-bit zbuffer with a near clip
plane
> of 1 meter, a far clip plane of 1000 meters and are looking at an object
50
> meters from the camera, then you can expect an error of .0381 meters in
the
> z buffer. Note that the result is given in world units. Looking at it a
> different way, an object 50 meters from the camera will be written to the
z
> buffer at value 64288 and an object 50.0381 meters will be written to the
z
> buffer at value 64289.
>
> As long as we are at it we might as well consider the precision of a
> wbuffer:
>
> werror(znear, zfar,n) = ( zfar - znear) / (2^n -1)
>
> Note that is does not depend on the distance from the camera, it is
uniform
> over the entire range.
>
> werror(1,1000,16) = .0152
>
> Means a 16-bit wbuffer with a near clip plane of 1 meter and a far clip
> plane of 1000 meters, then the wbuffer error is .0152 meters, regardless
of
> the location of the object.
>
> So, now lets look at 4 different near/far combinations, calculate the
> wbuffer error and tabulate the z buffer error.
>
> znear = 1 meters, zfar =1000 meters, n = 16
> werror(1,1000,16) = .0152 meters
> z zerror(1,1000,z,16) meters
> --------------------------------
> 1 0.0000152438
> 10 0.00152438
> 100 0.152438
> 1000 15.2438
> 10000 clipped
> 100000 clipped
>
> Lets increase zfar up to 100000
>
> znear = 1 meters, zfar =100000 meters, n = 16
> werror(1,100000,16) = 1.52 meters
> z zerror(1,100000,z,16) meters
> --------------------------------
> 1 0.0000152589
> 10 0.00152589
> 100 0.152589
> 1000 15.2589
> 10000 1525.89
> 100000 152589.
>
> Notice how changing the far clip plane had essentially no effect on the z
> buffer, but w buffer precision has suffered horribly. Now let more the far
> plane back to 1000 and move the near clip plane to 10:
>
> znear = 10 meters, zfar =1000 meters, n = 16
> werror(10,1000,16) = .0151 meters
> z zerror(10,1000,z,16) meters
> --------------------------------
> 1 clipped
> 10 0.000151064
> 100 0.0151064
> 1000 1.51064
> 10000 151.064
> 100000 15106.4
>
> Changing the near clip plane does not affect wbuffering much, but has a
> radical effect on the z buffer precision.
>
> And as a bonus, lets go near = 1, far = infinity:
>
> znear = 1 meters, zfar =infinity, n = 16
> werror(1,inifnity,16) = not possible
> z zerror(1,infinity,z,16) meters
> --------------------------------
> 1 0.000015259
> 10 0.0015259
> 100 0.15259
> 1000 15.259
> 10000 1525.9
> 100000 152590.
>
> This is nearly identical to zfar = 100000.
> -Gil

Share this post


Link to post
Share on other sites
Thanks for the replys.

Problem 1 was fixed by changing the near clip plane in the perpective projection matrix. I had it too close.

I also tried setting the zbuffer to 32 bit but this resulted in my program finding problems with my direct input code and other unrelated areas! any idea why that would be? I tried a 24bit zbuffer with 8 bit stencil buffer and that worked fine.

Am still looking into problem 1. If I find a way around this I will let you now sirob. Im thinking per pixel lighting might help as geoffrey suggested.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this