0
\$\begingroup\$

How would I convert even a section of the following code, which was taken from this GitHub Source to Godot C# or GDScript? I'm trying to make a Godot version of this project, but I don't know how to translate from one to the other. To start with, how do I copy GPU buffers in Godot as is done in this line:

Graphics.CopyBuffer(m_GpuSplatSelectedInitBuffer, m_GpuSplatSelectedBuffer);

Full code:

// SPDX-License-Identifier: MIT
using System;
using System.Collections.Generic;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Profiling;
using Unity.Profiling.LowLevel;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;

class GaussianSplatRenderSystem
{
    static ProfilerMarker s_ProfDraw = new(ProfilerCategory.Render, "GaussianSplat.Draw", MarkerFlags.SampleGPU);
    internal static ProfilerMarker s_ProfCompose = new(ProfilerCategory.Render, "GaussianSplat.Compose", MarkerFlags.SampleGPU);
    
    public static GaussianSplatRenderSystem instance => ms_Instance ??= new GaussianSplatRenderSystem();
    static GaussianSplatRenderSystem ms_Instance;
    
    readonly Dictionary<GaussianSplatRenderer, MaterialPropertyBlock> m_Splats = new();
    readonly HashSet<Camera> m_CameraCommandBuffersDone = new();
    readonly List<(GaussianSplatRenderer, MaterialPropertyBlock)> m_ActiveSplats = new();
    
    CommandBuffer m_CommandBuffer;

    public void RegisterSplat(GaussianSplatRenderer r)
    {
        if (m_Splats.Count == 0)
        {
            if (GraphicsSettings.currentRenderPipeline == null)
                Camera.onPreCull += OnPreCullCamera;
        }

        m_Splats.Add(r, new MaterialPropertyBlock());
    }

    public void UnregisterSplat(GaussianSplatRenderer r)
    {
        if (!m_Splats.ContainsKey(r))
            return;
        m_Splats.Remove(r);
        if (m_Splats.Count == 0)
        {
            if (m_CameraCommandBuffersDone != null)
            {
                if (m_CommandBuffer != null)
                {
                    foreach (var cam in m_CameraCommandBuffersDone)
                    {
                        if (cam)
                            cam.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, m_CommandBuffer);
                    }
                }
                m_CameraCommandBuffersDone.Clear();
            }
            
            m_ActiveSplats.Clear();
            m_CommandBuffer?.Dispose();
            m_CommandBuffer = null;
            Camera.onPreCull -= OnPreCullCamera;
        }
    }

    public bool GatherSplatsForCamera(Camera cam)
    {
        if (cam.cameraType == CameraType.Preview)
            return false;
        // gather all active & valid splat objects
        m_ActiveSplats.Clear();
        foreach (var kvp in m_Splats)
        {
            var gs = kvp.Key;
            if (gs == null || !gs.isActiveAndEnabled || !gs.HasValidAsset || !gs.HasValidRenderSetup)
                continue;
            m_ActiveSplats.Add((kvp.Key, kvp.Value));
        }
        if (m_ActiveSplats.Count == 0)
            return false;

        // sort them by depth from camera
        var camTr = cam.transform;
        m_ActiveSplats.Sort((a, b) =>
        {
            var trA = a.Item1.transform;
            var trB = b.Item1.transform;
            var posA = camTr.InverseTransformPoint(trA.position);
            var posB = camTr.InverseTransformPoint(trB.position);
            return posA.z.CompareTo(posB.z);
        });

        return true;
    }

    public Material SortAndRenderSplats(Camera cam, CommandBuffer cmb)
    {
        Material matComposite = null;
        foreach (var kvp in m_ActiveSplats)
        {
            var gs = kvp.Item1;
            matComposite = gs.m_MatComposite;
            var mpb = kvp.Item2;

            // sort
            var matrix = gs.transform.localToWorldMatrix;
            if (gs.m_FrameCounter % gs.m_SortNthFrame == 0)
                gs.SortPoints(cmb, cam, matrix);
            ++gs.m_FrameCounter;

            // cache view
            kvp.Item2.Clear();
            Material displayMat = gs.m_RenderMode switch
            {
                GaussianSplatRenderer.RenderMode.DebugPoints => gs.m_MatDebugPoints,
                GaussianSplatRenderer.RenderMode.DebugPointIndices => gs.m_MatDebugPoints,
                GaussianSplatRenderer.RenderMode.DebugBoxes => gs.m_MatDebugBoxes,
                GaussianSplatRenderer.RenderMode.DebugChunkBounds => gs.m_MatDebugBoxes,
                _ => gs.m_MatSplats
            };
            if (displayMat == null)
                continue;

            gs.SetAssetDataOnMaterial(mpb);
            mpb.SetBuffer("_SplatChunks", gs.m_GpuChunks);
            mpb.SetInteger("_SplatChunkCount", gs.m_GpuChunks.count);

            mpb.SetBuffer("_SplatViewData", gs.m_GpuView);

            mpb.SetBuffer("_OrderBuffer", gs.m_GpuSortKeys);
            mpb.SetFloat("_SplatScale", gs.m_SplatScale);
            mpb.SetFloat("_SplatOpacityScale", gs.m_OpacityScale);
            mpb.SetFloat("_SplatSize", gs.m_PointDisplaySize);
            mpb.SetInteger("_SplatCount", gs.asset.m_SplatCount);
            mpb.SetInteger("_SHOrder", gs.m_SHOrder);
            mpb.SetInteger("_DisplayIndex", gs.m_RenderMode == GaussianSplatRenderer.RenderMode.DebugPointIndices ? 1 : 0);
            mpb.SetInteger("_DisplayChunks", gs.m_RenderMode == GaussianSplatRenderer.RenderMode.DebugChunkBounds ? 1 : 0);

            gs.CalcViewData(cmb, cam, matrix);

            // draw
            int indexCount = 6;
            int instanceCount = gs.asset.m_SplatCount;
            MeshTopology topology = MeshTopology.Triangles;
            if (gs.m_RenderMode is GaussianSplatRenderer.RenderMode.DebugBoxes or GaussianSplatRenderer.RenderMode.DebugChunkBounds)
                indexCount = 36;
            if (gs.m_RenderMode == GaussianSplatRenderer.RenderMode.DebugChunkBounds)
                instanceCount = gs.m_GpuChunks.count;

            cmb.BeginSample(s_ProfDraw);
            cmb.DrawProcedural(gs.m_GpuIndexBuffer, matrix, displayMat, 0, topology, indexCount, instanceCount, mpb);
            cmb.EndSample(s_ProfDraw);
        }
        return matComposite;
    }

    //...
    //500 lines
    //...

    public void EditUpdateSelection(Vector2 rectMin, Vector2 rectMax, Camera cam)
    {
        if (!EnsureSelectionBuffers()) return;

        Graphics.CopyBuffer(m_GpuSplatSelectedInitBuffer, m_GpuSplatSelectedBuffer);
        
        var tr = transform;
        Matrix4x4 matView = cam.worldToCameraMatrix;
        Matrix4x4 matProj = GL.GetGPUProjectionMatrix(cam.projectionMatrix, true);
        Matrix4x4 matO2W = tr.localToWorldMatrix;
        Matrix4x4 matW2O = tr.worldToLocalMatrix;
        int screenW = cam.pixelWidth, screenH = cam.pixelHeight;
        Vector4 screenPar = new Vector4(screenW, screenH, 0, 0);
        Vector4 camPos = cam.transform.position;

        var cmb = new CommandBuffer { name = "SplatSelectionUpdate" };
        SetAssetDataOnCS(cmb, m_CSSplatUtilities, (int)KernelIndices.SelectionUpdate);
        cmb.SetComputeIntParam(m_CSSplatUtilities, "_SplatCount", m_Asset.m_SplatCount);
        cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.SelectionUpdate, "_SplatChunks", m_GpuChunks);

        cmb.SetComputeMatrixParam(m_CSSplatUtilities, "_MatrixVP", matProj * matView);
        cmb.SetComputeMatrixParam(m_CSSplatUtilities, "_MatrixMV", matView * matO2W);
        cmb.SetComputeMatrixParam(m_CSSplatUtilities, "_MatrixP", matProj);
        cmb.SetComputeMatrixParam(m_CSSplatUtilities, "_MatrixObjectToWorld", matO2W);
        cmb.SetComputeMatrixParam(m_CSSplatUtilities, "_MatrixWorldToObject", matW2O);

        cmb.SetComputeVectorParam(m_CSSplatUtilities, "_VecScreenParams", screenPar);
        cmb.SetComputeVectorParam(m_CSSplatUtilities, "_VecWorldSpaceCameraPos", camPos);
        
        cmb.SetComputeVectorParam(m_CSSplatUtilities, "_SelectionRect", new Vector4(rectMin.x, rectMax.y, rectMax.x, rectMin.y));

        m_CSSplatUtilities.GetKernelThreadGroupSizes((int)KernelIndices.SelectionUpdate, out uint gsX, out _, out _);
        cmb.DispatchCompute(m_CSSplatUtilities, (int)KernelIndices.SelectionUpdate, (m_Asset.m_SplatCount + (int)gsX - 1)/(int)gsX, 1, 1);
        Graphics.ExecuteCommandBuffer(cmb);
        cmb.Dispose();
        UpdateEditCountsAndBounds();
    }

    public void EditDeleteSelected()
    {
        if (!EnsureSelectionBuffers()) return;
        UnionGraphicsBuffers(m_GpuSplatDeletedBuffer, m_GpuSplatSelectedBuffer);
        EditDeselectAll();
        UpdateEditCountsAndBounds();
        if (editDeletedSplats != 0)
            editModified = true;
    }

    public void EditSelectAll()
    {
        if (!EnsureSelectionBuffers()) return;
        ClearGraphicsBuffer(m_GpuSplatSelectedBuffer, ~0u);
        UpdateEditCountsAndBounds();
    }

    public void EditDeselectAll()
    {
        if (!EnsureSelectionBuffers()) return;
        ClearGraphicsBuffer(m_GpuSplatSelectedBuffer);
        UpdateEditCountsAndBounds();
    }

    public void EditInvertSelection()
    {
        if (!EnsureSelectionBuffers()) return;
        InvertGraphicsBuffer(m_GpuSplatSelectedBuffer);
        UpdateEditCountsAndBounds();
    }

    public bool EditExportData(GraphicsBuffer dstData)
    {
        if (!EnsureSelectionBuffers()) return false;
        
        var cmb = new CommandBuffer { name = "SplatExportData" };
        SetAssetDataOnCS(cmb, m_CSSplatUtilities, (int)KernelIndices.ExportData);
        cmb.SetComputeIntParam(m_CSSplatUtilities, "_SplatCount", m_Asset.m_SplatCount);
        cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.ExportData, "_SplatChunks", m_GpuChunks);
        cmb.SetComputeBufferParam(m_CSSplatUtilities, (int)KernelIndices.ExportData, "_ExportBuffer", dstData);

        m_CSSplatUtilities.GetKernelThreadGroupSizes((int)KernelIndices.ExportData, out uint gsX, out _, out _);
        cmb.DispatchCompute(m_CSSplatUtilities, (int)KernelIndices.ExportData, (m_Asset.m_SplatCount + (int)gsX - 1)/(int)gsX, 1, 1);
        Graphics.ExecuteCommandBuffer(cmb);
        cmb.Dispose();
        return true;
    }

    public GraphicsBuffer gpuSplatDeletedBuffer => m_GpuSplatDeletedBuffer;
}
\$\endgroup\$
5
  • 1
    \$\begingroup\$ You've given us a lot of code here. Can you narrow the focus to any specific areas that are giving you trouble? If this is your first foray into conversion, you may want to start with a smaller script, and work your way up, using what you've learned from simpler examples to tackle more complex ones. Diving straight into the deep end is often a recipe for frustration. \$\endgroup\$
    – DMGregory
    Oct 23, 2023 at 13:59
  • \$\begingroup\$ @DMGregory lets say, "Graphics.CopyBuffer(m_GpuSplatSelectedInitBuffer, m_GpuSplatSelectedBuffer);" How would I do that in Godot? \$\endgroup\$
    – Ethan
    Oct 23, 2023 at 14:23
  • \$\begingroup\$ Want to edit your question to ask "How to copy GPU buffers in Godot?" \$\endgroup\$
    – DMGregory
    Oct 23, 2023 at 14:27
  • \$\begingroup\$ @DMGregory done. \$\endgroup\$
    – Ethan
    Oct 23, 2023 at 14:33
  • 3
    \$\begingroup\$ Have you reviewed the Godot documentation on creating these buffers and interacting with them through script? How have you tried applying this in your work so far to mimic the action of this script? \$\endgroup\$
    – DMGregory
    Oct 23, 2023 at 14:36

0

You must log in to answer this question.

Browse other questions tagged .