欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  数据库

【OpenGL】Shader技巧集合

程序员文章站 2024-01-12 15:05:58
...

这篇文章将收集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 

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  1. - border.y ) c.y = 2. - c.y - 2. * border.y;
				if ( c.y  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 
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 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 64
			#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 

CGINCLUDE的使用