Jump to content
  • Advertisement
Sign in to follow this  
wong_bo

[MDX2] How to fill a 3D polygon with texture brush

This topic is 4397 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

Hi, I am new to DirectX. My problem is that I need to fill a polygon defined in a 3D space with small 2D bitmap patterns. The patterns are tiled within the polygon and get clipped off at the polygon edges. This fill effect can be achieved using simple 2D drawing methods like
Graphics.FillPolygon (TextureBrush, Point[]) 
in C# and
CBrush brush; brush.CreateDIBPatternBrush(...);
pDC->SelectObject(&brush);
pDC->Polygon(...);
in MFC/C++. I tried to project all the 3D vertices to screen and use these 2D drawing methods. But the result is that the filling patterns are always on top of my 3D models. Is there a native DirectX method to do this and it is depth aware? I am using MDX2.

Share this post


Link to post
Share on other sites
Advertisement
You can apply textures directly onto Direct3D polygons, as explained in this tutorial, so there should be no need to do the postprocessing you're doing. The way it basically works is that you specify the texture by calling device.SetTexture(0, someTexture) and DirectX will handle the rest, provided the vertices for your polygon have texture coordinates defined. I believe there's also a small article on that in the MDX docs.

On a related note, the 2.0 versions of MDX are still in beta and will not be released in their current form, so it's probably best to stick with the 1.x assemblies for now.

Share this post


Link to post
Share on other sites
remigius, thanks for the quick reply.
The tutorial you point out is for normal texture mapping. What I really need is a texture brush to fill a polygon in TILED format. Below is an image showing the desired effect using the post-rendering method I mentioned at the start of this thread. Please note that no matter how I rotate the rectangle, the tiled bitmaps should always facing the user (2D drawing effect).


What I really want is to use native DirectX method to achieve this.

Image and video hosting by TinyPic

Share this post


Link to post
Share on other sites
Couldn't you just use a bitmap that's tiled as your texture and then do normal texture mapping? Hope this helps.

-AJ

Share this post


Link to post
Share on other sites
One way to do it could be that you set the texture state to wrap/loop and then use the x,y coordinates of the vertices as texture coordinates, or alternatively generate your texture coordinates based on where the vertex x,y are on the screen in 2d coordinates.

Share this post


Link to post
Share on other sites
Quote:
the tiled bitmaps should always facing the user (2D drawing effect).


Sorry, I misunderstood your question there. Mace's solution sounds like the way to go for this indeed. I've fixed up a little demo project that shows both approaches, updating the texture coordinates manually and just reusing the vertex xy coordinates in a shader. You can find the project over here in this zip. It does require a card that supports linear texture filtering (I think nearly all non-ancient cards can do this though), since with point filtering you get massive amounts of 'texture twitching'.

Hope this does help :)

Share this post


Link to post
Share on other sites
Thank you very much remigius (and mace).

I tested your code and it does almost exactly what I want. I still got some texture 'twitching' or 'shaking' in my current project code when I rotate the polygons. I put

device.SamplerState[0].MinFilter = TextureFilter.Linear;
device.SamplerState[0].MagFilter = TextureFilter.Linear;


right before device.SetTexture(0, mFillTexture). I even tried to create texture with Filter.Linear parameter. Nothing seems to work. But in your code, there is no twitching at all. Do you know what could be the problem?


By the way, is there a way to display the bitmap exactly the same size as they are? In your sample code, test.jpg is a 256x256 image. I want it to be 256x256 when it is used as tiled texture, no matter how I scale, rotate or move the triangle.

Share this post


Link to post
Share on other sites
If the twitching occurs when you're rotating the polygon's verices towards and away from the camera, it's probably an issue with the MIP filtering still being a Point filter. If that's indeed the case, adding the following line should solve the problem:

device.SamplerState[0].MipFilter = TextureFilter.Linear;


D3D essentially is built to scale your world according to the size of the presentation, so keeping a texture fixed in position and size on the screen is actually exceptional behavior. This means you'll have to do some math to get this to work and the result may not match 'pixel-perfect'. Anyway, the following should do the trick:

[source lang=c#]
// First we'll apply the world transform to our
// triangle's vertices. If you're not using a
// world transform, you can skip this step and
// just use triangle.Position
Vector3 transformedPos = Vector3.TransformCoordinate(triangle.Position, world);

// Get texture description, for the sizes
SurfaceDescription sd = t.GetLevelDescription(0);
float projectionWidth = 5f; // from OrthoLH projection
float projectionHeight = 5f; // from OrthoLH projection

// Scale x and y coordinates to the current 'world size'.
// This maps the x, y coordinates to the [0,1] ranges, so
// it looks like the texture is covering the entire screen.
float xScaled = (transformedPos.X - (projectionWidth/2)) / projectionWidth;
float yScaled = (-transformedPos.Y - (projectionHeight/2)) / projectionHeight;

// Since we don't want to have the texture covering the
// entire screen, we'll multiply the texture coordinates
// by 'screenSize/textureSize'. The code below does this,
// but the calculation is grouped a bit unintuitively to
// avoid the int/int fraction you'd get otherwise.
xScaled = (xScaled * sampleFramework.BackBufferSurfaceDescription.Width) / sd.Width;
yScaled = (yScaled * sampleFramework.BackBufferSurfaceDescription.Height) / sd.Height;

// apply the mapped texture coordinates
triangle.Tu = xScaled;
triangle.Tv = yScaled;

Share this post


Link to post
Share on other sites
Thanks remigius. The code works fine on your samples.

I am still battling with the twitching problem. I tried to set MipFilter to TextureFilter.Linear but then I got a solid filled grey polygon and no texture anymore.

I suspect the twitching is because I am using a vertex buffer and Device.DrawPrimitives() for rendering which requires constant updating of vertex buffer. Your code use Device.DrawUserPrimitives() and it doesn't need vertex buffer at all. I can use DrawUserPrimitives() but as I am using MDX2, the method signature is:

public void DrawUserPrimitives(
PrimitiveType primitiveType,
Int32 primitiveCount,
GraphicsBuffer vertexStreamZeroData

The last parameter is GraphcsBuffer not GraphcsBuffer<T>. How am I going to put the triangle[] data into a non-generic GraphcsBuffer? I searched the forum and found people talking about DrawUserPrimitives in MDX2 but haven't found the solution I want.

Share this post


Link to post
Share on other sites
I wouldn't know how the GraphicsBuffer works exactly, since I'm still using MDX1.1. From what I've picked up you can create one with GraphicsBuffer<VertexClass> and then use an indexed (myBuffer[index]) to set the data. As a side note, using MDX2 isn't particularly recommended since it's still in beta and will not be released in it's current form.

Be that as it may, if you can prevent it you shouldn't use DrawUserPrimitives either. I used it to quickly fix up the sample, but essentially it sticks your data into a new VertexBuffer every frame and uploads that to the videocard, which is of course not too efficient. Your vertexbuffer approach should actually work better than my code. Anyway I've updated the sample project so the HLSL shader now also uses the tiling code. By using the shader path, you don't have to bother to lock/transform/unlock your vertices manually.

I doubt the transformation is the cause of your twitching problem though. You could try moving the SamplerState changes to the code right after your device reset, so the states don't need to be updated each frame. I put them into the rendering method for convenience, but it should be more efficient to just set them once when the device resets.

Hope this helps :)

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.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!