罪恶装备背德之炎卡通角色_二次元风格_Unity 角色渲染
- 角色初始效果:
- 基础渲染SimpleBas
- 资源分析
- 模型
- 顶点颜色:
- 贴图资源
- SOL_base_基础色块效果:
- 其中SOL_base_A通道的效果:
- SOL_ilm:如下
- SOL_ilm模型上区域分布
- - 左到右,依次为RGBA。
- SOL_Sss:如下
- SOL_ilm在模型上的效果
- 优化
- 优化前全身图
- 优化后全身图
- 面部对比图
- 腰带和手臂描边对比图
- 对比图
- 卡渲代码
- 卡渲参考链接:
角色初始效果:
基础渲染SimpleBas
Shader "SimpleBase"
{Properties{[Header(BaseColor)]_MainTex ("BaseTex", 2D) = "white" {}[Space(20)][Header(ILM)]_ILMTex("ILMTex",2D) = "white"{}[Space(20)][Header(SSS)]_SssTex("SssTex",2D) = "white"{}[Space(20)][Header(Detail)]_DetailTex("DetailTex",2D) = "white"{}}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{Tags{"LightMode"="ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"struct appdata{float4 vertex : POSITION;float2 uv0 : TEXCOORD0;float2 uv1 : TEXCOORD1;float4 tangent :TEXCOORD2;half3 normal : NORMAL;half4 color : COLOR;};struct v2f{float4 uv : TEXCOORD0;float4 pos : SV_POSITION;half4 vertexColor : TEXCOORD1;half3 worldNormal : TEXCOORD2;float3 worldPos : TEXCOORD3;};sampler2D _MainTex;float4 _MainTex_ST;sampler2D _ILMTex;sampler2D _SssTex;sampler2D _DetailTex;v2f vert (appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv.xy = TRANSFORM_TEX(v.uv0, _MainTex);o.uv.zw = v.uv1;o.vertexColor = v.color;o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);return o;}fixed4 frag (v2f i) : SV_Target{fixed4 ilm = tex2D(_ILMTex,i.uv.xy);fixed4 baseColor = tex2D(_MainTex, i.uv.xy);fixed4 sssColor = tex2D(_SssTex,i.uv.xy);fixed3 detail = tex2D(_DetailTex,i.uv.zw);half ao = saturate((i.vertexColor.r - 0.7) * 50);half3 worldNormal = normalize(i.worldNormal);half3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));half3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));half3 halfDir = normalize(worldLightDir + worldViewDir);half NdotH = saturate(dot(halfDir,worldNormal));half NdotL = dot(worldLightDir,worldNormal);half sssFactor = saturate((NdotL * 0.5 + 0.5 - i.vertexColor.b * 0.5) * 50) * ao;fixed4 finalColor = 1;finalColor.rgb = lerp(sssColor,baseColor,sssFactor) * detail * ilm.a;return finalColor;}ENDCG}}
}
资源分析
模型
顶点颜色:
模型的B通道灰色
贴图资源
SOL_base_基础色块效果:
其中SOL_base_A通道的效果:
- 其中A通道,是将人物身上的文字图案区域 描黑。
SOL_ilm:如下
SOL_ilm模型上区域分布
如下:
- 左到右,依次为RGBA。
-
R通道:控制整体的高光强度。
-
G通道:控制NdotL光照的偏移值,例如褶皱。
-
B通道:控制高光的大小、范围或者形状。
-
A通道:人物模型的内描线。
-
顶点颜色:
-
R通道:AO,也是控制NdotL光照偏移。
SOL_Sss:如下
SOL_ilm在模型上的效果
SSSTexture的值与环境光的颜色相乘得到的颜色来决定阴影颜色。
明部主光颜色
暗部 环境光颜色
优化
优化前全身图
优化后全身图
面部对比图
腰带和手臂描边对比图
对比图
卡渲代码
Shader "SOL"
{Properties{[Header(BaseColor)]_MainTex ("BaseTex", 2D) = "white" {}[Space(20)][Header(ILM)]_ILMTex("ILMTex",2D) = "gray"{}[Space(20)][Header(SSS)]_SssTex("SssTex",2D) = "black"{}[Space(20)][Header(Detail)]_DetailTex("DetailTex",2D) = "white"{}_ToonThreshold("ToonThreshold",Range(0,1)) = 0.5_ToonHardness("ToonHardness",Float) = 20.0_SpecColor("spec color", Color) = (1,1,1,1)_SpecSize("Spec Size",Range(0,1)) = 1[Space(20)][Header(OutLine)]_OutlineColor("Outline Color", Color) = (0,0,0,0)_Outlinewidth("Outline Width",Range(0,1)) = 1}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{Tags{"LightMode"="ForwardBase"}CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"struct appdata{float4 vertex : POSITION;float2 uv0 : TEXCOORD0;float2 uv1 : TEXCOORD1;half3 normal : NORMAL;half4 color : COLOR;};struct v2f{float4 uv : TEXCOORD0;float4 pos : SV_POSITION;half4 vertexColor : TEXCOORD1;half3 worldNormal : TEXCOORD2;float3 worldPos : TEXCOORD3;};sampler2D _MainTex;sampler2D _ILMTex;sampler2D _SssTex;sampler2D _DetailTex;half _ToonThreshold;half _ToonHardness;half _SpecSize;//没有定义"float4 _SpecColor" 是因为在#include "UnityLightingCommon.cginc"文件里已经被声明。// float4 _SpecColor;v2f vert (appdata v){v2f o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = float4 (v.uv0,v.uv1);o.vertexColor = v.color;o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject);return o;}fixed4 frag (v2f i) : SV_Target{half2 uv1 = i.uv.xy;half2 uv2 = i.uv.zw;//贴图采样、亮部和暗部的颜色、控制高光的强度fixed4 ilm = tex2D(_ILMTex,i.uv.xy);half spec_intensity = ilm.r;//控制高光强度half diffuse_control = ilm.g * 2.0 - 1.0;//光照偏移half spec_size = ilm.b;//控制高光形状half inner_line = ilm.a;//内描线fixed4 baseColor = tex2D(_MainTex, i.uv.xy);//亮部的颜色fixed4 sssColor = tex2D(_SssTex,i.uv.xy);//暗部的颜色fixed3 detail = tex2D(_DetailTex,i.uv.zw);//细节线条//顶点处理half ao = saturate((i.vertexColor.r - 0.7) * 50);//向量half3 worldNormal = normalize(i.worldNormal);half3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));half3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));//漫反射half NdotL = dot(worldLightDir,worldNormal);half halflambert = (NdotL + 1.0) * 0.5;half lambertterm = halflambert * ao + diffuse_control;half toondiffuse = saturate ((lambertterm - _ToonThreshold) * _ToonHardness);half3 finaldiffuse = lerp(sssColor ,baseColor,toondiffuse);//高光float NdotV = (dot(worldNormal,worldViewDir) + 1.0) * 0.5;float spec_term = NdotV * ao + diffuse_control;spec_term = halflambert * 0.9 + spec_term * 0.1;half toon_spec = saturate((spec_term - (1.0 - spec_size * _SpecSize)) * 500);half3 speccolor = (_SpecColor.xyz + baseColor) * 0.5;half3 finaspec = toon_spec * speccolor * spec_intensity;//描线half3 inner_line_Color = lerp(baseColor * 0.2 , float3(1.0,1.0,1.0),inner_line);half3 ditailcolor = tex2D(_DetailTex , uv2);ditailcolor = lerp(baseColor * 0.2, float3(1.0,1.0,1.0),ditailcolor);half3 finalline = inner_line_Color * inner_line_Color * ditailcolor;fixed3 finalColor = (finaldiffuse + finaspec) * finalline;return float4(finalColor,1.0);}ENDCG}Pass{Cull FrontCGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_fwdbase#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv0 : TEXCOORD0;half3 normal : NORMAL;half4 color : COLOR;};struct v2f{float2 uv : TEXCOORD0;float4 pos : SV_POSITION;half4 vertexColor : TEXCOORD1;half3 worldNormal : TEXCOORD2;float3 worldPos : TEXCOORD3;};sampler2D _MainTex;float4 _OutlineColor;float _Outlinewidth;v2f vert (appdata v){v2f o;float3 pos_VS = UnityObjectToViewPos(v.vertex);float3 normal_WS = UnityObjectToWorldNormal(v.normal);float3 outline_dir = normalize(mul((float3x3)UNITY_MATRIX_V,normal_WS));o.vertexColor = v.color;pos_VS += outline_dir * _Outlinewidth * 0.001 * v.color.a;o.pos = mul(UNITY_MATRIX_P,float4(pos_VS,1.0));o.uv = v.uv0;return o;}fixed4 frag (v2f i) : SV_Target{fixed3 baseColor = tex2D(_MainTex, i.uv.xy).xyz;half maxComponent = max(max(baseColor.r,baseColor.g),baseColor.b) - 0.004;half3 saturatedColor = step(maxComponent.rrr,baseColor) * baseColor;saturatedColor = lerp(baseColor.rgb,saturatedColor,0.6);half3 outlineColor = 0.8 * saturatedColor * baseColor * _OutlineColor.xyz;return float4(outlineColor,1.0);}ENDCG}}
}
卡渲参考链接:
西川善司:【纯卡通动画的实时3D图形】的秘密
【翻译】西川善司「实验做出的游戏图形」「GUILTY GEAR Xrd -SIGN-」中实现的「纯卡通动画的实时3D图形」的秘密,前篇(1)