vec3 localToWorld( vec3 _VERTEX, mat4 _MODEL_MATRIX ) { return ( _MODEL_MATRIX * vec4( _VERTEX, 1.0 ) ).xyz; } vec3 localToWorldDirection( vec3 _VERTEX, mat4 _MODEL_MATRIX ) { mat4 mw = _MODEL_MATRIX; mw[ 3 ][ 0 ] = 0.0; mw[ 3 ][ 1 ] = 0.0; mw[ 3 ][ 2 ] = 0.0; mw[ 3 ][ 3 ] = 1.0; return ( mw * vec4( _VERTEX, 1.0 ) ).xyz; } vec3 worldToLocal( vec3 _VERTEX, mat4 _MODEL_MATRIX ) { return ( inverse( _MODEL_MATRIX ) * vec4( _VERTEX, 1.0 ) ).xyz; } vec3 extractScale( mat3 _MODEL_NORMAL_MATRIX ) { mat3 m = _MODEL_NORMAL_MATRIX; float x = length( vec3( m[ 0 ][ 0 ], m[ 1 ][ 0 ], m[ 2 ][ 0 ] ) ); float y = length( vec3( m[ 0 ][ 1 ], m[ 1 ][ 1 ], m[ 2 ][ 1 ] ) ); float z = length( vec3( m[ 0 ][ 2 ], m[ 1 ][ 2 ], m[ 2 ][ 2 ] ) ); return vec3( x, y, z ); } vec2 tilingOffset( vec2 uv, vec4 tilingOffset ) { uv *= tilingOffset.xy; uv += tilingOffset.zw; return uv; } vec2 tilingOffsetRepeat( vec2 uv, vec4 tilingOffset ) { uv *= tilingOffset.xy; uv += tilingOffset.zw; return mod( uv, vec2(1,1) ); } vec3 billboardWorldOffset( vec2 _UV, mat4 _INV_VIEW_MATRIX, mat4 _MODEL_MATRIX ) { vec2 mappedUV = mix( vec2(-1,1), vec2( 1, -1 ), _UV ); vec4 offset = vec4( mappedUV.x, mappedUV.y, 0, 0 ); offset = _INV_VIEW_MATRIX * offset; mat4 mw = _MODEL_MATRIX; mw[ 3 ][ 0 ] = 0.0; mw[ 3 ][ 1 ] = 0.0; mw[ 3 ][ 2 ] = 0.0; vec3 worldOffset = worldToLocal( offset.xyz, mw ); worldOffset = normalize( worldOffset ); return worldOffset; } vec2 rotate_v2( vec2 uv, float angle ) { float s = sin( angle ); float c = cos( angle ); float x = uv.x; float y = uv.y; uv.x = c * x - s * y; uv.y = s * x + c * y; return uv; } vec2 rotateAround_v2( vec2 uv, float angle, vec2 pivot ) { uv -= pivot; uv = rotate_v2( uv, angle ); uv += pivot; return uv; } vec3 cameraWorldPosition( mat4 _INV_VIEW_MATRIX ) { return (_INV_VIEW_MATRIX * vec4(vec3(0.0), 1.0)).xyz; } vec3 cameraWorldForward( mat4 _INV_VIEW_MATRIX ) { vec3 pos = cameraWorldPosition( _INV_VIEW_MATRIX ); return normalize( (_INV_VIEW_MATRIX * vec4( vec3(0.0,0.0,1.0), 1.0)).xyz - pos ); }