Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HYDRA-1329 : Support dome lights in the GLSL shader and add a unit te… #229

Merged
merged 2 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,111 @@ BasicLightingCoeffs computeLightingCoefficients(vec3 L, vec3 N, vec3 V, float ex
return coeffs;
}

//To support dome lights
struct LightingContributions
{
vec3 diffuse;
vec3 specular;
};

mat4 GetDomeLightTransform(mat4 worldToLightTransform)
{
// transform from view space to light space
mat4 worldToViewInverse = GetWorldToViewInverseMatrix();
return worldToLightTransform * worldToViewInverse;
}

#define PI 3.1415
vec2 ProjectToLatLong(vec3 sample3D)
{
// project spherical coord onto latitude-longitude map with
// latitude: +y == pi/2 and longitude: +z == 0, +x == pi/2
float x = (atan(sample3D.z, sample3D.x) + 0.5 * PI) / (2.0 * PI);
float y = acos(sample3D.y) / PI;

return vec2(x,y);
}

LightingContributions
evaluateIndirectLighting(
vec3 diffuseColor,
vec3 specularColor,
vec3 Neye,
vec3 Reye,
float NdotE,
float EdotH,
float ior,
float metallic,
float occlusion,
float roughness,
bool useSpecularWorkflow,
float clearcoatAmount,
vec3 clearcoatColor,
float clearcoatRoughness,
mat4 worldToLightTransform)
{
LightingContributions indirect;
indirect.diffuse = vec3(0.0);
indirect.specular = vec3(0.0);

#ifdef HD_HAS_domeLightIrradiance
vec3 F0 = specularColor;
vec3 F90 = vec3(1.0);
vec3 d = diffuseColor;
const float R = (1.0 - ior) / (1.0 + ior);
if (!useSpecularWorkflow) {
vec3 specColor = mix(vec3(1.0), diffuseColor, metallic);
F0 = mix(R * R * specColor, specColor, metallic);
F90 = specColor;

// For metallic workflows, pure metals have no diffuse
d *= 1.0 - metallic;
}
// Adjust the diffuse so glazing angles have less diffuse
float fresnel = pow(max(0.0, 1.0 - EdotH), 5.0);//SchlickFresnel
vec3 F = mix(F0, F90, fresnel);
d *= (1.0 - F);

mat4 transformationMatrix = GetDomeLightTransform(worldToLightTransform);

// Diffuse Component
vec3 dir = normalize((transformationMatrix * vec4(Neye,0.0)).xyz);
vec2 coord = ProjectToLatLong(dir);
vec3 diffuse = HdGet_domeLightIrradiance(coord).rgb;

// Specular Component
const float MAX_REFLECTION_LOD =
textureQueryLevels(HdGetSampler_domeLightPrefilter());
float lod = roughness * MAX_REFLECTION_LOD;
vec3 Rdir = normalize((transformationMatrix * vec4(Reye,0.0)).xyz);
vec2 Rcoord = ProjectToLatLong(Rdir);
vec3 prefilter = HdTextureLod_domeLightPrefilter(Rcoord, lod).rgb;

vec2 brdf = HdGet_domeLightBRDF(vec2(NdotE, roughness)).rg;

vec3 specular = prefilter * (F * brdf.x + brdf.y);

// Clearcoat Component
vec3 clearcoat = vec3(0.0);
if (clearcoatAmount > 0.0) {
const vec3 clearcoatF = clearcoatAmount * mix(
R * R * clearcoatColor, // Clearcoat F0
clearcoatColor, // Clearcoat F90
fresnel);
lod = clearcoatRoughness * MAX_REFLECTION_LOD;
prefilter = HdTextureLod_domeLightPrefilter(Rcoord, lod).rgb;
clearcoat = prefilter * (clearcoatF * brdf.x + brdf.y);
}

// Indirect Lighting
indirect.diffuse = (d * diffuse) * occlusion;
indirect.specular = (specular + clearcoat) * occlusion;

#endif

return indirect;
}

vec4
surfaceShader(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord)
{
Expand All @@ -89,34 +194,65 @@ surfaceShader(vec4 Peye, vec3 Neye, vec4 color, vec4 patchCoord)

vec3 n = Neye;
vec3 e = normalize(-Peye.xyz);

vec3 directLight = vec3(0.0);
vec3 indirectLight = vec3(0.0);//For dome light
float glossiness = 30.0;//Hardcoded
float ior = 1.5; //Hardcoded
float metallic = 0.0;//Hardcoded
float occlusion = 1.0;//Hardcoded
bool useSpecularWorkflow = true;//Hardcoded
float clearcoatAmount = 0.0;//Hardcoded
vec3 clearcoatColor = vec3(1.0);//Hardcoded
float clearcoatRoughness = 0.01;//Hardcoded

//Do basic lighting
//Do lighting (with no shadows)
#if NUM_LIGHTS > 0
for (int i = 0; i < NUM_LIGHTS; ++i)
{
LightSource light = GetLightSource(i);
if (!light.isIndirectLight)
{
vec4 Plight = light.position;
vec3 l = (Plight.w == 0.0)
? normalize(Plight.xyz)
: normalize(Plight - Peye).xyz;
LightSource light = GetLightSource(i);
vec4 Plight = light.isIndirectLight //light.isIndirectLight is true for dome light.
? vec4(0,0,0,1)
: light.position;

vec3 l = (Plight.w == 0.0)
? normalize(Plight.xyz)
: normalize(Plight - Peye).xyz;

float atten = lightDistanceAttenuation(Peye, i);
float spot = lightSpotAttenuation(l, i);
float atten = lightDistanceAttenuation(Peye, i);
float spot = lightSpotAttenuation(l, i);

float intensity = 1.0 * atten * spot;
float intensity = 1.0 * atten * spot;

vec3 lightDiffuseIrradiance = intensity * light.diffuse.rgb;
vec3 lightSpecularIrradiance = intensity * light.specular.rgb;
vec3 lightDiffuseIrradiance = intensity * light.diffuse.rgb;
vec3 lightSpecularIrradiance = intensity * light.specular.rgb;

BasicLightingCoeffs coeffs = computeLightingCoefficients(l, n, e, glossiness);
directLight += (light.ambient.rgb *ambientColor + lightDiffuseIrradiance * coeffs.diffuse * diffuseColor + lightSpecularIrradiance * coeffs.specular * specularColor);
BasicLightingCoeffs coeffs = computeLightingCoefficients(l, n, e, glossiness);

if (light.isIndirectLight) {
float NdotE = max(0.0, dot(n, e));
vec3 Reye = reflect(-e, n);

vec3 h = normalize(e + l);
float NdotL = max(0.0, dot(n, l));
float NdotH = max(0.0, dot(n, h));
float EdotH = max(0.0, dot(e, h));
// Calculate the indirect light (DomeLight)
LightingContributions indirectLightContrib =
evaluateIndirectLighting(diffuseColor, specularColor,
Neye, Reye, NdotE, EdotH, ior, metallic, occlusion,
glossiness, useSpecularWorkflow,
clearcoatAmount, clearcoatColor, clearcoatRoughness,
light.worldToLightTransform);
indirectLight += (indirectLightContrib.diffuse * light.diffuse.rgb
+ indirectLightContrib.specular * light.specular.rgb);
}
else {
// All other light sources contribute to the direct lighting
directLight += (light.ambient.rgb *ambientColor + lightDiffuseIrradiance * coeffs.diffuse * diffuseColor + lightSpecularIrradiance * coeffs.specular * specularColor);
}
}
#endif

return vec4(directLight, 1.0);
return vec4(directLight+indirectLight, 1.0);
}
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 15 additions & 2 deletions test/lib/mayaUsd/render/mayaToHydra/testCustomShadersNode.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,34 @@
import mtohUtils
import mayaUtils
from testUtils import PluginLoaded
import platform

class TestCustomShadersNode(mtohUtils.MayaHydraBaseTestCase): #Subclassing mtohUtils.MayaHydraBaseTestCase to be able to call self.assertSnapshotClose
# MayaHydraBaseTestCase.setUpClass requirement.
_file = __file__

IMAGE_DIFF_FAIL_THRESHOLD = 0.01
IMAGE_DIFF_FAIL_PERCENT = 0.1
@property
def IMAGE_DIFF_FAIL_PERCENT(self):
if platform.system() == "Darwin":
return 3
return 2 #We have errors on Windows and Linux of about 1%, so we need to increase the threshold

def test_LoadCustomShaderNode(self):
with PluginLoaded('mayaHydraCustomShadersNode'):
testFile = mayaUtils.openTestScene(
"testCustomShadersNode",
"testCustomShadersNode.ma")
cmds.refresh()
self.assertSnapshotClose("testCustomShadersNode.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT)
self.assertSnapshotClose("testCustomShadersNodeDefaultLight.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT)

# Switch the lighting mode to use all scene lights.
cmds.modelEditor(mayaUtils.activeModelPanel(), edit=True, displayLights = 'all')
self.assertSnapshotClose("testCustomShadersNodeUseAllLights.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT)

#Remove the direct lighting to check if the dome light works fine
cmds.setAttr("pointLightShape1.intensity", 0);
self.assertSnapshotClose("testCustomShadersNodeDomeLightOnly.png", self.IMAGE_DIFF_FAIL_THRESHOLD, self.IMAGE_DIFF_FAIL_PERCENT)

if __name__ == '__main__':
fixturesUtils.runTests(globals())
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading