private void DispatchComputeShader(IRayCastingCamera camera)
    {
        var width            = camera.Width;
        var height           = camera.Height;
        var threadGroupSizeX = width / (int)threadsPerThreadGroup.x;
        var threadGroupSizeY = height / (int)threadsPerThreadGroup.y;

        // We diving from THREAD_PER_GROUP, because here we specify not the total thread count, but thread group count.
        shaderForRayCasting.Dispatch(kernelIndexOfMain, threadGroupSizeX, threadGroupSizeY, 1);
    }
    // TODO: Cache.
    private void SetAllPropertiesForShader(IRayCastingCamera camera)
    {
        var bodyManager = RayCastingBodyManager.Instance;

        // All this data came from body manager.
        shaderForRayCasting.SetBuffer(kernelIndexOfMain, "vertexDataBuffer", vertexDataBuffer);
        shaderForRayCasting.SetBuffer(kernelIndexOfMain, "triangleDataBuffer", triangleDataBuffer);
        shaderForRayCasting.SetBuffer(kernelIndexOfMain, "meshDataBuffer", meshDataBuffer);
        shaderForRayCasting.SetBuffer(kernelIndexOfMain, "bodyDataBuffer", bodyDataBuffer);
        shaderForRayCasting.SetInt("bodyDataCount", bodyManager.BodyCount);

        // This data came from camera.
        shaderForRayCasting.SetBuffer(kernelIndexOfMain, "rayDataBuffer", rayDataBuffer);
        shaderForRayCasting.SetInt("width", camera.Width);
        shaderForRayCasting.SetInt("height", camera.Height);
        shaderForRayCasting.SetTexture(kernelIndexOfMain, "renderTarget", camera.RenderTarget);
        shaderForRayCasting.SetVector("backgroundColor", camera.BackgroundColor);
    }
    private void SetDataForRayDataBuffer(IRayCastingCamera camera)
    {
        // There could be multiple resolution cameras, so in this function we decide if we need bigger buffer.
        var width           = camera.Width;
        var height          = camera.Height;
        var totalPixelCount = width * height;

        if (rayDataBuffer == null || rayDataBuffer.count < totalPixelCount)
        {
            rayDataBuffer = new ComputeBuffer(totalPixelCount, Marshal.SizeOf(typeof(RayCastingRayData)));
        }

        if (rayDataBuffer != null && rayDataBuffer.count < totalPixelCount)
        {
            rayDataBuffer.Release();
            rayDataBuffer = new ComputeBuffer(totalPixelCount, Marshal.SizeOf(typeof(RayCastingRayData)));
        }

        rayDataBuffer.SetData(camera.RayDatas);
    }
    public void Render(IRayCastingCamera camera)
    {
        Debug.Assert(camera != null);
        // TODO: Execute in different threads, these tasks area really cpu-heavy.

        // Update all compute buffers with mesh data.
        var bodyManager = RayCastingBodyManager.Instance;         // We use singleton, because unity allows only one scene at the time.

        bodyManager.CalculateBodies();

        // Update all rays that will be used for casting.
        camera.CalculateRays();

        // Update all compute buffers with calulcate information on GPU.
        UpdateComputeBuffers(camera);

        // Update shader properties, with updated compute buffers.
        SetAllPropertiesForShader(camera);

        // Run shader on gpu.
        DispatchComputeShader(camera);
    }
    private void UpdateComputeBuffers(IRayCastingCamera camera)
    {
        var bodyManager = RayCastingBodyManager.Instance;

        // Lets check if we don't exceed the buffer capcities.
        Debug.Assert(bodyDataBuffer.count >= bodyManager.BodyDataList.Count,
                     "There is to many bodies, you can change the maximum value in this script");
        Debug.Assert(vertexDataBuffer.count >= bodyManager.VertexDataList.Count,
                     "There is to many vertices, you can change the maximum value in this script");
        Debug.Assert(triangleDataBuffer.count >= bodyManager.TriangleDataList.Count,
                     "There is to many triangles, you can change the maximum value in this script");
        Debug.Assert(meshDataBuffer.count >= bodyManager.MeshDataList.Count,
                     "There is to many meshes, you can change the maximum value in this script");

        // Update the buffers on gpu.
        SetDataForRayDataBuffer(camera);
        // TODO: make other buffers resizable too.
        bodyDataBuffer.SetData(bodyManager.BodyDataList.ToArray());
        vertexDataBuffer.SetData(bodyManager.VertexDataList.ToArray());
        triangleDataBuffer.SetData(bodyManager.TriangleDataList.ToArray());
        meshDataBuffer.SetData(bodyManager.MeshDataList.ToArray());
    }