Open-source project
d4rkc0d3r/d4rkAvatarOptimizer avatar
d4rkc0d3r/d4rkAvatarOptimizer

d4rkAvatarOptimizer trades shader behaviour for fewer draw calls

d4rkpl4y3r's VRChat Avatar 3.0 optimizer

617 stars34 forksC#MIT

At a glance

What is it?
d4rkAvatarOptimizer is a Unity package from d4rkc0d3r that reduces the skinned mesh and material count of a VRChat avatar before upload, with presets that range from behaviour preserving to behaviour changing. The interesting part is that the aggressive savings come from rewriting shaders, and the documentation is honest about what breaks.
Who is it for?
d4rkAvatarOptimizer suits VRChat creators whose avatars exceed the triangle or material budget and who are willing to test the result in game, and it suits anyone comfortable reading shader code when a material renders pink. It does not suit creators who need their avatar to behave identically under every shader combination, and it does not suit creators who use non-destructive tooling such as VRCFury or ModularAvatar on the old copy workflow.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

It runs on upload, so the scene you edit stays untouched

The usage model is short. You add the d4rkAvatarOptimizer component to your avatar, on any transform, and the optimizations are applied automatically before upload with the default settings. The apply on upload option is described as non destructive, because the avatar in your scene stays as it is. That design decision removes the usual anxiety of an optimization tool, which is that you no longer have the original. There is a second path, a Create Optimized Copy button that produces a new avatar with optimized materials and meshes so you can test in the editor before uploading, and the author explicitly advises against it because it cannot work properly with non destructive tooling such as VRCFury or ModularAvatar. That recommendation is worth taking seriously if your avatar is assembled with those tools, since an optimizer that rewrites materials and merges meshes will happily destroy the setup those tools rely on. The package itself is a Unity package, and the manifest shows the version it targets and the VRChat package it depends on.

json
  "name": "d4rkpl4y3r.d4rkavataroptimizer",
  "version": "4.7.0-beta.0",
  "unity": "2022.3",

The vpmDependencies section of the same manifest pins the VRChat avatar package to >=3.9.0 <4.0.0-a, so an installation will refuse to resolve against a VRChat SDK outside that range.

The Standard preset removes what nothing reads

The Standard preset only uses optimizations that do not affect the behaviour of the avatar, with some exceptions documented separately. What it removes is unused components, blend shapes and bones from skinned meshes, and it bakes non animated blend shapes into the mesh. It then merges all skinned meshes that are always animated in the same way, and merges material slots that use the same material, except slots affected by material swap animations. Two further merges handle the animation side: toggles in the FX layer are merged into a direct blend tree, and blend shapes that are always animated in the same ratio to each other are merged. The guiding principle is visible in every line. If two things are always animated identically, they can be one thing, and if nothing reads a component, it can go. That is why the recommendation for an avatar over 150k triangles with many materials is the Standard preset, with shader and NaNimation toggles avoided because merging too many meshes could cause performance regressions. The trade-off is that the preset leaves performance on the table when the avatar is large, because merging is where the win is and merging is where the risk is.

Shader Toggles buys draw calls by rewriting the shader

The Shader Toggles preset uses everything Standard does plus optimizations that change how the shaders behave. For this mode the documentation says you should keep shaders unlocked, since that allows for more merging. Meshes can be merged even if they are animated or toggled differently, because logic is injected into the shaders to hide and reveal them. Materials with the same shader are merged even when their properties differ, and a generalized version of lock in is applied to the new shaders. The cost is stated plainly: because of the added shader logic this preset slightly increases the GPU cost of the avatar as a trade off for fewer draw calls. You are trading per frame GPU work for a lower draw call count, which is the right trade on some hardware and the wrong one on others. The documentation also predicts the behaviour changes to expect, reduced where NaNimation toggles are involved. World effects that rely on projectors or shader replacement do not understand shader toggles and will show the merged meshes as always visible, with wire frame shaders and screen space ambient occlusion given as examples.

The Aggressive preset is documented as quality damaging

The third preset is named for what it does. Some of the settings used in the Aggressive mode compromise the quality of the avatar heavily when animations or shaders are blocked, and it contains more experimental and more behaviour changing options. The guidance for using it is not subtle: testing that the avatar still works as intended is very necessary in this mode, and if it does not work correctly the recommendation is to switch to a lower optimization preset. That is a different posture from the other two, which are presented as tuning choices. Aggressive is presented as a thing you try, break, and back out of. The pattern across all three presets is that the further you move from Standard, the more of your avatar's behaviour becomes conditional on the state of the shader and the animation graph at a given moment. Blocked shaders, projectors, penetrators and shader replacement effects are the places where that conditionality shows up first, which is why the Aggressive mode carries the strongest testing requirement.

Pink shaders come from shader authors, and there is a fallback

The project has a dedicated section on shaders rendering pink, and its explanation is direct: shaders can do a lot of weird things, therefore the optimizer is bound to fail on some of them. The suggestions are three. Use different shaders, with Poiyomi Toon, Silent Crosstone and ACLS named as options. Use the Standard preset, which causes the optimizer not to touch the shaders at all. Or use the Exclusions foldout to manually exclude only the meshes that are broken. There is also guidance for the other direction of the relationship. Shader authors are pointed to a Guidelines for Shader Authors document so they can make their shaders compatible with the optimizer. The in-game symptom to watch for is specific: with blocked shaders, all merged meshes that now rely on shader toggles are always visible, and the documentation singles out DPS and TPS penetrators as the thing to check. The optimizer tries to detect and exclude them, and if that fails you need to exclude them manually. There is also an in-game check available, opening the action menu, then Options, then Avatar, then Fallback Shaders.

Write Properties as Static Values is where NaNs bite

One option deserves its own warning because it operates on the shader source rather than on the mesh graph. Write Properties as Static Values is similar to what some shaders call locking in or baking, and the documentation says you should disable the locking in or baking feature of your own shader if you use it, with one exception for materials that use the Rename Animated feature, which should stay locked in. What it does mechanically is replace uniform parameter definitions with a static value on all materials, so a uniform declaration becomes a static declaration with an initial value. The reason to do it is that it lets the shader compiler do more constant folding and therefore makes the shader run faster. The reason it can go wrong is unusually specific: the shader compiler is allowed to ignore NaNs while doing that, so if a shader was not written with that in mind it might cause issues. A shader that produces a NaN in a branch that constant folding changes can therefore behave differently after the optimization, and the failure will look like a rendering bug rather than a compile error. This is the option to try last and to undo first when something breaks.

A beta release cadence, MIT licence, and a documented bug report path

The release history shows a project moving quickly. Version 4.5.4 was tagged on 2026-07-31, 4.6.0 on 2026-09-16, and 4.7.0-beta.0 on 2026-10-19, with the last push to the main branch a few days after that beta tag. The repository is not archived, so the work is current, and the current package version in package.json is 4.7.0-beta.0. Note the beta tag on the newest release, because a beta in a Unity package can behave differently from a stable one and the presets are exactly the kind of feature that changes between versions. The licence is MIT, which permits reuse and modification with the notice retained and no warranty, and that matters for a package that rewrites other people's assets inside their project. The bug report path is unusually well defined. Open the settings button on the optimizer component, click the button with the open folder icon, and a trash bin folder opens with a _TrashBin.zip file selected, containing the generated animation controllers, materials, shaders and the log file of the optimization. Attaching that file to an issue gives the maintainer exactly what is needed to reproduce.

Editorial conclusion

d4rkAvatarOptimizer suits VRChat creators whose avatars exceed the triangle or material budget and who are willing to test the result in game, and it suits anyone comfortable reading shader code when a material renders pink. It does not suit creators who need their avatar to behave identically under every shader combination, and it does not suit creators who use non-destructive tooling such as VRCFury or ModularAvatar on the old copy workflow. Before adopting it, install it through VCC with the custom repository, run the Standard preset first, then compare the in-game fallback shaders view against your original avatar before switching to Shader Toggles.

Frequently asked questions

How do I install d4rkAvatarOptimizer?

Add the url https://d4rkc0d3r.github.io/vpm-repos/main.json as a custom repository in VCC, follow the redirect link, allow it to open with VCC, and confirm the repository in the popup. After that the optimizer can be added and updated like any other package in your VCC projects.

Which preset should I use for my VRChat avatar?

The documentation recommends the Standard preset for avatars over 150k triangles or with many materials, and the Shader Toggles preset for avatars under 150k triangles with a moderate number of materials. The Aggressive preset is for experimentation and needs testing.

Does d4rkAvatarOptimizer modify my avatar in the scene?

No. The apply on upload behaviour is non destructive and the avatar in your scene stays as it is. The older Create Optimized Copy workflow does produce a separate copy, and the author advises against it because it cannot work properly with non destructive tooling such as VRCFury or ModularAvatar.

Why do my shaders turn pink after optimization?

Shaders can do unusual things, so the optimizer is bound to fail on some of them. The documented options are to use a different shader, to switch to the Standard preset which does not touch shaders, or to exclude the broken meshes through the Exclusions foldout.

How do I report a bug in d4rkAvatarOptimizer?

Open the trash bin folder from the optimizer component settings and attach the _TrashBin.zip file it contains, which holds the generated animation controllers, materials, shaders and the optimization log, to an issue on the issue tracker.

Official sources

  1. d4rkc0d3r/d4rkAvatarOptimizer on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/d4rkc0d3r-d4rkavataroptimizer.svg)](https://hysenlabs.com/projects/d4rkc0d3r-d4rkavataroptimizer)

Was this useful?