disfigure
Version:
A library to rig non-rigged 3D models
186 lines (95 loc) • 3.64 kB
JavaScript
// disfigure
//
// Module to put clothes on bodies
//
// clothes.elements[0] = color
// clothes.elements[1] = (roughness, metalness)
// Trisha's Spontaneous Look
// https://www.instagram.com/reel/DMd39iqoMN2/
// "Is it really TSL if you can’t style it in different ways?"
import { Color } from "three";
import { float, Fn, If, mat3, mix, positionGeometry, rotate, vec2, vec3 } from "three/tsl";
// simple material based on color, roughness and metalness
var tslSimpleMaterial = Fn( ( { color, roughness, metalness } ) => {
return mat3(
color,
vec3( roughness, metalness, 0 ),
vec3( 0, 0, 0 )
);
}, { color: 'vec3', roughness: 'float', metalness: 'float', return: 'mat3' } ); // tslSimpleMaterial
// check whether a value is between two values
var between = Fn( ( { value, fromValue, toValue } ) => {
return value.greaterThanEqual( fromValue ).and( value.lessThanEqual( toValue ) );
}, { value: 'float', fromValue: 'float', toValue: 'float', return: 'float' } ); // between
// mix two mat3'savePreferences
var mixMat3 = Fn( ([ matA, matB, k ]) => {
return mat3(
mix( matA[ 0 ], matB[ 0 ], k ),
mix( matA[ 1 ], matB[ 1 ], k ),
vec3( 0, 0, 0 ),
);
}, { matA: 'mat3', matB: 'mat3', k: 'float', return: 'mat3' } ); // mixMat3
// convert Three.js color to vec3
var _color = new Color();
function toVec3( color ) {
_color.set( color );
return vec3( ..._color );
} // toVec3
// generates latex matrix
function latex( color ) {
return tslSimpleMaterial( toVec3( color ), 0.2, 0.3 );
} // latex
// generates velour matrix
function velour( color ) {
return tslSimpleMaterial( toVec3( color ).mul( 3 ), 1, 1 );
} // velour
// generates bands of two materials
var bands = Fn( ( { matA, matB, width=float( 0.1 ), options={} } ) => {
var { balance, blur, angle, polar, x, z } = options;
var k, p;
if ( polar ) {
p = positionGeometry.xz.sub( vec2( x??0, z??0 ) );
k = p.y.atan( p.x ).div( float( width ).mul( 2 ) ).cos();
} else {
p = rotate( positionGeometry.xy, ( angle??0 ) * Math.PI/180 );
k = p.y.div( width, 1/Math.PI ).cos();
}
if ( balance??0 ) k = k.add( balance );
blur = blur??0.00001;
if ( blur ) k = k.smoothstep( -blur, blur );
return mixMat3( matA, matB, k );
} ); // bands
// generates a slice through a body
var slice = Fn( ( { from, to, options={} } )=>{
var p = positionGeometry.toVar();
var axes = 'yxzyx',
idx = 0;
if ( options.side ) idx=1;
if ( options.front ) idx=2;
if ( options.angle ) p[ axes[ idx ] ].addAssign( p[ axes[ idx+1 ] ].mul( Math.tan( options.angle*Math.PI/180 ) ) );
if ( options.sideAngle ) p[ axes[ idx ] ].addAssign( p[ axes[ idx+2 ] ].mul( Math.tan( options.sideAngle*Math.PI/180 ) ) );
var value = p[ axes[ idx ] ];
if ( options.wave ) {
var w = p[ axes[ idx+1 ] ].mul( float( Math.PI ).div( options.width??Math.PI ) ).cos().toVar();
var dWave = float( options.sharpness??0 ).mix( w, w.acos().mul( -2/Math.PI ).sub( 1 ) ).mul( options.wave, 0.5 );
value = value.add( dWave );
}
if ( options.symmetry ) value = value.abs();
return between( value, from, to );
} ); // slice
var compileClothing = Fn( ([ clothingData ]) => {
var mat = mat3( clothingData[ 0 ]);
for ( /*MUST*/let i=1; i<clothingData.length; i+=2 ) {
If( clothingData[ i ], ()=>{
mat.assign( clothingData[ i+1 ]);
} );
}
return mat;
} );
export {
compileClothing,
slice,
bands,
velour,
latex,
};