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

Started by
18 comments, last by wong_bo 17 years, 10 months ago
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.
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.
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
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
Couldn't you just use a bitmap that's tiled as your texture and then do normal texture mapping? Hope this helps.

-AJ
V/R,-AJThere are 10 kinds of people in the world: Those who understand binary and those who don't...
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.
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 :)
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
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.
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.PositionVector3 transformedPos = Vector3.TransformCoordinate(triangle.Position, world);// Get texture description, for the sizesSurfaceDescription sd = t.GetLevelDescription(0);float projectionWidth = 5f; // from OrthoLH projectionfloat 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 coordinatestriangle.Tu = xScaled;triangle.Tv = yScaled;
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
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.
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 :)
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!

This topic is closed to new replies.

Advertisement