UnityShader实例08:广告牌(Billboard)材质

广告牌(Billboard)材质

Billboard概述

Billboard技术在游戏引擎中占有很重要的地位,一般用在粒子效果或者光晕效果上,让粒子面片z轴朝向摄影机。Unity里面也不例外 ,在Unity的粒子系统中的render面板的render mode中就四中billboard模式可选,这些模式都是面对摄影机的,只是轴向的约束不同;另外Unity的Terrain系统里也有Billboard技术的使用;但是如果我们使用自己做的模型或者预设,要使它朝向摄影机的话,则得自己写脚本或者写相应的shader实现,在这里将拿shadowgun里面的一个写得不错的shader(MADFINGER/Transparent/Blinking
GodRays Billboarded)做例子实现billboard功能(如下图:),原来的例子中有一些与billboard无关的效果(如闪烁,根据距离渐隐等)我将它去掉了,只讲述billboard的实现。

模型在3d软件中的准备

在这个shader里面,为了获得面片的中心,将一些数据存在顶点颜色和UV2里面,在顶点颜色R通道和G通道里面存储一个单位面片(长宽为1的面片)的坐标,即四个顶点的顶点色(0,0,0),(255,0,0),(255,255,0),(0,255,0),而在UV2里面存下这个面片的长宽值(6,8),需要注意的是要保证单位为米,方便匹配unity的单位;如下图本例使用的面片:四个顶点的顶点色如下图所示,长宽为6和8,四个顶点的UV2如下图所示,记录长宽的单位6和8。

shader实现

这个shader是一个可以约束Y轴的billboard效果,因此在属性里我们需要定义一个参数,来控制轴向约束的开关:

_VerticalBillboarding("Vertical Restraints", Range(0,1)) = 1

接下来主要工作是在vert函数里修改面片模型的顶点,进行顶点位置的计算,首先我们先获得面片中心到摄影机位置的向量;这个时候我们存在模型顶点颜色和uv2的数据就可以起作用了,下面的计算都是在object space下计算的。

float3	centerOffs  = float3(float(0.5).xx - v.color.rg,0) * v.texcoord1.xyy;//利用事先存在模型顶点色和UV2的数据获得每个顶点相对与中心的偏移量
// float3	centerOffs  = float3(float(0.5).xx - v.color.rg,0) * v.color.bbb*255;
float3	centerLocal = v.vertex.xyz + centerOffs.xyz;//将顶点坐标偏移到中心位置
float3	viewerLocal = mul(_World2Object,float4(_WorldSpaceCameraPos,1));//获得观察点在object space下的坐标
float3	localDir    = viewerLocal - centerLocal;//获得面片中心到观察点的方向向量
localDir.y =localDir.y * _VerticalBillboarding;//如果_VerticalBillboarding为0,则面片则绕y轴旋转

然后将得到的方向向量正则化,并将该方向向量作为Z轴,重构出面片中心面对视角的右手方向向量rightLocal和向上方向向量upLocal;

		float3	rightLocal;
		float3	upLocal;

		CalcOrthonormalBasis(normalize(localDir) ,rightLocal,upLocal);//localDir的正则化很重要!

这里使用了CalcOrthonormalBasis(float3 dir,out float3 right,out float3 up),该函数作用就是根据dir重构出右手方向和向上方向up;这个函数是需要自己定义的 ,原型如下:

	void CalcOrthonormalBasis(float3 dir,out float3 right,out float3 up)
	{
		up    = abs(dir.y) > 0.999f ? float3(0,0,1) : float3(0,1,0);
		right = normalize(cross(up,dir));
		up    = cross(dir,right);
	}

从上述原型可以看出dir,right,up是相互垂直的向量,从而构建出一个在坐标系统;在这里我们的输入时归一化后的localDir向量,因此得到一个在object space下的以localDir作为Z轴,rightLocal做X轴,upLocal做Y轴的新的坐标系,而localDir视线方向,所以rightLocal和upLocal 所构成的平面与视线垂直;最后我们根据这两个单位向量将之前偏移到面片中心的顶点坐标centerLocal重新按偏移量centerOffs偏移回去,构成一个垂直于视线的新的平面;

float3	BBLocalPos = centerLocal - (rightLocal * centerOffs.x + upLocal * centerOffs.y);	

当然这个新的平面是在object space下的,还需要转换到屏幕投影空间;

o.pos   = mul(UNITY_MATRIX_MVP, float4(BBLocalPos,1));//w分量设为1表明float4(BBLocalPos,1)是一个顶点

VF版本代码01

Shader "PengLu/Billboard/UnlitAddVF" {

Properties {
	_MainTex ("Base texture", 2D) = "white" {}
	_VerticalBillboarding("Vertical Restraints", Range(0,1)) = 1
}

SubShader {

	Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }

	Blend One One
	Cull Off Lighting Off ZWrite Off Fog { Color (0,0,0,0) }

	LOD 100

	CGINCLUDE
	#include "UnityCG.cginc"

	sampler2D _MainTex;
	float _VerticalBillboarding;

	struct v2f {
		float4	pos	: SV_POSITION;
		float2	uv	: TEXCOORD0;
	};

	void CalcOrthonormalBasis(float3 dir,out float3 right,out float3 up)
	{
		up    = abs(dir.y) > 0.999f ? float3(0,0,1) : float3(0,1,0);
		right = normalize(cross(up,dir));
		up    = cross(dir,right);
	}

	v2f vert (appdata_full v)
	{
		v2f o;

		float3	centerOffs  = float3(float(0.5).xx - v.color.rg,0) * v.texcoord1.xyy;
		//float3	centerOffs  = float3(float(0.5).xx - v.color.rg,0) * v.color.bbb*256;
		float3	centerLocal = v.vertex.xyz + centerOffs.xyz;
		float3	viewerLocal = mul(_World2Object,float4(_WorldSpaceCameraPos,1));
		float3	localDir    = viewerLocal - centerLocal;

		localDir.y =localDir.y * _VerticalBillboarding;

		float3	rightLocal;
		float3	upLocal;

		CalcOrthonormalBasis(normalize(localDir) ,rightLocal,upLocal);

		float3	BBNormal   = rightLocal * v.normal.x + upLocal * v.normal.y;
		float3	BBLocalPos = centerLocal - (rightLocal * centerOffs.x + upLocal * centerOffs.y);
		o.uv    = v.texcoord.xy;
		o.pos   = mul(UNITY_MATRIX_MVP, float4(BBLocalPos,1));

		return o;
	}
	ENDCG

	Pass {
		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#pragma fragmentoption ARB_precision_hint_fastest
		fixed4 frag (v2f i) : COLOR
		{
			return tex2D (_MainTex, i.uv.xy);
		}
		ENDCG
	}
}

}

VF版本代码01效果:

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 12:49:51

UnityShader实例08:广告牌(Billboard)材质的相关文章

UnityShader实例11:屏幕特效之马赛克(Mosaic)材质

马赛克(Mosaic)材质 概述 马赛克(Mosaic),估计是大伙平时很常见最讨厌的图片处理手段,嘿嘿,没错我说的就是"打码".好了,正经点,马赛克指现行广为使用的一种图像(视频)处理手段,此手段将影像特定区域的色阶细节劣化并造成色块打乱的效果,因为这种模糊看上去有一个个的小格子组成,便形象的称这种画面为马赛克.其目的通常是让图像大规模的降低图像()视频分辨率,而让图像(视频)的一些细节隐藏起来,使之无法辨认,一般用来保护隐私,或者隐藏某些不健康的画面. 原理 要实现马赛克的效果,需

UnityShader实例11:积雪材质

积雪材质 概述 积雪材质是我自己给这个材质取的名字,既然是积雪,那顾名思义,雪是从天而降的,因此积雪都是在物体朝上的表面:不管你的模型怎么摆放 ,雪都保证是积在物体朝上(在unity里就是y轴正方向)的表面,如下图所示: 实现原理 要保证向上的面有积雪,其实就是模型表面的法线方向与世界坐标空间的Y轴正方向保持一致积雪多,否则积雪就少雪,所以将模型的法线方向normal从模型空间转化到世界空间,然后与y轴正方向float3(0,1,0)做点积,根据结果来确认法相的朝向和Y轴的夹角大小,从而确认是否

UnityShader实例15:屏幕特效之Bloom

http://blog.csdn.net/u011047171/article/details/48522073 Bloom特效 概述 Bloom,又称"全屏泛光",是游戏中常用的一种镜头效果,是一种比较廉价的"伪HDR"效果(如下右图):使用了Bloom效果后,画面的对比会得到增强,亮的地方曝光也会得到加强,画面也会呈现一种朦胧,梦幻的效果,婚纱摄影中照片处理经常用到这种类似处理效果.Bloom效果一般用来近似模拟HDR效果,效果也比较相向,但实现原理却完全不同.

卡通渲染

Shader的学习方法总结 http://www.cnblogs.com/Esfog/p/How_To_Learn_Shader.html 图形学原理之卡通渲染 http://sanwen8.cn/p/1f1p0DF.html http://mp.weixin.qq.com/s?__biz=MjM5NjM3NDA1Mg==&mid=207340425&idx=2&sn=c8c93322e9ccf21176cfb31a241baa7b&scene=21#wechat_redi

【Unity】9.3 粒子系统生成器详解

分类:Unity.C#.VS2015 创建日期:2016-05-02 一.简介 上一节已经介绍过了在Unity 5.x中两种创建粒子效果的方式(方式1.方式2). 这一节我们主要学习第2种方式的基本概念和用法. Unity 5.x提供的新版粒子系统生成器(Particle System)也叫Shuriken粒子系统,该生成器采用模块化管理,个性化的粒子模块,配台粒子曲线编辑器,使用户很容易就能创作出各种缤纷复杂的粒子效果. 1.粒子系统检视器 粒子系统检视器 (Particle System I

(转载)虚幻引擎3--基础知识

这是虚幻引擎3UDN的技术文档,共有六个章节.以下将分别把中文译本贴出来,方便懒人学习[偷笑]  一.虚幻引擎 3 基础知识 概述 -------------------------------------------------------------------- 有几个游戏性元素实际上是所有使用虚幻引擎3或虚幻开发工具包创建的项目所共有的.自定义这些元素可以创建出完全独特的.外观和行为符合期望的游戏.没有任何两个项目是相同的,尽管虚幻引擎提供了这些元素的默认实现,但是肯定需要对它们进行很大

粒子系统模块(Particle System Modules40)

粒子系统模块(忍者飞镖) 粒子系统(忍者飞镖)(Particle System (Shuriken)) 用模块描述粒子一段时间内的行为.此处记载了模块的详细说明.有关模块介绍,请参阅此页面. 初始化模块 该模块始终存在,无法删除或禁用.     持续时间 (Duration) 粒子系统 (Particle System) 发射粒子的持续时间. 循环 (Looping) 粒子系统 (Particle System) 是否循环. 预热 (Prewarm) 只可预热循环系统,这意味着,粒子系统 (Pa

UV动画

[猫猫的Unity Shader之旅]之UV动画 http://blog.csdn.net/dbtxdxy/article/details/44737133 UnityShader实例06:UV动画 http://blog.csdn.net/u011047171/article/details/46776713

【python】redis基本命令和基本用法详解

1.redis连接 redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令, 并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py. import redis 导入redis模块,通过python操作redis 也可以直接在redis主机的服务端操作缓存数据库 r = redis.Redis(host='192.168.19.130', port=6379) host是