unity中能用unity 代码替换shader修改shader吗

Unity3D教程:教你如何利用Shader来进行3D角色的渲染 | Unity3D教程手册
当前位置 :
>> Unity3D教程:教你如何利用Shader来进行3D角色的渲染
Unity3D教程:教你如何利用Shader来进行3D角色的渲染
本文主要介绍一下如何利用Shader来渲染游戏中的3D角色,以及如何利用Unity提供的Surface Shader来书写自定义Shader。
一、从Shader开始
1、通过Assets-&Create-&Shader来创建一个默认的Shader,并取名“MyShader”。
Unity3D教程:3D角色的渲染
2、将MyShader打开即可看见Unity默认的Shader代码
&&&01Shader &Custom/MyShader& {02Properties {03_MainTex (&Base (RGB)&, 2D) = &white& {}04}05SubShader {06Tags { &RenderType&=&Opaque& }07LOD 20008CGPROGRAM09#pragma surface surf Lambert10sampler2D _MainTex;11struct Input {12float2 uv_MainTex;13};14void surf (Input IN, inout SurfaceOutput o) {15half4 c = tex2D (_MainTex, IN.uv_MainTex);16o.Albedo = c.rgb;17o.Alpha = c.a;18}19ENDCG20}21FallBack &Diffuse&22}
3、将该Shader赋给一个角色,就可以看到该Shader所能表达出的Diffuse渲染效果。
Unity3D教程:3D角色的渲染
4、接来我们将以此默认Shader作为蓝本,编写出自定义的Shader。另外,该Shader所用到的参数,我们将在下一章节进行说明。
二、实现多种自定义渲染效果
1、 BumpMap效果
如果想实现Bump Map效果,可对上述的Shader做如下修改:
1.1 在属性Properties中加入:
&&&1Properties {2_MainTex (&Base (RGB)&, 2D) = &white& {}3_BumpMap(&Bumpmap&, 2D) = &bump& {}4}
1.2 在SubShader的变量中也进行相应修改:
&&&1sampler2D _MainTex;2sampler2D _BumpMap;3struct Input {4float2 uv_MainTex;5float2 uv_BumpMap;6};
1.3 最后修改surf函数,加入对Normal分量的计算:
&&&1void surf (Input IN, inout SurfaceOutput o) {2&white-space:&& half4 c = tex2D (_MainTex, IN.uv_MainTex);3o.Albedo = c.rgb;4o.Alpha = c.a;5o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));6}
这样,角色的材质部分即可变为如下形式(暂定BumpMap的Shader名为“MyShader1”):
Unity3D教程:3D角色的渲染
然后,根据Base图来创建其Normal Map图,并拖入到BumpMap中即可。BumpMap的效果显示如下:
Unity3D教程:3D角色的渲染
(1)首先是title的解释
&&&1Shader &Custom/MyShader1&
这种表示表明了该Shader在编辑器中的显示位置,例如我们可在如下地方找到该Shader。
Unity3D教程:3D角色的渲染
(2)其次是Properties
&&&1Properties {2_MainTex (&Base (RGB)&, 2D) = &white& {}3_BumpMap(&Bumpmap&, 2D) = &bump& {}4}
Properties可通过如下语义进行声明:
name ("displayname", property type) = default value
“name” 是与Shader脚本中对应的名字
“display name”是在材质视图中所显示的名字
“propertytype”是指该property的类型,一般可有如下几种类型:Range,Color,2D,Rect,Cube,Float和Vector
“defaultvalue”是指该property的默认值
这里需要注意的是,如果你在Properties中加入了新的属性,那么你需要在CGPROGRAM中的SubShader中加入同样名字的参数。
(3)接下来是“LOD”语义词的解释。
这里的“LOD”主要是指Shader的LOD程度,即对于超出该范围的物体将不再通过该Shader进行渲染,具体的Shader LOD说明可以参见:
(4)我们在SubShader中还加入了
&&&1sampler2D _BumpMap;2float2 uv_BumpMap;
其中,_BumpMap是为了关联Properties中的_BumpMap属性。
而uv_BumpMap,是为了获取BumpMap图中的uv坐标。
(5)最后,我们在surf函数中获取每个顶点的纹理信息以及法线信息,这些信息将被应用于接下来的Vertex Fragment和Pixel Fragment。
&&&1void surf (Input IN, inout SurfaceOutput o) {2half4 c = tex2D (_MainTex, IN.uv_MainTex);3o.Albedo = c.rgb;4o.Alpha = c.a;5o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));6}
其中,tex2D函数可以读取纹理_MainTex中的IN.uv_MainTex坐标位置的像素颜色值。
Albedo和Alpha分别获取该像素的RGB值和Alpha值,其中“Albedo”是一个漫反射参数,它表示一个表面的漫反射能力,即一个表面上出射光强与入射光强的比值。具体介绍可见:。
2、& Blinn-Phong效果
如果想实现Blinn-Phong效果,可对上述的Shader做如下修改:
2.1&&在属性Properties中加入:
&&&1_AmbientColor (&Ambient Color&, Color) = (0.1, 0.1, 0.1, 1.0)2_SpecularColor (&Specular Color&, Color) = (0.12, 0.31, 0.47, 1.0)3_Glossiness (&Gloss&, Range(1.0,512.0)) = 80.0
2.2&&在SubShader的变量中也加入相应修改:
&&&1fixed4 _AmbientColor;2fixed4 _SpecularColor;3half _Glossiness;
2.3&&最后修改surf函数,进行如下修改:
&&&1fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
这里将原有的half4替换为fixed4,这样做是为了提高渲染的性能,因为fixed的精度较之half要低,更高的精度意味着更大的计算量,而这里fixed的精度已经足够,所以使用fixed替代half4,从而来降低计算消耗,增加渲染性能。
2.4&&将“#pragma surface surf Lamber”改成“#pragma surfacesurf CustomBlinnPhong”,同时加入与其对应的LightingCustomBlinnPhong函数来计算顶点光照。
&&&01inline fixed4 LightingCustomBlinnPhong (SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, fixed atten) 02{03fixed3 ambient = s.Albedo * _AmbientColor.rgb;04&05fixed NdotL = saturate(dot (s.Normal, lightDir)); 06fixed3 diffuse = s.Albedo * _LightColor0.rgb * NdotL;07&08fixed3 h = normalize (lightDir + viewDir); 09float nh = saturate(dot (s.Normal, h)); 10float specPower = pow (nh, _Glossiness);11fixed3 specular = _LightColor0.rgb * specPower * _SpecularColor.rgb;12&13fixed4 c;14c.rgb = (ambient + diffuse + specular) * (atten * 2);15c.a = s.Alpha + (_LightColor0.a * _SpecularColor.a * specPower * atten);16return c;17}
该函数的名称为什么不是“CustomBlinnPhong”呢?这是因为该函数虽然是由“#pragma surface surf CustomBlinnPhong”来调用,但是为了让该函数可以正常工作,我们需要在其名称前加入“Lighting”关键字,这样Unity才能识别出这是一个自定义的光照函数。
通过以上设置,角色的材质部分即可变为如下形式(暂定该Shader名为“MyShader2”):
Unity3D教程:3D角色的渲染
其显示效果如下:
Unity3D教程:3D角色的渲染
3、& 边缘光照(Rim Light)和卡通渲染(Toon Shading)
可以通过对上述Shader做以下改进,来达到这种效果:
3.1&&在属性Properties中加入:
&&&1_RimColor (&Rim Color&, Color) = (0.12, 0.31, 0.47, 1.0) 2_RimPower (&Rim Power&, Range(0.5, 8.0)) = 3.0 3_Ramp (&Shading Ramp&, 2D) = &gray& {}
3.2&&在SubShader的变量中也加入相应修改:
&&&01sampler2D _MainTex;02sampler2D _BumpMap;03sampler2D _Ramp;04&05fixed4 _AmbientColor;06fixed4 _SpecularColor;07half _Glossiness;08&09fixed4 _RimColor;10half _RimPower;11&12struct Input {13float2 uv_MainTex;14float2 uv_BumpMap;15half3 viewDir; 16};
3.3&&修改surf函数,进行如下修改:
&&&1void surf (Input IN, inout SurfaceOutput o) {2fixed4 c = tex2D (_MainTex, IN.uv_MainTex);3o.Albedo = c.rgb;4o.Alpha = c.a;5o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));6fixed rim = 1.0 - saturate (dot (normalize(IN.viewDir), o.Normal));7o.Emission = (_RimColor.rgb * pow (rim, _RimPower));8}
这里主要是用来计算边缘光照的,首先通过视线与法线的夹角来找到模型的边缘,然后再根据距离的远近来控制发射光的强度。
3.4&&将“#pragma surface surf CustomBlinnPhong”改成“#pragma surfacesurf CustomBlinnPhong exclude_path:prepass”,同时在LightingCustomBlinnPhong函数来修改漫反射光的计算,来达到卡通渲染的效果。
&&&1fixed NdotL = saturate(dot (s.Normal, lightDir)); 2fixed diff = NdotL * 0.5 + 0.5;3fixed3 ramp = tex2D (_Ramp, float2(diff, diff)).rgb;4fixed diffuse = s.Albedo * LightColor0.rgb * ramp;
通过以上设置,角色的材质部分即可变为如下形式(暂定该Shader名为“MyShader3”):
Unity3D教程:3D角色的渲染
其显示效果如下:
Unity3D教程:3D角色的渲染
可以看出边缘光照的效果,同时还可以看出明显的明暗变化的卡通渲染效果。
三、&&&&&&&小结
综上所述,本文已经给出了人物的几种基本渲染方法及其Shader实现,在这里我并没有去分析每种渲染效果的原理,而仅是从实际出发,直接给出对应的简单实现方法。如果想要对光照模型进行深入理解,可以Google搜索其原理进行了解。最后,给出各种渲染方法的对比图,显示如下:
Unity3D教程:3D角色的渲染
本系列文章由&Unity公司开发支持工程师Amazonzx&编写,。
【上一篇】
【下一篇】
您可能还会对这些文章感兴趣!【Unity Shader】在Asset创建面板中添加新的shader模板
【Unity Shader】在Asset创建面板中添加新的shader模板
我们知道Unity4.x中,当在Asset目录中右键创建shader时默认新建的shader为unity的surface shader,而在5.x中,创建shader的选项中变成了四个shader模板,分别是Standard Surface Shader,Unlit Shader,Image Effect Shader 和 Compute Shader。可以看到原先默认的Surface Shader被Standard Surface Shader取代了,尽管Surface Shader的功能在5.x中仍然是存在的。
但如果我们仍希望使用Surface Shader为模板去编写shader,或者是希望编写一个针对UGUI的shader,那么就意味着我们需要新建一个shader并手动去修改shader的内容。
为了避免这种麻烦,实际上我们可以通过编写编辑器扩展,来扩充右键创建shader模板的数量,甚至可以自定义一些自己可能常用的shader模板。
如下是我扩展后的右键创建shader的选项:
可以看到我在shader创建面板加入了4.x的Surface Shader,同时还加入了UI-Default和UI-DefaultFont shader,这样当我需要编写一个基于UGUI的shader时就不必再从头将UGUIshader必须的模板测试部分等重新打一遍了。
接下来讲一下实现方式。
原理其实很简单,无疑就是使用MenuItem特性来增加Shader创建选项的按钮:
[MenuItem(&Assets/Create/Shader/Surface Shader&)]
注:最近更新的文章里浅析了一下unity通过模板创建代码的原理,因此可以不通过以下方式创建shader,文章链接:
http://blog.csdn.net/mobilebbki399/article/details/
然后获取右键创建shader的对象或目录
static string CreateShaderPath(string shaderTemplateName)
string path = AssetDatabase.GetAssetPath(Selection.activeObject);
if (path == &&)
path = &Assets&;
else if (Path.GetExtension(path) != &&)
path = path.Replace(Path.GetFileName(path), &&);
string shaderName = &New & + shaderTemplateN
if (string.IsNullOrEmpty(path))
path = &Assets&;
if (!shaderName.EndsWith(&.shader&))
shaderName += &.shader&;
string shaderFullName = AssetDatabase.GenerateUniqueAssetPath(path + &/& + shaderName);
return shaderFullN
}接下来,既然已经获得要创建的shader的路径了,之后就是创建一个shader,这里由于没找到直接创建shader类实例的好方法,所以没有使用AssetDataBase.CreateAsset方法去创建shader,而是直接使用System.IO命名空间中的相关类来创建了一个.shader文件,并将对应模板shader的内容写入这个文件(我将对应的模板shader放在自定的目录,并编写了一个EditorWindow作为创建模板shader的设置窗口,在这个窗口设置模板shader的目录,并通过EditorPrefs存储)。
最后,.shader文件创建完了,此时应该在你右键创建shader的目录已经生成了一个你想要的shader,但是想要右键生成shader之后立即在Asset目录中看到,还需要使用AssetDatabase.ImportAsset将其导入,否则的话你只有在Asset中点刷新后才能看到生成的shader:
static void CreateShader(string shaderTemplateName)
        string shaderPath = CreateShaderPath(shaderTemplateName);
        if(!ShaderCreateUtils.CreateShader(shaderPath, shaderTemplateName)){
&span style=&white-space:pre&&
        AssetDatabase.ImportAsset(shaderPath);
我的热门文章
即使是一小步也想与你分享问点有技术含量的吧,一个关于shader如何更换第二个材质球
默认ChangePart.material.SetTexture(&_MainTex&, FuZhuang1);这样只能更换一个材质球 就是默认的这个_MainTex,&如果一个物体里有多个材质球,如图726 || this.offsetHeight>700){if(this.offsetWidth/726 > this.offsetHeight/700){this.width=726;}else{this.height=700;}}" style="max-width:726max-height:700" title="点击查看原图" onclick="if(this.parentNode.tagName!='A') window.open('/forum/attachment/Mon_8_fbcfcd816c5ca05.jpg');" />&如何更换 第二个 和 第三个 等等呢? 用的是官方的shader,里边的 Self-Illumin/Diffuse&请指教
要评论请先&或者&
shader里面加多几个2Dtexture就行了,这样&_Tex1 (&Display Name&, 2D) = &white& {}不过这个不能太多 有硬件限制
:shader里面加多几个2Dtexture就行了,这样&_Tex1 (&Display Name&, 2D) = &white& {}不过这个不能太多 有硬件限制 ( 20:45) 对于 shader 不太了解 请问加载哪里呢?
要在shader的代码里加 但是这个texture怎么用是要shader代码控制的,并不是简单的材质球叠加的概念,和3dmax的什么不一样如果不了解shader,还是基于现成的shader实现你想要的效果吧系统很多shader都有多重贴图的,只要知道texture的变量名就可以设置选中shader在inspector里就能看见shader的properties726 || this.offsetHeight>700){if(this.offsetWidth/726 > this.offsetHeight/700){this.width=726;}else{this.height=700;}}" style="max-width:726max-height:700" title="点击查看原图" onclick="if(this.parentNode.tagName!='A') window.open('/forum/attachment/Mon_7_797a4d0d77a089a.jpg');" />
:要在shader的代码里加 但是这个texture怎么用是要shader代码控制的,并不是简单的材质球叠加的概念,和3dmax的什么不一样如果不了解shader,还是基于现成的shader实现你想要的效果吧系统很多shader都有多重贴图的,只要知道texture的变量名就可以设置....... &726 || this.offsetHeight>700){if(this.offsetWidth/726 > this.offsetHeight/700){this.width=726;}else{this.height=700;}}" style="max-width:726max-height:700" title="点击查看原图" onclick="if(this.parentNode.tagName!='A') window.open('/forum/attachment/Mon_8_6a862e5a7fb3249.jpg');" />我用的是官方的这个,请问怎么查看这个shader的信息呢?
哦,你是要了解更换官方shader的第2 第3texture,那个只要知道名字就可以设置官网有下载内置shader的源代码,打开看里面名字怎么写的内置shader缺省是隐藏的 没法直接看properties,但命名基本都是统一的主贴图都叫:_MainTex法线贴图都叫:_BumpMap发光贴图都叫:_IllumParallax贴图都叫_ParallaxMap反射贴图都叫:_Cube(这是个Cube贴图不是2D了)这个Self-Illumin/Diffuse的代码:Shader &Self-Illumin/Diffuse& {Properties {&& &_Color (&Main Color&, Color) = (1,1,1,1)&& &_MainTex (&Base (RGB) Gloss (A)&, 2D) = &white& {}&& &_Illum (&Illumin (A)&, 2D) = &white& {}&& &_EmissionLM (&Emission (Lightmapper)&, Float) = 0}所以ChangePart.material.SetTexture(&_Illum&, FuZhuang2);这样就行了
:哦,你是要了解更换官方shader的第2 第3texture,那个只要知道名字就可以设置官网有下载内置shader的源代码,打开看里面名字怎么写的内置shader缺省是隐藏的 没法直接看properties,但命名基本都是统一的主贴图都叫:_MainTex法线贴图都叫:_BumpMap....... &非常感谢你~~真的很感谢,可以再我看一下 第三个材质的命名吗?顺序是不是就是这里的顺序726 || this.offsetHeight>700){if(this.offsetWidth/726 > this.offsetHeight/700){this.width=726;}else{this.height=700;}}" style="max-width:726max-height:700" title="点击查看原图" onclick="if(this.parentNode.tagName!='A') window.open('/forum/attachment/Mon_8_c3ec.jpg');" />
:非常感谢你~~真的很感谢,可以再我看一下 第三个材质的命名吗?顺序是不是就是这里的顺序[附件] ( 21:13) 你这是3组材质 不是一个shader内的不同贴图.........ChangePart.Materials[0].SetTexture(&_MainTex&,FuZhuang1);ChangePart.Materials[1].SetTexture(&_MainTex&,FuZhuang2);ChangePart.Materials[2].SetTexture(&_MainTex&,FuZhuang3);这是访问一个物体不同材质的同一类贴图
:你这是3组材质 不是一个shader内的不同贴图.........ChangePart.Materials[0].SetTexture(&_MainTex&,FuZhuang1);ChangePart.Materials[1].SetTexture(&_MainTex&,FuZhuang2);....... &这就是我实验后要问的~~很感谢你,刚才那个是实验结果是726 || this.offsetHeight>700){if(this.offsetWidth/726 > this.offsetHeight/700){this.width=726;}else{this.height=700;}}" style="max-width:726max-height:700" title="点击查看原图" onclick="if(this.parentNode.tagName!='A') window.open('/forum/attachment/Mon_8_e0d95142dcbf651.jpg');" />和你说的一样 这是我要的效果,可是恰好和你说的一样,我再试试你的 谢谢~
你的问题是两个:如何设置一个材质内的不同贴图?用不同名字索引就行了ChangePart.Materials[0].SetTexture(&_MainTex&,FuZhuang1);ChangePart.Materials[0].SetTexture(&_Illum&,FuZhuang2);如何访问一个物体的不同材质?用材质数组下标就行了ChangePart.Materials[0].SetTexture(&_MainTex&,FuZhuang1);ChangePart.Materials[0].SetTexture(&_Illum&,FuZhuang2);ChangePart.Materials[1].SetTexture(&_MainTex&,FuZhuang1);ChangePart.Materials[1].SetTexture(&_Illum&,FuZhuang2);}

我要回帖

更多关于 unity 代码控制shader 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信