블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2797)
Unity3D (853)
Programming (479)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (185)
협업 (61)
3DS Max (3)
Game (12)
Utility (68)
Etc (98)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (55)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

[링크] https://toconakis.tech/glassmorphism/

 

【Unity】すりガラス風UIの作り方を解説 -グラスモーフィズム-|toconakis.tech

現在開発中の個人開発ゲーム「EUREKA5」で使っている「すりガラス風UI」の作り方を解説します。   EUR

toconakis.tech

 

Shader "glassShader"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _Blur("Blur", Float) = 10
    }
    SubShader
    {

        Tags{ "Queue" = "Transparent" }

        GrabPass
        {   
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                fixed4 color : COLOR;
            };

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 vertColor : COLOR;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.vertColor = v.color;
                return o;
            }

            sampler2D _GrabTexture;
            fixed4 _GrabTexture_TexelSize;

            float _Blur;

            half4 frag(v2f i) : SV_Target
            {
                float blur = _Blur;
                blur = max(1, blur);

                fixed4 col = (0, 0, 0, 0);
                float weight_total = 0;

                [loop]
                for (float x = -blur; x <= blur; x += 1)
                {
                    float distance_normalized = abs(x / blur);
                    float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0);
                    weight_total += weight;
                    col += tex2Dproj(_GrabTexture, i.grabPos + float4(x * _GrabTexture_TexelSize.x, 0, 0, 0)) * weight;
                }

                col /= weight_total;
                return col;
            }
            ENDCG
        }
        GrabPass
        {   
        }

        Pass
        {
            CGPROGRAM

            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                fixed4 color : COLOR;
            };

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 pos : SV_POSITION;
                float4 vertColor : COLOR;
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.grabPos = ComputeGrabScreenPos(o.pos);
                o.vertColor = v.color;
                return o;
            }

            sampler2D _GrabTexture;
            fixed4 _GrabTexture_TexelSize;

            float _Blur;

            half4 frag(v2f i) : SV_Target
            {
                float blur = _Blur;
                blur = max(1, blur);

                fixed4 col = (0, 0, 0, 0);
                float weight_total = 0;

                [loop]
                for (float y = -blur; y <= blur; y += 1)
                {
                    float distance_normalized = abs(y / blur);
                    float weight = exp(-0.5 * pow(distance_normalized, 2) * 5.0);
                    weight_total += weight;
                    col += tex2Dproj(_GrabTexture, i.grabPos + float4(0, y * _GrabTexture_TexelSize.y, 0, 0)) * weight;
                }

                col /= weight_total;
                return col;
            }
            ENDCG
        }

    }
}
반응형
Posted by blueasa
, |

[요약]

1) Tags { "Queue"="Transparent" "RenderType" = "Opaque" }

2) #pragma surface surf Lambert alpha

 

----------------------------------------------------------------------------

Three steps:

Add objects rendered with this shader to the Transparent queue by adding “Queue”=“Transparent” to the subshader’s Tags list.
Add “alpha” to the surface function declaration, after the lighting function declaration, so the line becomes “#pragma surface surf Lambert alpha”
Actually set the alpha to something in the surface function, i.e. set o.Alpha = whatever you want.
I have done these modifications and used the _ColorTint’s alpha channel in the example. Then the shader becomes this:

 

Shader "-smn-/GlowingBorder" {
    Properties {
       _ColorTint("ColorTint", Color) = (1,1,1,1)
       _MainTex("Main Texture", 2D) = "white" {}
       _BumpMap("Normal Map", 2D) = "bump" {}
       _RimColorOuter("Rim Color Outer", Color) = (1,1,1,1)
       _RimColorInner("Rim Color Inner", Color) = (1,1,1,1)
       _RimPowerOuter("Rim Power Outer", Range(0.0, 7.0)) = 3.0
       _RimPowerInner("Rim Power Inner", Range(0.0, 20.0)) = 3.0
    }
    SubShader {
       Tags { "Queue"="Transparent" "RenderType" = "Opaque" }
 
 
       CGPROGRAM
       #pragma surface surf Lambert alpha
 
       struct Input {
         float4 color : COLOR;
         float2 uv_MainTex;
         float2 uv_BumpMap;
         float3 viewDir;
       };
 
       float4 _ColorTint;
       sampler2D _MainTex;
       sampler2D _BumpMap;
       float4 _RimColorOuter;
       float4 _RimColorInner;
       float _RimPowerOuter;
       float _RimPowerInner;
 
       void surf (Input IN, inout SurfaceOutput o) {
         IN.color = _ColorTint;
         o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * IN.color;
         o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
 		 o.Alpha = _ColorTint.a; // For example. Could also be the alpha channel on the interpolated vertex color (IN.color.a), or the one from the texture.
		
         half rimOuter = 1.0 -saturate(dot(normalize(IN.viewDir), o.Normal));
         half rimInner = saturate(dot(normalize(IN.viewDir), o.Normal));
         o.Emission = (_RimColorOuter.rgb * pow(rimOuter, _RimPowerOuter)) + (_RimColorInner.rgb * pow(rimInner, _RimPowerInner)) ;
       }
       ENDCG
    } 
    FallBack "Diffuse"
}

 

 

[출처] https://discussions.unity.com/t/how-can-i-add-alpha-channel-to-this-shader/100942

 

How can I add alpha-channel to this shader?

Hello, I have this shader that does not support alpha map. How can I modify it so I can adjust the alpha channel so as to be transparent? Thanks! Shader "-smn-/GlowingBorder" { Properties { _ColorTint("ColorTint", Color) = (1,1,1,1) _MainTex("Main Texture"

discussions.unity.com

 

 

반응형
Posted by blueasa
, |

[링크] https://liveupdate.tistory.com/308

 

[unity3d] 서피스 쉐이더 정리

ShaderLab : http://liveupdate.tistory.com/336 Unity3D 쉐이더 레퍼런스 : https://docs.unity3d.com/kr/530/Manual/SL-Reference.html 서피스 쉐이더 Shader "이름" {Properties {_프로퍼티("이름", 타입) = 값} Subshaders {Tags {// 유니티

liveupdate.tistory.com

 

반응형
Posted by blueasa
, |

[파일]

Transparent - Cutout ChromakeyShader.shader
0.00MB

 

[링크] https://seokiki0413.tistory.com/1

 

[Unity] Chromakey 동영상 투명하게 플레이 하는 Tip

유니티에서 동영상 배경을 투명하게 처리하는 방법은 Shader를 이용해서 합니다.Shader란 정의를 찾아보았으나 없었고,제가 생각하기에 Shader란 자바스크립트 계열의 일종으로 보입니다.(제 생각)

seokiki0413.tistory.com

 

 

반응형
Posted by blueasa
, |

[링크] https://docs.unity3d.com/Packages/com.unity.toonshader@0.8/manual/index.html

 

Unity Toon Shader overview | Unity Toon Shader | 0.8.5-preview

Unity Toon Shader overview The Unity Toon Shader (UTS3) is a set of toon shaders designed to meet the needs of creators working on cel-shaded 3D-CG animations. The Unity Toon Shader is compatible with all the render pipelines, the Built-in Render Pipeline,

docs.unity3d.com

 

반응형
Posted by blueasa
, |

[추가]

[Fixed] iOS: Fixed game objects' colors in light mode. (1379817)

2020.3.27f1 버전에서 해당 이슈가 수정되었다.

 

--------------------------------------------------------------------------------------------------------

Unity 2020.3.21f1에서 Unity 2020.3.22f1으로 업데이트 하고나니 Android는 문제없는데, iOS에서 기존에 발생하지 않던 쉐이더 문제가 생겼다.

 

[증상] 기존에 검은 느낌이던 텍스쳐가 약간 회색빛이 나옴

아래 이미지에서 A이던 느낌이 B느낌이 남

그래서 Unity 2020.3.21f1으로 내리니 다시 정상동작 하는걸 확인했다.

링크 내용을 보니 iOS Dark Mode 관련 버그라고 한다.

 

현재 임시로 해결하는 방법은 iOS Info.plist에서 강제로 Dark Mode로 셋팅 하는 방법이 있다고 한다.

 

버그가 수정될 때까지 Dark Mode로 셋팅하거나, Unity 2020.3.21f1 이하 버전을 사용해야 될 것 같다.

 

 

 

[Unity 소스상에서 Info.plist 수정]

var projectPath = pathToBuiltProject + "/Unity-iPhone.xcodeproj/project.pbxproj";
var plistPath = System.IO.Path.Combine(pathToBuiltProject, "Info.plist");
var plist = new PlistDocument();
plist.ReadFromFile(plistPath);

// [iOS15+Unity2020.3.22f1 이슈] Force Dark Mode(Automatic/Light/Dark) - Appearance
plist.root.SetString("UIUserInterfaceStyle", "Dark");

 

 

 

[Info.plist 수정 참조 링크] https://stackoverflow.com/questions/56537855/is-it-possible-to-opt-out-of-dark-mode-on-ios-13/64015200

 

Is it possible to opt-out of dark mode on iOS 13?

A large part of my app consists of web views to provide functionality not yet available through native implementations. The web team has no plans to implement a dark theme for the website. As such,...

stackoverflow.com

 

 

 

[출처] https://stackoverflow.com/questions/70239569/unity-shader-glitches-according-to-the-dark-mode-on-ios-15

 

Unity shader glitches according to the Dark Mode on iOS 15

I'm using a shader (code below) which allows me to turn an image color into a grayscale (with transparency if needed). Everything was perfect until I updated my device to iOS 15. Since that update,...

stackoverflow.com

 

반응형
Posted by blueasa
, |

출처 : https://qiita.com/kuuki_yomenaio/items/00d74762e930d037ad27

Spine 오브젝트는?

Spine 개체는 Unity에서 말하는 MeshRenderer로 렌더링되고 있습니다. 
(spine-unity의 SkeletonRenderer.cs가 해당 소스입니다) 
즉, MeshRenderer의 Mask 처리를 만들 수 있다면, Mask를 사용할 수 있게 됩니다. 


(왜 이런 엄한 부분을 가지고 예제를 만든 걸까...)

Mask 처리에 대해

요는 Renderer를 Mask하면 되는 것이지만, 
SpriteRenderer 자체를 Mask하는 처리는 Unity에는 없는 것 같습니다. 
그래서, 간단히 자작하기로 했습니다.

Shader로 실제 제작

간단한 것은 역시 스텐실 테스트를 사용하는 것이군요. 
아주 간단하게 설명하면, 스텐실이란 모양을 도려낸다는 의미로 
픽셀 렌더링을 할 때 이 점을 찍는가 찍지 않는다인지를 판정하는 테스트입니다. 
이것을 이용합니다.

Spine 쪽에 적용하는 shader

SpineShader.shader
Shader "Custom/SpineShader"{
Properties
{
        _MainTex ("Base (RGB)", 2D) = "white" {}
}

SubShader
{
        Tags {"Queue"="Transparent+2" "IgnoreProjector"="True" "RenderType"="Transparent"}
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

        Stencil {
                                Ref 1
                                Comp Equal
        }

        Pass
        {
                CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag

                        #include "UnityCG.cginc"

                        struct appdata_t
                        {
                                float4 vertex : POSITION;
                                float2 texcoord : TEXCOORD0;
                        };

                        struct v2f
                        {
                                float4 vertex : SV_POSITION;
                                half2 texcoord : TEXCOORD0;
                        };

                        sampler2D _MainTex;
                        float4 _MainTex_ST;

                        v2f vert (appdata_t v)
                        {
                                v2f o;
                                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                                o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                                return o;
                        }

                        fixed4 frag (v2f i) : COLOR
                        {
                                fixed4 col = tex2D(_MainTex, i.texcoord);
                                return col;
                        }
                ENDCG
        }
}

}

Mask할 Sprite에 설정하는 Shader

SpineSoriteMask.shader
Shader "Custom/SpineSpriteMask"{
Properties
{
        _MainTex ("Base (RGB)", 2D) = "white" {}
}

SubShader
{
        Tags {"Queue"="Transparent+1" "IgnoreProjector"="True"}
        ZWrite Off
        AlphaTest Greater 0.5
        ColorMask 0
        ZTest Always


        Stencil {
                                Ref 1
                                Comp always
                                Pass replace
                        }


        Pass
        {
                CGPROGRAM
                        #pragma vertex vert
                        #pragma fragment frag

                        #include "UnityCG.cginc"

                        struct appdata_t
                        {
                                float4 vertex : POSITION;
                                float2 texcoord : TEXCOORD0;
                        };

                        struct v2f
                        {
                                float4 vertex : SV_POSITION;
                                half2 texcoord : TEXCOORD0;
                        };

                        sampler2D _MainTex;
                        float4 _MainTex_ST;

                        v2f vert (appdata_t v)
                        {
                                v2f o;
                                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                                o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                                return o;
                        }

                        fixed4 frag (v2f i) : COLOR
                        {
                                fixed4 col = tex2D(_MainTex, i.texcoord);
                                if(col.a<0.1)discard;
                                return col;
                        }
                ENDCG
        }
}

}

해설

SpineShader.shader
   Stencil {
             Ref 1
             Comp Equal
   }
SpineSoriteMask.shader
   ColorMask 0
   Stencil {
             Ref 1
             Comp always
             Pass replace
   }

Stencil

해설에 대해서는 
edo_m18 씨의 [Unity] Unity의 Shader 스텐실 버퍼를 시도
를 참고하십시오.

먼저, SpineSpriteMask 입니다만, 
"참조 값 1의 것과 비교하고, 모두 OK로 해서,
참조 값을 버퍼에 기록하고, ColorMask 0 으로 묘화는 하지 않음" 
이 됩니다.

그리고 SpineShader. 
"참조 값은 1, 값의 일치를 체크" 
가 됩니다.

이 설정을 함으로써 
SpineShader 측의 묘화는  StencilTest 를 받게 되고, 
SpineSpriteMask 측에서 설정한 모양대로 도려내지도록 그려집니다.

Unity에서 사용할 때에는 Material화 시킬 필요가 있습니다만, 
그에 대해서는
github
여기를 참고하십시오.

---

* 스파인측 설정

 

* 마스크이미지측 설정

* 매터리얼 설정은 이렇게(특별히 이미지는 지정하지 않고 쉐이더만 넣음)



출처: https://devdata.tistory.com/166 [CH:Windship DevDATA Center]

 

[Unity] Spine 오브젝트를 Mask하기

출처 : https://qiita.com/kuuki_yomenaio/items/00d74762e930d037ad27 Spine 오브젝트는? Spine 개체는 Unity에서 말하는 MeshRenderer로 렌더링되고 있습니다. (spine-unity의 SkeletonRenderer.cs가 해당 소스..

devdata.tistory.com

[참조] https://rainyrizzle.github.io/kr/AdvancedManual/AD_SpriteMask.html

 

Sprite Mask 적용하기

유니티의 "스프라이트 마스크(Sprite Mask)"를 이용하면 다른 Sprite Renderer의 일부를 숨기면서 렌더링을 할 수 있습니다. - 스프라이트 마스크 (유니티 공식 메뉴얼) AnyPortrait에서 제작된 캐릭터들은 S

rainyrizzle.github.io

 

반응형

'Unity3D > Shader' 카테고리의 다른 글

[링크] Unity Toon Shader(with Outline)  (0) 2023.02.22
[링크] Unity-Chan Toon Shader 2.0 (UTS2)  (0) 2021.11.30
[펌] Celery - Toon/Cel shader  (0) 2021.03.30
[펌] Toon Shader  (0) 2021.03.30
[링크] Unity Cel Shading - 카툰렌더링  (0) 2021.03.30
Posted by blueasa
, |
2019-02-08 update:
Celery is now available for free here!

Here's a toon/cel/anime shader I've been working on that I am redying up for release. It has been designed to be easy for artists to use but also to offer heavy customizability.
I'm making this thread to gauge if there is interest in any particular features, or just general feedback.

The gist of the asset is:
  • Forward-rendered cel-shader with full support for realtime lights + shadows
  • Ramp texture support for custom styles or skin shading
  • Smoothly control the cel-effect with a slider, ranging from "normal" smooth shading to 100% sharp edges
  • Supports a number of effects aimed towards making a material appear to be animated/drawn (specular, rim lighting, cubemap reflections)
  • Supports vertex colors, HSV adjustment with color masking, specular/gloss maps, normal maps, alpha testing, alpha blending (separate material), vertex-displaced outline (integrated in the same material or as a separate shader) as well as some custom ambient lighting
  • Also bundled with the asset is a number of stylized cubemaps useful for toon-like reflections (such as hair reflections or eye glints)
  • Runs well on mobile and plan is to test and make sure it is VR-compatible as well.
Anyway, here are some screenshots:








Currently I am interested in testing it out with more models (as well as gathering some screenshots and feedback). If you've got a smiple-styled model (preferably a character) and you'd like to give it a try, send me a PM with an image of it and I'll send you the asset so you can test it out!

 

 

[출처] forum.unity.com/threads/celery-toon-cel-shader.510330/

 

Celery - Toon/Cel shader

2019-02-08 update: Celery is now available for free here! Here's a toon/cel/anime shader I've been working on that I am redying up for release. It has...

forum.unity.com

 

반응형
Posted by blueasa
, |

[펌] Toon Shader

Unity3D/Shader / 2021. 3. 30. 13:50

You will learn to write a lit toon shader from scratch. The shader will be lit by a single directional light, and cast and receive shadows.

Toon shading (often called cel shading) is a rendering style designed to make 3D surfaces emulate 2D, flat surfaces. This style entered the mainstream with games like Jet Set Radio and The Wind Waker.

This tutorial will describe step-by-step how to write a toon shader in Unity. The shader will receive light from a single directional source, and have specular reflections and rim lighting. We will use the art style of The Legend of Zelda: Breath of the Wild as our reference, although we will not implement some of the more complex rendering techniques used in the game.

Breath of the Wild divides surfaces into two bands of lightness, adding rim and specular on top. The rim is only applied to surfaces illuminated by the main directional light.

The completed project is provided at the end of the article. Note that it also contains a large amount of comments in the created shader file to aid understanding.

Prerequisites

To complete this tutorial, you will need a working knowledge of Unity engine, and a basic understanding of shader syntax and functionality.

Download starter project .zip

These tutorials are made possible, and kept free and open source, by your support. If you enjoy them, please consider becoming my patron through Patreon.

 

Getting started

Download the starter project provided above and open it in the Unity editor. Open the Main scene, and open the Toon shader in your preferred code editor.

This file contains a simple shader that outputs a sampled texture, tinted by a color (with the default color set to cornflower blue). We will build off this file to create our toon shader.

1. Directional lighting

When writing shaders in Unity that interact with lighting it is common to use Surface Shaders. Surface shaders use code generation to automate the object's interaction with lights and global illumination. However, as our shader will only interact with a single directional light, it will not be necessary to use surface shaders.

We will set up our shader to receive lighting data. Add the following code at the top of the Pass, just after its opening curly brace.

Tags { "LightMode" = "ForwardBase" "PassFlags" = "OnlyDirectional" }

The first line requests some lighting data to be passed into our shader, while the second line further requests to restrict this data to only the main directional light. You can read more about Pass tags here.

To calculate our lighting, we will use a common shading model called Blinn-Phong, and apply some additional filters to give it a toon look. The first step is to calculate the amount of light received by the surface from the main directional light. The amount of light is proportional to the direction, or normal of the surface with respect to the light direction.

Blinn-Phong shading vectors, where L is the vector to the light source and N is the normal of the surface.

We'll need access to the object's normal data within our shader. Add the following code.

// Inside the appdata struct. float3 normal : NORMAL;// Inside the v2f struct. float3 worldNormal : NORMAL;

The normals in appdata are populated automatically, while values in v2f must be manually populated in the vertex shader. As well, we want to transform the normal from object space to world space, as the light's direction is provided in world space. Add the following line to the vertex shader.

o.worldNormal = UnityObjectToWorldNormal(v.normal);

With the world normal now available in the fragment shader, we can compare it to the light's direction using the Dot Product.

The dot product takes in two vectors (of any length) and returns a single number. When the vectors are parallel in the same direction and are unit vectors (vectors of length 1), this number is 1. When they are perpendicular, it returns 0. As you move a vector away from parallel—towards perpendicular—the dot product result will move from 1 to 0 non-linearly. Note that when the angle between the vectors is greater than 90, the dot product will be negative.

Add the following to the fragment shader. Note that existing code that is modified will be highlighted in yellow. New code is not highlighted.

// At the top of the fragment shader. float3 normal = normalize(i.worldNormal); float NdotL = dot(_WorldSpaceLightPos0, normal);// Modify the existing return line. return _Color * sample * NdotL;

This has rendered out a realistic style of illumination. To modify it to be toon-like, we will divide the lighting into two bands: light and dark.

// Below the NdotL declaration. float lightIntensity = NdotL > 0 ? 1 : 0; … return _Color * sample * lightIntensity;

What if we wanted more than two discrete bands of shading?

2. Ambient light

This looks good, but the dark side is too dark; right now it is completely black. Also, the edge between dark and light looks a bit sharp, but we'll deal with that later. For now, we will add ambient light.

Ambient light represents light that bounces off the surfaces of objects in the area and is scattered in the atmosphere. We will model it as a light that affects all surfaces equally and is additive to the main directional light.

// Add as a new property. [HDR] _AmbientColor("Ambient Color", Color) = (0.4,0.4,0.4,1)// Matching variable, add above the fragment shader. float4 _AmbientColor; … return _Color * sample * (_AmbientColor + lightIntensity);

You'll notice that modifying the intensity or color of the Directional Light in the scene does not affect our shader. We will add some code to include this in our lighting calculations.

What does [HDR] mean above the _AmbientColor property?

// Add below the existing #include "UnityCG.cginc" #include "Lighting.cginc"// Add below the lightIntensity declaration. float4 light = lightIntensity * _LightColor0;return _Color * sample * (_AmbientColor + light);

We multiply our existing lightIntensity value and store it in a float4, so that we include the light's color in our calculation. _LightColor0 is the color of the main directional light. It is a fixed4 declared in the Lighting.cginc file, so we include the file above to make use of the value.

Before going further, we'll soften the edge between light and dark to remove the jaggedness. Right now, the transition from light to dark is immediate and occurs over a single pixel. Instead, we'll smoothly blend the value from one to zero, using the smoothstep function.

smoothstep takes in three values: a lower bound, an upper bound and a value expected to be between these two bounds. smoothstep returns a value between 0 and 1 based on how far this third value is between the bounds. (If it is outside the lower or upper bound, smoothstep returns a 0 or 1, respectively).

Comparison between smoothstep (left) and a linear function (right). The values are mapped to the greyscale background, as well as the curves in red.

smoothstep is not linear: as the value moves from 0 to 0.5, it accelerates, and as it moves from 0.5 to 1, it decelerates. This makes it ideal for smoothly blending values, which is how we'll use it to blend our light intensity value.

float lightIntensity = smoothstep(0, 0.01, NdotL);

Our lower and upper bounds, 0 and 0.01, are very close together—this helps maintain a relatively sharp, toony edge. When NdotL is above 0.01 or below 0 it returns one and zero like before, respectively. However, in between that range it will smoothly blend between 0 and 1.

3. Specular reflection

Specular reflection models the individual, distinct reflections made by light sources. This reflection is view dependent, in that it is affected by the angle that the surface is viewed at. We will calculate the world view direction in the vertex shader and pass it into the fragment shader. This is the direction from the current vertex towards the camera.

// Add to the v2f struct. float3 viewDir : TEXCOORD1;// Add to the vertex shader. o.viewDir = WorldSpaceViewDir(v.vertex);

We'll now implement the specular component of Blinn-Phong. This calculation takes in two properties from the surface, a specular color that tints the reflection, and a glossiness that controls the size of the reflection.

// Add as new properties. [HDR] _SpecularColor("Specular Color", Color) = (0.9,0.9,0.9,1) _Glossiness("Glossiness", Float) = 32// Matching variables. float _Glossiness; float4 _SpecularColor;

The strength of the specular reflection is defined in Blinn-Phong as the dot product between the normal of the surface and the half vector. The half vector is a vector between the viewing direction and the light source; we can obtain this by summing those two vectors and normalizing the result.

// Add to the fragment shader, above the line sampling _MainTex. float3 viewDir = normalize(i.viewDir); float3 halfVector = normalize(_WorldSpaceLightPos0 + viewDir); float NdotH = dot(normal, halfVector); float specularIntensity = pow(NdotH * lightIntensity, _Glossiness * _Glossiness);return _Color * sample * (_AmbientColor + light + specularIntensity);

We control the size of the specular reflection using the pow function. We multiply NdotH by lightIntensity to ensure that the reflection is only drawn when the surface is lit. Note that _Glossiness is multiplied by itself to allow smaller values in the material editor to have a larger effect, and make it easier to work with the shader.

Once again we will use smoothstep to toonify the reflection, and multiply the final output by the _SpecularColor.

// Add below the specularIntensity declaration. float specularIntensitySmooth = smoothstep(0.005, 0.01, specularIntensity); float4 specular = specularIntensitySmooth * _SpecularColor;return _Color * sample * (_AmbientColor + light + specular);

4. Rim lighting

Rim lighting is the addition of illumination to the edges of an object to simulate reflected light or backlighting. It is especially useful for toon shaders to help the object's silhouette stand out among the flat shaded surfaces.

The "rim" of an object will be defined as surfaces that are facing away from the camera. We will therefore calculate the rim by taking the dot product of the normal and the view direction, and inverting it.

// In the fragment shader, below the line declaring specular. float4 rimDot = 1 - dot(viewDir, normal);return _Color * sample * (_AmbientColor + light + specular + rimDot);

Once again, we'll toonify the effect by thresholding the value with smoothstep.

// Add as new properties. [HDR] _RimColor("Rim Color", Color) = (1,1,1,1) _RimAmount("Rim Amount", Range(0, 1)) = 0.716// Matching variables. float4 _RimColor; float _RimAmount;// Add below the line declaring rimDot. float rimIntensity = smoothstep(_RimAmount - 0.01, _RimAmount + 0.01, rimDot); float4 rim = rimIntensity * _RimColor;return _Color * sample * (_AmbientColor + light + specular + rim);

With the rim being drawn around the entire object, it tends to resemble an outline more than a lighting effect. We'll modify it to only appear on the illuminated surfaces of the object.

// Add above the existing rimIntensity declaration, replacing it. float rimIntensity = rimDot * NdotL; rimIntensity = smoothstep(_RimAmount - 0.01, _RimAmount + 0.01, rimIntensity);

This is better, but it would be useful to be able to control how far the rim extends along the lit surface. We'll use the pow function to scale the rim.

// Add as a new property. _RimThreshold("Rim Threshold", Range(0, 1)) = 0.1// Matching variable. float _RimThreshold;float rimIntensity = rimDot * pow(NdotL, _RimThreshold);

5. Shadows

As a final step, we will add the ability for our shader to cast and receive shadows. Shadow casting is very simple. Add the following line of code below the entire Pass (outside the curly braces).

// Insert just after the closing curly brace of the existing Pass. UsePass "Legacy Shaders/VertexLit/SHADOWCASTER"

UsePass grabs a pass from a different shader and inserts it into our shader. In this case, we are adding a pass that is used by Unity during the shadow casting step of the rendering process.

In order to receive shadows, we will need to know in the fragment shader whether a surface is in a shadow or not, and factor that in to our illumination calculation. To sample the shadow map cast by a light, we'll need to transfer texture coordinates from the vertex shader to the fragment shader.

// As a new include, below the existing ones. #include "AutoLight.cginc"// Add to the v2f struct. SHADOW_COORDS(2)// Add to the vertex shader. TRANSFER_SHADOW(o)

We include Autolight.cginc, a file that contains several macros we will use to sample shadows. SHADOW_COORDS(2) generates a 4-dimensional value with varying precision (depending on the target platform) and assigns it to the TEXCOORD semantic at the provided index (in our case, 2).

TRANSFER_SHADOW transforms the input vertex's space to the shadow map's space, and then stores it in the SHADOW_COORD we declared.

Before we can sample the shadow map, however, we need to ensure our shader is set up to handle two different lighting cases: when the main directional light does and does not cast shadows. Unity will help us handle these two configurations by compiled multiple variants of this shader for each use case. You can read more about shader variants here. We will use a built-in shortcut to compile our variants. Add the following line of code just below the #pragma fragment frag line.

#pragma multi_compile_fwdbase

This shortcut instructs Unity to compile all variants necessary for forward base rendering. We can now sample the value in the shadow map, and apply it to our lighting calculation.

// In the fragment shader, above the existing lightIntensity declaration. float shadow = SHADOW_ATTENUATION(i); float lightIntensity = smoothstep(0, 0.01, NdotL * shadow);

SHADOW_ATTENUATION is a macro that returns a value between 0 and 1, where 0 indicates no shadow and 1 is fully shadowed. We multiply NdotL by this value, as it is the variable that stores how much light we received from the main directional light.

Conclusion

Toon shaders come in a wide variety of graphical styles, but achieving the effect usually centers around taking a standard lighting setup (as we did with Blinn-Phong) and applying a step function to it. In fact, when normals and lighting data is available it can be done as a post process effect. An example of this can be found in this tutorial for Unreal Engine 4.

View source GitHub repository

Leave me a message

Send me some feedback about the tutorial in the form below. I'll get back to you as soon as I can! You can alternatively message me through Twitter or Reddit.

 

 

[출처] roystan.net/articles/toon-shader.html

 

Unity Toon Shader Tutorial at Roystan

Learn to write a toon shader for Unity engine with specular reflections, rim lighting and shadow casting.

roystan.net

 

반응형
Posted by blueasa
, |

So I had some spare time to study things I've always wanted to.

Left: Default shader // Right: Blur shader

Note:
All shader files (including the files with number suffix) must be downloaded together.
The numbers represent the clipping panel count when using Soft Clip on UIPanel components.
Refer to: http://www.tasharen.com/forum/index.php?topic=13985.0

 

Unlit - Transparent Colored Blur.shader
0.00MB
Unlit - Transparent Colored Blur 1.shader
0.00MB
Unlit - Transparent Colored Blur 2.shader
0.00MB
Unlit - Transparent Colored Blur 3.shader
0.00MB

 

 

You can customize the amount of blurring by editing the two fields below.
iterations variable represents the radius.
blurSize variable represents the scale (in UV coordinate) which the other pixel should be sampled from.
It should be possible to expose these fields so you can mess around with them through Materials or C# scripts.

half blurSize = 0.005; half iterations = 4;

Limitations:
Originally I wanted to implement a Gaussian Blur effect but it's quite complicated and expensive.
So it ended up in a sort of "hack" by blurring the pixels in horizontal and vertical axis only.
While it may look fine on low iteration count, it doesn't take the diagonal pixels in to calculation, making high radius blurs look unnatural.
I am planning to make another workaround for this issue some time.

 

 

[출처] m.blog.naver.com/reisenmoe/221268044207

 

[Unity, NGUI, Shader] Transparent Colored Blur shader

So I had some spare time to study things I've always wanted to.Note: All shader files (includin...

blog.naver.com

 

반응형
Posted by blueasa
, |