[SlimDX] Drawing Crosshairs without redrawing the entire model

Started by
5 comments, last by porters 12 years, 8 months ago
Hi,

I want to draw some crosshairs at the mouse cursor location in my application. Currently i have been drawing my crosshairs along with the rest of my model. My application is a CAD/3DS Max style of program, so i dont use a render loop. I only render when i need to i.e. when something changes.

Basically i want to draw my crosshairs 'on top' of my model so i dont have to redraw the entire scene everytime the mouse moves. Theres no point redrawing every object in the model again if they havent changed (or the view hasnt changed). I guess im trying to draw the crosshair directly to the front buffer rather than the back buffer or something like that?

How do i achieve what im after?

Thanks.
Advertisement
You could do your main 3D render to an off screen render target, and your crosshair render would then consist of copying that target by mapping the texture across a full screen quad, and then drawing the crosshair on top of that.

You could also consider simply changing the standard Windows mouse cursor icon into a crosshair.

You could do your main 3D render to an off screen render target, and your crosshair render would then consist of copying that target by mapping the texture across a full screen quad, and then drawing the crosshair on top of that.

You could also consider simply changing the standard Windows mouse cursor icon into a crosshair.



Thanks Adam. So how do i about doing this? i.e what should i use as the render target, how do i draw to it, map etc? You wouldnt happen to have some example code of this procedure would you? I dont really know where to start.

I can't change the windows cursor as the crosshair im talking has lines that extend to the edge of the form, where as the windows crosshair only uses short lines if i remember correctly.
Your code should go something like this:

To create your render target create a new Texture specifying Usage.RenderTarget and Pool.Default. I'd suggest creating it without multisampling or mip maps as those just complicate things.

You can use GetSurfaceLevel(0) to get the surface from that texture.

To begin rendering to that surface call SetRenderTarget(0, surface). To stop switch the render target back to Device.GetBackBuffer().

You can then use that texture as you would any other.

Your code should go something like this:

To create your render target create a new Texture specifying Usage.RenderTarget and Pool.Default. I'd suggest creating it without multisampling or mip maps as those just complicate things.

You can use GetSurfaceLevel(0) to get the surface from that texture.

To begin rendering to that surface call SetRenderTarget(0, surface). To stop switch the render target back to Device.GetBackBuffer().

You can then use that texture as you would any other.



Thanks Adam. I've followed that procedure but am not having any luck. First off, just to test my code, i used a texture derived from a bitmap file. This worked and rendered a full screen quad. So im confident that portion of my code is fine. The DX debug output keeps spitting this out:

"Direct3D9: (WARN) :Can not render to a render target that is also used as a texture. A render target was detected as bound, but couldn't detect if texture was actually used in rendering."

Now this is only a warning, and the program still runs, but im not seeing anything on the screen, so i can only assume that, as the warning states, nothing is being rendered to my texture. Im a little confused as to how data is actually written to the texture. You get a surface from the texture, and the device renders to this surface (after you set it as the render target), but how does it write this data from the surface back to the texture without being explicity told to do so? I assume that there is some internal reference to the texture the surface was derived from?

Anyway, i would be most grateful to anyone who can explain what im doing wrong.

Cheers.

That warning means you still have a texture set on the device when you're also using it as a render target, and D3D doesn't support simultaneous reading and writing of a render target. To fix that you can do something like this just before you call SetRenderTarget():


for (int i=0; i < 16; i++)
{
Device.SetTexture(i, null);
}


The surface is part of the texture - each mip level is an individual surface.

That warning means you still have a texture set on the device when you're also using it as a render target, and D3D doesn't support simultaneous reading and writing of a render target. To fix that you can do something like this just before you call SetRenderTarget():


for (int i=0; i < 16; i++)
{
Device.SetTexture(i, null);
}


The surface is part of the texture - each mip level is an individual surface.


Thanks for the reply Adam. I actually solved this issue about 10mins ago but i did it a different way. I abandoned using textures and quads altogether - i could not get the texture method working (prior to your last post). I'll explain how i did it so as to help any others interested in this (there were a few similar post about the same topic).

Render targets are surfaces it seems. So if we could use the surfaces directly, without using them to derive a texture, then it makes the process a whole lot simpler. Thats exactly what i did using the following procedure. I basically replaced the textured quad methodology with the device.StretchRectangle method which copies the contents of one surface to the other. Everything works nicely now.

Thanks heaps for the help. Very much appreciated!



[color="#0000ff"][color="#0000ff"]Private [color="#0000ff"][color="#0000ff"]Sub RenderToSurfaceExample()

[color="#008000"][color="#008000"]'NOTES
[color="#008000"][color="#008000"]'D3Ddev = Device
[color="#008000"][color="#008000"]'D3Dpp = Present Parameters

[color="#008000"][color="#008000"]'clear any previously drawn data from the back buffer
D3Ddev.Clear(ClearFlags.ZBuffer, Color.Black, 0.0F, 1)

[color="#008000"][color="#008000"]'start rendering
D3Ddev.BeginScene()

[color="#008000"][color="#008000"]'surfaces
[color="#0000ff"][color="#0000ff"]Dim modelSurface [color="#0000ff"][color="#0000ff"]As Surface = Surface.CreateRenderTarget(D3Ddev, D3Dpp.BackBufferWidth, D3Dpp.BackBufferHeight, D3Dpp.BackBufferFormat, D3Dpp.Multisample, D3Dpp.MultisampleQuality, [color="#0000ff"][color="#0000ff"]False)
[color="#0000ff"][color="#0000ff"]Dim backbufferSurface [color="#0000ff"][color="#0000ff"]As Surface = D3Ddev.GetBackBuffer(0, 0)

[color="#008000"][color="#008000"]'set the render target as the surface we want to render our model on
D3Ddev.SetRenderTarget(0, modelSurface)

[color="#008000"][color="#008000"]'clear any previously drawn data from the model surface
D3Ddev.Clear(ClearFlags.Target, Color.Black, 0.0F, 1)


[color="#008000"][color="#008000"]'draw stuff to the model surface

[color="#008000"][color="#008000"]'set the render target as the back buffer surface
D3Ddev.SetRenderTarget(0, backbufferSurface)

[color="#008000"][color="#008000"]'copy model surface to backbuffer surface
D3Ddev.StretchRectangle(Surfaces_Model, Surfaces_Backbuffer, TextureFilter.None)


[color="#008000"][color="#008000"]'draw any further graphics to the back buffer surface i.e. over the top of the model surface

[color="#008000"][color="#008000"]'end rendering
D3Ddev.EndScene()

[color="#008000"][color="#008000"]'present the back buffer
D3Ddev.Present()

[color="#2e8b57"]'dispose surfaces
modelSurface.Dispose()
backbufferSurface.Dispose()

[color="#0000ff"][color="#0000ff"]End [color="#0000ff"][color="#0000ff"]Sub

This topic is closed to new replies.

Advertisement