文字Shader实现

最近一直在做课件,一些化学相关的课件里面有很多化学式的微观反应,于是我开发了一个小插件,输入化学式,即可生成微对应的元子,并有正确的键值对连接。效果大概是下面的子,展示的是Fe2(SO4)3…这个化合物。

插件还可以支持两重化合物中变换的过程,比如输入NaOH+HCl=NaCl+H2O…即可生成等号前化合物,变换到等号后化合物的动画过程与重新连键的过程…

好啦,今天要讲的不是这个组件,而是要讲讲这个不争气的Shader…

加粗样式输入化学式后给这些球贴上不同的材质,但用的都是同一个Shader,是怎么做的呢?下面来讲解一下。

在这里插入图片描述
在这里插入图片描述

哦什么说他是一个不争气的Shader…是因为里面确实用了很多if语句,而且一张图重复使用了四次,效率方面确实不高。

因为用在球上的,让它接受一般的光照就好了,因为重点不是背景,背景色在顶点着色器中计算了。

v2f vert(a2v v){
	v2f o;
	o.pos=UnityObjectToClipPos(v.vertex);
	fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
	fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); 
	fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
	fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));
	o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
	o.uv2=TRANSFORM_TEX(v.texcoord,_BG);
	o.color = (ambient + diffuse);
	return o;
}

核心在这里,先来看下这张图:
在这里插入图片描述
这图是化学式中可能用到的符号,刚好8乘8…64个。索引即是从0~63。
能过索引来计算显示的字符,解释在注释中。

		fixed4 getCanShow(sampler2D tex,float2 uv,int index,float2 move,float scale){
			
			//如果索引小于0则不显示.
			if(index<0){
				return fixed4(1,1,1,1);
			}

			//直接缩放UV
			uv*=1/scale;
			//计算行
			int han = index % 8 -3;
			//计算列
			int lie = 4-floor(index/8) ;
			//这里是计算UV的位置,因为UV是0~1,这里是分八格,一个则是0.125
			//正常来说正返面都要有一个字母,所以UV的水平方向是缩小一半,平辅两次。
			//所以下面的行是0.125/2 = 0.0625,Y则保持正堂
			fixed2 uv2 = uv+fixed2(0.0625*han-move.x,0.125*lie-move.y);
			//平辅两次
			uv2.x*=2;
			
			//用这个来控制显示范围,即这个范围以外的都不显示直接返回白色。
			if(uv.x>0.1875+move.x && uv.x<0.25+move.x &&
				uv.y>0.375+move.y && uv.y<0.5+move.y){
				return tex2D(tex,uv2);
			}else{
				return fixed4(1,1,1,1);
			}
		}

然后下面是在顶点着色器中显示出来:

		float4 frag(v2f i):COLOR{
			//显示四个不同的索引再将他们相乘
			fixed4 texColor1 = getCanShow(_MainTex,i.uv,_FirstLetter,fixed2(-0.09,-0.19),2);
			fixed4 texColor2 = getCanShow(_MainTex,i.uv,_SecondLetter,fixed2(-0.06,-0.19),2);
			fixed4 texColor3 = getCanShow(_MainTex,i.uv,_FirstNumber,fixed2(0.13,0.15),1);
			fixed4 texColor4 = getCanShow(_MainTex,i.uv,_FirstSymbol,fixed2(0.17,0.15),1);
			fixed4 bg =_AdditionalColor + (tex2D(_BG,i.uv2)*0.3);
			
			//这个是将黑色转为白色
			fixed3 text = fixed3(1,1,1) - (texColor1*texColor2*texColor3*texColor4);

			return fixed4((i.color*bg)+text,1);
		}

下面是完整代码,分享给大家,如果有更好的办法请私信我,谢谢。

Shader "Custom/ElementCountShader" {
	Properties{
		_Diffuse("Diffuse",Color)=(1,1,1,1)
		_AdditionalColor("AdditionalColor",Color)=(1,1,1,1)
		_MainTex("Main Tex",2D)="white"{}
		_BG("BGCloud",2D)="white"{}

		_FirstLetter("_FirstLetter",Int)=0
		_SecondLetter("_SecondLetter",Int)=0
		_FirstNumber("_FirstNumber",Int)=0
		_FirstSymbol("_FirstSymbol",Int)=0
	}
	SubShader{
	Pass{
		//定义了这个才能得到一些内置的光照变量
		Tags{"LightMode"="ForwardBase"}
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#include "Lighting.cginc"

		fixed4 _Diffuse;
		fixed4 _AdditionalColor;
		sampler2D _MainTex;
		float4 _MainTex_ST;
		sampler2D _BG;
		float4 _BG_ST;
		int _FirstLetter;
		int _SecondLetter;
		int _FirstNumber;
		int _FirstSymbol;

		//Appction To Vertex
		struct a2v{
			float4 vertex:POSITION;
			float3 normal:NORMAL;
			float4 texcoord:TEXCOORD0;
		};
		//Vertex To Fragment
		struct v2f{
			float4 pos:SV_POSITION;
			float2 uv:TEXCOORD0;
			float2 uv2:TEXCOORD1;
			fixed3 color:COLOR;
		};

		fixed4 getCanShow(sampler2D tex,float2 uv,int index,float2 move,float scale){
			
			if(index<0){
				return fixed4(1,1,1,1);
			}

			//直接缩放UV
			uv*=1/scale;
			//计算行列
			int han = index % 8 -3;
			int lie = 4-floor(index/8) ;
			//这里是计算UV的位置,因为UV是0~1,这里是分八格,一个则是0.125
			//正常来说正返面都要有一个字母,所以UV的水平方向是缩小一半,平辅两次。
			//所以下面的行是0.125/2 = 0.0625,Y则保持正堂
			fixed2 uv2 = uv+fixed2(0.0625*han-move.x,0.125*lie-move.y);
			//平辅两次
			uv2.x*=2;
			//注释是背面的显示,因为看不到就注释了
			//fixed2 uv3 = uv+fixed2(0.0625*han-0.5-move.x,0.125*lie-move.y);
			//uv3.x*=2;
			
			
			//用这个来控制显示范围,即这个范围以外的都不显示直接返回白色。
			if(uv.x>0.1875+move.x && uv.x<0.25+move.x &&
				uv.y>0.375+move.y && uv.y<0.5+move.y){
				return tex2D(tex,uv2);
			//注释是背面的显示,因为看不到就注释了
			//}else 
			//if(uv.x>0.6875+move.x && uv.x<0.75+move.x&&
			//	uv.y>0.375+move.y && uv.y<0.5+move.y){
			//	return tex2D(tex,uv3);
			}else{
				return fixed4(1,1,1,1);
			}
		}


		v2f vert(a2v v){
			v2f o;

			o.pos=UnityObjectToClipPos(v.vertex);

			fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;

			fixed3 worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject)); 

			fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

			fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal,worldLight));

			o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
			o.uv2=TRANSFORM_TEX(v.texcoord,_BG);

			o.color = (ambient + diffuse);

			return o;
		}

		float4 frag(v2f i):COLOR{
			//显示四个不同的索引再将他们相乘
			fixed4 texColor1 = getCanShow(_MainTex,i.uv,_FirstLetter,fixed2(-0.09,-0.19),2);
			fixed4 texColor2 = getCanShow(_MainTex,i.uv,_SecondLetter,fixed2(-0.06,-0.19),2);
			fixed4 texColor3 = getCanShow(_MainTex,i.uv,_FirstNumber,fixed2(0.13,0.15),1);
			fixed4 texColor4 = getCanShow(_MainTex,i.uv,_FirstSymbol,fixed2(0.17,0.15),1);
			fixed4 bg =_AdditionalColor + (tex2D(_BG,i.uv2)*0.3);
			//这个是将黑色转为白色
			fixed3 text = fixed3(1,1,1) - (texColor1*texColor2*texColor3*texColor4);

			return fixed4((i.color*bg)+text,1);
		}
		ENDCG
	}
	}
}

猜你喜欢

转载自blog.csdn.net/ww1351646544/article/details/91889468