Adjusting VRM MToon material outline thickness in three-vrm. Covers outline width modes, property access, and how to fix outlines that appear too thick when models are scaled.
58
66%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./.agent/skills/vrm-mtoon-outline/SKILL.mdThis skill covers how to adjust outline thickness for VRM models using MToon materials in @pixiv/three-vrm.
MToon materials have two main outline width modes:
| Mode | Description | Behavior |
|---|---|---|
'worldCoordinates' | Outline width is a physical world-space size | Outline appears thicker when model is scaled up or camera is closer |
'screenCoordinates' | Outline width is relative to screen pixels | Outline stays consistent size regardless of zoom/scale |
material.outlineWidthMode // 'none' | 'worldCoordinates' | 'screenCoordinates'
material.outlineWidthFactor // Number - the actual width value
material.isMToonMaterial // Boolean - true for MToon materials
material.needsUpdate // Set to true after modifying propertiesTo make outlines stay consistent regardless of zoom/scale:
function adjustOutlineThickness(vrm, screenFactor = 0.005) {
vrm.scene.traverse((object) => {
if (object.isMesh || object.isSkinnedMesh) {
const materials = Array.isArray(object.material) ? object.material : [object.material];
materials.forEach(material => {
if (!material || !material.isMToonMaterial) return;
// Check if this material has outlines enabled
const hasOutline = material.outlineWidthFactor > 0 &&
material.outlineWidthMode !== 'none';
if (hasOutline) {
// Switch to screen coordinates mode
material.outlineWidthMode = 'screenCoordinates';
material.outlineWidthFactor = screenFactor;
material.needsUpdate = true;
}
});
}
});
}For screenCoordinates mode:
| Factor Value | Approximate Effect |
|---|---|
0.002 - 0.003 | Very thin outline (1 pixel) |
0.005 | Thin outline (1-2 pixels) |
0.01 | Medium outline (2-3 pixels) |
0.02+ | Thick outline |
To diagnose outline issues, log all materials:
function debugOutlineMaterials(vrm) {
let count = 0;
vrm.scene.traverse((object) => {
if (!object.isMesh && !object.isSkinnedMesh) return;
const materials = Array.isArray(object.material) ? object.material : [object.material];
materials.forEach(material => {
if (material?.isMToonMaterial || 'outlineWidthFactor' in material) {
count++;
console.log({
name: material.name || '未命名',
type: material.type,
isMToonMaterial: material.isMToonMaterial,
outlineWidthMode: material.outlineWidthMode,
outlineWidthFactor: material.outlineWidthFactor
});
}
});
});
console.log(`Found ${count} MToon/Outline materials`);
}[!IMPORTANT] Call timing matters! The function must be called AFTER
currentModelis set. Invrm-core.js, theloadModel()function setsmanager.currentModelnear line 923. Any function that accessescurrentModelmust be called after this point.
[!NOTE] Materials named
"XXX (Outline)"are outline pass materials automatically created by three-vrm. They share properties with the main material but render the outline effect.
The enum values for outlineWidthMode:
// From three-vrm.module.min.js
{
None: "none",
WorldCoordinates: "worldCoordinates",
ScreenCoordinates: "screenCoordinates"
}| Property | Type | Description |
|---|---|---|
outlineWidthMode | string | Width calculation mode |
outlineWidthFactor | number | Width value (meaning depends on mode) |
outlineColorFactor | Color | Outline color |
outlineLightingMixFactor | number | How much lighting affects outline |
outlineWidthMultiplyTexture | Texture | Texture to modulate outline width |
c6f1797
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.