Is it possible to create custom light node that use own created shader fragment?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Greetings maya forum!
Maya's native arealight can only render in rectangular shape in viewport. I want to create a custom area light that support various shape (sphere, round, cylinder, etc). I've gone through the documentation but it only says we can render custom light in viewport by specifing the classification as the same of native light.
I first tried registering a shading node and assign it a shader fragment XML (https://help.autodesk.com/view/MAYAUL/2023/ENU/?guid=Maya_SDK_Writing_a_Software_Shading_Node_Writin... in this page light seems to be a shading node) but failed to bind the override.
Then I find fragment manager can list and dump all non-hidden internal shader fragment- I found "mayaRectangleAreaLight3" is the one that calculate the irradiance of maya's native area light and I can override it to change maya's area light behavior.
<implementation render="OGSRenderer" language="HLSL" lang_version="11.000000" >
<function_name val="mayaRectAreaLight3" />
<source>
<![CDATA[
float3 LwAtMaxSpec( float3 ltPts[4], float3 ltCenter, float3 Pw, float3 Nw, float3 Vw )
{
float RL, RNl;
float3 L;
float3 R = reflect( -Vw, Nw );
const int nSampPerSide = 6;
float3 V = ( ltPts[1]-ltPts[0] ) / (nSampPerSide-1);
float3 U = ( ltPts[3]-ltPts[0] ) / (nSampPerSide-1);
float3 P0 = ltPts[0];
float3 maxL = float3(0,0,0);
float endSamp = nSampPerSide - 0.01f;
for( float u = 0; u < endSamp; u += 1.0f ) {
for( float v = 0; v < endSamp; v += 1.0f ) {
float3 LP = P0 + (u * U + v * V);
L = normalize( LP - Pw );
RL = dot( R, L );
if( RL > 0.0f ) maxL += RL * RL * L;
}
}
float d = length( maxL );
return ( d > 0.0f ) ? maxL/d : maxL;
}
float3 nearestPtOnLt( float3 ltPts[4], float3 ltCenter, float3 Pw )
{
float3 V = ( ltPts[1]-ltPts[0] );
float lenV = length( V );
V /= lenV; lenV *= 0.5;
float3 U = ( ltPts[3]-ltPts[0] );
float lenU = length( U );
U /= lenU; lenU *= 0.5f;
float3 L = Pw - ltCenter;
float LU = dot( L, U );
float LV = dot( L, V );
float3 Lw = ltCenter
+ U * clamp( LU, -lenU, lenU )
+ V * clamp( LV, -lenV, lenV );
return Lw;
}
irradiance mayaRectAreaLight3( float lightOn, bool lightActive, float intensity, float3 color, float emitDiff, float emitSpec,
float3 LP0, float3 LP1, float3 LP2, float3 LP3, float3 Pw, float3 Nw, float3 Vw,
float decayRate, bool useArea, int shape )
{
color = float3(0.0, 0.0, color.z);
float3 ltPts[4] = { LP3, LP2, LP1, LP0 };
float3 T = ddx( Pw );
float3 B = ddy( Pw );
float3 fN = normalize( cross( T, B ));
Nw = (dot( fN, Nw ) < 0.0f) ? -Nw : Nw;
float sumNG = 0;
for( int i = 0; i < 4; ++i ) {
int nextI = (i == 3)? 0 : (i+1);
float3 Li = normalize(ltPts[i] - Pw);
float3 Ln = normalize(ltPts[nextI] - Pw);
float3 Gi = normalize( cross(Ln, Li) );
float bi = acos( dot(Ln, Li) );
sumNG += bi * dot( Gi, Nw );
}
float ff = 6.0 * saturate( sumNG );
float3 ltCenter = (ltPts[0]+ltPts[1]+ltPts[2]+ltPts[3])/4.0f;
float3 Lp = nearestPtOnLt( ltPts, ltCenter, Pw );
float3 Ld = lerp( Lp, ltCenter, 0.35f ) - Pw;
float d = length( Ld ) + 1.0f;
float attn = 1.0f;
if( decayRate > 2.999f ) attn /= d; if( decayRate > 1.999f ) attn /= d; if( decayRate > 0.999f ) attn /= d;
float3 clr = lightOn * color * intensity * ff * attn;
if (useArea) {
float area = length(ltPts[1] - ltPts[0]) * length(ltPts[3] - ltPts[0]);
clr = clr / area;
}
irradiance irrad;
irrad.diffuseI = emitDiff * clr;
irrad.specularI = emitSpec * clr;
irrad.Ls = LwAtMaxSpec( ltPts, ltCenter, Pw, Nw, Vw );
irrad.Ld = normalize( Ld );
irrad.Lg = float4(0.0f, 0.0f, 0.0f, 1.0f);
irrad.lightType = 0x41524c54;
return irrad;
}
]]>
</source>
</implementation>
However, in order to implement multiple light shape I need to add more parameters to it and I cannot find a way to do that. The function is wrapped in <implementation render="OGSRenderer" ...> and I have no idea where is it being called.
FYI I'm using Maya2022. Appreciate for any suggestions!