Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
6
Help us understand the problem. What is going on with this article?
@ShirakawaMaru

Unity でShaderの勉強 その9 ADSシェーディング

More than 3 years have passed since last update.

ADSシェーディングとは

Ambient LightingのA
Diffuse LightingのD
Speqular LightingのS
を合わせてADSシェーディングというらしい。
環境光とディフューズ反射、スペキュラ反射を組み合わせてライティングを行うので簡単にリッチな表現ができるらしい。

計算式はこうなる
I(Intensity:強度) = Ia + Id + Is
Ia = La * Ka
Id = Ld * Kd * max((s・n),0)
Is = Ls * Ks * pow((r・n),f)

Lは光の強さを表す
Kは光の反射率を表す
Laの場合、aはambientを表すからLaはambientのLightの強さ=環境光の強さを表すことになる。

Id(ディフューズの強度)は前回?くらいにやったので省略

Is(スペキュラの強度)について

スペキュラ成分はサーフェイスの輝き具合を表す。
1. 入射光s
2. sの反射光r
3. サーフェイスのノーマルn
4. サーフェイスから視点へのベクトルv
5. vとrの距離に応じてどれくらいスペキュラを小さくするか f

が使われる。

入射光sから反射光rを求めるには以下の式を使う

r = -s + 2(s・n)n

反射光rによってもたらされる反射の強さは、視点までのベクトルvと全く同じ時に最大となり、rとvがずれると大幅に減衰する。
rとvの内積結果を累乗することでθ分離れた時に急速に値を小さくすることができる。何乗するかはfで表す。
これにスペキュラライトの強度Lsとスペキュラ反射率Ksを組み合わせることでIsの式はいかになる。

Is = Ls * Ks * Pow((r・v),f)

r・vの結果が0未満になると2乗した時に整数になるからスペキュラがおかしくなるのかな?
ひょっとしたらPow(max(r・v),0),f)の方が良いかもしれない。

コード

Shader "Custom/TestShader" {
    Properties {
        _MainColor("MainColor",Color) = (1,1,1,1)

        _Ka("Ambient反射",Range(0,1)) = 0.5

        _Kd("Diffse反射",Range(0,1)) = 0.5

        _Ks("Speqular反射",Range(0,1)) = 0.5
        _f("Speqular減衰率",Int) = 5

        [Toggle] _useAmbient("Use Ambient",Float) = 1
        [Toggle] _useDiffuse("Use Diffuse",Float) = 1
        [Toggle] _useSpeqular("Use Speqular",Float) = 1

    }

    SubShader {
        Tags { "Queue" = "Geometry" "RenderType" = "Opaque" "LightMode" = "ForwardBase"}
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            uniform float4 _LightColor0;

            uniform float4 _MainColor;

            uniform float _Ka;

            uniform float _Kd;

            uniform float _Ks;
            uniform int _f;

            uniform float _useAmbient;
            uniform float _useDiffuse;
            uniform float _useSpeqular;

            struct v2f {
                float4 wPos : SV_POSITION;
                float4 ambientColor : Color0;
                float4 diffuseColor : Color1;
                float4 speqularColor : Color2;
            };

            v2f vert(float4 pos : POSITION,float3 normal : NORMAL) {
                v2f output;
                output.wPos = mul(UNITY_MATRIX_MVP,pos);
                float3 wNormal = UnityObjectToWorldNormal(normal);

                //calculate ia
                output.ambientColor = unity_AmbientSky * _Ka;

                //calculate id
                output.diffuseColor = _LightColor0 * _Kd * max(dot(_WorldSpaceLightPos0 ,wNormal),0);

                //calculate is
                float3 r = -_WorldSpaceLightPos0 + 2 * dot(_WorldSpaceLightPos0,wNormal)* wNormal;
                output.speqularColor = _LightColor0 * _Ks * pow(max(dot(r,_WorldSpaceCameraPos),0),_f);
                return output;
            }

            float4 frag(v2f input) : SV_TARGET {
                float4 adsColor = (0,0,0,0);
                if(_useAmbient) {
                    adsColor += input.ambientColor;
                }

                if(_useDiffuse) {
                    _MainColor += input.diffuseColor;
                }

                if(_useSpeqular) {
                    adsColor += input.speqularColor;
                }
                return _MainColor * adsColor;

            }
            ENDCG
        }
    }
}

結果:正常に描画された。
スクリーンショット 2017-02-23 19.36.07.png
ライトの向きを変えてみる
スクリーンショット 2017-02-23 19.37.19.png
Materialの設定
スクリーンショット 2017-02-23 19.37.38.png

注意点

NORMALセマンティクスがNormalとなっていたためUnityObjectToWorldNormal関数が正常に動作せずdiffuseが0になってSphereが真っ暗になっていた。注意。

正しい
v2f vert(float4 pos : POSITION,float3 normal : NORMAL) {
間違い
v2f vert(float4 pos : POSITION,float3 normal : Normal) {
6
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
6
Help us understand the problem. What is going on with this article?