Converted ShaderToy shader showing up black
I'm attempting to convert this shader from ShaderToy into Unity: https://www.shadertoy.com/view/XsXSz2
I've reached a point where it doesn't throw any errors, but when placed on a quad it just appears solid black. I'm at a loss as to where to go from here. Are there any obvious mistakes I'm making?
Here is my code:
Shader "Custom/Warp Center" {
Properties {
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"PreviewType" = "Plane"
}
Pass
{
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
float PI = 3.14159265359;
float RATIO_SPIN = .1;
float RATIO_SPREAD = 23.3;
float REPETITION_POWER = 35.0;
float RIPPLE_POWER = 20.0;
float RIPPLE_DISTANCE = 0.1;
float getAngle(float2 uvCenter){
float angle = atan2(uvCenter.x, uvCenter.y)/(2.0*PI);
if(angle <0.0) angle +=1.0;
return angle;
}
float getDis(float2 v){
return sqrt(v.x* v.x + v.y*v.y);
}
float4 frag(v2f i) : SV_Target
{
float2 uv = i.uv.xy / _ScreenParams.xy;
float2 uvCenter = uv - float2(0.5,0.5);
float angle = getAngle(uvCenter) + _Time.y*RATIO_SPIN;
float dis = getDis(uvCenter);
dis *= 1.0+ sin(angle*2.0*PI*RIPPLE_POWER) *RIPPLE_DISTANCE; // distorts distance to ripple effect
float color = sin(dis*PI*REPETITION_POWER -_Time.y*RATIO_SPREAD); //final color, use sin to create "repetition" pattern effect
float4 fragColor = float4(color * 0.1, color * 0.1, color, 1);
return fragColor;
}
ENDCG
}
}
}
Answer by Sourav11 · Jul 06, 2018 at 10:54 AM
Hello @BulchyC
The reason of the shader is turned black is because the shader has some properties which need to assign to make it work.
You need to make a script which does this for you. Here is a C# script which i created :-
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
public class ChronoTriggerCenter : MonoBehaviour {
public Material material;
// Use This For Initialization
private void Start () {
if (material == null) {
material = new Material (Shader.Find ("ChronoTriggerCenter"));
}
}
// Update Is Called Once Per Frame
private void Update () {
material.SetVector ("_MousePosition", new Vector4 (Input.mousePosition.x, Input.mousePosition.y, 0, 0));
}
private void OnRenderImage (RenderTexture source, RenderTexture destination) {
if (material == null) {
Graphics.Blit (source, destination);
return;
}
material.SetFloat ("_RATIO_SPIN", 0.1f);
material.SetFloat ("_RATIO_SPREAD", 23.3f);
material.SetFloat ("_REPETITION_POWER", 35.5f);
material.SetFloat ("_RIPPLE_POWER", 20.0f);
material.SetFloat ("_RIPPLE_DISTANCE", 0.1f);
Graphics.Blit (source, destination, material);
}
}
And here a shader script which goes with it :-
// Original Shader By BlueBug.
// Original Link Https://www.ShaderToy.Com/view/XsXSz2
// Converted By K.S.
Shader "ChronoTriggerCenter" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
}
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
uniform float _RATIO_SPIN;
uniform float _RATIO_SPREAD;
uniform float _REPETITION_POWER;
uniform float _RIPPLE_POWER;
uniform float _RIPPLE_DISTANCE;
struct appData {
float4 vertex : POSITION;
float2 uv : TEXCOORD;
};
struct v2f {
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD;
};
v2f vert (appData v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
float getAngle (float2 uvCenter) {
float angle = atan2(uvCenter.y, uvCenter.x) / (2.0 * UNITY_PI);
if (angle < 0.0) {
angle += 1.0;
}
return angle;
}
float getDistance (float2 v) {
return sqrt(v.x * v.x + v.y * v.y);
}
float4 frag (v2f i) : SV_Target {
float2 uvCenter = i.uv - float2(0.5, 0.5);
float angle = getAngle(uvCenter) + _Time.y * _RATIO_SPIN;
float distance = getDistance(uvCenter);
distance *= 1.0 + sin(angle * 2.0 * UNITY_PI * _RIPPLE_POWER) * _RIPPLE_DISTANCE;
float color = sin(distance * UNITY_PI * _REPETITION_POWER - _Time.y * _RATIO_SPREAD);
return float4(color * 0.1, color * 0.1, color, 1.0);
}
ENDCG
}
}
}
I replace PI with UNITY_PI variable and cleaned up code a bit.
Hope this help.
Thank you so much for this. I'm new to shaders and this is a lot of help.
I'm afraid I'm messing this up somewhere still though: I have my editor script and my shader script in place, but a material is never generated, if I place one in manually then I just get the same black quad as before.
The c# script is definitely supposed to run in the editor and not be placed on a gameobject, right?
You do need to attach C# script to gameobject. [ExecuteInEdit$$anonymous$$ode] attribute simply execute any $$anonymous$$onoBehaviour callback even when not in playmode. it must not be mistaken with Custom Editors. https://docs.unity3d.com/ScriptReference/ExecuteInEdit$$anonymous$$ode.html Attach the C# script to your Camera.
Ah yep, it was me being dumb and putting the script in my Editor folder which was causing the issue. Thank you very much for helping, it works perfectly!