4
\$\begingroup\$

In a Raymarching project I need to have a collision detection for my Signed Distance Field shapes.

I find a project that Implemented simple collision detection.but I need a more stable Physic when walking on a complex shape (e.g Fractal).

I have an Idea to create collider for my complex shape by voxelizing It.this Is mean I want to Instancing cubes that have box collider , but I don't know how can I do It.

Colliders

Suppose that we have SDF voxel tours.how can I do collision detection?

Voxel Tours

Shader "Voxel torus"
{
    Subshader
    {
        Tags {"Queue"="Transparent" "IgnoreProjector"="true" "RenderType"="Transparent"}
        ZWrite Off Blend SrcAlpha OneMinusSrcAlpha Cull Off
        Pass
        {
            CGPROGRAM
            #pragma vertex vertex_shader
            #pragma fragment pixel_shader
            #pragma target 3.0

            struct custom_type
            {
                float4 screen_vertex : SV_POSITION;
                float3 world_vertex : TEXCOORD1;
            };

            static const float voxel_size = 0.1;

            float torus (float3 p, float2 t) //torus signed distance field function
            {
                float2 q = float2(length(p.xz)-t.x,p.y);
                return length(q)-t.y;
            }

            float map (float3 p) //scene geometry
            {
                return torus(p-float3(4,4,4),float2(2.0,0.6));
            }

            float4 lighting (float3 p, float3 normal) //surface color
            {
                float3 voxel = fmod(p, voxel_size) / voxel_size;
                float3 a = max(abs(normal), smoothstep(0.0, 0.1, voxel));
                float3 b = max(abs(normal), smoothstep(0.0, 0.1, 1.0 - voxel));
                float Line = a.x * a.y * a.z *b.x * b.y * b.z;
                float4 AmbientLight = float4 (0.2,0.2,0.2,1.0);
                float3 LightDirection = normalize(float3(1,1,-20));
                float3 NormalDirection = normal;
                float4 LightColor = float4(0.7,0.7,0.7,1.0) ;   
                float4 Lambert =  max(dot(LightDirection,NormalDirection),0.0)*LightColor+AmbientLight;      
                return lerp(float4(0,0,1,1.0), Lambert, Line);
            }

            float4 raymarch (float3 ro, float3 rd) //renderer
            {
                float3 voxel = floor(ro / voxel_size);
                float3 next = ((voxel + max(sign(rd), 0.0)) * voxel_size - ro) / rd;
                float3 step = sign(rd);
                float3 delta = voxel_size / abs(rd);
                float3 normal;
                float t = 0.0;
                for(int i = 0; i < 256; i++)
                {
                    float d = map(voxel * voxel_size);
                    if (d < 0.0001) 
                    {               
                        ro += rd*t*(1.0-abs(normal));
                        return lighting(ro,normal);
                    }
                    if(next.x < next.y && next.x < next.z)
                    {
                        voxel.x += step.x;
                        t = next.x;
                        next.x += delta.x;
                        normal = float3(-step.x, 0.0, 0.0);
                    }
                    else if(next.y < next.x && next.y < next.z) 
                    {
                        voxel.y += step.y;
                        t = next.y;
                        next.y += delta.y;
                        normal = float3(0.0, -step.y, 0.0);
                    }
                    else if(next.z < next.x && next.z < next.y) 
                    {
                        voxel.z += step.z;
                        t = next.z;
                        next.z += delta.z;
                        normal = float3(0.0, 0.0, -step.z);
                    }
                }
                return float4(0,0,0,0);
            }

            custom_type vertex_shader (float4 vertex:POSITION) //vertex shader 
            {
                custom_type vs;
                vs.screen_vertex = UnityObjectToClipPos (vertex);
                vs.world_vertex = mul(unity_ObjectToWorld,vertex);
                return vs;
            }

            float4 pixel_shader (custom_type ps ):SV_TARGET //fragment shader
            {
                float3 worldPosition = ps.world_vertex;
                float3 viewDirection = normalize(ps.world_vertex-_WorldSpaceCameraPos.xyz);
                return raymarch(worldPosition,viewDirection);
            }

            ENDCG

        }
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ Have you tried using a MeshCollider with convex? \$\endgroup\$ Commented Apr 14, 2018 at 12:28
  • \$\begingroup\$ @TomTsagk It's not possible because In raymarching, the entire scene is defined in terms of a signed distance function. please read this What is Raymarching and try It yourself Raymarching Example \$\endgroup\$ Commented Apr 14, 2018 at 12:49
  • \$\begingroup\$ Discretizing your signed distance function as a collection of cubes or as a collection of convex polygon meshes aren't fundamentally different. Neither on is impossible, they're just work to do, and come with different optimization strategies and trade-offs. \$\endgroup\$
    – DMGregory
    Commented Apr 14, 2018 at 16:19
  • \$\begingroup\$ @DMGregory It just was an Idea , It may be wrong but any way I don't know how can I have something like MeshCollider. \$\endgroup\$ Commented Apr 14, 2018 at 16:45
  • \$\begingroup\$ Signed distance field → Marching Cubes → Polygon Mesh → Convex subdivision → Convex mesh colliders. It's simple in principle; the devil is in the details. ;) \$\endgroup\$
    – DMGregory
    Commented Apr 14, 2018 at 16:47

1 Answer 1

1
\$\begingroup\$

Ray marching is nothing more than a collision detection algorithm. It just tends to be used for finding ray collisions, partly because it's in the name and partly because engineers tend to think through visualization.

So I can think of a way, but I'm just thinking... You are probably familiar with how intersections are rendered. It's taking the max of two SDFs. In this case you could "render" intersections by taking the max of two physical bounds. This way you know when you intersect and by how much along any possible direction (it's more than you need). You also know the vectors along which objects travel. From this and what your buffer or "render" tells you you should be able to deduce how to react to a collision. Conveniently I'll stop here.

I can't emphesise this enough that this is just a thought. I don't really know much about ray marching or rendering in general. So it could be that it's wrong reasoning or missing something.

The reason I found this post was because I plan to prototype a game using ray marching for some systems in the future using sparse voxels. So I may come back to this with a more detailled and helpful answer, but right now I'm not even supposed to be on stackexchange.

This is another way, but exclusive to something that has a root object (a.k.a. a fractal). from CodeParade on Marble Marcher

\$\endgroup\$
2
  • \$\begingroup\$ Hi dear friend thanks for spending time to answer my question.I upvoted your answer but I'll accept your question if you give me some pseudo codes \$\endgroup\$ Commented Dec 28, 2019 at 16:52
  • \$\begingroup\$ I used this repository and solved my problem but I didn't know how it works.your video help me to understand how it works. \$\endgroup\$ Commented Dec 28, 2019 at 16:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .