This example demonstrates how to obtain existing shader code and customize it for a GLSL/CGFX environment in Maya, so that you can use it with ShaderFX in OpenGL mode. It then demonstrates how to customize the code for an HLSL environment, so that you can use it in DirectX 11 mode in Maya also.
The shader code used in this example is courtesy of Iñigo Quilez from https://www.shadertoy.com/view/ldB3zc. You can visit this site to obtain the following sample code and modify it for use in Maya.
A video demonstration of the following workflow is available. See Video tutorials below for more information.
float hash1( float n ) { return fract(sin(n)*43758.5453); } vec2 hash2( vec2 p ) { p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) ); return fract(sin(p)*43758.5453); } vec4 voronoi( in vec2 x, float w ) { vec2 n = floor( x ); vec2 f = fract( x ); vec4 m = vec4( 8.0, 0.0, 0.0, 0.0 ); for( int j=-2; j<=2; j++ ) for( int i=-2; i<=2; i++ ) { vec2 g = vec2( float(i),float(j) ); vec2 o = hash2( n + g ); // animate o = 0.5 + 0.5*sin( iGlobalTime + 6.2831*o ); // distance to cell float d = length(g - f + o); // do the smooth min for colors and distances vec3 col = 0.5 + 0.5*sin( hash1(dot(n+g,vec2(7.0,113.0)))*2.5 + 3.5 + vec3(2.0,3.0,0.0)); float h = smoothstep( 0.0, 1.0, 0.5 + 0.5*(m.x-d)/w ); m.x = mix( m.x, d, h ) - h*(1.0-h)*w/(1.0+3.0*w); // distance m.yzw = mix( m.yzw, col, h ) - h*(1.0-h)*w/(1.0+3.0*w); // cioloe } return m; } void main( void ) { vec2 p = gl_FragCoord.xy/iResolution.yy; float k = 2.0 + 70.0 * pow( 0.5 + 0.5*sin(0.25*6.2831*iGlobalTime), 4.0 ); k = 0.5 - 0.5*cos(0.25*6.2831*iGlobalTime); vec4 c = voronoi( 6.0*p, k ); vec3 col = c.yzw; col *= 1.0 - 0.8*c.x*step(p.y,0.33); col *= mix(c.x,1.0,step(p.y,0.66)); col *= smoothstep( 0.005, 0.007, abs(p.y-0.33) ); col *= smoothstep( 0.005, 0.007, abs(p.y-0.66) ); gl_FragColor = vec4( col, 1.0 ); }
To modify the code so that it is compatible with SFX_GLSL_*/SFX_CGFX_3 so that you can use it with ShaderFX in OpenGL mode in Maya, do as follows:
gl_FragCoord.xy is a global variable used in GLSL to obtain texture co-ordinates. In Maya, you use a UV set to obtain the texture co-ordinates.
Change main (void) to a function definition, similar to the one provided by default with the Custom Code node:
CustomCode1178Output CustomCode1178Func( float2 UV )
struct CustomCode1178Output { float3 color; };
Replace iGlobalTime with time.
Add float time to the function definition as an input parameter.
Add float time to the voronoi function definition as an input parameter.
Add time as an input parameter where voronoi is called.
CustomCode1178Output OUT; OUT.color = col; return OUT;
The modified code is as follows:
float VoronoiSmooth_hash1( float n ) { return fract(sin(n)*43758.5453); } float2 VoronoiSmooth_hash2( float2 p ) { p = float2( dot(p,float2(127.1,311.7)), dot(p,float2(269.5,183.3)) ); return fract(sin(p)*43758.5453); } float4 VoronoiSmooth( in float2 x, float w, float time ) { float2 n = floor( x ); float2 f = fract( x ); float4 m = float4( 8.0, 0.0, 0.0, 0.0 ); for( int j=-2; j<=2; j++ ) for( int i=-2; i<=2; i++ ) { float2 g = float2( float(i),float(j) ); float2 o = VoronoiSmooth_hash2( n + g ); // animate o = 0.5 + 0.5*sin( time + 6.2831*o ); // distance to cell float d = length(g - f + o); // do the smooth min for colors and distances float3 col = 0.5 + 0.5*sin( VoronoiSmooth_hash1(dot(n+g,float2(7.0,113.0)))*2.5 + 3.5 + float3(2.0,3.0,0.0)); float h = smoothstep( 0.0, 1.0, 0.5 + 0.5*(m.x-d)/w ); m.x = mix( m.x, d, h ) - h*(1.0-h)*w/(1.0+3.0*w); // distanec m.yzw = mix( m.yzw, col, h ) - h*(1.0-h)*w/(1.0+3.0*w); // cioloe } return m; } struct VoronoiSmoothOutput { float3 color; }; VoronoiSmoothOutput VoronoiSmoothFunc( float2 UV, float time ) { float2 p = UV; float k = 2.0 + 70.0 * pow( 0.5 + 0.5*sin(0.25*6.2831*time), 4.0 ); k = 0.5 - 0.5*cos(0.25*6.2831*time); float4 c = VoronoiSmooth( 6.0*p, k, time ); float3 col = c.yzw; col *= 1.0 - 0.8*c.x*step(p.y,0.33); col *= mix(c.x,1.0,step(p.y,0.66)); col *= smoothstep( 0.005, 0.007, abs(p.y-0.33) ); col *= smoothstep( 0.005, 0.007, abs(p.y-0.66) ); VoronoiSmoothOutput OUT; OUT.color = col; return OUT; }
You can now use this code for your custom code node. Connect it as follows, and witness its animation in both the ShaderFX editor and in Viewport 2.0 OpenGL mode.
If you create the same ShaderFX network in DirectX 11 mode, and then try to perform swatch rendering, you will not be able to compile the shader swatch. To help debug, select Settings > Show Swatch Compile Errors and inspect the errors that appear.
To modify the code so that it is compatible with SFX_HLSL_3/SFX_HLSL_5 so that you can use it with ShaderFX in DirectX 11 mode in Maya, do as follows:
#if ( defined(SFX_HLSL_3) || defined( SFX_HLSL_5) ) #define fract frac #define mix lerp #endif
The modified code is as follows:
#if ( defined(SFX_HLSL_3) || defined( SFX_HLSL_5) ) #define fract frac #define mix lerp #endif float VoronoiSmooth_hash1( float n ) { return fract(sin(n)*43758.5453); } float2 VoronoiSmooth_hash2( float2 p ) { p = float2( dot(p,float2(127.1,311.7)), dot(p,float2(269.5,183.3)) ); return fract(sin(p)*43758.5453); } float4 VoronoiSmooth( in float2 x, float w, float time ) { float2 n = floor( x ); float2 f = fract( x ); float4 m = float4( 8.0, 0.0, 0.0, 0.0 ); for( int j=-2; j<=2; j++ ) for( int i=-2; i<=2; i++ ) { float2 g = float2( float(i),float(j) ); float2 o = VoronoiSmooth_hash2( n + g ); // animate o = 0.5 + 0.5*sin( time + 6.2831*o ); // distance to cell float d = length(g - f + o); // do the smooth min for colors and distances float3 col = 0.5 + 0.5*sin( VoronoiSmooth_hash1(dot(n+g,float2(7.0,113.0)))*2.5 + 3.5 + float3(2.0,3.0,0.0)); float h = smoothstep( 0.0, 1.0, 0.5 + 0.5*(m.x-d)/w ); m.x = mix( m.x, d, h ) - h*(1.0-h)*w/(1.0+3.0*w); // distanec m.yzw = mix( m.yzw, col, h ) - h*(1.0-h)*w/(1.0+3.0*w); // cioloe } return m; } struct VoronoiSmoothOutput { float3 color; }; VoronoiSmoothOutput VoronoiSmoothFunc( float2 UV, float time ) { float2 p = UV; float k = 2.0 + 70.0 * pow( 0.5 + 0.5*sin(0.25*6.2831*time), 4.0 ); k = 0.5 - 0.5*cos(0.25*6.2831*time); float4 c = VoronoiSmooth( 6.0*p, k, time ); float3 col = c.yzw; col *= 1.0 - 0.8*c.x*step(p.y,0.33); col *= mix(c.x,1.0,step(p.y,0.66)); col *= smoothstep( 0.005, 0.007, abs(p.y-0.33) ); col *= smoothstep( 0.005, 0.007, abs(p.y-0.66) ); VoronoiSmoothOutput OUT; OUT.color = col; return OUT; }
After you have created a Custom Code node using the code above, you can create a network such as the one below.
For more details about creating groups and using the Default Value node, see Provide alternative inputs to the group node and label the group node ports.
In this example, we provide a default UV set and a default time node, while allowing the user to provide an alternate UV set.
Watch the following videos for a visual demonstration of the above example workflow: