Make fire shader more cartoonish like the reference
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled

- Создан URP HLSL шейдер CartoonFire.shader с процедурным FBM-шумом искажения и 3-ступенчатой постеризацией цветов (красный/оранжевый/желтый).
- Создан редакторский скрипт ApplyCartoonFireShader.cs для быстрого переключения материала.
- Материал Fire_Material.mat обновлен и переведен на новый мультяшный шейдер с настроенными параметрами.
This commit is contained in:
Данил Ярош 2026-08-06 13:54:29 +03:00
parent a0211d50fc
commit 150f84decd
6 changed files with 240 additions and 7 deletions

View File

@ -0,0 +1,42 @@
using UnityEngine;
using UnityEditor;
public static class ApplyCartoonFireShader
{
[MenuItem("Tools/Apply Cartoon Fire Shader")]
public static void Apply()
{
string materialPath = "Assets/Materials/Fire_Material.mat";
Material mat = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
if (mat == null)
{
Debug.LogError($"Material not found at {materialPath}");
return;
}
Shader cartoonShader = Shader.Find("Custom/CartoonFire");
if (cartoonShader == null)
{
Debug.LogError("Shader Custom/CartoonFire not found! Make sure it compiled successfully.");
return;
}
Undo.RecordObject(mat, "Apply Cartoon Fire Shader");
mat.shader = cartoonShader;
// Set properties
mat.SetColor("_ColorOuter", new Color(1.5f, 0.2f, 0.1f, 1.0f));
mat.SetColor("_ColorMid", new Color(1.8f, 0.55f, 0.0f, 1.0f));
mat.SetColor("_ColorInner", new Color(2.2f, 0.95f, 0.15f, 1.0f));
mat.SetVector("_Speed", new Vector4(0.0f, -1.8f, 0.0f, 0.0f));
mat.SetFloat("_DistortStrength", 0.08f);
mat.SetFloat("_ThresholdOuter", 0.15f);
mat.SetFloat("_ThresholdMid", 0.38f);
mat.SetFloat("_ThresholdInner", 0.58f);
mat.SetFloat("_NoiseScale", 15.0f);
EditorUtility.SetDirty(mat);
AssetDatabase.SaveAssets();
Debug.Log("Successfully applied CartoonFire shader to Fire_Material.mat and set default values!");
}
}

View File

@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ccc774ec6a36cbd41af560b342b39471

View File

@ -8,7 +8,7 @@ Material:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Fire_Material
m_Shader: {fileID: -6465566751694194690, guid: ec072c5cefc89e045946ddcbed457f8a, type: 3}
m_Shader: {fileID: 4800000, guid: 8b5db5774fae5da4e8d1096b76b05ba6, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
@ -45,11 +45,19 @@ Material:
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _DistortStrength: 0.08
- _Fade: 0.4
- _FireCellsCount: 5
- _NoiseScale: 15
- _ThresholdInner: 0.58
- _ThresholdMid: 0.38
- _ThresholdOuter: 0.15
m_Colors:
- _Color: {r: 2, g: 2, b: 2, a: 1}
- _Speed: {r: 0, g: -0.5, b: 0, a: 0}
- _ColorInner: {r: 2.2, g: 0.95, b: 0.15, a: 1}
- _ColorMid: {r: 1.8, g: 0.55, b: 0, a: 1}
- _ColorOuter: {r: 1.5, g: 0.2, b: 0.1, a: 1}
- _Speed: {r: 0, g: -1.8, b: 0, a: 0}
m_BuildTextureStacks: []
m_AllowLocking: 1
--- !u!114 &3751385830976373873

View File

@ -511322,9 +511322,9 @@ Transform:
m_GameObject: {fileID: 1960185702}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 359.75, y: -8.25, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_LocalPosition: {x: 350.75, y: -7.25, z: 0}
m_LocalScale: {x: 0.35, y: 0.35, z: 0.35}
m_ConstrainProportionsScale: 1
m_Children:
- {fileID: 2060491968}
m_Father: {fileID: 215445643}
@ -511378,7 +511378,7 @@ SpriteRenderer:
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_Sprite: {fileID: -6229913347053766037, guid: 1b1114bc71f1d3f429880f34c5fd8246, type: 3}
m_Sprite: {fileID: 8051134168378353487, guid: c25aa87244f398143b580fa4102b0db1, type: 3}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_FlipX: 0
m_FlipY: 0
@ -516711,7 +516711,7 @@ ParticleSystem:
m_PostInfinity: 2
m_RotationOrder: 4
cycleCount: 1
repeatInterval: 0.0001
repeatInterval: 0.01
probability: 1
SizeModule:
enabled: 0

View File

@ -0,0 +1,172 @@
Shader "Custom/CartoonFire"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Main Color (Multiplier)", Color) = (1,1,1,1)
[HDR] _ColorOuter ("Outer Color (Red)", Color) = (1.5, 0.2, 0.1, 1)
[HDR] _ColorMid ("Mid Color (Orange)", Color) = (1.8, 0.55, 0.0, 1)
[HDR] _ColorInner ("Inner Color (Yellow)", Color) = (2.2, 0.95, 0.15, 1)
_Speed ("Scroll Speed (XY)", Vector) = (0.0, -1.8, 0.0, 0.0)
_DistortStrength ("Distort Strength", Range(0, 0.5)) = 0.08
_ThresholdOuter ("Threshold Outer", Range(0, 1)) = 0.15
_ThresholdMid ("Threshold Mid", Range(0, 1)) = 0.38
_ThresholdInner ("Threshold Inner", Range(0, 1)) = 0.58
_NoiseScale ("Noise Scale", Range(1, 50)) = 15.0
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
"RenderPipeline" = "UniversalPipeline"
}
Cull Off
Lighting Off
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
Pass
{
Name "SpriteUnlit"
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
CBUFFER_START(UnityPerMaterial)
float4 _MainTex_ST;
float4 _Color;
float4 _ColorOuter;
float4 _ColorMid;
float4 _ColorInner;
float4 _Speed;
float _DistortStrength;
float _ThresholdOuter;
float _ThresholdMid;
float _ThresholdInner;
float _NoiseScale;
CBUFFER_END
// Procedural noise functions
float hash(float2 p)
{
p = frac(p * float2(123.34, 456.21));
p += dot(p, p + 45.32);
return frac(p.x * p.y);
}
float noise(float2 p)
{
float2 i = floor(p);
float2 f = frac(p);
float2 u = f * f * (3.0 - 2.0 * f);
return lerp(lerp(hash(i + float2(0.0,0.0)), hash(i + float2(1.0,0.0)), u.x),
lerp(hash(i + float2(0.0,1.0)), hash(i + float2(1.0,1.0)), u.x), u.y);
}
float fbm(float2 p)
{
float v = 0.0;
float a = 0.5;
float2 shift = float2(100.0, 100.0);
float2x2 rot = float2x2(0.8, 0.6, -0.6, 0.8);
for (int i = 0; i < 4; ++i) {
v += a * noise(p);
p = mul(rot, p) * 2.0 + shift;
a *= 0.5;
}
return v;
}
Varyings vert(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = input.uv;
output.color = input.color;
return output;
}
float4 frag(Varyings input) : SV_Target
{
// Calculate moving noise coordinates
float2 noiseUV = input.uv * _NoiseScale + _Speed.xy * _Time.y;
float n = fbm(noiseUV);
// Distort the UV coordinates
float2 distortedUV = input.uv + float2(n - 0.5, n - 0.5) * _DistortStrength;
// Sample the main sprite texture
float4 mainTex = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, distortedUV);
// Base value is derived from texture transparency and color
float value = mainTex.a;
// Fade out at the top of the sprite (vertical gradient)
value *= saturate(1.15 - input.uv.y);
// Combine with noise value
value = saturate(value * 0.3 + value * n * 0.7);
// Toon stepping (thresholds)
float stepOuter = step(_ThresholdOuter, value);
float stepMid = step(_ThresholdMid, value);
float stepInner = step(_ThresholdInner, value);
// Select color based on steps
float4 fireColor = float4(0, 0, 0, 0);
if (stepInner > 0.5)
{
fireColor = _ColorInner;
}
else if (stepMid > 0.5)
{
fireColor = _ColorMid;
}
else if (stepOuter > 0.5)
{
fireColor = _ColorOuter;
}
// Final alpha is gated by the outer step
fireColor.a *= stepOuter;
// Modulate by sprite / particle vertex color
fireColor *= input.color * _Color;
return fireColor;
}
ENDHLSL
}
}
}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8b5db5774fae5da4e8d1096b76b05ba6
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant: