So, I’m sure many of you are familiar with VRChat by now. I have been working on a fur shader intended to work on their platform, however, they have this awful thing that prevents anyone from using even the most basic of custom scripts. Originally I had a neat shader that used a script for physics, as you would expect. Since I found out that scripts aren’t allowed I’ve been working very hard to get my shader to work without it. I’m determined that there is some way to get it to work. The main problem is that I need somewhere to store data about each vertex such as past position and velocity. The solution was to use an RWStructuredBuffer, until I found out that it also needs a script to initialize it! I am utterly stumped now, and mostly want to cry from how many hours I sunk into this thing.
Regardless, I will post some of my code and if anyone has ANY Ideas for how I could proceed I would be oh so grateful.
From variables file:
float3 _Gravity;
float _ForceMult;
float _ForceDamp;
float3 _WindForce;
float _WindMin;
float _WindMax;
float _WindDamp;
float _PrevTime;
float _OurTimeDelta;
float _UpdateRate;
float _MaxForceFinal;
struct vertdata {
float3 position;
float3 force;
float computeTime;
};
#ifdef SHADER_API_D3D11
uniform RWStructuredBuffer<vertdata> _PosBuffer : register(u0);
#endif
From the vertex file:
float wDelta = _Time.y - _PrevTime;
if(wDelta > 1 / _UpdateRate){
float windMagnitude = (_WindMax - _WindMin) * 2.0;
float3 wind = float3(_WindMax,_WindMax,_WindMax) - hash33(_Time.yzw)*windMagnitude;
_WindForce = lerp(_WindForce,wind,wDelta * _WindDamp);
_PrevTime = _Time.y;
}
float4 c = tex2Dlod (_ControlTex, float4(v.texcoord.xy,0,0));
float3 startdisp = float3(0,0,0);
float hairLength = _MaxHairLength * CURRENTLAYER;
hairLength *= _UseHeightMap ? c.r : 1;
float movementFactor = pow(CURRENTLAYER, 2);
#ifdef SHADER_API_D3D11
vertdata inp = _PosBuffer[v.vid];
float3 force = inp.force;
float tDelta = _Time.y - inp.computeTime;
if(tDelta > 1 / _UpdateRate){
vertdata outp;
float4 pos = mul(unity_ObjectToWorld, v.vertex);
outp.position = pos.xyz / pos.w;
float3 mforce = outp.position - inp.position;
//float3 mforce = 0;
mforce /= tDelta;
mforce *= _ForceMult;
//mforce += _WindForce;
float mmult = min(1,MaxForce*MaxForce / (mforce.x*mforce.x + mforce.y*mforce.y + mforce.z*mforce.z));
mforce *= mmult;
float3 totaldisp = mforce;
float3 noisecoords = _Time.www / 4 + v.vertex.xyz;
float3 noisecoords2 = _Time.www / 4 + v.vertex.xyz * 2;
float3 randNums = hash33(_Time.www / 4 + v.vertex.xyz * 16) * 2 + float3(-1,-1,-1);
randNums *= randFac;
float3 finaldisp;
finaldisp.x = totaldisp.x*(1 + NoiseFac*(snoise(noisecoords) + snoise(noisecoords2) * FractFac + randNums.x));
finaldisp.y = totaldisp.y*(1 + NoiseFac*(snoise(noisecoords + float3(712,712,712)) + snoise(noisecoords2 + float3(712,712,712)) * FractFac + randNums.y));
finaldisp.z = totaldisp.z*(1 + NoiseFac*(snoise(noisecoords + float3(1916,1916,1916)) + snoise(noisecoords2 + float3(1916,1916,1916)) * FractFac + randNums.z));
finaldisp += _Gravity;
force = lerp(force,finaldisp,tDelta * _ForceDamp);
force *= min(1,_MaxForceFinal*_MaxForceFinal / (force.x*force.x + force.y*force.y + force.z*force.z));
outp.force = force;
outp.computeTime = _Time.y;
_PosBuffer[v.vid] = outp;
}
#else
float3 force = float3(0,-3,0);
#endif
if (_UseBiasMap) {
fixed skinLength = _MaxHairLength - (_MaxHairLength * c.b);
v.vertex.xyz -= v.normal * skinLength;
}
v.vertex.xyz += (v.normal * hairLength);
float4x4 transmatrix = unity_WorldToObject;
transmatrix[0].w=0;
transmatrix[1].w=0;
transmatrix[2].w=0;
float4 forcedisp = mul(transmatrix, float4(force,1.0f));
v.vertex.xyz += (forcedisp.xyz * v.vertex.w / forcedisp.w) * movementFactor * hairLength;