SDK Bug & Feature Requests

Please check out the following rules and use the provided template when posting a bug report! Off-topic posts will be deleted.http://bit.ly/vrchat-bug-reports
Revert Boolean "Value" Visibility in Avatar Expressions Menu Editor
With the SDK 3.10.2 update, the Avatar Expressions Menu editor received the following UX change: When targeting a Boolean parameter, the Value attribute is now hidden and is always treated as enabled, since that's the only valid option for a Boolean (true when activated, false when deactivated). While I understand the reasoning behind this change, it removed a useful workflow that was previously possible. Before this update, it was possible to create two menu controls targeting the same Boolean parameter: one with Value = True and another with Value = False. This allowed both controls to toggle the same parameter while only the control matching the current state would appear visually active. For example: Badge toggle (Value = True) Nameplate toggle (Value = False) When the Boolean is true, only the Badge toggle appears active. When it's false, only the Nameplate toggle appears active. This made it possible to represent two mutually exclusive states using a single Boolean while providing clear visual feedback in the Expressions Menu. Since the Value field is now hidden and always forced to true, this behavior is no longer possible. I'd like to see the Value option restored for Boolean parameters, even if it's tucked behind an advanced setting or warning. While the current behavior is simpler for most users, the previous implementation enabled legitimate use cases that are no longer possible.
1
·
Feature Request
·
tracked
[Optimization] Better implementation of Helpers.cginc : ApplyHue
The function ApplyHue in Packages/com.vrchat.base/Runtime/VRCSDK/Sample Assets/Shaders/Mobile/ToonStandard/CG/Helpers.cginc I felt could be rewritten, here are my findings if you so choose to use them. The original ApplyHue function compiles to this shader code: 0: sample r0.xyzw, v1.xyxx, t0.xyzw, s0 1: eq r0.w, cb0[2].x, l(0.000000) 2: if_z r0.w 3: sincos r1.x, r2.x, cb0[2].x 4: mul r1.yzw, r0.zzxy, l(0.000000, 0.577350, 0.577350, 0.577350) 5: mad r1.yzw, r0.zzxy, l(0.000000, 0.577350, 0.577350, 0.577350), -r1.wwyz 6: mul r1.xyz, r1.xxxx, r1.yzwy 7: mad r1.xyz, r0.xyzx, r2.xxxx, r1.xyzx 8: dp3 r0.w, l(0.577350, 0.577350, 0.577350, 0.000000), r0.xyzx 9: mul r0.w, r0.w, l(0.577350) 10: add r1.w, -r2.x, l(1.000000) 11: mad r1.xyz, r0.wwww, r1.wwww, r1.xyzx 12: add r1.xyz, -r0.xyzx, r1.xyzx 13: mad r0.xyz, v1.zzzz, r1.xyzx, r0.xyzx 14: endif 15: mov o0.xyz, r0.xyzx 16: mov o0.w, l(1.000000) 17: ret temp registers: r0.xyzw, r1.xyzw, r2.x mad x 4 mul x 3 add x 2 sincos x 1 dp3 x 1 None of these instructions are inherently expensive, in fact they're some of the cheapest outside of sincos, but I love bringing more ways to do things to the table. My first method is shorter in assembly and only uses the cosine part of sincos. // Rotates white-point to Z axis, rotates around Z, undo white-point rotation. half3 ApplyHue(half3 col, half hueAngle, half mask) { UNITY_BRANCH if (hueAngle == 0) { return col; } else { const half PI = 3.14159265359; const half3 OFFSETS = PI * half3(0.0/3.0, 2.0/3.0, 4.0/3.0); half3 ct = (1.0/3.0) + (2.0/3.0) * cos(hueAngle + OFFSETS); half3 shifted = (col.rgb * ct.x) + (col.gbr * ct.y) + (col.brg * ct.z); return lerp(col, shifted, mask); } } Which compiles to the following with the same usage 0: sample r0.xyzw, v1.xyxx, t0.xyzw, s0 1: eq r0.w, cb0[2].x, l(0.000000) 2: if_z r0.w 3: add r1.xyz, cb0[2].xxxx, l(0.000000, 2.094395, 4.188790, 0.000000) 4: sincos null, r1.xyz, r1.xyzx 5: mad r1.xyz, r1.xyzx, l(0.666667, 0.666667, 0.666667, 0.000000), l(0.333333, 0.333333, 0.333333, 0.000000) 6: mul r2.xyz, r0.yzxy, r1.yyyy 7: mad r1.xyw, r0.xyxz, r1.xxxx, r2.xyxz 8: mad r1.xyz, r0.zxyz, r1.zzzz, r1.xywx 9: add r1.xyz, -r0.xyzx, r1.xyzx 10: mad r0.xyz, v1.zzzz, r1.xyzx, r0.xyzx 11: endif 12: mov o0.xyz, r0.xyzx 13: mov o0.w, l(1.000000) 14: ret temp registers: r0.xyzw, r1.xyzw, r2.xyz mad x 4 add x 2 mul x 1 sincos x 1 This version uses slightly less instructions total, but parallelizes into three components used for r2, which might bump the temporary register count in some cases by one. This annoyed me, so I decided to make a slightly different version that's more in the middle while still using the same component count. // Rotates white-point to Z axis, rotates around Z, undo white-point rotation. half3 ApplyHue(half3 col, half hueAngle, half mask) { UNITY_BRANCH if (hueAngle == 0) { return col; } else { const half k = 0.57735026919; //1/sqrt(3) half ct = cos(hueAngle) * (1.0/3.0); half st = sin(hueAngle) * k; half a = -2.0/3.0 + ct + ct; half b = +1.0/3.0 - ct - st; half c = +1.0/3.0 - ct + st; half3 shifted = col.rgb*a + col.gbr*b + col.brg*c; return col.rgb + mask * shifted; } } Which still manages to strip the original down by a bit. 0: sample r0.xyzw, v1.xyxx, t0.xyzw, s0 1: eq r0.w, cb0[2].x, l(0.000000) 2: if_z r0.w 3: sincos r1.x, r2.x, cb0[2].x 4: mad r0.w, r2.x, l(0.666667), l(-0.666667) 5: mad r1.y, -r2.x, l(0.333333), l(0.333333) 6: mad r1.z, -r1.x, l(0.577350), r1.y 7: mad r1.x, r1.x, l(0.577350), r1.y 8: mul r1.yzw, r0.yyzx, r1.zzzz 9: mad r1.yzw, r0.xxyz, r0.wwww, r1.yyzw 10: mad r1.xyz, r0.zxyz, r1.xxxx, r1.yzwy 11: mad r0.xyz, v1.zzzz, r1.xyzx, r0.xyzx 12: endif 13: mov o0.xyz, r0.xyzx 14: mov o0.w, l(1.000000) 15: ret temp registers: r0.xyzw, r1.xyzw, r2.x mad x 7 sincos x 1 mul x 1 Optionally, if you wish to make the range of both of these, you can still simply multiply hueAngle by UNITY_TWO_PI , to resolve feedback like this one https://feedback.vrchat.com/sdk-bug-reports/p/mobile-toon-standard-hue-shift-should-go-from-0-to-1-not-628 I have also verified the shader compiler does unroll everything to become a single mov instruction if mask = 0. I have made supplemental demos in Desmos to showcase the methods: https://www.desmos.com/3d/w6lx6thiga https://www.desmos.com/calculator/qssso8prah I hereby grant legal rights to all shader code presented in this feature request. I present all of the above, granting full rights to use, reuse, modify, redistribute, and will not persue any form of legal action, following the guidelines of the MIT-0 No Attribution licence. blablabla open source, use it as you wish! ApplyHueMinimal.shader (which I have renamed to .txt for sending) has the MIT-0 licence as a header segment by the way.
1
·
Feature Request
Proposal for fixing Audio Filters (eg low-pass) support for AVPro
I believe it is time to get a solution to the most plaguing issue (in my opinion) of AVPro: Audio Filters I do not think this is a "can't fix" situation. In this proposal I will go over the problem, considerations that have been discussed historically, and the solution I believe is feasible to implement with working sample code. ### Previous Cannys 1) https://feedback.vrchat.com/open-beta/p/986-avpro-player-ignores-lowpass-reverb-and-other-filters 2) https://feedback.vrchat.com/sdk-bug-reports/p/avpro-video-player-audio-filter-issue 3) https://feedback.vrchat.com/sdk-bug-reports/p/sound-effects-are-not-applied-to-audiosource-using-avpro-that-comes-with-sdk3 4) https://feedback.vrchat.com/feature-requests/p/usharpvideo-stream-audio-does-not-support-filters ### Crux of the issue As previously discussed in above canny #1, the current way of handling the AVPro speaker component (type named AudioOutput ) is that the component is implicitly created via AddComponent on the same game object. This has the critical drawback of being unable to respect any audio filters due to the DSP filter chain being _component order dependent_. The second half of this issue is that Unity has no runtime native way to change the ordering of components without fully reconstructing the references. This causes very obvious issues in regards to dependent scene references. (TCL's comment in canny #1 clarifies this as well) ### What has been considered Detecting and destroying/rebuilding known filter components after the implicit component is added. This is bad because all scene references to those components would be lost (eg: UI Events or public Udon variables). To avoid the lost components issue, a full scene search would be required in order to update the references which is costly and fragile. Placeholder components (shims) for each filter type that gets implicitly created after the implicit AudioOutput This is bad because it does not allow users to reference the actual filter components in the inspector (namely an issue for UI Events) Allow adding the AudioOutput script manually in scene and have the speaker search for it before trying to implicitly add the component. This is bad because it requires that the user import the AVProTrial package to be able to use built-in unity audio filters. This needs to be compatible with situations where the user does not wish to import that package so the dependency is decoupled from the feature itself. ### Proposed Solution A shim script that inherits from the AudioOutput class combined with a compiler flag for detecting if AVPro is present, and if not, then have a stub type of the _same namespace and type name_ which is _ONLY_ present in the sdk. Then update the VRCAVProVideoSpeaker to check for the existence of the shim component before creating an implicit AudioOutput, using it instead if found on the game object. This ensures that when the main shim script is loaded in editor, it is already a valid AudioOutput component and the component order is correctly retained so the Audio Filters will work correctly. In the SDK, the script type will check for the existence of AVPro through a version define, and if NOT present, will enable the AudioOutput stub class of the same namespace. An example of what it might be like: https://gist.github.com/techanon/41efc336604e148dde55862bff1778d9 I've tested this specific example in editor and it works there. Can't test in-client obviously.
24
·
tracked
Load More