Oren-Nayar артефакты

Шейдеры и все-все-все.

Oren-Nayar артефакты

Сообщение darkPassenger 11 май 2011, 19:48

Доброго времени суток!
Попытка реализовать в юнити алгоритм Орен-Наяр. Вот что получилось:
Изображение
Помогите разобраться
Шейдер:
Синтаксис:
Используется glsl
Shader "MyShaders/Oren-Nayar" {
        Properties {
                _Color("Main Color", Color) = (1,1,1,1)
                _SpecColor("Specular Color", Color) = (1,1,1,1)
                _MainTex ("Base (RGB)", 2D) = "white" {}
                _BumpMap ("Normalmap", 2D) = "bump" {}
                _Shininess("Shininess", Range(0.001, 1)) = 0.1
                _Roughness("Roughness", Range(0, 1)) = 0.3
        }
        SubShader {
                Tags { "RenderType"="Opaque" }
                LOD 200
               
                CGPROGRAM
                #pragma surface surf OrenNayarBlinn
                #pragma target 3.0
               
                half _Roughness;
               
                half4 LightingOrenNayarBlinn (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
               
                        half diff = max(dot(s.Normal, lightDir), 0.0);
               
                        half nh = max (0, dot (s.Normal, normalize(lightDir + viewDir)));
                                          half spec = pow(nh, s.Specular * 128);
               
                        half rs = _Roughness * _Roughness;
                       
                        half a = 1 - 0.5 * rs / (rs + 0.33);
                        half b = 0.45 * rs / (rs + 0.09);
                       
                        half nl = dot(s.Normal, lightDir);
                        half nv = dot(s.Normal, viewDir);
                       
                        half3 lProj = normalize(lightDir - s.Normal * nl);
                        half3 vProj = normalize(viewDir - s.Normal * nv);
                        half cx = max(dot(lProj, vProj), 0);
                       
                        half cosAlpha = nl > nv ? nl : nv;
                        half cosBeta = nl > nv ? nv : nl;
                        half dx = sqrt((1 - cosAlpha * cosAlpha) * (1 - cosBeta * cosBeta)) / cosBeta;
                       
                        half4 c;
                        c.rgb = ((s.Albedo * max(0, nl) * diff * _LightColor0.rgb * (a + b * cx * dx)) + (_LightColor0.rgb * spec * _SpecColor.rgb)) * atten;
                        c.a = 1.0;
                        return c;
               
                }

                half _Shininess;
                half4 _Color;
                sampler2D _MainTex;
                sampler2D _BumpMap;

                struct Input {
               
                        float2 uv_MainTex;
                        float2 uv_BumpMap;
                       
                };

                void surf (Input IN, inout SurfaceOutput o) {
               
                        half4 c = tex2D (_MainTex, IN.uv_MainTex);
                        o.Albedo = c.rgb * _Color.rgb;
                       
                        o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
                        o.Specular = _Shininess;
                       
                        o.Alpha = c.a * _Color.a;
                       
                }
               
                ENDCG
        }
       
        FallBack "Diffuse"
}
 

Источник http://steps3d.narod.ru/tutorials/lighting-tutorial.html
darkPassenger
UNец
 
Сообщения: 11
Зарегистрирован: 26 янв 2011, 20:55

Re: Oren-Nayar артефакты

Сообщение discouraged_one 12 май 2011, 01:49

Как правило сие происходит из-за precision и nans
вот например у вас всё в half - этого не хватает
Я в свое время пытался портировать свой metal шейдер в unity чтобы всем ;-) [Cook-Torrance + Strauss] - из-за этого собственно и не вышло и нету мятала в стандартной поставке 8)
Мораль - используйте полноценный float (у вас это не везде получится) и будьте аккуратней с nan
Unity Technologies
Аватара пользователя
discouraged_one
Unity Technologies
 
Сообщения: 197
Зарегистрирован: 19 май 2010, 15:56

Re: Oren-Nayar артефакты

Сообщение darkPassenger 12 май 2011, 22:06

discouraged_one, спасибо большое за советы!) Но, как оказалось, проблема не в точности или nan. Все дело в этой строке:

half dx = sqrt((1 - cosAlpha * cosAlpha) * (1 - cosBeta * cosBeta)) / cosBeta;

Получалось слишком большое значение, что и давало артефакты. Ограничил данную переменную, стало гораздо лучше. Но результат все равно не радует. Свет слишком резкий, реалистичности никакой (хотя Орен-Наяр должен быть куда точнее Ламберта). Но думаю дело не в исходниках а в моих руках и малом опыте)
Собственно, что получилось:
Изображение
Шейдер:
Синтаксис:
Используется glsl
Shader "MyShaders/Oren-Nayar" {
        Properties {
                _Color("Main Color", Color) = (1,1,1,1)
                _SpecColor("Specular Color", Color) = (1,1,1,1)
                _MainTex ("Base (RGB)", 2D) = "white" {}
                _BumpMap ("Normalmap", 2D) = "bump" {}
                _Shininess("Shininess", Range(0.001, 5)) = 0.1
                _Roughness("Roughness", Range(0, 1)) = 0.3
        }
        SubShader {
                Tags { "RenderType"="Opaque" }
                LOD 200
               
                CGPROGRAM
                #pragma surface surf OrenNayarBlinn
                #pragma target 3.0
               
                half _Roughness;
               
                half4 LightingOrenNayarBlinn (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
               
                        half nh = max (0.0, dot (s.Normal, normalize(lightDir + viewDir)));
            half spec = pow(nh, s.Specular * 128);
               
                        half rs = _Roughness * _Roughness;
                       
                        half a = 1.0 - 0.5 * rs / (rs + 0.33);
                        half b = 0.45 * rs / (rs + 0.09);
                       
                        half nl = dot(s.Normal, lightDir);
                        half nv = dot(s.Normal, viewDir);
                       
                        half3 lProj = normalize(lightDir - s.Normal * nl);
                        half3 vProj = normalize(viewDir - s.Normal * nv);
                        half cx = max(dot(lProj, vProj), 0.0);
                       
                        half cosAlpha = max(nl, nv);
                        half cosBeta = min(nl, nv);
                       
                        half dx = clamp(sqrt((1.0 - cosAlpha * cosAlpha) * (1.0 - cosBeta * cosBeta)) / cosBeta, 0, 3.5);
                       
                        half diff = max(nl, 0.0);
                       
                        half4 c;
                        c.rgb = ((s.Albedo * diff * _LightColor0.rgb * (a + b * cx * dx)) + (_LightColor0.rgb * spec * _SpecColor.rgb)) * (atten * 2);
                        c.a = s.Alpha * diff * (a + b * cx * dx) + spec * _SpecColor.a;
                        return c;
               
                }

                half _Shininess;
                half4 _Color;
                sampler2D _MainTex;
                sampler2D _BumpMap;

                struct Input {
               
                        float2 uv_MainTex;
                        float2 uv_BumpMap;
                       
                };

                void surf (Input IN, inout SurfaceOutput o) {
               
                        half4 c = tex2D (_MainTex, IN.uv_MainTex);
                        o.Albedo = c.rgb * _Color.rgb;
                       
                        o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
                        o.Specular = _Shininess;
                       
                        o.Alpha = c.a * _Color.a;
                       
                }
               
                ENDCG
        }
       
        FallBack "Diffuse"
}
 

P.S шейдер не дружит с бистом
darkPassenger
UNец
 
Сообщения: 11
Зарегистрирован: 26 янв 2011, 20:55


Вернуться в Shader Lab

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3