视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
【OpenGL】Shader技巧集合
2020-11-09 08:06:56 责编:小采
文档


这篇文章将收集unity中使用shader的相关技巧和特效,会不断地更新内容。关于在Unity中使用shader的介绍,请参考《【OpenGL】使用Unity来学习OpenGL》 常用的内置uniform iResolution =》_ScreenParams iGlobalTime = _Time.y glFragCoord = f loat4 sp:WPOS

这篇文章将收集unity中使用shader的相关技巧和特效,会不断地更新内容。关于在Unity中使用shader的介绍,请参考《【OpenGL】使用Unity来学习OpenGL》

常用的内置uniform

iResolution =》_ScreenParams

iGlobalTime => _Time.y

glFragCoord => float4 sp:WPOS // 需要 #pragma target 3.0, 另外的方式请见下面

vec2 => float2

mix => lerp

mod => fmod

texture2D => tex2D

textureCube => texCUBE

mat2=>float2x2

fract=>frac

========

关于glFragCoord, 可以使用另外一种方式计算(支持3.0之前的)参考官方例子

o.scrPos = ComputeScreenPos(o.pos);

float2 wcoord = (i.scrPos.xy/i.scrPos.w);

-------

float2 wcoord = sp.xy/_ScreenParams.xy;


关于数学的Shader:https://www.shadertoy.com/view/ldlSD2 https://www.shadertoy.com/view/ldlSWj


很好的一个教程:http://ogldev.atspace.co.uk/index.html


Deferred Shading 原理: http://ogldev.atspace.co.uk/www/tutorial35/tutorial35.html


关于Stencil Buffer 的理解:http://www.cnblogs.com/mikewolf2002/archive/2012/05/15/2500867.html

更多文章:1)http://docs.unity3d.com/Manual/SL-Stencil.html

2) http://answers.unity3d.com/questions/590800/how-to-cullrender-to-through-a-window.html


Stencil Shadow Volume : http://ogldev.atspace.co.uk/www/tutorial40/tutorial40.html

http://en.wikipedia.org/wiki/Shadow_volume


镜面反射的实现原理:

ftp://ftp.sgi.com/sgi/opengl/contrib/blythe/advanced99/notes/node158.html

其它镜面反射:

http://en.wikibooks.org/wiki/Cg_Programming/Unity/Mirrors


在unity cg中可以使用[HideInInspector]来隐藏uniform属性,这样就可以用作自定义常量。

Physically Based Rendering: Tutorial: Physically Based Rendering, And you can too!

边缘检测:1) http://www.codeproject.com/Articles/94817/Pixel-Shader-for-Edge-Detection-and-Cartoon-Effect

2) http://coding-experiments.blogspot.hk/2010/06/edge-detection.html

3) http://en.wikipedia.org/wiki/Edge_detection

Cg函数表:http://http.developer.nvidia.com/CgTutorial/cg_tutorial_appendix_e.html

heat effect : http://forum.unity3d.com/threads/50132-Heat-Distortion, http://www.cnblogs.com/geoffyange/archive/2013/06/06/3122570.html

skin shading in unity: http://www.altdevblogaday.com/2011/12/31/skin-shading-in-unity3d/

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch14.html

http://gamedev.stackexchange.com/questions/31308/algorithm-for-creating-spheres

RenderMan University: http://renderman.pixar.com/view/renderman-university

一些shader的例子:











Shader "stalendp/shaderTest02" { //see https://www.shadertoy.com/view/4sj3zy
	Properties {
	_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
	Pass {
	CGPROGRAM
	#pragma vertex vert
	#pragma fragment frag
	#pragma target 3.0
	
	#include "UnityCG.cginc"

	sampler2D _MainTex;
	
	//Variable declarations
	
	struct myvars {
	float3 bgColor;
	float sphereScale;
	float sphereShine;
	float3 sphereDiff;
	float3 sphereSpec;
	float2 specPoint;
	};

	float4 vert(appdata_base v) : POSITION {
	return mul(UNITY_MATRIX_MVP, v.vertex);
	}
	
	float4 frag(float4 sp:WPOS): COLOR {
	myvars mv;
	mv.bgColor = float3(0.6, 0.5, 0.6);
	mv.sphereScale = 0.7;
	mv.sphereShine = 0.5;
	mv.sphereDiff = float3(0.5, 0.0, 0.5);
	mv.sphereSpec = float3(1.0, 1.0, 1.0);
	mv.specPoint = float2(0.2, -0.1);
	
	// creates shader pixel coordinates
	float2 uv = sp.xy/_ScreenParams.xy;
	// sets the position of the camera
	float2 p = uv * 2.5 - float2(1.0, 1.0);
	p.x *= _ScreenParams.x / _ScreenParams.y;
	
	// Rotates the sphere in a circle
	p.x += cos(-_Time.y) *0.35;
	p.y += sin(-_Time.y) * 0.35;
	
	// Rotates the specular point with the sphere
	mv.specPoint.x += cos(-_Time.y) * 0.35;
	mv.specPoint.y += sin(-_Time.y) * 0.35;
	
	//Sets the radius of the sphere to the middle of the screen
	float radius = length(p);//sqrt(dot(p, p));
	
	float3 col = mv.bgColor;
	
	//Sets the initial dark shadow around the edge of the sphere
	float f = smoothstep(mv.sphereScale * 0.7, mv.sphereScale, length(p + mv.specPoint));
	col -= lerp(col, float3(0.0,0.0,0.0), f) * 0.2;
	
	//Only carries out the logic if the radius of the sphere is less than the scale
	if(radius < mv.sphereScale) {
	float3 bg = col;
	
	//Sets the diffuse colour of the sphere (solid colour)
	col = mv.sphereDiff;
	
	//Adds smooth dark borders to help achieve 3D look
	f = smoothstep(mv.sphereScale * 0.7, mv.sphereScale, radius);
	col = lerp(col, mv.sphereDiff * 0.45, f);
	
	//Adds specular glow to help achive 3D look
	f = 1.0 - smoothstep(-0.2, 0.6, length(p - mv.specPoint));
	col += f * mv.sphereShine * mv.sphereSpec;
	
	//Smoothes the edge of the sphere
	f = smoothstep(mv.sphereScale - 0.01, mv.sphereScale, radius);
	col = lerp(col, bg, f);
	}
	
	
	//The final output of the shader logic above
	//gl_FragColor is a vector with 4 paramaters(red, green, blue, alpha)
	//Only 2 need to be used here, as "col" is a vector that already carries r, g, and b values
	return float4(col, 1);
	}
	
	ENDCG
	}
	} 
	FallBack "Diffuse"
}


Shader "Custom/shaderTest03" { // https://www.shadertoy.com/view/Xdf3DS
	Properties {
	_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
	
	Pass {
	CGPROGRAM
	#pragma vertex vert
	#pragma fragment frag
	#pragma target 3.0
	
	#include "UnityCG.cginc"

	sampler2D _MainTex;

	
	struct myvars {
	float k;
	float f;
	float threshold;

	float3 colour;
	float3 normal;

	float3 lightPos;
	float3 lightColour;
	float3 ambient;
	float shinyness;
	float diffuseFactor;
	float4 fragCoord;
	};
	

	float2 center ( float2 border , float2 _offset , float2 vel, myvars mv) {
	float2 c = _offset + vel * _Time * 0.5;
	c = fmod ( c , 2. - 4. * border );
	if ( c.x > 1. - border.x ) c.x = 2. - c.x - 2. * border.x;
	if ( c.x < border.x ) c.x = 2. * border.x - c.x;
	if ( c.y > 1. - border.y ) c.y = 2. - c.y - 2. * border.y;
	if ( c.y < border.y ) c.y = 2. * border.y - c.y;
	return c;
	}
	
	float field ( float b, float r , myvars mv) {
	if ( r > b )
	return 0.0;
	if ( r >= b/3.0 ) {
	float rb = 1.0 - r/b;
	return (3.0*mv.k)/2.0 * rb * rb;
	}
	if ( r >= 0.0 && r <= b/3.0 ) {
	return mv.k * ( 1.0 - ( (3.0*r*r)/(b*b) ) );	
	}
	return 0.0;
	}
	
	void circle ( float r , float2 col , float2 _offset , float2 vel, myvars mv ) {
	float2 pos = mv.fragCoord.xy / _ScreenParams.y;
	float aspect = _ScreenParams.x / _ScreenParams.y;
	float2 c = center ( float2 ( r / aspect , r ) , _offset , vel, mv);
	c.x *= aspect;
	float d = distance ( pos , c );
	float thisField = field (r, d, mv);
	mv.f += thisField;
	mv.colour += float3(col, 0) * thisField;
	mv.normal += normalize(float3(pos.x-c.x, pos.y-c.y,r))*thisField;
	}
	

	float4 vert(appdata_base v) : POSITION {
	return mul(UNITY_MATRIX_MVP, v.vertex);
	}
	
	float4 frag(float4 sp:WPOS): COLOR {
	myvars mv;
	mv.fragCoord = sp;
	mv.k = 100.0;
	mv.f = 0.0;
	mv.threshold = 10.0;

	mv.colour = float3(0.0,0.0,0.0);
	mv.normal = float3(0.0,0.0,0.0);

	mv.lightPos = float3(_ScreenParams.xy,2000.0);
	mv.lightColour = float3(0.9,0.9,1.0);
	mv.ambient = float3(0.1,0.0,0.0);
	mv.shinyness = 20.0;
	mv.diffuseFactor = 0.0006;
	
	circle ( .10 , float3 ( 0.7 , 0.2 , 0.8 ) , float2 ( .6 ) , float2 ( .30 , .70 ), mv );
	circle ( .09 , float3 ( 0.7 , 0.9 , 0.6 ) , float2 ( .1 ) , float2 ( .02 , .20 ), mv );
	circle ( .12 , float3 ( 0.3 , 0.4 , 0.1 ) , float2 ( .1 ) , float2 ( .10 , .04 ), mv );
	circle ( .15 , float3 ( 0.2 , 0.5 , 0.1 ) , float2 ( .3 ) , float2 ( .10 , .20 ), mv );
	circle ( .20 , float3 ( 0.1 , 0.3 , 0.7 ) , float2 ( .2 ) , float2 ( .40 , .25 ), mv );
	circle ( .30 , float3 ( 0.9 , 0.4 , 0.2 ) , float2 ( .0 ) , float2 ( .15 , .20 ), mv );
	
	float3 c;
	
	if (mv.f < mv.threshold)
	c = float3(0.0,0.0,0.0);
	else {
	mv.colour /= mv.f;
	mv.normal = mv.normal/mv.f;
	
	c = mv.ambient;
	float3 lightDir = mv.lightPos - float3(sp.xy,0.0);
	c += mv.colour * mv.diffuseFactor * max(dot(mv.normal,lightDir), 0.0);
	float3 r = normalize ( reflect ( lightDir, mv.normal ) );
	c += mv.lightColour * pow(max(dot(r,float3(0.0,0.0,-1.0)), 0.0), mv.shinyness);	
	}
	return float4(c, 1);
	}
	
	ENDCG
	}
	} 
}

Shader "stalendp/shaderTest04" { //see https://www.shadertoy.com/view/Xsf3R8
	Properties {
	_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
	Pass {
	CGPROGRAM
	#pragma vertex vert
	#pragma fragment frag
	#pragma target 3.0
	
	#include "UnityCG.cginc"

	sampler2D _MainTex;
	
	struct Ray {
	float3 org;
	float3 dir;
	};
	
	float rayPlaneIntersect( Ray ray, float4 plane ) {
	float f = dot( ray.dir, plane.xyz );
	
	float t = -( dot( ray.org, plane.xyz ) + plane.w );
	t /= f;
	
	return t;
	}
	
	float3 shade( float3 pos, float3 nrm, float4 light ) {
	float3 toLight = light.xyz - pos;
	float toLightLen = length( toLight );
	toLight = normalize( toLight );
	
	float diff = dot( nrm, toLight );
	float attn = 1.0 - pow( min( 1.0, toLightLen / light.w ), 2.0 );
	float comb = 2.0 * diff * attn;
	
	return float3( comb, comb, comb );
	}


	float4 vert(appdata_base v) : POSITION {
	return mul(UNITY_MATRIX_MVP, v.vertex);
	}
	
	float4 frag(float4 sp:WPOS): COLOR {
	
	// gl_FragCoord: location (0.5, 0.5) is returned 
	// for the lower-left-most pixel in a window
	
	// XY of the normalized device coordinate
	// ranged from [-1, 1]
	float2 ndcXY = -1.0 + 2.0 * sp.xy / _ScreenParams.xy;
	
	// aspect ratio
	float aspectRatio = _ScreenParams.x / _ScreenParams.y;
	
	// scaled XY which fits the aspect ratio
	float2 scaledXY = ndcXY * float2( aspectRatio, 1.0 );
	
	// camera XYZ in world space
	float3 camWsXYZ = float3( 0.0, 1.0, 0.0 );
	camWsXYZ.z += 10.0 * cos( _Time.y );
	
	// construct the ray in world space
	Ray ray;
	ray.org = camWsXYZ;
	ray.dir = float3( scaledXY, -2.0 ); // OpenGL is right handed
	
	// define the plane in world space
	float4 plane = float4( 0.0, 1.0, 0.0, 0.0 );
	
	float t = rayPlaneIntersect( ray, plane );
	
	// define the point light in world space (XYZ, range)
	float4 lightWs = float4( 0.0, 5.0, -5.0, 10.0 );
	
	if ( t >= 0.0 )
	{
	float3 sceneWsPos = ray.org + t * ray.dir;
	float3 sceneWsNrm = plane.xyz;
	float2 sceneUV = sceneWsPos.xz / 4.0;
	
	float4 sceneBase = tex2D( _MainTex, sceneUV );	
	float3 sceneShade = shade( sceneWsPos, sceneWsNrm, lightWs );
	
	return float4( sceneShade * sceneBase.xyz, 1.0 );
	}
	
	return float4( 0.0, 0.0, 0.0, 1.0 );
	}
	
	ENDCG
	}
	} 
	FallBack "Diffuse"
}


Shader "stalendp/shaderTest04" { //see https://www.shadertoy.com/view/MdB3Dw
	Properties {
	_MainTex ("Base (RGB)", 2D) = "white" {}
	}
	SubShader {
	Pass {
	CGPROGRAM
	#pragma vertex vert
	#pragma fragment frag
	#pragma target 3.0
	
	#include "UnityCG.cginc"
	
	#define USE_ANALYTICAL_MBLUR

	sampler2D _MainTex;
	
	// intersect a MOVING sphere
	float2 iSphere( in float3 ro, in float3 rd, in float4 sp, in float3 ve, out float3 nor )
	{
	 float t = -1.0;
	float s = 0.0;
	nor = float3(0.0);
	
	float3 rc = ro - sp.xyz;
	float A = dot(rc,rd);
	float B = dot(rc,rc) - sp.w*sp.w;
	float C = dot(ve,ve);
	float D = dot(rc,ve);
	float E = dot(rd,ve);
	float aab = A*A - B;
	float eec = E*E - C;
	float aed = A*E - D;
	float k = aed*aed - eec*aab;
	
	if( k>0.0 )
	{
	k = sqrt(k);
	float hb = (aed - k)/eec;
	float ha = (aed + k)/eec;
	
	float ta = max( 0.0, ha );
	float tb = min( 1.0, hb );
	
	if( ta < tb )
	{
	 ta = 0.5*(ta+tb);	
	 t = -(A-E*ta) - sqrt( (A-E*ta)*(A-E*ta) - (B+C*ta*ta-2.0*D*ta) );
	 nor = normalize( (ro+rd*t) - (sp.xyz+ta*ve ) );
	 s = 2.0*(tb - ta);
	}
	}

	return float2(t,s);
	}

	// intersect a STATIC sphere
	float iSphere( in float3 ro, in float3 rd, in float4 sp, out float3 nor )
	{
	 float t = -1.0;
	nor = float3(0.0);
	
	float3 rc = ro - sp.xyz;
	float b = dot(rc,rd);
	float c = dot(rc,rc) - sp.w*sp.w;
	float k = b*b - c;
	if( k>0.0 )
	{
	t = -b - sqrt(k);
	nor = normalize( (ro+rd*t) - sp.xyz );
	}

	return t;
	}

	float3 getPosition( float time ) { return float3( 2.5*sin(8.0*time), 0.0, 1.0*cos(8.0*time) ); }
	float3 getVelocity( float time ) { return float3( 8.0*2.5*cos(8.0*time), 0.0, -8.0*1.0*sin(8.0*time) ); }


	float4 vert(appdata_base v) : POSITION {
	return mul(UNITY_MATRIX_MVP, v.vertex);
	}
	
	float4 frag(float4 sp:WPOS): COLOR {
	float2 q = sp.xy / _ScreenParams.xy;
	float2 p = -1.0 + 2.0*q;
	p.x *= _ScreenParams.x/_ScreenParams.y;	

	// camera
	float3 ro = float3(0.0,0.0,4.0);
	 float3 rd = normalize( float3(p.xy,-2.0) );
	
	 // sphere	
	
	// render
	float3 col = float3(0.0);
	
	#ifdef USE_ANALYTICAL_MBLUR
	
	 //---------------------------------------------------	
	 // render with analytical motion blur
	 //---------------------------------------------------	
	float3 ce = getPosition( _Time.y );
	float3 ve = getVelocity( _Time.y );
	 	
	col = float3(0.25) + 0.3*rd.y;
	float3 nor = float3(0.0);
	float3 tot = float3(0.25) + 0.3*rd.y;
	 float2 res = iSphere( ro, rd, float4(ce,1.0), ve/24.0, nor );
	float t = res.x;
	if( t>0.0 )
	{
	float dif = clamp( dot(nor,float3(0.5703)), 0.0, 1.0 );
	float amb = 0.5 + 0.5*nor.y;
	float3 lcol = dif*float3(1.0,0.9,0.3) + amb*float3(0.1,0.2,0.3);
	col = lerp( tot, lcol, res.y );
	}
	
	#else
	
	 //---------------------------------------------------	
	 // render with brute force sampled motion blur
	 //---------------------------------------------------	
	
	 #define NUMSAMPLES 32
	float3 tot = float3(0.0);
	for( int i=0; i0.0 )
	 {
	 float dif = clamp( dot(nor,float3(0.5703)), 0.0, 1.0 );
	 float amb = 0.5 + 0.5*nor.y;
	 tmp = dif*float3(1.0,0.9,0.3) + amb*float3(0.1,0.2,0.3);
	 }
	 col += tmp;
	}	
	col /= float(NUMSAMPLES);
	
	 #endif
	
	col = pow( clamp(col,0.0,1.0), float3(0.45) );

	return float4( col, 1.0 );
	}
	
	ENDCG
	}
	} 
	FallBack "Diffuse"
}

Shader "stalendp/shaderTest05" { //see https://www.shadertoy.com/view/XsB3DW
	Properties {
	_MainTex ("Base (RGB)", 2D) = "white" {}
	_CubeDiffuse ("Cubemap Diffuse Map", CUBE) = "" {}
	vv1("vv1", float) = -1.0
	vv2("vv2", float) = 2.0
	}
	SubShader {
	Pass {
	CGPROGRAM
	#pragma vertex vert
	#pragma fragment frag
	#pragma target 3.0
	//下面防止编译错误:instruction limit of 1024 exceed;
	#pragma glsl 
	
	#include "UnityCG.cginc" 
	
	#define MAX_STEPS 
	#define MAX_REFLECTIONS 4
	#define PI 3.1415926536

	sampler2D _MainTex;
	samplerCUBE _CubeDiffuse;
	float vv1, vv2;
	
	struct Ray {
	float3 o;
	float3 d;
	};
	struct Sphere {
	float3 o;
	float r;
	};
	struct Box {
	float3 o;
	float3 s;
	};
	struct Torus {
	float3 o;
	float2 s;
	};
	
	float2 rotate2d(in float2 v, in float a) {
	float sinA = sin(a);
	float cosA = cos(a);
	return float2(v.x * cosA - v.y * sinA, v.y * cosA + v.x * sinA);	
	}

	float sdSphere(in float3 p, in Sphere s) {
	return length(p-s.o)-s.r;
	}
	float sdBox(in float3 p, in Box b) {
	float3 d = abs(p-b.o) - b.s;
	return min(max(d.x,max(d.y,d.z)),0.0) +
	length(max(d,0.0));
	}
	float sdTorus(in float3 p, in Torus t) {
	p -= t.o;
	float2 q = float2(length(p.xz)-t.s.x,p.y);
	return length(q)-t.s.y;
	}
	float world(in float3 p) {
	float ti = fmod(_Time.y,10.);
	if(ti > 2.) {
	Sphere s0 = Sphere(float3(0),1.);
	Box b0 = Box(float3(0),float3(.8));
	if(ti < 4.) {
	return max(-sdSphere(p,s0),sdBox(p,b0));
	} else if(ti < 6.) {
	return min(sdSphere(p,s0),sdBox(p,b0));
	} else if(ti < 8.) {
	return max(sdSphere(p,s0),sdBox(p,b0));
	} else {
	return max(sdSphere(p,s0),-sdBox(p,b0));
	}
	} else {
	float3 pr = p.xzy;
	return sdTorus(pr, Torus(float3(0),float2(1.,.5)));
	}
	}
	
	float3 getNormal(in float3 p) {
	float3 d = float3(.005,0,0);
	float3 n;
	n.x = world(p+d.xyy);
	n.y = world(p+d.yxy);
	n.z = world(p+d.yyx);
	return normalize(n);
	}

	bool march(in Ray r, out float3 p) {
	p = r.o;
	float d;
	for(int i = 0; i < MAX_STEPS; i++) {
	d = world(p);
	p += r.d*d;
	}
	return d<=0.01;
	}

	float3 colorMarch(in Ray r) {
	float3 p;
	float3 col = float3(0);
	for(int i = 0; i < MAX_REFLECTIONS; i++) {
	if(march(r,p)) {
	float3 ldir = normalize(float3(1,-1,.5));
	float3 n = getNormal(p);
	col += float3(dot(n,-ldir))*.25;
	r = Ray(p,reflect(r.d,n));
	r.o += r.d*0.2;
	} else {
	break;
	}
	}
	col += texCUBE(_CubeDiffuse, r.d).rgb;
	return col;
	}

	float4 vert(appdata_base v) : POSITION {
	return mul(UNITY_MATRIX_MVP, v.vertex);
	}
	
	float4 frag(float4 sp:WPOS): COLOR {
	float2 uv = 2.*sp.xy/_ScreenParams.xy-1.;
	uv.x *= _ScreenParams.x/_ScreenParams.y;
	
	Ray r = Ray(float3(0,0,-2),normalize(float3(uv,1)));
	r.o.xz = rotate2d(r.o.xz,_Time.y*.5);
	r.d.xz = rotate2d(r.d.xz,_Time.y*.5);
	float3 cc =colorMarch(r);

	return float4( cc, 1.0 );
	}
	
	ENDCG
	}
	} 
	FallBack "Diffuse"
}


CGINCLUDE的使用

 




下载本文
显示全文
专题