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

카테고리

분류 전체보기 (2835)
Unity3D (883)
Script (93)
Extensions (16)
Effect (3)
NGUI (81)
UGUI (9)
Physics (2)
Shader (39)
Math (1)
Design Pattern (2)
Xml (1)
Tips (203)
Link (26)
World (1)
AssetBundle (25)
Mecanim (2)
Plugins (85)
Trouble Shooting (71)
Encrypt (7)
LightMap (4)
Shadow (4)
Editor (12)
Crash Report (3)
Utility (9)
UnityVS (2)
Facebook SDK (2)
iTween (3)
Font (18)
Ad (14)
Photon (2)
IAP (1)
Google (11)
URP (4)
Android (51)
iOS (46)
Programming (479)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (188)
협업 (64)
3DS Max (3)
Game (12)
Utility (140)
Etc (99)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (52)
Android (16)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (19)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

[펌] 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
, |

[링크] darkcatgame.tistory.com/27

 

Unity Cel Shading - 카툰렌더링

Cel Shading은 3D 오브젝트에 외각선을 강조하고, 명암을 표현 할 때 그라데이션이 아닌 단계별로 표현하여 만화 같은 느낌을 내는 것으로 Toon Shading, Cartoon Rendering이라고도 불린다. 대표적인 Cel Sha

darkcatgame.tistory.com

 

반응형
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
, |

[링크] www.elopezr.com/photoshop-blend-modes-in-unity/

 

Photoshop Blend Modes Without Backbuffer Copy

[latexpage] For the past couple of weeks, I have been trying to replicate the Photoshop blend modes in Unity. It is no easy task; despite the advances of modern graphics hardware, the blend unit st…

www.elopezr.com

Photoshop Blend Modes Without Backbuffer Copy

 BY ADMINOCTOBER 7, 2016GRAPHICS, UNITY

For the past couple of weeks, I have been trying to replicate the Photoshop blend modes in Unity. It is no easy task; despite the advances of modern graphics hardware, the blend unit still resists being programmable and will probably remain fixed for some time. Some OpenGL ES extensions implement this functionality, but most hardware and APIs don’t. So what options do we have?

1) Backbuffer copy

A common approach is to copy the entire backbuffer before doing the blending. This is what Unity does. After that it’s trivial to implement any blending you want in shader code. The obvious problem with this approach is that you need to do a full backbuffer copy before you do the blending operation. There are certainly some possible optimizations like only copying what you need to a smaller texture of some sort, but it gets complicated once you have many objects using blend modes. You can also do just a single backbuffer copy and re-use it, but then you can’t stack different blended objects on top of each other. In Unity, this is done via a GrabPass. It is the approach used by the Blend Modes plugin.

2) Leveraging the Blend Unit

Modern GPUs have a little unit at the end of the graphics pipeline called the Output Merger. It’s the hardware responsible for getting the output of a pixel shader and blending it with the backbuffer. It’s not programmable, as to do so has quite a lot of complications (you can read about it here) so current GPUs don’t have one.

The blend mode formulas were obtained here and here. Use it as reference to compare it with what I provide. There are many other sources. One thing I’ve noticed is that provided formulas often neglect to mention that Photoshop actually uses modified formulas and clamps quantities in a different manner, especially when dealing with alpha. Gimp does the same. This is my experience recreating the Photoshop blend modes exclusively using a combination of blend unit and shaders. The first few blend modes are simple, but as we progress we’ll have to resort to more and more tricks to get what we want.

Two caveats before we start. First off, Photoshop blend modes do their blending in sRGB space, which means if you do them in linear space they will look wrong. Generally this isn’t a problem, but due to the amount of trickery we’ll be doing for these blend modes, many of the values need to go beyond the 0 – 1 range, which means we need an HDR buffer to do the calculations. Unity can do this by setting the camera to be HDR in the camera settings, and also setting Gamma for the color space in the Player Settings. This is clearly undesirable if you do your lighting calculations in linear space. In a custom engine you would probably be able to set this up in a different manner (to allow for linear lighting).

If you want to try the code out while you read ahead, download it here.

 

[File]

BlendModesNoBackbuffer.zip
0.00MB

 

A) Darken

Formula min(SrcColor, DstColor)
Shader Output color.rgb = lerp(float3(1, 1, 1), color.rgb, color.a);
Blend Unit Min(SrcColor · One, DstColor · One)

Darken

As alpha approaches 0, we need to tend the minimum value to DstColor, by forcing SrcColor to be the maximum possible color float3(1, 1, 1)

 

B) Multiply

Formula SrcColor · DstColor
Shader Output color.rgb = color.rgb * color.a;
Blend Unit SrcColor · DstColor + DstColor · OneMinusSrcAlpha

Multiply

 

C) Color Burn

Formula 1 – (1 – DstColor) / SrcColor
Shader Output color.rgb = 1.0 - (1.0 / max(0.001, color.rgb * color.a + 1.0 - color.a)); // max to avoid infinity
Blend Unit SrcColor · One + DstColor · OneMinusSrcColor

Color Burn

 

D) Linear Burn

Formula SrcColor + DstColor – 1
Shader Output color.rgb = (color.rgb - 1.0) * color.a;
Blend Unit SrcColor · One + DstColor · One

Linear Burn

 

E) Lighten

Formula Max(SrcColor, DstColor)
Shader Output color.rgb = lerp(float3(0, 0, 0), color.rgb, color.a);
Blend Unit Max(SrcColor · One, DstColor · One)

Lighten

 

F) Screen

Formula 1 – (1 – DstColor) · (1 – SrcColor) = Src + Dst – Src · Dst
Shader Output color.rgb = color.rgb * color.a;
Blend Unit SrcColor · One + DstColor · OneMinusSrcColor

Screen

 

G) Color Dodge

Formula DstColor / (1 – SrcColor)
Shader Output color.rgb = 1.0 / max(0.01, (1.0 - color.rgb * color.a));
Blend Unit SrcColor · DstColor + DstColor · Zero

Color Dodge

You can see discrepancies between the Photoshop and the Unity version in the alpha blending, especially at the edges.

 

H) Linear Dodge

Formula SrcColor + DstColor
Shader Output color.rgb = color.rgb;
Blend Unit SrcColor · SrcAlpha + DstColor · One

Linear Dodge

This one also exhibits color “bleeding” at the edges. To be honest I prefer the one to the right just because it looks more “alive” than the other one. Same goes for Color Dodge. However this limits the 1-to-1 mapping to Photoshop/Gimp.

All of the previous blend modes have simple formulas and one way or another they can be implemented via a few instructions and the correct blending mode. However, some blend modes have conditional behavior or complex expressions (complex relative to the blend unit) that need a bit of re-thinking. Most of the blend modes that follow needed a two-pass approach (using the Pass syntax in your shader). Two-pass shaders in Unity have a limitation in that the two passes aren’t guaranteed to render one after the other for a given material. These blend modes rely on the previous pass, so you’ll get weird artifacts. If you have two overlapping sprites (as in a 2D game, such as our use case) the sorting will be undefined. The workaround around this is to move the Order in Layer property to force them to sort properly.

 

I) Overlay

Formula 1 – (1 – 2 · (DstColor – 0.5)) · (1 – SrcColor), if DstColor > 0.5
2 · DstColor · SrcColor, if DstColor <= 0.5
Shader Pass 1 color.rgb *= color.a;
float3 A = (4.0 * color.rgb - 1.0) / (2.0 - 4.0 * color.rgb);
float3 B = (1.0 * color.a) / ((2.0 - 4.0 * color.rgb) * max(0.001, color.a));
color.rgb = A + B;
Blend Pass 1 SrcColor · DstColor + DstColor · DstColor
Shader Pass 2 color.rgb = (2.0 - 4.0 * color.rgb * color.a) max(0.001, color.a);
Blend Pass 2 SrcColor · DstColor + DstColor · Zero

Overlay

How I ended up with Overlay requires an explanation. We take the original formula and approximate via a linear blend:

We simplify as much as we can and end up with this

The only way I found to get DstColor · DstColor is to isolate the term and do it in two passes, therefore we extract the same factor in both sides:

However this formula doesn’t take alpha into account. We still need to linearly interpolate this big formula with alpha, where an alpha of 0 should return Dst. Therefore

If we include the last term into the original formula, we can still do it in 2 passes. We need to be careful to clamp the alpha value with max(0.001, a) because we’re now potentially dividing by 0. The final formula is

 

J) Soft Light

Formula 1 – (1 – DstColor) · (1 – (SrcColor – 0.5)), if SrcColor > 0.5
DstColor · (SrcColor + 0.5), if SrcColor <= 0.5
Shader Pass 1

float3 A = 2.0 * color.rgb * color.a / (1.0 - 2.0 * color.rgb * color.a);
float3 B = (1.0 - color.a) / ((1.0 - 2.0 * color.rgb * color.a) * max(0.001, color.a));
color.rgb = A + B;

Blend Pass 1 SrcColor · DstColor + SrcColor · DstColor
Shader Pass 2 color.rgb = (1.0 - 2.0 * color.rgb * color.a) * max(0.001, color.a);
Blend Pass 2 SrcColor · DstColor + SrcColor * Zero

Soft Light

For the Soft Light we apply a very similar reasoning to Overlay, which in the end leads us to Pegtop’s formula. Both are different from Photoshop’s version in that they don’t have discontinuities. This one also has a darker fringe when alpha blending.

 

K) Hard Light

Formula 1 – (1 – DstColor) · (1 – 2 · (SrcColor – 0.5)), if SrcColor> 0.5
DstColor · (2 · SrcColor), if SrcColor <= 0.5
Shader Pass 1

float3 A (2.0 * color.rgb * color.rgb - color.rgb) * color.a;

float3 B max(0.001, (4.0 * color.rgb - 4.0 * color.rgb * color.rgb) * color.a + 1.0 - color.a);

color.rgb = A B;

Blend Pass 1 SrcColor · One + DstColor · One
Shader Pass 2 color.rgb = max(0.001, (4.0 * color.rgb - 4.0 * color.rgb * color.rgb) * color.a + 1.0 - color.a);
Blend Pass 2 SrcColor · DstColor + SrcColor * Zero

Hard Light

Hard Light has a very delicate hack that allows it to work and blend with alpha. In the first pass we divide by some magic number, only to multiply it back in the second pass! That’s because when alpha is 0 it needs to result in DstColor, but it was resulting in black.

 

L) Vivid Light

Formula 1 – (1 – DstColor) / (2 · (SrcColor – 0.5)), if SrcColor > 0.5
DstColor / (1 – 2 · SrcColor), if SrcColor <= 0.5
Shader Pass 1

color.rgb *= color.a;

color.rgb = color.rgb &gt;0.5 ? 1.0 / max(0.0001, 2.0 - 2.0 * color.rgb) : 1.0);

Blend Pass 1 SrcColor · DstColor + SrcColor · Zero
Shader Pass 2 color.rgb = color.rgb &lt; 0.5 ? (color.a - color.a / max(0.0001, 2.0 * color.rgb)) : 0.0;
Blend Pass 2 SrcColor · One + SrcColor · OneMinusSrcColor

Vivid Light

 

M) Linear Light

Formula DstColor + 2 · (SrcColor – 0.5), if SrcColor > 0.5
DstColor + 2 · SrcColor – 1, if SrcColor <= 0.5
Shader Output color.rgb = (2 * color.rgb - 1.0) * color.a;
Blend Unit  SrcColor · One + DstColor · One

Linear Light

[29/04/2019] Roman in the comments below reports that he couldn’t get Linear Light to work using the proposed method and found an alternative. His reasoning is that the output color becomes negative which gets clamped. I’m not sure what changed in Unity between when I did it and now but perhaps it relied on having an RGBA16F render target which may have changed since then to some other HDR format such as RG11B10F or RGB10A2 which do not support negative values. His alternative becomes (using RevSub as the blend op):

Formula DstColor + 2 · (SrcColor – 0.5), if SrcColor > 0.5
DstColor + 2 · SrcColor – 1, if SrcColor <= 0.5
Shader Output color.rgb = -(2 * color.rgb - 1.0) * color.a;
Blend Unit DstColor · One – SrcColor · One

 

 

 
반응형
Posted by blueasa
, |

[링크] https://www.shadertoy.com/browse

 

Browse (1) - Shadertoy BETA

Results (40693):

www.shadertoy.com

 

반응형
Posted by blueasa
, |

Rim lighting and realtime shadows for sprites in Unity (2D) – 1/2

Rim lighting and realtime shadows for sprites in Unity (2D) – 2/2

 

[github] https://github.com/Rafarfn/SpriteLighting

 

Rafarfn/SpriteLighting

Custom 2D sprite lighting with shadow casting and rim lighting - Rafarfn/SpriteLighting

github.com

 

반응형
Posted by blueasa
, |

 

https://github.com/sunduk/UnityRoundedShader

 

 

유니티에서 셰이더로 원이나 모서리가 둥근 사각형 만들때 쓸 수 있는 셰이더 입니다.

구글 검색하면 자료는 많이 나오는데 쉽게 이해되는 코드가 없는것 같아서 정리할겸 만들어 봤습니다.

 

UI쪽은 사실 유니티에서 지원하는 mask기능도 있어서 쓸일이 많지는 않겠지만

실시간으로 만든 텍스쳐 다룰때는 유용할것 같습니다.

 

 

p.s 

이거 구현하면서 인터넷과 구글이 없었으면 어떻게 이런 기법들을 배우고 공유할 수 있었을까 하는 생각이 많이 들었습니다.

특히 셰이더토이, 더 북 오브 셰이더 여기 두곳은 정말 보물섬 같은 곳이네요.

 

https://www.shadertoy.com/view/ldfSDj

https://thebookofshaders.com/

 

 

[출처]

게임코디 태풍의그라운드

http://www.gamecodi.com/board/zboard.php?id=GAMECODI_Talkdev&page=1&page_num=35&select_arrange=headnum&desc=asc&sn=off&ss=on&sc=on&keyword=&no=5239&category=

반응형
Posted by blueasa
, |

Note:

Unity 5.6’s release made some changes to the default sprite shader which make parts of the shader in the following post invalid. At the bottom of this post you’ll find an updated version of the demo project that works in Unity 5.6.

Unity provides a component to outline UI objects, but it doesn’t work on world space sprites. This post will demonstrate a simple way to add outlines to sprites using an extended version of the default sprite shader along with a simple component. This could be used to highlight sprites on mouse over, highlight items in the environment, or just to make sprites stand out from their surroundings.

To begin, create a new shader in your project called Sprite-Outline. This shader provides all the functionality of the default sprite shader, with the additions to allow sprite outlines.

Shader "Sprites/Outline"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)
        [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0

        // Add values to determine if outlining is enabled and outline color.
        [PerRendererData] _Outline ("Outline", Float) = 0
        [PerRendererData] _OutlineColor("Outline Color", Color) = (1,1,1,1)
    }

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Cull Off
        Lighting Off
        ZWrite Off
        Blend One OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile _ PIXELSNAP_ON
            #pragma shader_feature ETC1_EXTERNAL_ALPHA
            #include "UnityCG.cginc"

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

            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                float2 texcoord  : TEXCOORD0;
            };

            fixed4 _Color;
            float _Outline;
            fixed4 _OutlineColor;

            v2f vert(appdata_t IN)
            {
                v2f OUT;
                OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
                OUT.texcoord = IN.texcoord;
                OUT.color = IN.color * _Color;
                #ifdef PIXELSNAP_ON
                OUT.vertex = UnityPixelSnap (OUT.vertex);
                #endif

                return OUT;
            }

            sampler2D _MainTex;
            sampler2D _AlphaTex;
            float4 _MainTex_TexelSize;

            fixed4 SampleSpriteTexture (float2 uv)
            {
                fixed4 color = tex2D (_MainTex, uv);

                #if ETC1_EXTERNAL_ALPHA
                // get the color from an external texture (usecase: Alpha support for ETC1 on android)
                color.a = tex2D (_AlphaTex, uv).r;
                #endif //ETC1_EXTERNAL_ALPHA

                return color;
            }

            fixed4 frag(v2f IN) : SV_Target
            {
                fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;

                // If outline is enabled and there is a pixel, try to draw an outline.
                if (_Outline > 0 && c.a != 0) {
                    // Get the neighbouring four pixels.
                    fixed4 pixelUp = tex2D(_MainTex, IN.texcoord + fixed2(0, _MainTex_TexelSize.y));
                    fixed4 pixelDown = tex2D(_MainTex, IN.texcoord - fixed2(0, _MainTex_TexelSize.y));
                    fixed4 pixelRight = tex2D(_MainTex, IN.texcoord + fixed2(_MainTex_TexelSize.x, 0));
                    fixed4 pixelLeft = tex2D(_MainTex, IN.texcoord - fixed2(_MainTex_TexelSize.x, 0));

                    // If one of the neighbouring pixels is invisible, we render an outline.
                    if (pixelUp.a * pixelDown.a * pixelRight.a * pixelLeft.a == 0) {
                        c.rgba = fixed4(1, 1, 1, 1) * _OutlineColor;
                    }
                }

                c.rgb *= c.a;

                return c;
            }
            ENDCG
        }
    }
}

Now create a new material called SpriteOutline and assign the newly created shader to it in the inspector.

Sprite Outline Material

Next create a new C# script and name it SpriteOutline. This component is going to handle updating our material in the editor and at runtime to toggle the outline off or on and also change the color. This component can also be targetted in an animation to enable or disable outlines for specific animation frames or to change the outline color.

using UnityEngine;

[ExecuteInEditMode]
public class SpriteOutline : MonoBehaviour {
    public Color color = Color.white;

    private SpriteRenderer spriteRenderer;

    void OnEnable() {
        spriteRenderer = GetComponent<SpriteRenderer>();

        UpdateOutline(true);
    }

    void OnDisable() {
        UpdateOutline(false);
    }

    void Update() {
        UpdateOutline(true);
    }

    void UpdateOutline(bool outline) {
        MaterialPropertyBlock mpb = new MaterialPropertyBlock();
        spriteRenderer.GetPropertyBlock(mpb);
        mpb.SetFloat("_Outline", outline ? 1f : 0);
        mpb.SetColor("_OutlineColor", color);
        spriteRenderer.SetPropertyBlock(mpb);
    }
}

Now that the hard work is done, add a few sprites to your scene. Change the material field of the SpriteRenderer component to the SpriteOutline material created above. You’ll also want to add the SpriteOutline component to this game object to show a white outline by default. To hide the outline simply disable or remove the component.

Completed Sprite

With all that completed, you should now have a sprite with a white outline. In the inspector you can change the color to anything you’d like, independently from the SpriteRenderer color. The custom shader also maintains all existing functionality of the default sprite shader.

Completed Sprite

Please download the demo project and play around with it to get a better idea of how this technique looks and works. It contains a single scene with three examples of outlined sprites, one of which is animated.

Shaders can be complicated, but they are very powerful and make it quite easy to implement graphical features, even in 2D. If you have any further questions please feel free to message me on Twitter @RyanNielson or comment below.

Update (June 2, 2016)

Some people have been asking about how to change the thickness of the sprite outlines. Please download this new demo project with the changes to add this functionality. Changes were made to both the shader and component. Just adjust the outline size slider on the sprite outline component to change outline size. There is a limited outline size of 16 to prevent issues with shader for loop unrolling. It hasn’t been tested throughly, so your results may vary, but it’s probably a good place to start.

Update (April 7, 2017)

Unity 5.6 has been released, and along with that came some changes to the default sprite shader. Unfortunetely this seems to be causing issues with parts of the method used above. Please download this new demo project which changes the sprite outline shader to incorporate the 5.6 shader changes.



[출처] https://nielson.io/2016/04/2d-sprite-outlines-in-unity/

반응형
Posted by blueasa
, |

[파일]

Super-Blur-master.zip




[링크] https://github.com/PavelDoGreat/Super-Blur



Super Blur

Blur effect that you can apply on Camera and UI. Gaussian weights was taken from this project.

view

Usage

Just add SuperBlur.cs or SuperBlurFast.cs script to Camera and attach Blur Material and UI Material to it.

  • SuperBlur - (recommended way) It's using OnRenderImage to grab screen texture.

  • SuperBlurFast - Render scene directly to render texture. Much better perfomance on mobile devices, but doesn't work with other post effects.

Properties

editor

  • Render Mode - Chooses to render as Post Effect or just apply blurred texture to UI material.

  • Kernel Size - Bigger kernels produces bigger blur, but are more expensive.

  • Interpolation - Use if you want to create smooth blurring transition.

  • Downsample - Controls buffer resolution (0 = no downsampling, 1 = half resolution... etc.).

  • Iterations - More iterations = bigger blur, but comes at perfomance cost.

  • Gamma Correction - Enables gamma correction to produce correct blur in Gamma Colorspace. Disable this option if you use Linear Colorspace.

License

If you'd try to sell it on Asset Store, then I'm gonna find you.

See LICENSE for details.



반응형
Posted by blueasa
, |

[파일]

Dvornik-Unity-Distortion.zip



Unity 3D Anoxemia Heat Distort Tutorial



Hello. It is a part of Anoxemia tutorials. Here I want to share some experience of creating 2D game with Unity

What we going to do here:



DOWNLOAD:
https://dl.dropboxusercontent.com/u/106482752/Dvornik-Unity-Distortion.zip

Root tutorial: http://kostiantyn-dvornik.blogspot.com/2014/07/anoxemia-unity-2d-tutorial.html


If you ever want to create cool effects like hot air waving or thick glass refraction or some underwater streams you will came to Detonator package and HeatDistort shader.But as for me it looks very complicated, so write my own and use it well with latest Unity 2D system.

NOTE: it works only with Unity Pro and Deffered lighting on. It works the same way how Detonator'a works. It tooks image and project it correctly on a plane with texture distortion.

We will split tutorial into 2 steps.
1.Explain shader
2. How to use it.

1.
Lets take a look at the shader:

Shader "Dvornik/Distort" {
Properties {
_Refraction ("Refraction", Range (0.00, 100.0)) = 1.0
_DistortTex ("Base (RGB)", 2D) = "white" {}
}

SubShader {

Tags { "RenderType"="Transparent" "Queue"="Overlay" }
LOD 100

GrabPass
{

}

CGPROGRAM
#pragma surface surf NoLighting
#pragma vertex vert

fixed4 LightingNoLighting(SurfaceOutput s, fixed3 lightDir, fixed atten){
        fixed4 c;
        c.rgb = s.Albedo;
        c.a = s.Alpha;
        return c;
  }

sampler2D _GrabTexture : register(s0);
sampler2D _DistortTex : register(s2);
float _Refraction;

float4 _GrabTexture_TexelSize;

struct Input {
float2 uv_DistortTex;
float3 color;
float3 worldRefl;
float4 screenPos;
INTERNAL_DATA
};

void vert (inout appdata_full v, out Input o) {
  UNITY_INITIALIZE_OUTPUT(Input,o);
  o.color = v.color;
}

void surf (Input IN, inout SurfaceOutput o) {

    float3 distort = tex2D(_DistortTex, IN.uv_DistortTex) * float3(IN.color.r,IN.color.g,IN.color.b );
    float2 offset = distort * _Refraction * _GrabTexture_TexelSize.xy;
    IN.screenPos.xy = offset * IN.screenPos.z + IN.screenPos.xy;
    float4 refrColor = tex2Dproj(_GrabTexture, IN.screenPos);
    o.Alpha = refrColor.a;
    o.Emission = refrColor.rgb;
}
ENDCG
}
}

We have just 2 properties. It is

_Refraction -amount of distortion
_DistortText - texture according to what we gonna distort our environment. You can use any colored texture. To make distortion. But in fact only Red and Green channels are working as distortion vector.

Tags { "RenderType"="Transparent" "Queue"="Overlay" } - We set Queue to Overlay because we want to render this effect after everything.

#pragma surface surf NoLighting
#pragma vertex vert

We used custom NoLigthing model and custom vertex shader to have deal with vertex color that used in particle system. There is a little chunk, cuz we write only Emission to have absolutely No Lighting shader.

 float3 distort = tex2D(_DistortTex, IN.uv_DistortTex) * float3(IN.color.r,IN.color.g,IN.color.b );
 float2 offset = distort * _Refraction * _GrabTexture_TexelSize.xy;
 IN.screenPos.xy = offset * IN.screenPos.z + IN.screenPos.xy;
 float4 refrColor = tex2Dproj(_GrabTexture, IN.screenPos);

Here we read distort texture, calculate offset of the screen and project on the model correctly. That's it.

2. 
Create a simple material and apply that shader. Next if you use particle system apply particle render order script to that. Other way some object will be rendered after distortion so it will looks weird. You can use particle Color or Color Over LifeTime to make distortion more/less. I often setup it thats way:

to make distortion fade in and fade out. Thats probabbly all that you need to know about.

Know bugs:
1.

How to resolve:
Add particle order script to PS and set order to  bigger then foreground sprite.
Effect is not working with orthographic camera

2. To much distortion on large distance to camera

How to resolve: add script that decreasing material property distortion with distance to camera.




[출처] http://kostiantyn-dvornik.blogspot.kr/2014/10/unity-3d-anoxemia-heat-distort-tutorial.html

반응형
Posted by blueasa
, |