Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Drawing 3D Models over primitives in XNA


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
14 replies to this topic

#1 LemonBiscuit   Members   -  Reputation: 147

Like
0Likes
Like

Posted 14 February 2014 - 07:23 AM

Hello,

 

I use DrawIndexedPrimtives to draw my terrain. If I draw a model over it, the intersection between the model and the terrain is pretty messy:

 

http://i.imgur.com/zbEXzQM.png (the water is only a blue plane (3D model))

 

http://i.imgur.com/fzXvFy6.png (here the grey thing is a model)

 

How can I fix it?

 

Thank you


Edited by LemonBiscuit, 14 February 2014 - 07:25 AM.


Sponsor:

#2 phil_t   Crossbones+   -  Reputation: 4090

Like
1Likes
Like

Posted 14 February 2014 - 11:53 AM

Looks a lot like z fighting, but I can't imagine why. Model.Draw uses DrawIndexedPrimitives underneath the covers, so this shouldn't make a difference.

 

I think you'll need to post more of your drawing code (what values are you passing to your shader, what blend states and depthstencil states are you using).

 

One possibility is that your objects are being drawn at roughly the same depth. This could happen if your near/far plane are really far apart (show us how you create your projection matrix).


Edited by phil_t, 14 February 2014 - 11:55 AM.


#3 LemonBiscuit   Members   -  Reputation: 147

Like
0Likes
Like

Posted 14 February 2014 - 03:56 PM

Here's the projection matrix:

 _projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(40), 0.02f, 10000, GraphicsDevice.Viewport.AspectRatio);

I don't use any special blenstates/depthpencils, I tried the projection with 100 instead of 10000, and it still the same result. sad.png

 

EDIT: The problem seems to be coming from the near plane. I set 1f as the near plane, and it worked. Now, I'll need to fix the problem that I can't see the very near models (FPS Guns)..

Thank you for your help!


Edited by LemonBiscuit, 14 February 2014 - 04:00 PM.


#4 Buckeye   Crossbones+   -  Reputation: 6138

Like
1Likes
Like

Posted 14 February 2014 - 04:25 PM

Take a look at http://msdn.microsoft.com/en-us/library/windows/desktop/bb219616%28v=vs.85%29.aspx

 

From that article:

At a [far- to near-plane] ratio of 1,000, 98 percent of the range is spent on the first 2 percent of the depth range.

 

 

With a near plane of 0.02, and a far plane at 10000, your ratio was 500,000! Always keep the ratio of far- to near-plane as small as can possibly be used.


Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#5 ankhd   Members   -  Reputation: 1355

Like
0Likes
Like

Posted 14 February 2014 - 07:23 PM

Its because you are using Gouraud shading and that is smoothing out your terrain.

You would have to increase your vertex count or find where the overlapping mesh is on the terrain and do some edge filtering on the terrain mesh where they meet.

Let me know how you do it because I'll need to do it when I get to the bells and whistles stage lol.



#6 phil_t   Crossbones+   -  Reputation: 4090

Like
0Likes
Like

Posted 14 February 2014 - 07:56 PM


Its because you are using Gouraud shading and that is smoothing out your terrain.

 

You're incorrect. It has nothing to do with the way he is shading it. We've already established it was z-fighting due to limited depth buffer precision because of the large far/near plane ratio.



#7 LemonBiscuit   Members   -  Reputation: 147

Like
0Likes
Like

Posted 15 February 2014 - 07:20 AM

I can't find a way to fix my problem with my hands.

I set the nearplane to 0.02f so I can draw models very close to the camera, and as my game is a FPS, I need to draw guns close to the camera.

Is there any solutions to counter fix that?



#8 unbird   Crossbones+   -  Reputation: 5990

Like
0Likes
Like

Posted 15 February 2014 - 07:55 AM

Draw your gun last, clear depth before and use a different projection. It will be "wrong" (gun is now always drawn, like a HUD) but it should work.



#9 Buckeye   Crossbones+   -  Reputation: 6138

Like
0Likes
Like

Posted 15 February 2014 - 08:01 AM

EDIT: See last comment below.

 

See http://msdn.microsoft.com/en-us/library/windows/desktop/bb206341%28v=vs.85%29.aspx

 

In particular:

the D3DVIEWPORT9 structure... MinZ and MaxZ indicate the depth-ranges into which the scene will be rendered... For instance, to render a heads-up display in a game, you can set both values to 0.0 to force the system to render objects in a scene in the foreground...

 

 

You should draw the weapons (and any other head-up display items) first, with viewport.MaxZ = 0. [EDIT - use a projection matrix with 0.02 / 1.0 or whatever works to draw the HUD.] Then set MaxZ back to 1 for the rest of the render. [EDIT - and set the projection matrix with 1.0 / 10000, or whatever works for the terrain.] That ensures they'll be rendered in the foreground, and will provide a little efficiency in (not) drawing occluded objects later.

 

@Unbird: smile.png Your method will work also. But maybe better not to take the time to clear the depth buffer?

 

EDIT: Draw the weapons first with a small ratio projection. Then set a larger projection ratio for the rest of the scene. No changes needed for the viewport. Sorry about this mess of a post.


Edited by Buckeye, 15 February 2014 - 08:32 AM.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#10 LemonBiscuit   Members   -  Reputation: 147

Like
0Likes
Like

Posted 15 February 2014 - 08:34 AM

Here's what I did:

 

I set back the projection to (1, 10000) as nearplane/farplane.
I created another to (0.02, 1) to apply it to my weapon draw.

 

I moved my weapon draw to first, and but I have a problem, the weapon traverses all models and terrain, it's like if it was huge.

Also I can't set nearplane and farplane to 0, XNA asks me to have a positive value for nearPlaneDistance.



#11 Buckeye   Crossbones+   -  Reputation: 6138

Like
0Likes
Like

Posted 15 February 2014 - 08:35 AM

Sorry about the crappy previous post.

 

If it suits you, another approach which may be to add to the game - fog at a reasonable distance. You can then use a smaller far plane in your projection, just beyond where fog = 1.


Edited by Buckeye, 15 February 2014 - 08:37 AM.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#12 LemonBiscuit   Members   -  Reputation: 147

Like
0Likes
Like

Posted 15 February 2014 - 08:56 AM

Thanks, I did like you said but still have two problems:

 

- My weapon is drawn as if it was "huge": it goes through terrain and traverses models.

- I put a LensFlare system, which use occlusion query, so it has to be called last: I draw everything I need to draw, then I check how much the sun is visible, and I draw the lensflares images according to this result. Problem is, it doesn't draw if I call it last.



#13 Buckeye   Crossbones+   -  Reputation: 6138

Like
0Likes
Like

Posted 15 February 2014 - 09:36 AM

EDIT: See my next post for revised code to show the HUD with fixed relationship to the eyepoint.

 

I made some assumptions and errors in my previous post. I do apologize for that.

 

Regarding the weapons draw - how do you set the world position of the weapon for each render frame? Do you set it according to the current eye position and direction?

 

Putting together some quick code, I got the following to work:

 

- set viewport.MaxZ = 0

- set the world transform to position the object (for instance) forward and to the right of the eye position

- set the projection to 0.2, 10.0 (near/far), other parameters otherwise the same as for the rest of the scene

- draw the object

- set viewport.MaxZ = 1

- set the projection back to (whatever you use for the rest of the scene)

- set the world transform back to (whatever you use for the rest of the scene)

- continue rendering

 

I found that the "hugeness" of the weapon is due to not setting the viewport parameters.

 

You might try that algorithm and see what happens. FYI, you needn't draw the weapons first provided you reset the viewport / projection / world transforms as indicated. However, by drawing the weapons first, as mentioned above, you'll save the overdrawing of a few pixels.

 

EDIT: Here's what I did. vBufAxes is just a set of axes for the world. "aspect" is the aspect ratio of the window (or backbuffer, depending on what you're drawing).

    if (vBufAxes)
    {
        if (bShowWorldAxes)
        {
            ////// testing - the origin always appears in the foreground
            D3DVIEWPORT9 vp;
            gd3dDevice->GetViewport(&vp);
            vp.MaxZ = 0;
            gd3dDevice->SetViewport(&vp);
            // world axes
            // draw them near the camera
            D3DXVECTOR3 camPos = vDxChildren[dxChildNum].dxChild->camPos;
            D3DXVECTOR3 camDir = vDxChildren[dxChildNum].dxChild->camDir;
            D3DXVECTOR3 camUp = vDxChildren[dxChildNum].dxChild->camUp;
            D3DXVECTOR3 camRight;
            D3DXVec3Normalize(&camRight, D3DXVec3Cross(&camRight, &camUp, &camDir));
            D3DXVECTOR3 axesPos = camPos + 3.0f*camDir - camUp + camRight;
            D3DXMATRIX axesWorld;
            D3DXMatrixTranslation(&axesWorld, axesPos.x, axesPos.y, axesPos.z);
            gd3dDevice->SetTransform(D3DTS_WORLD, &axesWorld);
            D3DXMATRIX tmpProj;
            D3DXMatrixPerspectiveFovLH(&tmpProj, D3DX_PI * 0.25f, aspect, 0.20f, 10.0f);
            gd3dDevice->SetTransform(D3DTS_PROJECTION, &tmpProj);
            gd3dDevice->SetFVF(COLORVERTEXFORMAT);
            gd3dDevice->SetStreamSource(0, vBufAxes, 0, sizeof(COLORVERTEX));
            gd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 24);
            vp.MaxZ = 1;
            gd3dDevice->SetViewport(&vp);
            gd3dDevice->SetTransform(D3DTS_PROJECTION, &mProj);
            gd3dDevice->SetTransform(D3DTS_WORLD, &mWorld);
        }
    }

axesHUD1.jpg

 

axesHUD2.jpg

 

NOTE: this draws the axes to reflect the orientation of the camera! I have to change the code to draw them as a fixed object. I'll be back in a while.


Edited by Buckeye, 15 February 2014 - 10:41 AM.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#14 Buckeye   Crossbones+   -  Reputation: 6138

Like
0Likes
Like

Posted 15 February 2014 - 10:39 AM

I have to apologize again. It's been a few years since I created a HUD. I understand it's a pain-in-the-patootie when someone posts a crappy suggestion. I appreciate your patience.

 

In any case, implementation depends on how you draw your weapons.

 

In the following code, the axes are setup at the world origin (i.e., based at (0,0,0) with axes "boxes" in each direction). I've commented out the incorrect code from the previous post.

 

First: set the viewport MaxZ to 0.

Second: create a view matrix positioned to view the origin-based object as you want it to appear in the HUD and set the device view matrix.

Third: set up the projection for a short field of view - i.e., near/far to something small. Ensure that the far-plane value will render all of the HUD objects.

Fourth: draw the HUD objects.

Fifth: restore the viewport and projection matrices.

    if (vBufAxes)
    {
        if (bShowWorldAxes)
        {
            ////// testing - the origin always appears in the foreground
            D3DVIEWPORT9 vp;
            gd3dDevice->GetViewport(&vp);
            vp.MaxZ = 0;
            gd3dDevice->SetViewport(&vp);
            // world axes
            D3DXMATRIX tmpView;
            D3DXVECTOR3 camPos = D3DXVECTOR3(-3,3,-10);
            D3DXVECTOR3 camDir = D3DXVECTOR3(0,0,1);
            D3DXVECTOR3 camUp = D3DXVECTOR3(0,1,0);
            D3DXVECTOR3 camAt = camPos + camDir;
            D3DXMatrixLookAtLH(&tmpView, &camPos, &camAt, &camUp);
            gd3dDevice->SetTransform(D3DTS_VIEW, &tmpView);

            //// draw them near the camera
            //D3DXVECTOR3 camPos = vDxChildren[dxChildNum].dxChild->camPos;
            //D3DXVECTOR3 camDir = vDxChildren[dxChildNum].dxChild->camDir;
            //D3DXVECTOR3 camUp = vDxChildren[dxChildNum].dxChild->camUp;
            //D3DXVECTOR3 camRight;
            //D3DXVec3Normalize(&camRight, D3DXVec3Cross(&camRight, &camUp, &camDir));
            //D3DXVECTOR3 axesPos = camPos + 3.0f*camDir - camUp + camRight;
            //D3DXMATRIX axesWorld;
            //D3DXMatrixTranslation(&axesWorld, axesPos.x, axesPos.y, axesPos.z);
            //gd3dDevice->SetTransform(D3DTS_WORLD, &axesWorld);
            D3DXMATRIX tmpProj;
            D3DXMatrixPerspectiveFovLH(&tmpProj, D3DX_PI * 0.25f, aspect, 0.20f, 20.0f);
            gd3dDevice->SetTransform(D3DTS_PROJECTION, &tmpProj);
            gd3dDevice->SetFVF(COLORVERTEXFORMAT);
            gd3dDevice->SetStreamSource(0, vBufAxes, 0, sizeof(COLORVERTEX));
            gd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 24);
            vp.MaxZ = 1;
            gd3dDevice->SetViewport(&vp);
            gd3dDevice->SetTransform(D3DTS_PROJECTION, &mProj);
            //gd3dDevice->SetTransform(D3DTS_WORLD, &mWorld);
            gd3dDevice->SetTransform(D3DTS_VIEW, &mView);
        }
    }

axesHUD_rev1.jpg

 

axesHUD_rev2.jpg


Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.


#15 LemonBiscuit   Members   -  Reputation: 147

Like
0Likes
Like

Posted 17 February 2014 - 12:23 PM

Thank you very much! :)






Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS