From 8b9d073991838af875ffe3889167e8d168cdbb3b Mon Sep 17 00:00:00 2001 From: Keunhong Park Date: Thu, 22 Aug 2019 16:13:18 -0700 Subject: [PATCH 1/2] Fix SpecularGlossinessMaterial --- pyrender/material.py | 6 +- pyrender/mesh.py | 29 +++++- pyrender/renderer.py | 2 +- pyrender/shaders/mesh.frag | 206 ++++++++++++++++++++++++++++++------- 4 files changed, 198 insertions(+), 45 deletions(-) diff --git a/pyrender/material.py b/pyrender/material.py index 3ce9c2d..d97484d 100644 --- a/pyrender/material.py +++ b/pyrender/material.py @@ -659,12 +659,12 @@ def specularFactor(self, value): def glossinessFactor(self): """float : The glossiness of the material. """ - return self.glossinessFactor + return self._glossinessFactor @glossinessFactor.setter def glossinessFactor(self, value): - if value < 0 or value > 1: - raise ValueError('glossiness factor must be in range [0,1]') + if value < 0: + raise ValueError('glossiness factor must be non-zero') self._glossinessFactor = float(value) @property diff --git a/pyrender/mesh.py b/pyrender/mesh.py index ad26a7f..dc67442 100644 --- a/pyrender/mesh.py +++ b/pyrender/mesh.py @@ -5,10 +5,11 @@ """ import numpy as np import trimesh +import trimesh.visual from .primitive import Primitive from .constants import GLTF -from .material import MetallicRoughnessMaterial +from .material import MetallicRoughnessMaterial, SpecularGlossinessMaterial class Mesh(object): @@ -305,9 +306,31 @@ def _get_trimesh_props(mesh, smooth=False): alphaCutoff=mat.alphaCutoff ) elif isinstance(mat, trimesh.visual.texture.SimpleMaterial): - material = MetallicRoughnessMaterial( + glossiness = mat.kwargs.get('Ns', 1.0) + if isinstance(glossiness, list): + glossiness = float(glossiness[0]) + roughness = (2 / (glossiness + 2)) ** (1.0/4.0) + # material = MetallicRoughnessMaterial( + # alphaMode='BLEND', + # roughnessFactor=roughness, + # baseColorTexture=mat.image, + # baseColorFactor=rgba_to_float(mat.diffuse), + # ) + material = SpecularGlossinessMaterial( alphaMode='BLEND', - baseColorTexture=mat.image + diffuseTexture=mat.image, + emissiveFactor=rgba_to_float(mat.ambient), + diffuseFactor=rgba_to_float(mat.diffuse), + specularFactor=rgba_to_float(mat.specular), + glossinessFactor=glossiness, + doubleSided=True, ) return colors, texcoords, material + + +def rgba_to_float(rgba): + if rgba is None: + return None + + return rgba.astype(np.float) / 255.0 diff --git a/pyrender/renderer.py b/pyrender/renderer.py index 3c015d1..8c3919a 100644 --- a/pyrender/renderer.py +++ b/pyrender/renderer.py @@ -949,7 +949,7 @@ def _get_primitive_program(self, primitive, flags, program_flags): defines['HAS_SPECULAR_GLOSSINESS_TEX'] = 1 if isinstance(primitive.material, MetallicRoughnessMaterial): defines['USE_METALLIC_MATERIAL'] = 1 - elif isinstance(material, SpecularGlossinessMaterial): + elif isinstance(primitive.material, SpecularGlossinessMaterial): defines['USE_GLOSSY_MATERIAL'] = 1 program = self._program_cache.get_program( diff --git a/pyrender/shaders/mesh.frag b/pyrender/shaders/mesh.frag index ff3ed7c..3698159 100644 --- a/pyrender/shaders/mesh.frag +++ b/pyrender/shaders/mesh.frag @@ -177,7 +177,7 @@ vec3 get_normal() #ifdef NORMAL_LOC vec3 ng = normalize(frag_normal); #else - vec3 = cross(pos_dx, pos_dy); + vec3 ng = cross(pos_dx, pos_dy); #endif t = normalize(t - ng * dot(ng, t)); @@ -262,6 +262,25 @@ vec3 compute_brdf(vec3 n, vec3 v, vec3 l, return color; } + +vec3 compute_blinn_phong_brdf(vec3 n, vec3 v, vec3 l, float glossiness, + vec3 diffuse, vec3 specular, vec3 radiance) +{ + vec3 h = normalize(l+v); + float nl = clamp(dot(n, l), 0.001, 1.0); + float nv = clamp(abs(dot(n, v)), 0.001, 1.0); + float nh = clamp(dot(n, h), 0.0, 1.0); + float lh = clamp(dot(l, h), 0.0, 1.0); + float vh = clamp(dot(v, h), 0.0, 1.0); + + vec3 diffuse_contrib = diffuse * nl / PI; + vec3 spec_contrib = specular * pow(nh, glossiness); + + vec3 color = radiance * (diffuse_contrib + spec_contrib); + return color; +} + + float texture2DCompare(sampler2D depths, vec2 uv, float compare) { return compare > texture(depths, uv.xy).r ? 1.0 : 0.0; } @@ -308,26 +327,19 @@ float shadow_calc(mat4 light_matrix, sampler2D shadow_map, float nl) return shadow; } -/////////////////////////////////////////////////////////////////////////////// -// MAIN -/////////////////////////////////////////////////////////////////////////////// -void main() -{ - vec4 color = vec4(vec3(0.0), 1.0); -/////////////////////////////////////////////////////////////////////////////// -// Handle Metallic Materials -/////////////////////////////////////////////////////////////////////////////// #ifdef USE_METALLIC_MATERIAL +vec4 compute_metallic_color() { + vec4 color = vec4(vec3(0.0), 1.0); // Compute metallic/roughness factors float roughness = material.roughness_factor; float metallic = material.metallic_factor; -#ifdef HAS_METALLIC_ROUGHNESS_TEX + #ifdef HAS_METALLIC_ROUGHNESS_TEX vec2 mr = texture(material.metallic_roughness_texture, uv_0).rg; roughness = roughness * mr.r; metallic = metallic * mr.g; -#endif + #endif roughness = clamp(roughness, min_roughness, 1.0); metallic = clamp(metallic, 0.0, 1.0); // In convention, material roughness is perceputal roughness ^ 2 @@ -335,9 +347,9 @@ void main() // Compute albedo vec4 base_color = material.base_color_factor; -#ifdef HAS_BASE_COLOR_TEX + #ifdef HAS_BASE_COLOR_TEX base_color = base_color * srgb_to_linear(texture(material.base_color_texture, uv_0)); -#endif + #endif // Compute specular and diffuse colors vec3 dialectric_spec = vec3(min_roughness); @@ -359,18 +371,18 @@ void main() // Compute outbound color vec3 res = compute_brdf(n, v, l, roughness, metallic, - f0, c_diff, base_color.rgb, radiance); + f0, c_diff, base_color.rgb, radiance); // Compute shadow -#ifdef DIRECTIONAL_LIGHT_SHADOWS + #ifdef DIRECTIONAL_LIGHT_SHADOWS float nl = clamp(dot(n,l), 0.0, 1.0); float shadow = shadow_calc( - directional_lights[i].light_matrix, - directional_lights[i].shadow_map, - nl + directional_lights[i].light_matrix, + directional_lights[i].shadow_map, + nl ); res = res * (1.0 - shadow); -#endif + #endif color.xyz += res; } @@ -386,7 +398,7 @@ void main() // Compute outbound color vec3 res = compute_brdf(n, v, l, roughness, metallic, - f0, c_diff, base_color.rgb, radiance); + f0, c_diff, base_color.rgb, radiance); color.xyz += res; } for (int i = 0; i < n_spot_lights; i++) { @@ -407,50 +419,168 @@ void main() // Compute outbound color vec3 res = compute_brdf(n, v, l, roughness, metallic, - f0, c_diff, base_color.rgb, radiance); -#ifdef SPOT_LIGHT_SHADOWS + f0, c_diff, base_color.rgb, radiance); + #ifdef SPOT_LIGHT_SHADOWS float nl = clamp(dot(n,l), 0.0, 1.0); float shadow = shadow_calc( spot_lights[i].light_matrix, spot_lights[i].shadow_map, - nl - ); + nl); res = res * (1.0 - shadow); -#endif + #endif color.xyz += res; } color.xyz += base_color.xyz * ambient_light; // Calculate lighting from environment -#ifdef USE_IBL + #ifdef USE_IBL // TODO -#endif + #endif // Apply occlusion -#ifdef HAS_OCCLUSION_TEX + #ifdef HAS_OCCLUSION_TEX float ao = texture(material.occlusion_texture, uv_0).r; color.xyz *= ao; -#endif + #endif // Apply emissive map vec3 emissive = material.emissive_factor; -#ifdef HAS_EMISSIVE_TEX + #ifdef HAS_EMISSIVE_TEX emissive *= srgb_to_linear(texture(material.emissive_texture, uv_0)).rgb; -#endif + #endif color.xyz += emissive * material.emissive_factor; -#ifdef COLOR_0_LOC + #ifdef COLOR_0_LOC color *= color_multiplier; + #endif + + return clamp(vec4(pow(color.xyz, vec3(1.0/2.2)), color.a * base_color.a), 0.0, 1.0); +} #endif - frag_color = clamp(vec4(pow(color.xyz, vec3(1.0/2.2)), color.a * base_color.a), 0.0, 1.0); +#ifdef USE_GLOSSY_MATERIAL +vec4 compute_glossy_color() { + vec4 color = vec4(vec3(0.0), 1.0); -#else - // TODO GLOSSY MATERIAL BRDF + // Compute metallic/roughness factors + float glossiness = material.glossiness_factor; + #ifdef HAS_SPECULAR_GLOSSINESS_TEX + glossiness = glossiness * texture(material.specular_glossiness, uv_0).r; + #endif + + // Compute albedo + vec4 diffuse_color = material.diffuse_factor; + vec4 specular_color = vec4(material.specular_factor, 1.0); + #ifdef HAS_DIFFUSE_TEX + diffuse_color = diffuse_color * srgb_to_linear(texture(material.diffuse_texture, uv_0)); + #endif + + // Compute normal + vec3 n = normalize(get_normal()); + + // Loop over lights + for (int i = 0; i < n_directional_lights; i++) { + vec3 direction = directional_lights[i].direction; + vec3 v = normalize(cam_pos - frag_position); // Vector towards camera + vec3 l = normalize(-1.0 * direction); // Vector towards light + + // Compute attenuation and radiance + float attenuation = directional_lights[i].intensity; + vec3 radiance = attenuation * directional_lights[i].color; + + // Compute outbound color + vec3 res = compute_blinn_phong_brdf( + n, v, l, glossiness, diffuse_color.rgb, specular_color.rgb, radiance); + + // Compute shadow + #ifdef DIRECTIONAL_LIGHT_SHADOWS + float nl = clamp(dot(n,l), 0.0, 1.0); + float shadow = shadow_calc( + directional_lights[i].light_matrix, + directional_lights[i].shadow_map, + nl); + res = res * (1.0 - shadow); + #endif + color.xyz += res; + } + + for (int i = 0; i < n_point_lights; i++) { + vec3 position = point_lights[i].position; + vec3 v = normalize(cam_pos - frag_position); // Vector towards camera + vec3 l = normalize(position - frag_position); // Vector towards light + + // Compute attenuation and radiance + float dist = length(position - frag_position); + float attenuation = point_lights[i].intensity / (dist * dist); + vec3 radiance = attenuation * point_lights[i].color; + + // Compute outbound color + vec3 res = compute_blinn_phong_brdf( + n, v, l, glossiness, diffuse_color.rgb, specular_color.rgb, radiance); + color.xyz += res; + } + for (int i = 0; i < n_spot_lights; i++) { + vec3 position = spot_lights[i].position; + vec3 v = normalize(cam_pos - frag_position); // Vector towards camera + vec3 l = normalize(position - frag_position); // Vector towards light + + // Compute attenuation and radiance + vec3 direction = spot_lights[i].direction; + float las = spot_lights[i].light_angle_scale; + float lao = spot_lights[i].light_angle_offset; + float dist = length(position - frag_position); + float cd = clamp(dot(direction, -l), 0.0, 1.0); + float attenuation = clamp(cd * las + lao, 0.0, 1.0); + attenuation = attenuation * attenuation * spot_lights[i].intensity; + attenuation = attenuation / (dist * dist); + vec3 radiance = attenuation * spot_lights[i].color; + + // Compute outbound color + vec3 res = compute_blinn_phong_brdf( + n, v, l, glossiness, diffuse_color.rgb, specular_color.rgb, radiance); + #ifdef SPOT_LIGHT_SHADOWS + float nl = clamp(dot(n,l), 0.0, 1.0); + float shadow = shadow_calc( + spot_lights[i].light_matrix, + spot_lights[i].shadow_map, + nl); + res = res * (1.0 - shadow); + #endif + color.xyz += res; + } + + // Apply occlusion + #ifdef HAS_OCCLUSION_TEX + float ao = texture(material.occlusion_texture, uv_0).r; + color.xyz *= ao; + #endif + + // Apply emissive map + vec3 emissive = material.emissive_factor; + #ifdef HAS_EMISSIVE_TEX + emissive *= srgb_to_linear(texture(material.emissive_texture, uv_0)).rgb; + #endif + color.xyz += emissive * material.emissive_factor; + + #ifdef COLOR_0_LOC + color *= color_multiplier; + #endif + + return clamp(vec4(pow(color.xyz, vec3(1.0/2.2)), color.a), 0.0, 1.0); +} #endif /////////////////////////////////////////////////////////////////////////////// -// Handle Glossy Materials +// MAIN /////////////////////////////////////////////////////////////////////////////// - +void main() +{ +#ifdef USE_METALLIC_MATERIAL + frag_color = compute_metallic_color(); +#elif USE_GLOSSY_MATERIAL + // TODO GLOSSY MATERIAL BRDF + frag_color = compute_glossy_color(); +#else + frag_color = vec4(1.0, 0.0, 1.0, 1.0); +#endif } From 9dd7841159fde3386bae42879885210ca5dfbe12 Mon Sep 17 00:00:00 2001 From: Keunhong Park Date: Thu, 22 Aug 2019 16:39:08 -0700 Subject: [PATCH 2/2] Clean up. --- pyrender/mesh.py | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/pyrender/mesh.py b/pyrender/mesh.py index dc67442..ce14b0e 100644 --- a/pyrender/mesh.py +++ b/pyrender/mesh.py @@ -309,28 +309,14 @@ def _get_trimesh_props(mesh, smooth=False): glossiness = mat.kwargs.get('Ns', 1.0) if isinstance(glossiness, list): glossiness = float(glossiness[0]) - roughness = (2 / (glossiness + 2)) ** (1.0/4.0) - # material = MetallicRoughnessMaterial( - # alphaMode='BLEND', - # roughnessFactor=roughness, - # baseColorTexture=mat.image, - # baseColorFactor=rgba_to_float(mat.diffuse), - # ) material = SpecularGlossinessMaterial( alphaMode='BLEND', diffuseTexture=mat.image, - emissiveFactor=rgba_to_float(mat.ambient), - diffuseFactor=rgba_to_float(mat.diffuse), - specularFactor=rgba_to_float(mat.specular), + emissiveFactor=mat.ambient, + diffuseFactor=mat.diffuse, + specularFactor=mat.specular, glossinessFactor=glossiness, doubleSided=True, ) return colors, texcoords, material - - -def rgba_to_float(rgba): - if rgba is None: - return None - - return rgba.astype(np.float) / 255.0