// 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();
        }
        //#TODO: implement Spotlight and Area light support
        private Color GetDiffuseColor(Vector3 normal, LightingRig lightingRig, Vector3 hitPoint)
        {
            Color color = Color.black;

            // We can use "foreach" because Array doesn't create garbage
            foreach (Light light in lightingRig.Lights)
            {
                Vector3 direction;
                float   intensity;

                switch (light.type)
                {
                case LightType.Directional:
                    intensity = light.intensity;
                    // inverse  because we need direction from sampling point to light
                    direction = -light.transform.forward;
                    break;

                case LightType.Point:
                    var     transform = light.transform;
                    Vector3 distance  = transform.localPosition - hitPoint;
                    intensity = light.intensity * Mathf.Sqrt(distance.magnitude);
                    direction = distance.normalized;
                    break;

                default:
                    continue;
                }

                // Lambert lighting
                color += light.color * intensity * Math.Max(0, Vector3.Dot(normal, direction));
            }

            return(color);
        }
 public abstract void Render(MatCapSnapshot matCapSnapshot, LightingRig lightingRig, CameraRuntimeRef cameraRef);
 public override void Render(MatCapSnapshot matCapSnapshot, LightingRig lightingRig, CameraRuntimeRef cameraRef)
 {
     // #TODO Implement compute shader version
 }