0

I'm implementing kind of 3D Model tools using DirectX 11 and I need to paint the collision area between 2 meshes with Pixel-level accuracy.

So I think I should do something in pixel shader but I don't have enough experience with shader programming.

here is my approximate solution and I'm not sure if it will work or not and whether it's effective or not.

  1. first model is passed to the shader through inputlayout.

  2. second model is passed to the shader through structuredbuffer.

  3. when pixel shader draw first model, calculate collision algorithm in pixel shader

    if it is true paint it red.

  4. UAV is not required because there is no output from shader. it is used in pixel shader only.

is there any other good way? this solution have to check with all triangles in second model at every pixel.

I know there is the compute shader, but I've never use it before. if it is necessary, I will take this opportunity to study.

  • I partially succeeded. it works but too slow when I zoom up the scene because it depends on number of pixels. Models transmitted through structuredbuffer have up to 200,000 triangles. is there any other solutions? – I hate cucumber Sep 20 '20 at 13:05
  • What do you mean “collision area”? When you have 2 models on input you don’t have collision, you have intersection, and it’s a volume not an area. – Soonts Sep 22 '20 at 19:15
  • Yes I talk about intersection. I'm not English speaker so I may have used wrong word – I hate cucumber Sep 23 '20 at 20:36
  • So you want to render intersection mesh? A complete one (=solid body, intersection of the two meshes), or just parts of the mesh which was originally inside of either of the meshes (won’t be solid, will generally have holes)? Also, do you want to render it with completely opaque pixel shader, or translucent? – Soonts Sep 24 '20 at 09:18
  • In short, I think you need to creatively use depth buffers. For instance, with 2 depth buffers you can render intersection solid mesh with just 4 draw calls and 1 compute shader dispatch between them. – Soonts Sep 24 '20 at 09:22
  • Could you explain me in on the details? what I want to do is when I draw the model A, if the pixel intersects with the triangle of model B(structuredbuffer), paint the pixels red. – I hate cucumber Sep 25 '20 at 04:26
  • I want to render it with translucent – I hate cucumber Sep 25 '20 at 04:29

1 Answers1

0

I think you should implement a screen-space approach. Here’s an approximate workflow.

  1. When creating your render target, create extra depth buffer of the same size as your render target, with the same or similar format (e.g. if your depth is DXGI_FORMAT_D32_FLOAT_S8X24_UINT, you don’t need stencil, you only need DXGI_FORMAT_D32_FLOAT). Create two views of that buffer, ID3D11DepthStencilView to write, and ID3D11ShaderResourceView to read.

  2. Before drawing model A, render a depth-only pass of your model B into that separate depth buffer. Don’t forget to clear the view first. Use the same vertex/geometry shaders you’d normally use. You don’t need any pixel shaders (pass nullptr into PSSetShader), and be sure to unbind any render targets, you only need the depth-stencil bound on output. Once done that, revert to your main render target view and the main depth-stencil view.

  3. Now, when rendering model A, modify your pixel shader, should be something like this:

     Texture2D<float> modelB_depth: register( t0 );
    
     float4 main( float4 pos: SV_Position ) : SV_Target0
     {
         const int3 depthLoadPosition = int3( (int2)pos.xy, 0 );
         const float b_depth = modelB_depth.Load( depthLoadPosition );
         if( b_depth < pos.z )
         {
             // Depth of the model B in this pixel is less than the current position of model A.
             // This means this pixel of model A is occluded by model B.
             // Paint it in red.
         }
         else
         {
             // Paint normally
         }
     }
    

If you use MSAA, you'll need to replace Texture2D with Texture2DMS there and adjust the shader accordingly.

  1. Once you’ll get it working, you’ll notice your model A is painted red even without intersections, when model B is in front of model A. If you want to fix that, you gonna need 2 of these extra depth buffers. Render your model B into both buffers. Clear first of them with 1.0 and render with D3D11_COMPARISON_LESS depth comparison, clear the second of them with 0 and render with D3D11_COMPARISON_GREATER depth comparison. Also don’t forget D3D11_CULL_FRONT when rendering into the second one. Once done, you’ll get 2 depth textures, together they tell you the range of depths of model B at each pixel. Then, when rendering model A’s triangles, read both depths and only paint red if the current pixel’s depth is within that interval. That’s not perfect still, gonna fails in some edge cases when your model B is a concave polyhedron, but performance-wise it’s very efficient. GPUs are asynchronous, the two depth-only passes of model B don’t have dependencies and will run in parallel. In general, GPUs are very fast at rasterizing triangles, as long as the shaders aren’t too complicated.

Update: Also, it’s possible to compute both min and max depth textures with a single render pass. Setup two render targets, backed by textures of type DXGI_FORMAT_R32_FLOAT. Initialize with ClearRenderTargetView() to 1.0 and 0.0. Setup a blend state for that pass that uses D3D11_BLEND_OP_MIN for the first RT and D3D11_BLEND_OP_MAX for the second one. Write a pixel shader that outputs Z component of SV_Position into both render targets. Don’t use depth buffer, render your model B into these two RTs, both front faces and back faces i.e. D3D11_CULL_NONE. Might be slightly faster because this way vertices are only transformed once.

Soonts
  • 20,079
  • 9
  • 57
  • 130
  • Thank you for your kind explanation. It looks similar to shadow mapping if I remember correctly. – I hate cucumber Sep 25 '20 at 06:03
  • @Ihatecucumber Yep, shadow maps are usually implemented with depth-only passes. They’re way more complicated however. For shadows the pre-pass is in light space and you need substantial amount of complexity to make sense of the depth data. For screen-space intersection you don’t need to adjust camera at all. BTW when you work on such stuff, https://renderdoc.org/ helps tremendously, among other things allows to view both inputs and outputs of every draw call. – Soonts Sep 25 '20 at 07:24
  • If you have access to logical blends, rendering to a R32_UInt target with a OR operation and doing a small screen space pixel shader to visualize after can also work pretty nicely. – mrvux Sep 30 '20 at 12:38