[Solved] Drawing a sprite inside a 3D-Model (with transparency)


This is a follow-up question to the issue that I was having a few days ago (thank you guys again^^):

What I would like to do now is to add transparency to a 3D-Model that is enclosing a 2D-Sprite (which is also partly transparent).

I have reduced the issue as much as possible:

First, I´m drawing a ring-like 3D-Model (image 2) and then a sprite (image 1) with a depth that sets it in the middle (depth-wise) of the ring. As long as the Modell is entirely without transparency, everything looks fine (image 3).

In both drawing-operations, I use:

Game1.graphicsDevice.DepthStencilState = DepthStencilState.Default;

So the depth-handling is accurate.

However, if I reduce the transparency of the ring, the lower transparency is also applied to the sprite (Image 4).

Switching the drawing-order (first Sprite then Model) only turns the problem around and applies the transparency of the sprite to certain parts of the Modell (Image 5).

I think the core-problem is that the 3D-Model is simultaneously in front and behind the Sprite, because otherwise I could solve the issue by modifying the draw-order or/and the DepthStencilState like I have seen in other solution online.

So one solution would be if it was possible to only draw the front- and back-halve of the Model (depth-wise) individually. The Model is continuously rotating, so I cannot just cut the Model into two (e.g. in Blender) and render it as two models. The “cutting” has to happen at runtime.

I tried something similar in my first question by playing around with the far- and near-planes of the orthographic projection-Matrix, but I read here and in other places that this leads to a bunch of other problems… However, this does not seem to be a very elegant approach anyways.

If you are using sprite batch to draw your model you could clip the back half using a plane the problem with that though is that ring needs to be visible beyond the center of the model because it is angled.

What you are seeing though looks like its because the alpha value is pre-multiplied.

So you could try using non-premultiplied alpha and only allow the alpha to change not the rgb which is the exact opposite of what i see in that picture. You would have to have the abilty to draw your model and change just the alpha not the rgb components.

If that is not possible.

You could alternately use your own pixel shader and pass it into spritebatch for that you could define a plane and have it switch the alpha output depending on the side of the plane the model is on. (a plane is just a position and a direction in your case its forward and the position is the center of the ring.) You subtract each pixel position by that rays positional value then normalize that result which yeilds pixel directional normals (dn) in relation to that front and back dividing plane which is determined by the ray. You use dot(dn, rays.direction) which gives a spherical cosine in relation to the front facing ray. The result of the dot acosine value if negative means the models pixel is behind the plane were positive values mean they are in front (on the same side the ray points towards).

if you now repeat all your original steps by drawing to a render target first you could take the render target and pass it into this shader as well and read the textures colors as if they are behind or in front of the pixels of the model as you draw and apply the transparency yourself.

color = modelPixel.rgb * modelPixel.a + renderTargetPexel.rgb * (1.0f - modelPixel.a);
color = modelPixel.rgb * (1.0f - renderTargetPexel.a) + renderTargetPexel.rgb * (renderTargetPexel.a);
return color;

The problem is that the model itself can’t simply be handled by switching the winding.

You might be able to do this with blend states and switching the depth buffer to more then or less then but im not sure about how to do that it would be pretty complicated i imagine to do it that way.

1 Like

Hello Will,

I think you pushed me in the right direction with your idea about the pixel shader.

But my current solution is a little bit simpler that what you described:

I now use a shader that (depending on a parameter) only draws the front or back-halve of the model.
Since the whole affair is from an orthographic top-down view along the z-axis, the shader only needs the z-position to recognize which part is front- and which part is back-side. So there is no need for directional normals and dot-operations.

I also don’t need a separate render target (which is good because of performance). I can now create the desired effect by drawing all the elements (back-model. front–model, sprite) in the right order.

So, thank you for your valuable input^^