Quantcast
Channel: Questions in topic: "shader programming"
Viewing all articles
Browse latest Browse all 169

Help with making a trail effect in a fragment shader

$
0
0
So I am doing a simple simulation where I create a vector of positions that I move in the CPU and pass it to the GPU using an Image Effedct shader to render circles. I want to do a trail effect for each "particle". I've done this so many times using compute shaders, but never a using a fragment shader, and I'm having trouble passing the previous frame to the shader so it can fade the previous color and add to the next one in order to achieve this effect. I am using the Built-in render pipeline. This is the shader code: Shader "Custom/ChaosInACircle" { Properties { _PrevFrame ("Previous Frame", 2D) = "white" {} _Aspect ("Aspect", float) = 1.0 _Smoothness ("Smoothness", Range(0, 1)) = 0.01 _ColorDecay ("Color Decay", Range(0, 1)) = 0.01 _NumCircles ("Number of Circles", Range(0, 100)) = 0 [ShowAsVector2] _CircumferenceRadius ("Circumference Radius", vector) = (0.5, 0.505, 0, 0) } SubShader { Tags { "RenderType"="Opaque" } // No culling or depth Cull Off ZWrite Off ZTest Always Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; struct Circle { float2 center; float2 velocity; float4 color; float radius; }; float _Aspect; float _Smoothness; float _ColorDecay; float _NumCircles; float2 _CircumferenceRadius; float4 _Centers[100]; float4 _Colors[100]; float _Radius[100]; sampler2D _PrevFrame; float4 DrawCircle(float2 cuv, float2 uv, float innerRadius, float outerRadius, float4 color) { float2 diff = uv - cuv; diff.x *= _Aspect; float dist = sqrt(dot(diff, diff)); float alpha = smoothstep(outerRadius, outerRadius - _Smoothness, dist); alpha -= smoothstep(innerRadius, innerRadius - _Smoothness, dist); return color * alpha; } v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_Target { float4 circunference = DrawCircle(float2(0.5, 0.5), i.uv, _CircumferenceRadius.x, _CircumferenceRadius.y, float4(1, 1, 1, 1)); // this is where I tried to get the previous frame color float4 color = tex2D(_PrevFrame, i.uv) * (1 - _ColorDecay); for (int k = 0; k < _NumCircles; k++) color += DrawCircle(_Centers[k], i.uv, 0, _Radius[k], _Colors[k]); color += circunference; return color; } ENDCG } } } And my c# code: using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class ChaosInACircle : MonoBehaviour { [SerializeField] private Material _material; [SerializeField] private RawImage _image; [SerializeField] private AudioSource _audioSource; [SerializeField] private AudioClip _audioClip; [Header("Setup")] [SerializeField] private int _numCircles = 10; [SerializeField] private float _audioMaxCooldown = 0.01f; [SerializeField] private float _gravity = 0.1f; [SerializeField] private float _circleRadius = 0.01f; [SerializeField] private float _circumferenceOuterRadius = 0.505f; [SerializeField] private float _circumferenceInnerRadius = 0.5f; private Vector4[] _centers = new Vector4[100]; private Vector4[] _velocities = new Vector4[100]; private Color[] _colors = new Color[100]; private float[] _radius = new float[100]; private float _audioCooldown = 0; [SerializeField] private RenderTexture _previousFrameTex; private void Start() { Reset(); } private void FixedUpdate() { float aspect = (float)Screen.width / (float)Screen.height; _material.SetFloat("_Aspect", aspect); _material.SetInt("_NumCircles", _numCircles); _material.SetVector("_CircumferenceRadius", new Vector2(_circumferenceInnerRadius, _circumferenceOuterRadius)); UpdateCircles(); } private void CreateRenderTexture() { _previousFrameTex = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32); _previousFrameTex.enableRandomWrite = true; _previousFrameTex.Create(); } private void CreateCircle(int k) { float xOffset = .5f + (k - _numCircles / 2) * .0001f; _centers[k] = new Vector4(xOffset, .5f, 0, 0); _velocities[k] = Vector4.zero; _colors[k] = Random.ColorHSV(); _radius[k] = _circleRadius; } [EButton] private void Reset() { CreateRenderTexture(); _centers = new Vector4[100]; _velocities = new Vector4[100]; _colors = new Color[100]; _radius = new float[100]; for (int k = 0; k < _numCircles; k++) CreateCircle(k); } private void UpdateCircle(int k) { Vector4 velocity = _velocities[k]; Vector4 center = _centers[k]; float radii = _radius[k]; velocity.y -= _gravity * Time.fixedDeltaTime; Vector4 circumferenceCenter = new Vector4(0.5f, 0.5f, 0, 0); Vector4 toCenter = center - circumferenceCenter; float pos = toCenter.x * toCenter.x + toCenter.y * toCenter.y; float radius = _circumferenceInnerRadius - radii * 2; if (pos >= radius * radius) { velocity = Vector2.Reflect(velocity, toCenter.normalized); if (_audioCooldown <= 0) { _audioSource.pitch = Random.Range(0.7f, .9f); _audioSource.PlayOneShot(_audioClip); } _audioCooldown = _audioMaxCooldown; } center += velocity * Time.fixedDeltaTime; _centers[k] = center; _velocities[k] = velocity; } private void UpdateCircles() { for (int k = 0; k < _numCircles; k++) UpdateCircle(k); _audioCooldown -= Time.fixedDeltaTime; _material.SetVectorArray("_Centers", _centers); _material.SetColorArray("_Colors", _colors); _material.SetFloatArray("_Radius", _radius); } private void OnRenderImage(RenderTexture source, RenderTexture destination) { _material.SetTexture("_PrevFrame", _previousFrameTex); Graphics.Blit(source, _previousFrameTex, _material); Graphics.Blit(source, destination, _material); } } Can anyone point me in the right direction?

Viewing all articles
Browse latest Browse all 169

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>