最近一直在做课件,一些化学相关的课件里面有很多化学式的微观反应,于是我开发了一个小插件,输入化学式,即可生成微对应的元子,并有正确的键值对连接。效果大概是下面的子,展示的是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
}
}
}