Pivot Offset : 카메라가 회전하거나 흔들릴 때 중심이 되는 기준점
Impulse Listener도 같은 채널을 수신하고 있어야 진동이 전달됩니다.0: default로 충분하지만, 여러 종류의 진동을 분리하고 싶을 때 유용해요.100으로 설정되어 있어서,0.0에 가까울수록 천천히 사라짐 (멀리서도 강함),1.0에 가까울수록 빠르게 감쇠 (가까이 있어야 강하게 느껴짐).GenerateImpulse() 호출 시 기본으로 사용되는 진동의 방향과 세기.X: 0, Y: 0, Z: 0 → 방향 정보 없음 = Signal에서 정의된 대로 작동.🟢 사용 예시: 폭발이 캐릭터 중심에서 동시에 발생하고, 거리 무시하고 동일하게 흔들리고 싶을 때.
🟢 사용 예시: 발걸음, 총알 발사, 작은 폭발 등 — 가까울수록 더 세게 느껴지게 하고 싶을 때.
🟢 사용 예시: 지진, 우주선 충격파, 초음파나 마법 효과처럼 "멀리서 오는 충격"을 표현할 때.

Properties {
_MainTex ("MainTex", 2D) = "white" {}
_DecalTex ("Decal", 2D) = "white" {}
[Toggle] _ShowDecal("Show Decal?", Float) = 0
}
(생략)
void surf(Input IN, inout SurfaceOutput o) {
fixed4 a = tex2D(_MainTex, IN.uv_MainTex);
fixed4 b = tex2D(_DecalTex, IN.uv_MainTex) * _ShowDecal;
o.Albedo = b.r > 0.9 ? b.rgb : a.rgb;
}
void Start()
{
mat = this.GetComponent<Renderer>().sharedMaterial;
}
public void OnMouseDown()
{
showDecal = !showDecal;
if (showDecal)
mat.SetFloat("_ShowDecal", 1);
else
mat.SetFloat("_ShowDecal", 0);
}
c# 코드로 decal 표시 제어하는 연습
(OnMouseDown()은 deprecated됐길래 Player Input으로 받음)

Tags {"Queue" = "Geometry-1"}
ColorMask 0
ZWrite Off
Stencil
{
Ref 1 // 기준값
Comp always // 스텐실 테스트 (렌더링 할지말지)
Pass replace // 테스트 통과하면 뭐 할건지
}
Hole.shader
Tags { "Queue" = "Geometry" }
Stencil
{
Ref 1
Comp notequal // 스텐실이 1이랑 다르면 그린다
Pass keep // Comp 통과하면 스텐실 값 그대로 둔다
}
Wall.shader

Shader "Holistic/StencilWindow"
{
Properties
{
_SRef("Stencil Ref", Float) = 1
[Enum(UnityEngine.Rendering.CompareFunction)] _SComp("Stencil Comp", Float) = 8
[Enum(UnityEngine.Rendering.StencilOp)] _SOp("Stencil Op", Float) = 2
}
SubShader
{
Tags{ "Queue" = "Geometry-1" }
ZWrite Off
ColorMask 0
Stencil
{
Ref[_SRef]
Comp[_SComp]
Pass[_SOp]
}
CGPROGRAM
(생략)
ENDCG
}
}
StencilWindow.shader
[Enum(...)]을 붙이면 머테리얼 인스펙터에서 드롭다운으로 노출된다 Properties {
_SRef("Stencil Ref", Float) = 1
[Enum(UnityEngine.Rendering.CompareFunction)] _SComp("Stencil Comp", Float) = 8
[Enum(UnityEngine.Rendering.StencilOp)] _SOp("Stencil Op", Float) = 2
}
SubShader {
Stencil
{
Ref[_SRef]
Comp[_SComp]
Pass[_SOp]
}
StencilObject.shader
SubShader {
Tags {"Queue" = "Transparent"}
Pass {
Blend DstColor Zero
SetTexture [_MainTex] { combine texture }
}
}
이건 Pass만 적어도 되는 이유?
Impulse Source를 player에, Cinemachine Impulse Receiver를 Cinameachine camera에,
Cinemachine Basic Multichannel Perlin은 Cinemachine camera에.
if (direction != Vector3.zero) noise.NoiseProfile = walk_noise;
else noise.NoiseProfile = idle_noise;
noiseSetting(perline noise의 preset)을 불연속적으로 변화시켰더니 부자연스러운 전환 발생.
using UnityEngine;
using Unity.Cinemachine;
using System.Collections;
public class PlayerMove : MonoBehaviour
{
[SerializeField] CinemachineCamera player_vcam;
[SerializeField] float walk_gap = 0.5f;
[SerializeField] float amplitudeGain_walk = 2f;
[SerializeField] float frequencyGain_walk = 1.5f;
[SerializeField] AudioClip[] footstepSounds;
AudioSource footstep;
public float moveSpeed = 5f;
private CharacterController characterController;
private CinemachineImpulseSource impulse;
private CinemachineBasicMultiChannelPerlin noise;
private bool wait_nextFootstep = false;
private float targetAmplitudeGain;
private float targetFrequencyGain;
void Start()
{
characterController = GetComponent<CharacterController>();
impulse = GetComponent<CinemachineImpulseSource>();
noise = player_vcam.GetComponent<CinemachineBasicMultiChannelPerlin>();
footstep = gameObject.AddComponent<AudioSource>();
Cursor.lockState = CursorLockMode.Locked; // 마우스를 화면 중앙에 고정
Cursor.visible = false; // 마우스 커서 숨김
}
void Update()
{
Vector3 direction = Vector3.zero;
if (Input.GetKey(KeyCode.W)) direction += player_vcam.transform.forward;
if (Input.GetKey(KeyCode.S)) direction += -player_vcam.transform.forward;
if (Input.GetKey(KeyCode.A)) direction += -player_vcam.transform.right;
if (Input.GetKey(KeyCode.D)) direction += player_vcam.transform.right;
direction.y = 0f; // 점프를 구현하지 않는 이상 y 축 이동 방지 (중력 유지)
direction.Normalize();
if (direction != Vector3.zero)
{
targetAmplitudeGain = amplitudeGain_walk;
targetFrequencyGain = frequencyGain_walk;
if (!wait_nextFootstep)
{
wait_nextFootstep = true;
StartCoroutine(GenerateImpulseWithDelay());
}
}
else
{
targetAmplitudeGain = 0.7f;
targetFrequencyGain = 0.7f;
}
noise.AmplitudeGain = Mathf.Lerp(noise.AmplitudeGain, targetAmplitudeGain, Time.deltaTime * 5f);
noise.FrequencyGain = Mathf.Lerp(noise.FrequencyGain, targetFrequencyGain, Time.deltaTime * 5f);
characterController.Move(direction * moveSpeed * Time.deltaTime);
}
private IEnumerator GenerateImpulseWithDelay()
{
impulse.GenerateImpulse();
PlayFootstepSound();
yield return new WaitForSeconds(walk_gap);
wait_nextFootstep = false;
}
private void PlayFootstepSound()
{
if (footstepSounds.Length > 0)
{
int randomIndex = Random.Range(0, footstepSounds.Length);
footstep.clip = footstepSounds[randomIndex];
footstep.Play();
}
}
}
목표값을 향해 lerp로 변경

perlin preset은 handheld_normal_mild
문이 하나밖에 없는데 APV 적용시키기 애매해서
Light Probe를 뒀다가 문이 열리고 나면 꺼봤는데 효과 안 사라짐

Light Probe는 해당 점 안에 있는 오브젝트들 뿐만 아니라
모든 동적 오브젝트들에도 밝기를 적용시킨다