앞에 쓰기
오늘은 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 to shader에 대한 템플릿입니다. 템플릿에 대한 설명은 여기에서 볼 수 있습니다 . 핵심 코드는 원을 그리는 원 함수입니다. 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와의 호환성을 위해 정의 된 코드를 많이 작성했습니다. 30 분 동안 문법 오류를 찾을 수있을 거라 예상하지 못했지만 여전히 동일한 오류입니다. m 프로그래밍 학습으로 돌아갑니다. . . 오류 내용은 다음과 같습니다.
이 빨간 상자를 두려워하지 마십시오. 두 오류는 같은 이유이며 매개 변수 유형이 잘못되었습니다. shadertoy에서 float 유형을 정의하는 한 매개 변수는 float 유형이어야합니다. 그렇지 않으면 일치하는 오버로드 된 함수를 직접 찾을 수 없습니다. 오류를보고했을 때 문제를 인식하지 못했습니다. 정상적인 내장 함수라고 생각했습니다. 갑자기 오버로딩 방법이 없다고보고하는 이유는 무엇입니까? 당분간 다른 사람이 작성한 코드를 읽어 보았습니다. 사람,하지만 여전히 문제를 찾지 못했습니다., 결국 반환 값의 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에서 shader와 shadertoy 코드의 차이점은 다음과 같습니다.
1. shadetoy의 문자 유형은 자동으로 강제 적용되지 않습니다. 정의한 함수에 float 유형의 매개 변수가있는 경우 호출 할 때 int 유형을 사용하면 오류가보고됩니다. 값 0은 정수이고 0.0은 기호 유형입니다. (Unity가 강제로 유형을 전송하려고했지만 문제는 없습니다)
2. 두 셰이더의 입력 위치가 다릅니다.
Unity에서 셰이더의 조각 함수 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;
추신 : 이해하는 것을 설명하는 것은 쉽지 않습니다. . .