Accessing HLSL Variables from Code

The Unity manual states this:

Does this mean there is a way to access HLSL variables from code without mapping them to ShaderLab Properties? Or does it just mean you can use the Material API to access values in the Properties block regardless of whether or not those values are actually used to set some characteristic of a Material?

I ask because I can’t seem to find any way to access HLSL variables unless they are mapped to entries in the Properties block. That’s not a problem, but I just want to be sure I understand the quoted lines above from the manual.

The short answer is: the manual is wrong.

The GetFloat / SetFloat functions let you get / set the values that are set on the material itself that the rendering systems pass to the shader later. You can not access values that are set in HLSL because those values only exist temporarily on the GPU during the execution of the shader stage for each vertex or fragment for each frame. Values you set on a material are passed to the GPU, which passes a copy of that data to the shader when it renders. When the shader runs, it reads that copy of the data to use during execution. By the next vertex / fragment / frame any data you assigned to variables within the HLSL code was thrown out and you’re getting a fresh copy of the data to work from again. At no time does the data ever get sent back to the CPU to be accessed via C#.* The only output from each shader stage that is retained beyond the execution of each stage is the data that’s passed from the vertex to the fragment, after which it is forgotten, or written to the render target by the fragment shader.

* There are ways to get data back to the CPU from the GPU via compute buffers and read back commands. But unless you already know how to do that, you probably do not ever want to do this as this process is very slow.

Yeah it’s a one way street, like bgolus said. Once the CPU sends it to the GPU, it doesn’t know what’s happening over there.

If you want physics you can use the jobs system and burst compiler though, it’s very tricky at first to get used to though.

One question I do have though is about compute shaders, I’m not sure how to do something like this…It says ‘particle representation 8k rigidbodies’, not sure what that means. Pretty sure these days it’s how they get characters to effect tons and tons of foliage and have breakaway objects and all that.

GPU Buffers are managed which are frequently updated with information about colliders that are relevant to the particle simulation and a ComputeShader is run to process the “8,000 rigidbodies” and have them interact with eachother and those colliders. It’s an extremely advanced topic of GPU process and just programming in general though.

Like bgolus says in the note at the bottom of his comment, you technically can get data back from the GPU by using various types of buffers, and have the data persist. You can even bind said buffers to a fragment shader to have values written to which can then be read from the CPU side (though it can get expensive to read data from the GPU).

For folliage that’s often just a global float4 in your shader, where xyz is the position and W is the radius of effect from the player. Some system go more advanced and set a value for velocity and use an analytic shape like a capsule instead of just sphere radius. Or they might even use a buffer like I mentioned that contain multiple colliders of this type so limbs and the like can affect foliage as well. Then your vertex shader (or more ideally ComputeShader) can process that interaction.

To add on to Bgolus, it is possible to read data back to the CPU from a computebuffer using ComputeBuffer.GetData. However the CPU to GPU data transfer pipeline was only designed to be efficient one-way: CPU to GPU. So anytime you want to grab data from the GPU you have consider the cost of extreme memory latency in doing so. Unless what you are doing cannot be done on the CPU, or you have enough time to hide the latency, it’s usually not worth it.