如何在unity自发光材质里面使用decal材质

关于unity中贴花的怎么用,还有decal System插件怎么用_泰课在线吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0可签7级以上的吧50个
本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:39贴子:
关于unity中贴花的怎么用,还有decal System插件怎么用
关于unity中贴花的怎么用 ,还有decal System插件怎么用 如何实现如下效果: 还不能发地址,草 还有就是蛮牛的这个提问系统怎么做的这么奇葩,上传一个本地图片搞的跟脱裤子放屁一样,有病
贴吧热议榜
使用签名档&&
保存至快速回贴2521人阅读
使用3Dsmax2010进行制作,输出FBX的类型导入中。默认情况下,3Dsmax8可以和软件直接融合,自动转换为FBX物体。
1.面数控制
在MAX软件中制作单一Game Object物体的面数不能超过65000个三角形,即32500个多边形Poly,如果超过这个数量的物体不会显示出来,这就需要我们合理分布多边形和模型数量。
打开MAX场景,选择File/Properties/Summary Info可以打开文件属性记录。其中Faces可以看到每个物体的实际数量,个体数量不能超过65000个Faces面。
2.建模控制
Unity3D软件支持Line渲染和编辑之后所产生的模型。大部分模型都依靠Polygon进行制作。在模型表面可以承认多出四边形的面,但不渲染交错的面。
默认情况下,U3D引擎是不承认双面材质的,除非使用植物材质球Nature类型。所以在制作窗户、护栏等物体,如果想在两面都能看到模型,那需要制作出厚度,或者复制两个面翻转其中一个的Normal法线。
3.文件的放置
模型可以继承MAX的材质,但是文件的设置要按照以下形式进行放,在项目的Assets文件夹内,新创建一个Object文件夹。并在其中创建Materials和Texture文件夹(分别自动存放材质球和贴图)。模型物体并列保存在Object文件夹内。这个规律模式不要打乱,否则会破坏整个系统逻辑。
4.材质数量控制
如果一个物体给与一个材质球,那么Unity3D对于材质数量和贴图数量没有任何的限制。如果一个物体给与多个材质球,我们需要用Multi/SubObject来实现,但是这种罗列的材质球的数量没有严格的控制,但尽量保持在10以内,过多的数量会导致一些错误。如果不使用Multi/SubObject材质球,也可以选择一些面,然后给与一个材质球。这样系统会自动将其转换成Multi/SubObject材质。综合而言Unity3D软件对于材质的兼容还是很好的。
5.物体的质感
Diffuse、Diffuse Bumped、Bumped Specular这三种类型为常用类型,其中Bumped需要增加Normal法线贴图来实现凹凸。
Decal:这种材质为贴花材质,即相当于Mask类型,可以再Decal(RGBA)贴与一个带有Alpha通道的图像,形成和原图像相叠加的效果。
Diffuse Detail:这种材质可以创造出污迹和划痕的效果,即相当于Blend混合材质。
Reflective:其中各种类型可以创造出金属反射效果,需要增加Cubmap贴图。
Transparent:其中各种类型可以创造出透明的效果,需要增加具有Alpha的通道贴图。
注意:如果要做玻璃贴图,Alpha如果全是灰色或黑色(即要求全透明),那么Alpha就会失效,如果要全透明,材质Alpha其中必须至少有1像素为白色。
Nature:其中Soft Occlusion Leaves类型主要应用于片状的树叶材质。
6.物体尺寸
默认情况下U3D系统单位1等于1米,等于软件1单位。如果我们制作是按照实际大小比例制作,那么导入U3D引擎会自动变成原来的1%的大小。因为默认情况下,U3D的FBXImporter中的Scale Factor的数值为0.01。那个我们可以将Scale Factor的数值恢复为1,但是这样会占用模型资源,比较消耗物理缓存。我们也可以将这个物体从Hierarchy中选择,并使用Scale放大100倍,这种设置可以有很多好处,并且还能通过用脚本制作动画。
7.关于复制
场景中的灯光布局,重复的模型物体都可以使用系统Prefab进行关联复制,这样可以改变一个参数的同时将所有关联物体属性改变。
8.山脉控制
在创建山脉之后,选择Terrain/Set Resolution可以设置山脉的大小和属性。需要注意的是,默认情况下Terrain Width和Terrain Height为1000米。如果设置这个数值太小,那么绘制草的时候会产生偏移,因为草的尺寸必须减少到0.1的单位。也就是说,山脉在处理0.1单位的时候会产生0.01的偏差,如果模型太小,这种偏差是显而易见的,所以建议用户不要让模型过小。
9.光晕控制
光晕又称为Lens Flare即灯光光效。可以选择一个GameObject物体给与Component/Rendering/Lens Flare,并在Flare中增加一个Standard Assets/Light Flares/50mm Zoom项目。这样在运行之后就会产生光晕。但有时候如果光晕太远太高却看不到。一种办法是将光晕离近,另一种办法是将所有摄影机Camera的Far clip plane的数值增加。
10.摄影机控制
如果场景中有多架摄影机,那么如何确定第一打开时间所显示的摄影机,就需要设置Camera属性中的Depth数值,数值越大的摄影机越优先显示。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2794171次
积分:26983
积分:26983
排名:第167名
原创:312篇
转载:197篇
译文:10篇
评论:387条
(4)(4)(12)(27)(4)(2)(7)(16)(5)(10)(14)(14)(5)(2)(2)(4)(3)(2)(5)(4)(10)(3)(4)(3)(1)(3)(6)(1)(2)(6)(5)(5)(8)(7)(7)(19)(18)(5)(14)(4)(3)(1)(12)(12)(31)(21)(12)(14)(10)(11)(7)(4)(15)(10)(8)(56)(19)Shader(18)
本文主要讲解了Unity中SurfaceShader的具体写法,以及几个常用的CG函数的用法。
在这里先说明一下,表面着色器将分为两次讲解,本文介绍表面着色器的基本概念和一些写法,用内置的兰伯特光照模式来进行Surface Shader的书写,而下次将介绍Surface Shader+自定义的光照模式的写法。
PS:最近几天,在完美世界、腾讯互娱工作多年的几个朋友们问了浅墨一些表面着色器相关的Shader写法,浅墨当时回答他们的时候自己也是似懂非懂。通过这篇文章的书写,现在算是对这方面知识有了进一步的理解。所以说嘛,写作是总结自己所学的一种很好的方式~
OK,言归正传,依然是先来看看本文配套的游戏场景截图。
运行游戏,音乐响起,首先是一个欧式风格的集市映入眼帘:
雨淅沥沥、天空、晚霞、海平面:
天空中,一群飞鸟飞过:
暗黑城堡:
在小集市中逛荡:
城堡概况图:
OK,图先就上这么多。文章末尾有更多的运行截图,并提供了源工程的下载。可运行的exe下载在这里:
好的,我们正式开始。
一、表面着色器的标准输出结构(Surface Output)
要书写Surface Shader,了解表面着色器的标准输出结构必不可少。此为&表面着色器书写的第一个要素。
而定义一个“表面函数(surface function)”,需要输入相关的UV或数据信息,并在输出结构中填充SurfaceOutput。SurfaceOutput基本上描述了表面的特性(光照的颜色反射率、法线、散射、镜面等)。其实还是需要用CG或者HLSL编写此部分的代码。
我们其实是通过表面着色器(Surface Shader)来编译这段CG或者HLSL代码的,然后计算出需要填充输入什么,输出什么等相关信息,并产生真实的顶点(vertex)&像素(pixel)着色器,以及把渲染路径传递到正向或延时渲染路径。
说白了,还是那句话,Surface Shader是Unity微创新自创的一套着色器标准,是Unity自己发扬光大的一项使Shader的书写门槛降低和更易用的技术。
我们之前的文章中已经稍微了解过,表面着色器(Surface Shader)的标准输出结构是这样的:&
struct SurfaceOutput
而这个结构体的用法,其实就是对这些需要用到的成员变量在surf函数中赋一下值,比如说这样:
void surf (Input IN, inout SurfaceOutput o)
o.Albedo= 0.6;
注意到Albedo是half3类型的。那么o.Albedo = 0.6和o.Albedo = float3(0.6,0.6,0.6)是等价的。
二、表面着色器的编译指令
表面着色器的编译指令为编写表面着色器的第二个要素。
表面着色器放在CGPROGRAM .. ENDCG块里面,就像其他的着色器一样。区别是:
其必须嵌在子着色器(SubShader)块里面。而不是Pass块里面。因为表面着色器( Surface shader)将在多重通道(multiple passes)内编译自己,而不是放在某个Pass中。
我们甚至可以这样说,如果你写表面着色器,用不到Pass代码块,一般直接在SubShader块中完成就行了。
使用的 #pragma surface...指令,以声明这是一个表面着色器。指令的句法是:
#pragma&surface surfaceFunction lightModel[optionalparams]
所需参数的讲解:
surfaceFunction - 表示指定名称的Cg函数中有表面着色器(surface shader)代码。这个函数的格式应该是这样:void surf (Input IN,inout SurfaceOutput o), 其中Input是我们自己定义的结构。Input结构中应该包含所需的纹理坐标(texture coordinates)和和表面函数(surfaceFunction)所需要的额外的必需变量。lightModel -使用的光照模式。内置的是Lambert (diffuse)和 BlinnPhong (specular)两种,一般习惯用Lambert,也就是兰伯特光照模式。而编写自己的光照模式我们将在下次更新中讲解。
可以根据自己的需要,进阶选这样的一些可选参数:
alpha -透明( Alpha)混合模式。使用它可以写出半透明的着色器。alphatest:VariableName -透明( Alpha)测试模式。使用它可以写出 镂空效果的着色器。镂空大小的变量(VariableName)是一个float型的变量。vertex:VertexFunction - 自定义的顶点函数(vertex function)。相关写法可参考Unity内建的Shader:树皮着色器(Tree Bark shader),如Tree Creator Bark、Tree Soft Occlusion Bark这两个Shader。
finalcolor:ColorFunction - 自定义的最终颜色函数(final color function)。 比如说这样:
#pragma surfacesurf Lambert finalcolor:mycolor。
相关Shader示例可见下文Shader实战部分的第五个Shader(纹理载入+颜色可调)。
exclude_path:prepass 或者 exclude_path:forward - 使用指定的渲染路径,不需要生成通道。addshadow - 添加阴影投射 & 收集通道(collector passes)。通常用自定义顶点修改,使阴影也能投射在任何程序的顶点动画上。dualforward - 在&&渲染路径中使用&&&。fullforwardshadows - 在&&渲染路径中支持所有阴影类型。decal:add - 添加贴图着色器(decal shader) (例如: terrain AddPass)。decal:blend - 混合半透明的贴图着色器(Semitransparent decal shader)。softvegetation - 使表面着色器(surface shader)仅能在Soft Vegetation打开时渲染。noambient - 不适用于任何环境光照(ambient lighting)或者球面调和光照(spherical harmonics lights)。novertexlights - 在正向渲染(Forward rendering)中不适用于球面调和光照(spherical harmonics lights)或者每个顶点光照(per-vertex lights)。nolightmap - 在这个着色器上禁用光照贴图(lightmap)。(适合写一些小着色器)nodirlightmap - 在这个着色器上禁用方向光照贴图(directional lightmaps)。 (适合写一些小着色器)。noforwardadd - 禁用正向渲染添加通道(Forward&rendering additive pass)。 这会使这个着色器支持一个完整的方向光和所有光照的per-vertex/SH计算。(也是适合写一些小着色器).approxview - 着色器需要计算标准视图的每个顶点(per-vertex)方向而不是每个像索(per-pixel)方向。 这样更快,但是视图方向不完全是当前摄像机(camera) 所接近的表面。halfasview - 在光照函数(lighting function)中传递进来的是half-direction向量,而不是视图方向(view-direction)向量。 Half-direction会计算且会把每个顶点(per vertex)标准化。这样做会提高执行效率,但是准确率会打折扣。
此外,我们还可以在 CGPROGRA内编写 #pragma debug,然后表面编译器(surface compiler)会进行解释生成代码。
三、表面着色器输入结构(Input Structure)
表面着色器书写的第三个要素是指明表面输入结构(Input Structure)。
Input 这个输入结构通常拥有着色器需要的所有纹理坐标(texture coordinates)。纹理坐标(Texturecoordinates)必须被命名为“uv”后接纹理(texture)名字。(或者uv2开始,使用第二纹理坐标集)。
可以在输入结构中根据自己的需要,可选附加这样的一些候选值:
float3 viewDir - 视图方向( view direction)值。为了计算视差效果(Parallax effects),边缘光照(rim lighting)等,需要包含视图方向( view direction)值。float4 with COLOR semantic -每个顶点(per-vertex)颜色的插值。float4 screenPos - 屏幕空间中的位置。 为了反射效果,需要包含屏幕空间中的位置信息。比如在Dark Unity中所使用的 WetStreet着色器。float3 worldPos - 世界空间中的位置。float3 worldRefl - 世界空间中的反射向量。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。 请参考这个例子:Reflect-Diffuse 着色器。float3 worldNormal - 世界空间中的法线向量(normal vector)。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。float3 worldR INTERNAL_DATA - 世界空间中的反射向量。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。为了获得基于每个顶点法线贴图( per-pixel normal map)的反射向量(reflection vector)需要使用世界反射向量(WorldReflectionVector (IN, o.Normal))。请参考这个例子:
Reflect-Bumped着色器。float3 worldN INTERNAL_DATA -世界空间中的法线向量(normal vector)。如果表面着色器(surface shader)不写入法线(o.Normal)参数,将包含这个参数。为了获得基于每个顶点法线贴图( per-pixel normal map)的法线向量(normal vector)需要使用世界法线向量(WorldNormalVector (IN, o.Normal))。
四、一些本次写Shader用到的CG函数讲解
本次Shader书写用到了四个CG着色器编程语言中的函数——&UnpackNormal、&saturate、&dot、tex2D。&下面将分别对其进行讲解。
4.1&UnpackNormal( )函数
UnpackNormal接受一个fixed4的输入,并将其转换为所对应的法线值(fixed3),并将其赋给输出的Normal,就可以参与到光线运算中完成接下来的渲染工作了。
一个调用示例:
o.Normal = UnpackNormal (tex2D (_BumpMap,IN.uv_BumpMap));
4.2&saturate( )函数
saturate的字面解释是浸湿,浸透。其作用其实也就是将取值转化为[0,1]之内的一个值。
其可选的原型如下:
float saturate(float x);
float1 saturate(float1 x);
float2 saturate(float2 x);
float3 saturate(float3 x);
float4 saturate(float4 x);
half saturate(half x);
half1 saturate(half1 x);
half2 saturate(half2 x);
half3 saturate(half3 x);
half4 saturate(half4 x);
fixed saturate(fixed x);
fixed1 saturate(fixed1 x);
fixed2 saturate(fixed2 x);
fixed3 saturate(fixed3 x);
fixed4 saturate(fixed4 x);
其唯一的一个参数x表示矢量或者标量的饱和值(Vector or scalar to saturate.),也就是将这个x转化为[0,1]之内的值。
其返回值:
如果x取值小于0,则返回值为0.如果x取值大于1,则返回值为1.若x在0到1之间,则直接返回x的值。
其代码实现大致如下:
float saturate(float x)
return max(0,min(1, x));
一个调用示例:
half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal));
4.3&dot( )函数
dot函数顾名思义,是高等数学中的点积操作,用于返回两个向量的标量积。
可选原型如下:
float dot(float a, float b);
float dot(float1 a, float1 b);
float dot(float2 a, float2 b);
float dot(float3 a, float3 b);
float dot(float4 a, float4 b);
half dot(half a, half b);
half dot(half1 a, half1 b);
half dot(half2 a, half2 b);
half dot(half3 a, half3 b);
half dot(half4 a, half4 b);
fixed dot(fixed a, fixed b);
fixed dot(fixed1 a, fixed1 b);
fixed dot(fixed2 a, fixed2 b);
fixed dot(fixed3 a, fixed3 b);
fixed dot(fixed4 a, fixed4 b);
其代码实现大致是这样的:
float dot(float4 a, float4 b)
return a.x*b.x +a.y*b.y + a.z*b.z + a.w*b.w;
一个调用示例:
float answer= dot (normalize(IN.viewDir),o.Normal);
4.4&tex2D( )函数
让我们看一看CG中用得比较多的用于2D纹理采样的tex2D函数的用法。其备选的原型也是非常之多:
float4 tex2D(sampler2D samp, float2 s)
float4 tex2D(sampler2D samp, float2 s, inttexelOff)
float4 tex2D(sampler2D samp, float3 s)
float4 tex2D(sampler2D samp, float3 s, inttexelOff)
float4 tex2D(sampler2D samp, float2 s,float2 dx, float2 dy)
float4 tex2D(sampler2D samp, float2 s,float2 dx, float2 dy, int texelOff)
float4 tex2D(sampler2D samp, float3 s,float2 dx, float2 dy)
float4 tex2D(sampler2D samp, float3 s,float2 dx, float2 dy, int texelOff)
int4 tex2D(isampler2D samp, float2 s)
int4 tex2D(isampler2D samp, float2 s, inttexelOff)
int4 tex2D(isampler2D samp, float2 s,float2 dx, float2 dy)
int4 tex2D(isampler2D samp, float2 s,float2 dx, float2 dy, int texelOff)
unsigned int4 tex2D(usampler2D samp, float2s)
unsigned int4 tex2D(usampler2D samp, float2s, int texelOff)
unsigned int4 tex2D(usampler2D samp, float2s, float2 dx, float2 dy)
unsigned int4 tex2D(usampler2D samp, float2s, float2 dx, float2 dy,int texelOff)
参数简介:
samp-需要查找的采样对象,也就是填个纹理对象在这里。
s-需进行查找的纹理坐标。
dx-预计算的沿X轴方向的导数。
dy-预计算的沿Y轴方向的导数。
texelOff-添加给最终纹理的偏移量
而其返回值,自然是查找到的纹理。
最后,看一个综合了本次讲解的四个函数(UnpackNormal、saturate、tex2D、dot)的Surface Shader中surf函数的示例:
void surf (Input IN, inout SurfaceOutput o)
o.Albedo= tex2D (_MainTex, IN.uv_MainTex).
o.Normal= UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
halfrim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
o.Emission= _RimColor.rgb * pow (rim, _RimPower);
五、写Shdaer实战
上面都是些概念,下面我们将进行一些实战的Shader书写,将学到的这些概念用到实际当中去。
本次我们将讲解9个表面SurfaceShader的写法,从最基本的Surface Shader,循序渐进,一点一点加功能,到最后的稍微有点复杂的“凹凸纹理+颜色可调+边缘光照+细节纹理“表面Shader的写法。本期的全部Shader的合照如下:
在材质界面菜单中的显示:
OK,下面开始讲解,从最基本的开始。
1.最基本的Surface Shader
先看一个使用内建光照模式的最基本的Surface Shader应该怎么写:
Shader &浅墨Shader编程/Volume6/24.最基本的SurfaceShader&
Tags { &RenderType& = &Opaque& }
#pragma surface surf Lambert
struct Input
float4 color : COLOR;
void surf (Input IN, inout SurfaceOutput o)
o.Albedo = float3(0.5,0.8,0.3);
Fallback &Diffuse&
可以发现,一个最基本的Surface Shader,至少需要有光照模式的声明、输入结构和表面着色函数的编写这三部分。
另外,主要注意其中的surf函数的写法,就是把上文讲到的Surface Output结构体中需要用到的成员变量拿来赋值:
//【2】表面着色函数的编写
void surf (Input IN, inout SurfaceOutput o)
o.Albedo= float3(0.5,0.8,0.3);//(0.5,0.8,0.3)分别对应于RGB分量
//而o.Albedo = 0.6;等效于写o.Albedo =float3(0.6,0.6,0.6);
注释中已经写得很明白,且之前也已经讲过,o.Albedo = 0.6;等效于写o.Albedo = float3(0.6,0.6,0.6);
来个举一反三,则o.Albedo =1;等效于写o.Albedo= float3(1,1,1);
我们将此Shader编译后赋给材质,得到如下效果:
而在场景中的实测效果为:
2.颜色可调
在最基本的Surface Shader的基础上,加上一点代码,就成了这里的可调颜色的Surface Shader:
Shader &浅墨Shader编程/Volume6/25.颜色可调的SurfaceShader&
Properties
_Color (&【主颜色】Main Color&, Color) = (0.1,0.3,0.9,1)
Tags { &RenderType&=&Opaque& }
#pragma surface surf Lambert
struct Input
float4 color : COLOR;
void surf (Input IN, inout SurfaceOutput o)
o.Albedo = _Color.
o.Alpha = _Color.a;
FallBack &Diffuse&
我们将此Shader编译后赋给材质,得到如下效果,和之前的固定功能Shader一样,可以自由调节颜色:
其在场景中的实测效果为:
3.基本纹理载入
再来看看如何实现一个基本的纹理载入Surface Shader:
Shader &浅墨Shader编程/Volume6/26.基本纹理载入&
Properties
_MainTex (&【主纹理】Texture&, 2D) = &white& {}
Tags { &RenderType& = &Opaque& }
#pragma surface surf Lambert
struct Input
float2 uv_MainT
sampler2D _MainT
void surf (Input IN, inout SurfaceOutput o)
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).
Fallback &Diffuse&
我们将此Shader编译后赋给材质,得到如下效果:
场景中的实测效果图为:
4.凹凸纹理载入
让我们慢慢添加特性,使得到的Surface Shader的效果与功能越来越强大。接着来看看Surface Shader的凹凸纹理如何实现:
Shader &浅墨Shader编程/Volume6/27.凹凸纹理载入&
Properties
_MainTex (&【主纹理】Texture&, 2D) = &white& {}
_BumpMap (&【凹凸纹理】Bumpmap&, 2D) = &bump& {}
Tags { &RenderType& = &Opaque& }
#pragma surface surf Lambert
struct Input
float2 uv_MainT
float2 uv_BumpM
sampler2D _MainT
sampler2D _BumpM
void surf (Input IN, inout SurfaceOutput o)
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
Fallback &Diffuse&
我们将此Shader编译后赋给材质,得到如下效果:
场景中的实测效果图为:
5.纹理载入+颜色可调
接着看一看纹理如何通过一个finalcolor关键字自定义函数,来达到调色的目的:
Shader &浅墨Shader编程/Volume6/28.纹理+颜色修改&
Properties
_MainTex (&【主纹理】Texture&, 2D) = &white& {}
_ColorTint (&【色泽】Tint&, Color) = (0.6, 0.3, 0.6, 0.3)
Tags { &RenderType& = &Opaque& }
#pragma surface surf Lambert finalcolor:setcolor
struct Input
float2 uv_MainT
fixed4 _ColorT
sampler2D _MainT
void setcolor (Input IN, SurfaceOutput o, inout fixed4 color)
color *= _ColorT
void surf (Input IN, inout SurfaceOutput o)
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).
Fallback &Diffuse&
我们将此Shader编译后赋给材质,得到如下效果:
调些颜色玩一玩:
场景中的实测效果图为:
6. 凹凸纹理+边缘光照
在之前凹凸纹理的基础上让我们加上喜闻乐见的边缘光照:
Shader &浅墨Shader编程/Volume6/29.凹凸纹理+边缘光照&
Properties
_MainTex (&【主纹理】Texture&, 2D) = &white& {}
_BumpMap (&【凹凸纹理】Bumpmap&, 2D) = &bump& {}
_RimColor (&【边缘颜色】Rim Color&, Color) = (0.26,0.19,0.16,0.0)
_RimPower (&【边缘颜色强度】Rim Power&, Range(0.5,8.0)) = 3.0
Tags { &RenderType& = &Opaque& }
#pragma surface surf Lambert
struct Input
float2 uv_MainT
float2 uv_BumpM
float3 viewD
sampler2D _MainT
sampler2D _BumpM
float4 _RimC
float _RimP
void surf (Input IN, inout SurfaceOutput o)
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
o.Emission = _RimColor.rgb * pow (rim, _RimPower);
Fallback &Diffuse&
其中的viewDir 意为WorldSpace View Direction,也就是当前坐标的视角方向:
关于surf中的两句新加的代码在这里也讲一下。
上面已经提到过,Normalize函数,用于获取到的viewDir坐标转成一个单位向量且方向不变,外面再与点的法线做点积。最外层再用 saturate算出一[0,1]之间的最靠近的值。这样算出一个rim边界。原理可以这样解释:
这里o.Normal就是单位向量。外加Normalize了viewDir。因此求得的点积就是夹角的cos值。&因为cos值越大,夹角越小,所以,这时取反来。这样,夹角越大,所反射上的颜色就越多。于是就得到的两边发光的效果。哈哈这样明了吧。
这里再介绍一下这个half。CG里还有类似的float和fixed。half是一种低精度的float,但有时也会被选择成与float一样的精度。先就说这么多吧,后面还会遇到的,到时候再讲。
我们将此Shader编译后赋给材质,得到如下效果,除了凹凸纹理的选择之外,还有边缘发光颜色和强度可供自由定制:
依然是调一些颜色玩一玩:
场景中的实测截图为:
7.凹凸纹理+颜色可调
接下来我们看看凹凸纹理+颜色可调的Shader怎么写:
Shader &浅墨Shader编程/Volume6/30.凹凸纹理+颜色可调+边缘光照&
Properties
_MainTex (&【主纹理】Texture&, 2D) = &white& {}
_BumpMap (&【凹凸纹理】Bumpmap&, 2D) = &bump& {}
_ColorTint (&【色泽】Tint&, Color) = (0.6, 0.3, 0.6, 0.3)
_RimColor (&【边缘颜色】Rim Color&, Color) = (0.26,0.19,0.16,0.0)
_RimPower (&【边缘颜色强度】Rim Power&, Range(0.5,8.0)) = 3.0
Tags { &RenderType& = &Opaque& }
#pragma surface surf Lambert finalcolor:setcolor
struct Input
float2 uv_MainT
float2 uv_BumpM
float3 viewD
sampler2D _MainT
sampler2D _BumpM
fixed4 _ColorT
float4 _RimC
float _RimP
void setcolor (Input IN, SurfaceOutput o, inout fixed4 color)
color *= _ColorT
void surf (Input IN, inout SurfaceOutput o)
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
o.Emission = _RimColor.rgb * pow (rim, _RimPower);
Fallback &Diffuse&
我们将此Shader编译后赋给材质,得到如下非常赞的效果。除了载入纹理,还有色泽,边缘颜色和强度可供调节:
依然是调些效果玩一玩:
而在场景中的实测效果为:
8.细节纹理
接着我们来看一个在屏幕上显示纹理细节的Shader:
Shader &浅墨Shader编程/Volume6/31.细节纹理&
Properties
_MainTex (&【主纹理】Texture&, 2D) = &white& {}
_Detail (&【细节纹理】Detail&, 2D) = &gray& {}
Tags { &RenderType& = &Opaque& }
#pragma surface surf Lambert
struct Input
float2 uv_MainT
float2 uv_D
sampler2D _MainT
sampler2D _D
void surf (Input IN, inout SurfaceOutput o)
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).
o.Albedo *= tex2D (_Detail, IN.uv_Detail).rgb * 2;
Fallback &Diffuse&
我们将此Shader编译后赋给材质,&不加细节纹理如下:
加纹理细节的效果图如下:
而在场景中的实测效果为:
9.凹凸纹理+颜色可调+边缘光照+细节纹理
结合上面的8个Shader,我们可以完成本期文章这个结合了凹凸纹理+颜色可调+边缘光照+细节纹理的稍微复杂一点的Surface Shader:
Shader &浅墨Shader编程/Volume6/32.凹凸纹理+颜色可调+边缘光照+细节纹理&
Properties
_MainTex (&【主纹理】Texture&, 2D) = &white& {}
_BumpMap (&【凹凸纹理】Bumpmap&, 2D) = &bump& {}
_Detail (&【细节纹理】Detail&, 2D) = &gray& {}
_ColorTint (&【色泽】Tint&, Color) = (0.6, 0.3, 0.6, 0.3)
_RimColor (&【边缘颜色】Rim Color&, Color) = (0.26,0.19,0.16,0.0)
_RimPower (&【边缘颜色强度】Rim Power&, Range(0.5,8.0)) = 3.0
Tags { &RenderType& = &Opaque& }
#pragma surface surf Lambert finalcolor:setcolor
struct Input
float2 uv_MainT
float2 uv_BumpM
float2 uv_D
float3 viewD
sampler2D _MainT
sampler2D _BumpM
sampler2D _D
fixed4 _ColorT
float4 _RimC
float _RimP
void setcolor (Input IN, SurfaceOutput o, inout fixed4 color)
color *= _ColorT
void surf (Input IN, inout SurfaceOutput o)
o.Albedo = tex2D (_MainTex, IN.uv_MainTex).
o.Albedo *= tex2D (_Detail, IN.uv_Detail).rgb * 2;
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
o.Emission = _RimColor.rgb * pow (rim, _RimPower);
Fallback &Diffuse&
我们将此Shader编译后赋给材质,得到如下效果:
依然是调一些效果玩一玩:
而在场景中的实测效果为:
六、场景搭建
以大师级美工鬼斧神工的场景作品为基础,浅墨调整了场景布局,加入了音乐,并加入了更多高级特效,于是便得到了如此这次非常炫酷的暗黑城堡场景。
运行游戏,史诗级音乐渐渐响起,雨淅沥沥地下,我们来到了神秘的暗黑城堡:
在集市中逛荡1:
在集市中逛荡2:
在集市中逛荡3:
通向远方的桥梁:
壮观的瀑布:
感受瀑布溅起的水花:
在瀑布旁看远方,雾气氤氲:
成群的飞鸟飞过:
一片荒凉:
透过栅栏远眺:
画面太美,简直乱真:
海面上倒映出晚霞:&
城堡概况:
最后一张本次的Shader全家福:
OK,美图就放这么多。游戏场景可运行的exe可以在文章开头中提供的链接下载。而以下是源工程的下载链接。
本篇文章的示例程序源工程请点击此处下载:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:59815次
排名:千里之外
原创:12篇
转载:162篇
(7)(6)(1)(1)(1)(2)(4)(19)(2)(12)(3)(5)(5)(5)(8)(6)(3)(6)(3)(1)(2)(3)(1)(8)(5)(2)(1)(1)(1)(9)(16)(11)(20)

我要回帖

更多关于 unity 材质球 的文章

 

随机推荐