I’m currently using the vector type but that only accepts float values. Is there a type for an array of 4 doubles instead? I need the extra precision if possible. Help would be appreciated!
No.
You cannot pass doubles to shaders directly as doubles. It’s not something supported by graphics APIs, let alone Unity’s material and shader properties.
Instead you need to deconstruct each double into two uints and pack them into a compute buffer / structured buffer that you decode back into a double in the shader.
To pass a vector of doubles you’d need something like this:
// c#
ComputeBuffer CreateDoubleVectorBuffer()
{
// 4 doubles as an array of 8 uint values
return ComputeBuffer(8, sizeof(uint));
}
void SetDoubleVectorData(ComputeBuffer buffer, double[] values)
{
// 4 doubles as an array of 8 uint values
uint[] data = new uint[8];
for (int i=0; i<4; i++)
{
// cast double to uint64
uint64 bits = (uint64)values[i];
// split into low and high bits
uint lowBits = (uint)bits;
uint highBits = (uint)(bits << 32);
data[i*2+0] = lowBits;
data[i*2+1] = highBits;
}
buffer.SetData(data);
}
// elsewhere in C# create the buffer for and assign to each material once
ComputeBuffer doubleVectorBuffer = CreateDoubleVectorBuffer();
myMaterial.SetBuffer("MyDoubleVectorBuffer", doubleVectorBuffer);
// update the buffer with your doubles
// don't need to re-assign to the material, though you can
SetDoubleVectorData(doubleVectorBuffer, doubleVector);
// in the shader
// requires Shader Model 5.0 or better
#pragma target 5.0
// define the structured buffer as a uniform outside of any function, like other properties
StructuredBuffer<uint> MyDoubleVectorBuffer;
// get double vector from structured buffer
double4 myDoubleVector = double4(
asdouble(MyDoubleVector[0], MyDoubleVector[1]),
asdouble(MyDoubleVector[2], MyDoubleVector[3]),
asdouble(MyDoubleVector[4], MyDoubleVector[5]),
asdouble(MyDoubleVector[6], MyDoubleVector[7])
);
For some reason it’s not working as expected, but I’m not sure what’s wrong since it compiles just fine. Although surprisingly simply passing the doubles straight into the StructuredBuffer works perfectly. I think passing doubles to the fragment shader from the CPU is fine, but you can’t pass doubles from the vertex shader to the fragment shader? Thanks for the help!
I might have messed up the c# (either flipped the high and low, or otherwise got the cast behavior wrong), but passing it as a double is totally fine. The compute buffer gets passed to the GPU as the raw bits that the structured buffer can interpret any way it wants.
As for passing between the vertex and fragment shader, correct, you cannot do that. GPUs do not support doubles outside of doing math on them inside the shader. You either need to do the math you want to do in the fragment shader, or you need to deconstruct it into two uint values again and pass that.
Luckily that’s something HLSL has a function for.
uint lowBits, highBits;
asuint(myDoubleValue, lowBits, highBits);
Though if you’re using a Surface Shader you’re still out of luck as that only supports passing float values from the vertex to the fragment.