[Shader и ShaderToy] рисуем круг

Писать впереди

        Сегодня я попытаюсь обвести круг на веб-сайтах Unity и ShaderToy соответственно, чтобы увидеть конкретную разницу между ними.

        Некоторая подготовительная работа перед запуском Unity и shadertoy будет пропущена, а код и эффект отображения будут загружены напрямую.

Часть единства

        Использование Unity + VS для написания шейдеров - мое любимое, интуитивно понятное и быстрое, и вы также можете изменить эффект настройки параметров прямо на панели, которая намного выше, чем на веб-странице! Вставьте код шейдера ниже

Shader "Custom/circle" {
	Properties {
		//xy表示圆心在屏幕中的uv值,z为半径,w为圆边缘的平滑值
		_parameters("circleParameter",Vector)=(0.5,0.5,10,0)
		_Color("circleColor",COLOR)=(1,1,1,1)
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		Pass{
		CGPROGRAM
		#include "UnityCG.cginc"
		#pragma fragmentoption ARB_precision_hint_fastest   
		#pragma target 3.0
		#pragma vertex vert
		#pragma fragment frag

		#define vec2 float2
		#define vec3 float3
		#define vec4 float4
		#define mat2 float2
		#define mat3 float3
		#define mat4 float4
		#define iGlobalTime _Time.y
		#define mod fmod
		#define mix lerp
		#define fract frac
		#define Texture2D tex2D
		#define iResolution _ScreenParams

		float4 _parameters;
		float4 _Color;
		float4 _backgroundColor;

		struct v2f{
			float4 pos:SV_POSITION;
			float4 srcPos:TEXCOORD0;
		};

		v2f vert(appdata_base v){
			v2f o;
			o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
			o.srcPos=ComputeScreenPos(o.pos);
			return o;
		}
		vec4 main(vec2 fragCoord);
		float4 frag(v2f iParam):COLOR{
			//获取uv对应的当前分辨率下的点   uv范围(0-1) 与分辨率相乘
			vec2 fragCoord=((iParam.srcPos.xy/iParam.srcPos.w)*_ScreenParams.xy);
			return main(fragCoord);
		}
		//要先定义方法声明才能使用
		vec4 cicle(vec2 pos,vec2 center,float radius,float3 col,float antialias){
			//求出点到圆心距离,如果为正则在圆外 负在圆内 我们需要对圆内的点进行上色 即对负值进行处理
			float d=length(pos-center)-radius;
			//判断d的大小 如果小于0则返回0 如果大于antialias返回1 返回值在0-1之间
			//smoothstep(a,b,t) 判断t t<a返回0,t>b返回1,t在a-b之间反差值返回0-1 
			float t=smoothstep(0,antialias,d);
			//返回颜色值 在圆外的设置alpha=0透明 
			return vec4(col,1.0-t);

		}
		vec4 main(vec2 fragCoord){
			vec2 pos=fragCoord;
			//给背景一个动态的颜色
			vec3 temp = 0.5 + 0.5*cos(iGlobalTime+pos.xyx/_ScreenParams.y+vec3(0,2,4));
			//获取背景的颜色
			vec4 layer1=vec4(temp,1.0);
			//获取圆
			vec4 layer2=cicle(pos,_parameters.xy*iResolution.xy,_parameters.z,_Color.rgb,_parameters.w);
			//插值处理,使边界更模糊化,layer2中的_parameters.w值越大越模糊
			return mix(layer1,layer2,layer2.a);
		}



		ENDCG
		}
	}
	FallBack "Diffuse"
}

        Код выглядит как очень длинный и очень длинный раздел, но на самом деле это шаблон для шейдера, игрушки для шейдера. Описание шаблона можно посмотреть здесь . Код ключа - это функция круга для рисования круга. Общий принцип shadertoy состоит в том, чтобы рисовать слои один за другим, а затем смешивать их с различными эффектами, что похоже на рисование PS. Он знает, почему чем лучше эффект, тем более застрявшим выглядит веб-страница shadetoy, а я не не знаю, сколько слоев уложено.

        Чтобы сделать эффект Unity таким же, как и на стороне shadertoy, специально добавлен переменный цвет фона по умолчанию. Код выглядит следующим образом

//给背景一个动态的颜色
vec3 temp = 0.5 + 0.5*cos(iGlobalTime+pos.xyx/_ScreenParams.y+vec3(0,2,4));

        Используя функцию косинуса с постоянно меняющимся значением времени iGlobalTime, фон может непрерывно менять цвет. Эффект запуска Unity выглядит следующим образом

 

Раздел ShaderToy

        Я думал, что на shadertoy это будет сделано быстро. В конце концов, Unity написала кучу определенных кодов для совместимости с shadertoy. Я не ожидал найти грамматические ошибки в течение получаса, и это все та же ошибка, как будто я ' м вернулся к изучению программирования. . . Содержание ошибки следующее

        

        Не пугайтесь этих красных прямоугольников, это две ошибки по одной и той же причине, неверный тип параметра. В shadertoy, пока вы определяете тип с плавающей точкой, параметр должен быть типом с плавающей запятой, в противном случае вы не найдете напрямую соответствующей перегруженной функции. Когда я сообщил об ошибке, я не осознал проблему. Я подумал, что это обычная встроенная функция. Почему она внезапно сообщила, что нет метода перегрузки? На время я пошел читать код, написанный другим люди, но я все еще не нашел проблемы., В конце концов, я не знаю, почему я изменил 1.0-t возвращаемого значения на 1-t. Красный цвет всего содержимого ошибки только разбудил меня, это Оказалось, что тип параметра неправильный! ! ! ! Метод smoothstep должен быть с плавающей запятой! ! Не поможет конвертировать! ! ! Даже если вам 0, вы должны написать 0,0! ! !

        Ниже приведен неправильный код shadertoy.

float t=smoothstep(0,antialias,d);

        Ниже приведен правильный код shadertoy.

float t=smoothstep(0.0,antialias,d);

        Тихо. . . Строгий. . . Вставьте код shadertoy ниже

//输入参数(当前点位置,中心点位置,点的半径,颜色,与背景过渡的平滑值)
vec4 cicle(vec2 pos,vec2 center,float radius,vec3 col,float antialias){
    //求圆心距离
    float d=length(pos-center)-radius;
    //smoothstep(a,b,t)函数 t<a return a, t>b return b
    float t=smoothstep(0.0,antialias,d);
    return vec4(col,1.0-t);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    //获取点的位置
    //iResolution为屏幕的分辨率
    //fragCoord为当前点的位置 原点是左下角
    //返回的uv是以屏幕中心为原点
    vec2 uv =(2.0*fragCoord.xy-iResolution.xy) /iResolution.y;
    //中心点
    vec2 point1 = vec2(0,0);
    //圆的颜色
    vec3 color=vec3(1,0,0);
    // layer1 cos函数
    vec3 temp = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));
    vec4 layer1= vec4(temp,1);
    //layer2 平滑的圆
    vec4 layer2 = cicle(uv,point1,0.8,color,0.03);
    // 输出像素
    fragColor = mix(layer1,layer2,layer2.a);
}

       

        Очень простой эффект, принципиально отличный от единства, но писать раскраску плавно в браузере действительно неудобно! ! webGL действительно легко сломать! ! Да и входные параметры изменить не очень-то просто. . . Еще раз осознаем удобство единства. .

подводить итоги

        Вот некоторые различия между шейдером и кодом шейдера в Unity.

        1. Тип символа на shadetoy не будет автоматически изменяться. Если в определяемой вами функции есть параметр типа float, то при использовании типа int при вызове обязательно будет сообщено об ошибке; значение 0 - целое число, а 0,0 - тип символа. (Unity пытался принудительно передать тип, нет проблем)

        2. Входные позиции двух шейдеров различаются.

        На вход фрагментной функции frag () кода шейдера в единице поступают координаты проекции вершин, которые необходимо нормализовать, а затем умножить на разрешение экрана для получения соответствующих координатных точек.

//(iParam.srcPos.xy/iParam.srcPos.w)获取归一化的点 范围在(0-1)
//与屏幕分辨率相乘获得实际的像素坐标,坐标原点在正中心
vec2 fragCoord=((iParam.srcPos.xy/iParam.srcPos.w)*_ScreenParams.xy);

        Входными данными основного метода в shadertoy является позиция пикселя, соответствующая вершине. Начало координат - это нижний левый угол экрана. Его необходимо преобразовать в начало координат в центре. Эта операция преобразования исходного диапазона из (0 , a) до (-b, b) является исходным Положение координаты станет y = bx-b (0 <x <a). Но таким образом значение операнда будет увеличено во много раз, поэтому требуется единое масштабирование, а полученная координата положения делится на ось экрана.

//获取点的位置
//iResolution为屏幕的分辨率
//fragCoord为当前点的位置 原点是左下角
//返回的uv是以屏幕中心为原点 并且除以分辨率的一个轴进行缩放
vec2 uv =(2.0*fragCoord.xy-iResolution.xy) /iResolution.y;

PS: Непросто описать то, что вы понимаете. . .

рекомендация

отblog.csdn.net/ssssssilver/article/details/81129441
рекомендация