출처 - https://www.youtube.com/watch?v=Ws4ukvCgTOU
출처 영상에 있는 Peer Play 님의 쉐이더 튜토리얼은 쉐이더 기초와 프로그래밍 기초는 할 수 있다고 가정하고 진행하는 것 같다.
그래서 내용이 퀄리티가 높다.
구현해 본 영상
원리
1. 쉐이더 안에서 색이 있는 텍스쳐 변수 A와 회색인 텍스쳐 변수 B를 만들어준다.
회색을 만드는 방법은 r , g , b 를 더한 후, 3으로 나누면 된다.
// (c.r + c.g + c.b) * 0.333
(나누기 3) 보다 (곱하기 0.333)이 성능을 더 좋게 사용한다.
2. 마우스 포지션을 받아와서 일정 거리 이내이면 색을 입히고, 일정 거리를 벗어나면 회색을 입혀준다.
마우스 포지션은 c# 코드로 Ray를 이용해서 쉐이더 변수에 넘겨주었다.
소스 코드
c# 코드
마우스 포지션의 값을 받아 쉐이더 변수에 값을 넘겨준다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RaycastMousePos : MonoBehaviour
{
Camera _camera;
RaycastHit _hit;
Ray _ray;
Vector3 _mousePos, _smoothPoint;
public float _radius, _softness, _smoothSpeed, _scaleFactor;
void Start()
{
_camera = GetComponent<camera>();
}
void Update()
{
if (Input.GetKey(KeyCode.UpArrow))
{
_radius += _scaleFactor * Time.deltaTime;
}
if (Input.GetKey(KeyCode.DownArrow))
{
_radius -= _scaleFactor * Time.deltaTime;
}
if (Input.GetKey(KeyCode.LeftArrow))
{
_softness += _scaleFactor * Time.deltaTime;
}
if (Input.GetKey(KeyCode.RightArrow))
{
_softness -= _scaleFactor * Time.deltaTime;
}
Mathf.Clamp(_radius, 0, 100);
Mathf.Clamp(_softness, 0, 100);
_mousePos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
_ray = _camera.ScreenPointToRay(_mousePos);
if (Physics.Raycast(_ray, out _hit))
{
_smoothPoint = Vector3.MoveTowards(_smoothPoint, _hit.point, _smoothSpeed * Time.deltaTime);
Vector4 pos = new Vector4(_smoothPoint.x, _smoothPoint.y, _smoothPoint.z, 0);
Shader.SetGlobalVector("GLOBALmask_Position", pos);
}
Shader.SetGlobalFloat("GLOBALmask_Radius", _radius);
Shader.SetGlobalFloat("GLOBALmask_softness", _softness);
}
}
쉐이더 코드
Shader "MinGyu/SphericalMask" {
Properties{
_Color("Color", Color) = (1,1,1,1)
_MainTex("Albedo (RGB)", 2D) = "white" {}
_ColorStrength("Color Strength", Range(1,4)) = 1
_EmissionColor("Emission Color", Color) = (1,1,1,1)
_EmissionTex("Emission (RGB)", 2D) = "white" {}
_EmissionStrength("Emission Strength", Range(0,10)) = 1
_Position("World Position", Vector) = (0,0,0,0)
_Radius("Sphere Radius", Range(0,100)) = 0
_Softness("Sphere Softness", Range(0,100)) = 0
}
SubShader{
Tags { "RenderType" = "Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Standard fullforwardshadows
#pragma target 3.0
sampler2D _MainTex;
sampler2D _EmissionTex;
struct Input {
float2 uv_MainTex;
float2 uv_EmissionTex;
float3 worldPos;
};
fixed4 _Color, _EmissionColor;
half _ColorStrength, _EmissionStrength;
// Spherical Mask
uniform float4 GLOBALmask_Position;
uniform half GLOBALmask_Radius;
uniform half GLOBALmask_Softness;
void surf(Input IN, inout SurfaceOutputStandard o) {
// Color
fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
// Grayscale
float grayscale = (c.r + c.g + c.b) * 0.333;
fixed3 c_g = fixed3(grayscale, grayscale, grayscale);
// Emission
fixed4 e = tex2D(_EmissionTex, IN.uv_EmissionTex) * _EmissionColor * _EmissionStrength;
half d = distance(GLOBALmask_Position, IN.worldPos);
half sum = saturate((d - GLOBALmask_Radius) / -GLOBALmask_Softness);
fixed4 lerpColor = lerp(fixed4(c_g,1), c * _ColorStrength, sum);
fixed4 lerpEmission = lerp(fixed4(0,0,0,0), e, sum);
o.Albedo = lerpColor.rgb;
o.Emission = lerpEmission.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
느낀 점
c# 코드로 쉐이더 변수에 영향을 준 것은 처음 해보았는데, 재밌었다.
쉐이더로 할 수 있는 건 정말 많은 것 같다.
그리고 쉐이더에서 변수를 선언할 때, uniform을 처음 사용해보았다.
// shader 에서 이렇게 선언했으면
uniform float4 GLOBALmask_Position;
// c# 코드에서 바로 접근 가능하다.
Shader.SetGlobalVector("GLOBALmask_Position", 값);
'기타 > Unity' 카테고리의 다른 글
Sword Effect 제작 (1) | 2019.03.13 |
---|---|
Sword Effect 만들어봐야겠다 (1) | 2019.03.11 |
[Unity Effect] 에셋에 있는 이펙트 따라만들기 (1) | 2019.03.07 |
[Unity Shader] 뒤에 있는 물체의 실루엣을 보이게 하는 쉐이더 (0) | 2019.02.14 |
[Unity Shader] 눈 쌓이는 쉐이더 (0) | 2019.02.14 |