2

I don't understand why the _Positions property of ComputeShader was given as a parameter of material.SetBuffer.

I thought SetSomething(property, value) method give value to property.

But in this case, _Positions property is a ComputeShader's variable then what is the mean of giving it to material?

And experience has shown that the code actually stores the positions of the material. How and Why it does?

I think I'm missing something fundamental about Buffers.

And Is it relative with where does ShaderGraph's Position Node input come from?

C# Code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GPUGraph : MonoBehaviour
{
    [SerializeField]
    ComputeShader computeShader;
    static int positionID = Shader.PropertyToID("_Positions");
 // _Positions poperty in computeShader
 // RWStructuredBuffer<float3> _Positions;
 // Some position data saved in _Positions property

    [SerializeField]
    Material material;

    [SerializeField]
    Mesh mesh;

    ComputeBuffer positionBuffer;
    const int MaxResolution = 10;

    void OnEnable() {
        positionBuffer = new ComputeBuffer(MaxResolution * MaxResolution, 3 * 4);

    }
    
    void OnDisable() {
        positionBuffer.Release();
        positionBuffer = null;
    }
    void Update() {
        UpdateFunctionOnGPU();
    }

    void UpdateFunctionOnGPU() {        
        computeShader.SetBuffer(0, positionID, positionBuffer);

        int groups = Mathf.CeilToInt(MaxResolution / 8f);

        computeShader.Dispatch(0, groups, groups, 1);

        material.SetBuffer(positionID, positionBuffer);

        var bounds = new Bounds(Vector3.zero, Vector3.one * (2f + 2f / resolution));
        Graphics.DrawMeshInstancedProcedural(mesh, 0, material, bounds, resolution * resolution);
    }
}

ShaderGraph applied to material

y202100
  • 27
  • 6

1 Answers1

0

To make it clear for yourself, you should understand what shaders and materials are.

Shader - is a kind of program, that is executed on GPU. It differs from regular programs for CPU written in C#, Java or something. Mostly shaders are written in C-like languages (HLSL in Unity). There are also codeless tools, like Shader Graph in Unity for shaders creating. And shaders are used to draw something on your screen.

Material - is an abstract concept, that represents a... I think it can be called shader instance. In other words, it is a structure, that contains data about which shader should be executed and with which parameters, and maybe some other data about shader execution.

And speaking about buffers. As I said, shaders deffer from regular CPU program. And, to execute it, you should make three general steps.

  1. Load this program on GPU
  2. Load data, that should be handled by this program (parameters of this program).
  3. Say GPU to execute this program.

And if you have experience with low level network development, or different kind of hardware components interactions, you could know, that buffers are the main way to pass any data from component to component, or from computer to computer. So, to pass any data to the GPU, you should place it in the concrete buffer. It can be a buffer for executable code, or for parameters, or for some control instructions. And sometimes there is one buffer for several goals, and you should know which byte positions in the buffer are needed for you.

Unity encapsulate all this staff from you. And you can work only with materials, actually. In your code, you have positionID = Shader.PropertyToID("_Positions"). For Unity, it is an indicator of buffer, that should be loaded to the GPU to make it understand, that this data should be handled as "_Positions" variable. And after this you execute material.SetBuffer(positionID, positionBuffer); And, generally, link your created buffer for this indicator. And after you do it (not instantly, but probably in render step of Unity execution pipeline), this positionBuffer will be loaded to the GPU and will be handled as _Position variable.

Nikolai
  • 656
  • 6
  • 19
  • Thank you for your kind explanation of ``buffer''. The position information calculated in compute shader is stored in positionBuffer. And I understood that the buffer is connected to the material. However, how does material recognize that the data in the buffer is position data and affect position? Is the data of the buffer coming into the input of the Shader Graph Position Node? – y202100 Sep 27 '22 at 17:25
  • 1
    In this context "material" and "shader" are some kind of synonyms. In your shader you have `Fragment` and `Vertex` part. Mostly all input data is passed to the `Vertex` part of the shader. And output of the `Vertex` is passed to the `Fragment`. And also there is `Rasterization` step between `Vertex` and `Fragemtn` execution. There are two `Position` node in your graph, but you have to understand, that them are not same. Bottom one is just an output of your `Vertex` shader. And shader don't know that this variable is a position. For shader it just some data with name `_Positions` – Nikolai Sep 27 '22 at 17:52
  • 1
    ... Also I think it is important to metion that `_Positions` contains a lot of positions and shader separate them and handle them parallel. So `Position` in your shader is one element from `_Positions` buffer. – Nikolai Sep 27 '22 at 17:55