0
\$\begingroup\$

I'm writing a vertex deformation shader that can react to the presence of certain objects. Originally I was passing coordinates to the shader with SetVector, but from my understanding having the CPU set properties on a shader is somewhat expensive. So another idea I had was to have the shader react to light, and do some matrix multiplication to have the shader deform itself based on the intensity of the light hitting it. My question is, how could I approach writing a shader that would react to a light source, when that light would be invisible to the camera/player? In such a scenario I could write a fast & reasonably simple shader that could react to a special light source that would allow it to dynamically react to the light's location and distance. Only, such a light source would need to be invisible to the player, since its just being used as a representation of location and distance (with the added benefit of mixing multiple different sources easily). Or is there some other equally fast better way to do this that I'm not thinking of?

Thanks for the help!

EDIT: Imagine a shader that causes a surface to grow outwards when a certain type of object is near it, and its extrusion distance is proportional to the distance and "intensity" (some float) of the object. If there were several of these objects near the surface then it will form a pattern taking into account all of these nearby objects.

\$\endgroup\$
  • 1
    \$\begingroup\$ Think about this: how does the GPU know where the light is pointing? Because the CPU told it. So you still have the same data flow from the CPU to the GPU, you haven't necessarily made it any cheaper by calling that bundle of data a "light". While you're right that coupling the CPU and GPU too tightly can be a bottleneck, setting a few uniform vectors each frame is not an unreasonable cost. So, rather than going by what you've heard is slow, profile it and see if this particular case is really a problem that needs solving. \$\endgroup\$ – DMGregory Apr 27 '17 at 3:55
  • \$\begingroup\$ The main problem I'm having is blending from a potentially large number of different sources. The few examples I've found hard code x number of properties (e.g. "source0.. source25). Is there a better way you know of than hard coding a few dozen properties, having CPU logic to switch between them, and then some calculations in the shader to blend them? Thanks for the help :) \$\endgroup\$ – papathor Apr 27 '17 at 5:34
  • \$\begingroup\$ Edit your question to tell us more about how this data is being used, what end goal or effect you're trying to achieve. You might not need to access this data all in a single shader pass — a lot of graphics techniques are based on flipping the problem around in some way (eg moving from forward to deferred rendering, changing geometry x lights to geometry + lights) \$\endgroup\$ – DMGregory Apr 27 '17 at 5:37
  • \$\begingroup\$ Just added more explanation. This is for a hobby project so I don't have anything set in stone, I'm mostly just interested in creating a reactive shader that can dynamically morph based on the objects around it. \$\endgroup\$ – papathor Apr 27 '17 at 6:41
  • \$\begingroup\$ Think I'm going to create a shader later that does something like this because it would look cool. (Lights would still be lights, I mean using that same data to deform the mesh). \$\endgroup\$ – Draco18s Apr 27 '17 at 22:06
3
\$\begingroup\$

Given your edit and the comments about how you're using your data, you should probably look into packing the relevant object data (position, size, etc) into a Structured Buffer for use in your vertex shader.

Don't let the name fool you, the way to do this is through a compute buffer. https://docs.unity3d.com/ScriptReference/ComputeBuffer.html

To use, you create an array of the types on the cpu, set the buffer data, and then set it for the material.

You have a struct

//This struct exists in your shader AND in your script
struct data {
    float3 position;
    float3 scale
}

Your setup on the CPU

//CPU side
var objects = GameObject.FindGameObjectsWithTag("shaderstuff");
var dataArray[];

/*fill your data array here */

// struct has 2 float3's so it's 24 bytes
var buffer = new ComputeBuffer(dataArray.Length,24);
buffer.SetData(dataArray);
material.SetBuffer("dataStuff",buffer);
material.SetInt("_dataCount",dataArray.Length);

your gpu code

//put this with the rest of your uniforms
StructuredBuffer<data> dataStuff;
uniform int _dataCount;

now you can access your data (in your shaders) as if it were an array.

\$\endgroup\$
  • \$\begingroup\$ Thank you for the thoughtful and clear response, this was very helpful :) \$\endgroup\$ – papathor Apr 27 '17 at 18:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.