private Color RenderRay(RayData rayData)
        {
            float depth = 0;

            for (int step = 0; step < MaxMarchingSteps; step++)
            {
                Vector3 samplePoint = rayData.EyePosition + depth * rayData.RayDirection;
                float   distance    = SphereSDF(samplePoint);

                if (distance < rayData.Epsilon)
                {
                    // Since our sphere located in the center of the world we can easlity get normal of
                    // the point where we touching sphere by simple normalization
                    Vector3 normal = samplePoint.normalized;

                    // TODO: implement Specualr and Ambient sampling
                    Color color = GetDiffuseColor(normal, rayData.LightingRig, hitPoint: samplePoint);
                    return(color);
                }

                depth += distance;

                // Make sure we are not going too far from sphere
                if (depth > _distanceToSphere * 2)
                {
                    break;
                }
            }

            return(Color.black);
        }
        // TODO: implement split texture rendering for Diffuse, Alpha & Specular (now supported only Combined)
        // TODO: implement viriable view position (now supported only along Z axis)
        public override void Render(MatCapSnapshot matCapSnapshot, LightingRig lightingRig, CameraRuntimeRef cameraRef)
        {
            Texture2D combined = matCapSnapshot.Combined;

            Color[] pixels = combined.GetPixels();

            // Min distance to  sphere caluclated according to texel size
            float epsilon = GetEpsilon(combined.width, combined.height);

            // Pixels layed out left to right, bottom to top
            for (int row = combined.height - 1; row >= 0; row--)
            {
                for (int col = 0; col < combined.width; col++)
                {
                    var rayData = new RayData();
                    rayData.RayDirection = GetRayDirection(combined.width, col, combined.height, row, cameraRef);
                    rayData.LightingRig  = lightingRig;
                    rayData.EyePosition  = new Vector3(0, 0, -_distanceToSphere);
                    rayData.Epsilon      = epsilon;

                    // TODO: use new Unity data oriented desing with ECS and Burst
                    // This task could be parallelized
                    int index = row * combined.width + col;
                    pixels[index] = RenderRay(rayData);
                }
            }

            combined.SetPixels(pixels);
            combined.Apply();
        }