Roxy Gen
Posted on October 21, 2024
Sprite 2d with shadowcasting in 3d space
Isometric stylized water
Lowpoly rigging and skinning
Mixamo integration
Custom render feature with custom postprocessing volume
Adaptation of this built-in shader for URP.
Shader "PostProcess/TiltShift"
{
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"
float _Offset;
float _Area;
float _Spread;
float _Samples;
float _Radius;
float2 _PixelSize;
float _CubicDistortion;
float _DistortionScale;
float4 _GoldenRatioAngle;
float4 _BlitTexture_TexelSize;
inline half gradient (half2 uv)
{
half2 h = uv.xy - half2(0.5, 0.5);
half r2 = dot(h, h);
uv = (1.0 + r2 * (_CubicDistortion * sqrt(r2))) * _DistortionScale * h + 0.5;
half2 coord = uv * 2.0 - 1.0 + _Offset;
return pow ( abs (coord.y * _Area), _Spread);
}
half4 Tilt(Varyings input) : SV_Target
{
half2x2 rot = half2x2(_GoldenRatioAngle);
half4 accumulator = 0.0;
half4 divisor = 0.0;
half r = 1.0;
half2 angle = half2(0.0, _Radius * saturate(gradient(input.texcoord)));
for (int i = 0; i < _Samples; i++)
{
r += 1.0 / r;
angle = mul(rot, angle);
half4 bokeh = SAMPLE_TEXTURE2D(
_BlitTexture,
sampler_LinearClamp,
input.texcoord + _PixelSize * (r - 1.0) * angle
);
accumulator += bokeh * bokeh;
divisor += bokeh;
}
return accumulator/divisor;
}
ENDHLSL
SubShader
{
Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"}
// No culling or depth
Cull Off ZWrite Off
Pass
{
Name "TiltPass"
HLSLPROGRAM
#pragma vertex Vert
#pragma fragment Tilt
ENDHLSL
}
}
}
Custum Postprocessing voulme component
using System;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[Serializable, VolumeComponentMenuForRenderPipeline ("Postprocess/TiltShift", typeof(UniversalRenderPipeline))]
public class TiltShiftPostprocess : VolumeComponent, IPostProcessComponent
{
public BoolParameter Active = new BoolParameter(true);
public ClampedFloatParameter Offset = new ClampedFloatParameter(0f, 0f, 1f);
public ClampedFloatParameter Area = new ClampedFloatParameter(1f, 0f, 20f);
public ClampedFloatParameter Spread = new ClampedFloatParameter(1f, 0f, 20f);
public ClampedIntParameter Samples = new ClampedIntParameter(32, 4, 64);
public ClampedFloatParameter Radius = new ClampedFloatParameter(2f, 0f, 2f);
public ClampedFloatParameter CubicDistortion = new ClampedFloatParameter(5f, 0f, 20f);
public ClampedFloatParameter DistortionScale = new ClampedFloatParameter(1f, 0f, 1f);
public bool IsActive() => Active.value;
public bool IsTileCompatible() => true;
}
Render Feature code
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class TiltShiftRenderFeature : ScriptableRendererFeature
{
private Material m_Material;
class TiltShiftRenderPass : ScriptableRenderPass
{
private Material m_Material;
// private static readonly int m_tiltId = Shader.PropertyToID("_TiltPass");
private RTHandle m_Tilt;
private RenderTextureDescriptor m_TiltTextureDescriptor;
// Golden Ratio Angle
private Vector4 m_GoldenRatioAngle = Vector4.zero;
private const float m_GoldenRatio = 2.39996323f;
public TiltShiftRenderPass(Material material)
{
m_Material = material;
float goldenCos = Mathf.Cos(m_GoldenRatio);
float goldenSin = Mathf.Sin(m_GoldenRatio);
m_GoldenRatioAngle.Set(goldenCos, goldenSin, -goldenSin, goldenCos);
m_TiltTextureDescriptor = new RenderTextureDescriptor(
Screen.width, Screen.height,
RenderTextureFormat.Default, 0);
}
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
m_TiltTextureDescriptor.width = cameraTextureDescriptor.width;
m_TiltTextureDescriptor.height = cameraTextureDescriptor.height;
RenderingUtils.ReAllocateIfNeeded(ref m_Tilt, m_TiltTextureDescriptor); // move to configure
}
// In URP 14 have blit problem, need to investigate
// possible solution: https://discussions.unity.com/t/resolved-custom-render-pass-failing-urp-v14-0-6/911141/3
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer commandBuffer = CommandBufferPool.Get();
VolumeStack volumeStack = VolumeManager.instance.stack;
TiltShiftPostprocess tiltData = volumeStack.GetComponent<TiltShiftPostprocess>();
RTHandle cameraTargetHandle = renderingData.cameraData.renderer.cameraColorTargetHandle;
if (cameraTargetHandle == null)
return;
if (tiltData.IsActive())
{
UpdateTiltMaterial(tiltData);
if(m_Material!=null)
{
if(cameraTargetHandle == null)
{
Debug.LogWarning("TiltTex is null");
}
if( cameraTargetHandle == null)
{
Debug.LogWarning("Camera is null");
}
Blit(commandBuffer, cameraTargetHandle, m_Tilt, m_Material, 0);
Blit(commandBuffer, m_Tilt, cameraTargetHandle, null, 1);
}
}
context.ExecuteCommandBuffer(commandBuffer);
CommandBufferPool.Release(commandBuffer);
}
private void UpdateTiltMaterial(TiltShiftPostprocess tiltData)
{
if (m_Material == null)
{
return;
}
// TODO move string to const or Shader Property ID
m_Material.SetFloat("_Offset", tiltData.Offset.value);
m_Material.SetFloat("_Area", tiltData.Area.value);
m_Material.SetFloat("_Spread", tiltData.Spread.value);
m_Material.SetInt("_Samples", tiltData.Samples.value);
m_Material.SetFloat("_Radius", tiltData.Radius.value);
m_Material.SetFloat("_CubicDistortion", tiltData.CubicDistortion.value);
m_Material.SetFloat("_DistortionScale", tiltData.DistortionScale.value);
// Setting up precalulated staff from here https://www.shadertoy.com/view/4d2Xzw
// to not calculate at runtime
m_Material.SetVector("_GoldenRatioAngle", m_GoldenRatioAngle);
}
public void Dispose()
{
// would material be deleted twice?
// #if UNITY_EDITOR
// if (EditorApplication.isPlaying)
// {
// Destroy(m_Material);
// }
// else
// {
// DestroyImmediate(m_Material);
// }
// #else
// Destroy(m_Material);
// #endif
if (m_Tilt!= null)
{
m_Tilt.Release();
}
}
}
TiltShiftRenderPass m_ScriptablePass;
public override void Create()
{
if (m_Material == null || m_Material.shader == null)
{
if (m_Material!=null)
{
CoreUtils.Destroy(m_Material);
}
m_Material = CoreUtils.CreateEngineMaterial("PostProcess/TiltShift");
}
m_ScriptablePass = new TiltShiftRenderPass(m_Material);
m_ScriptablePass.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
renderer.EnqueuePass(m_ScriptablePass);
}
protected override void Dispose(bool disposing)
{
m_ScriptablePass.Dispose();
#if UNITY_EDITOR
if (EditorApplication.isPlaying)
{
Destroy(m_Material);
}
else
{
DestroyImmediate(m_Material);
}
#else
Destroy(m_Material);
#endif
}
}
Godot Cozy Test Scene
Grass shader modification:
void vertex()
{
//...
worldPos = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
}
void fragment()
{
/// ...
float filter = texture(grass_filter_texture, (worldPos.xz + filter_shift.xz)/ filter_scale).a;
if (filter > density_threshold)
{
discard;
}
/// ...
}
Filter texture. Using alpha channel, but can lower bit depth for to 8 for examle.
Round rect button shader code:
shader_type canvas_item;
uniform vec4 color : source_color = vec4(1.0, 1.0, 1.0, 1.0);
uniform vec4 border_color : source_color = vec4(1.0, 1.0, 1.0, 1.0);
uniform float border_size: hint_range(0.0, 1.0) = 0.1;
uniform float corner_radius = 0.0;
vec4 square(vec2 uv, float width)
{
uv = uv * 2.0 - 1.0;
vec2 abs_uv = abs(uv.xy);
float square = step(width, max(abs_uv.x, abs_uv.y));
return vec4(vec3(square), 1.0);
}
vec4 square_rounded(vec2 uv, float width, float radius){
uv = uv * 2.0 - 1.0;
radius *= width; // TODO: make radius go from 0-1 instead of 0-width
vec2 abs_uv = abs(uv.xy) - radius;
vec2 dist = vec2(max(abs_uv.xy, 0.0));
float square = smoothstep(width - radius, width - radius + 0.01, length(dist));
return vec4(vec3(square), 1.0);
}
void fragment() {
vec4 sq = square_rounded(UV,1, corner_radius);
vec4 sq2 = square_rounded(UV,1.0-border_size, corner_radius+0.1);
vec4 col = color;
col = mix(color, border_color, sq2.r);
col.a *= 1.0 - sq.r;
COLOR = col;
}
💖 💪 🙅 🚩
Roxy Gen
Posted on October 21, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.