콘텐츠로 건너뛰기

Gamma Space skin shader development.

Developer: JPLee

Email: leegoonz@163.com

JP Lee | creating Game | Patreon

Unity Version.

Rendering pipeline: Standard RP.

Summary.

Most of the latest game development is produced in a linear space.

However, I had to develop it in an environment that uses gamma space at the request of someone.

His game was not a game with many characters, so it was an environment that could be freely developed.

But it was a mobile game.

The development difficulty is not high, but I would like to write down what I developed.

I hope it helps.

Texture Channel information.

Albedo with Roughness

Albedo uses an RGB channel, and roughness for expressing light is an alpha channel.

Albedo
Roughness information is stored in the Albedo alpha channel.

A Roughness texture is stored in the channel.

The closer it is to white, the less glossy it is.

The closer it is to black, the stronger the amount of gloss.

This was converted directly into Linear Space inside the shader.

BRDF TEXTURE

LUT texture management.

Wrap Mode must be Clamp.
The format should be RGB24.

This is the texture that records the standard Diffusion profile information for the skin.

I think the final texture size is 512 * 512.

This texture should not be compressed.

If it is due to Memory bandwidth, it can sometimes be slow on old hardware.

In particular, there was a problem with Xiaomi products using Qualcomm GPUs (released in 2015).

In that case, reduce the size to 256.

Implementation.

alf2 brdfUV = FLOAT2((dot(lightDirection,normalTDirection)0.5+0.5),(dot(_LightColor0.rgb,half3(0.22,0.707,0.071))_SkinToneScale));
half2 blendNormalTex = lerp(_SurfaceTa
Code language: C++ (cpp)

brdfUV.x = normalFinalDirection * 0.5 + 0.5;
half2 brdfUV_Blur =  brdfUV.xy;

half4 _SkinBRDF_var = tex2D(_SkinBRDF,brdfUV_Blur); // Clamp Wrap Mode
Code language: C++ (cpp)

Normal map.

Normal ( use to XY and Z is directly calculated use to sign or set value to 1 )

If you see this screen in the editor edit screen, you need to ignore it.

I have to follow the rules for the UnpackNormal function of the shader I created.

Normal Map uses a total of two types, but it is stored in a single texture.

One texture is stored in the RG (xy) of the texture, and another one is stored in the BA (xy) channel.

Each z value is calculated directly from the shader as dot product with sqrt.

Channel combined structure like below.

The below two normal maps are stored in the RGBA channel.

Default surface normal ( Used to XY )

Blurry normal for Scattering shading.

Normal map texture import setting.

It does not use Unity’s NormalMap encoding method.

Texture Type is Default

sRGB (Color Texture) is Off

Implementation.

uniform sampler2D _SurfaceTangentMap;
Code language: C++ (cpp)

adding sampler.

inline half3 JP_UnpackNormalRG(half2 packednormal)
{
   half3 normal;
   normal.xy = packednormal.xy * 2 - 1;
   normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
   return normal;
}
Code language: C++ (cpp)

Let’s see how to handle surface normal map and blurry normal map.

half3 _SurfaceTangentMap_Local = JP_UnpackNormalRG(_SurfaceTangentTex.xy);
half3 normalT = normalize(_SurfaceTangentMap_Local);

FLOAT3 normalTDirection = mul( normalT, tangentTransform );// Perturbed normals
FLOAT3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);

half2 brdfUV = FLOAT2((dot(lightDirection,normalTDirection)*0.5+0.5),(dot(_LightColor0.rgb,half3(0.22,0.707,0.071))*_SkinToneScale));
half2 blendNormalTex = lerp(_SurfaceTangentTex.zw , _SurfaceTangentTex.xy, brdfUV.x);
half3 normalT_Final = normalize(JP_UnpackNormalRG(blendNormalTex.xy));
FLOAT3 normalDirectionFinal = mul( normalT_Final , tangentTransform);
float normalFinalDirection = dot( normalDirectionFinal, lightDirection );
Code language: C++ (cpp)

There is also a technique using DDX and DDY.
In Opengl3.1, there is no big problem even if you use this.
I’ll cover the implementation of this in the next topic.

Shader Map.

It is an important texture in skin expression.

Information on the curvature of the skin or the transmission weight of the face is stored in the R channel.

Occlusion information for light is recorded on the G channel.

In my shader, I used G channel information in addition to the Occlusion effect, so I saved it in the Shader map.

Color Transformation regulations for Linear space rendering When We use to Gamma mode in Unity3D Project.

Material Descriptions.

Roughness with Reflection

Multiply the Roughness texture and Roghness variable values to express the glossiness of the skin surface.

Reflection creates a reflected light effect.

This is linked to the final Roughness expression.

The above two values are greatly influenced by Tone Mapper.

SkinBRDF

For skin expression, we need to calculate SkinBRDF.

Default is on.

Skin Brdf Attenuation

Skin Brdf Attenuation slightly obscures the shadow boundary and the skin boundary.

Default is on.

The reason for implementing this feature is that Soft Shadow cannot be used in mobile rendering, and if you need to use Soft Shadow, you must implement your own shadow.

If you can’t implement shadows yourself, it’s best to use this feature as much as possible to blur the boundaries between the shadow and skin areas.

This can be modified with the Skin Tone Scale and BRDF Attenuation values.

You need to find a suitable range for both values.

Skin Brdf Attenuation off.

Implementation.

//attenuation *= pow(_SkinBRDF_var , _AttenuationScale);
half attenuation = _UseBrdfAtten?LIGHT_ATTENUATION(i) * (saturate( ( (normalFinalDirection * 0.5 + 0.5) * 2.0) * 2.0 - 1.0)) * pow(_SkinBRDF_var , _AttenuationScale ):LIGHT_ATTENUATION(i);
Code language: C++ (cpp)

Skin Tone Color

It is the Scattering colour of the skin.

Skin Trans Map

The R channel is used as a depth value for skin scattering.

The G channel is used for the Occlusion effect.

See ShaderMap for information on texture information.

BackLight Dir

It is a fake lighting direction.

This is for skin penetration effect only.

SubLighting

Indirect lighting was added without using auxiliary light.

It creates a lighting effect from the side.

You can turn it on or off and modify the intensity with Lighting Intensity.

On a mobile screen, if the gloss is strong, it tends to look whiter than the original color.

Therefore, it is not desirable to give Lighting Intensity too strong.

not used SubLighting.
Use SubLighting.

Implementation.

#include "./Common/JPStandardCoreForward.cginc"
Code language: C++ (cpp)

Define to include code path like this.

#if _USESUBLIGHT
static bool _UseSubLight = true;
#else
static bool _UseSubLight = false;
#endif
uniform half _SubLightScale;
#if USE_SECOND_DIRECTIONAL_LIGHT
half2 RoL = max(0, half2(dot(ReflectionVector, DirectionalLightDirection), dot(ReflectionVector, _WorldSpaceLightPos1.xyz)));
half2 PhongSpecular = PhongApprox(Roughness, RoL);
half3 Directional = (Shadow * NoL) * DirectionalLightColor * (DiffuseColor + SpecularColor * PhongSpecular.x);
half NoL2 = max(0, dot(normalWorld, _WorldSpaceLightPos1.xyz));
Directional += NoL2 * _LightColor1 * (DiffuseColor + SpecularColor * PhongSpecular.y);
#else
half3 halfDir = normalize(DirectionalLightDirection + s.viewdir);
half3 invhalfDir = -(normalize(DirectionalLightDirection + s.viewdir));
half RoL = max(0, dot(ReflectionVector, DirectionalLightDirection));
half RoLDual = max(0, dot(ReflectionVector , -s.viewdir * invhalfDir)) * _SubLightScale;
half LoH = max(0, dot(DirectionalLightDirection, halfDir));
half normalizationTerm = (Roughness + 0.5) * 4.0;
#if DUALLOBE
half specularTermBeckMann = (2.0 * PhongApprox(RoughnessBeckMan, RoL) / (max(0.1h, LoH) * normalizationTerm));
half specularTerm = (PhongApprox(Roughness, RoL) / 2 + specularTermBeckMann) ;
#else
half specularTerm = PhongApprox(Roughness, RoL);
#endif

TONE MAPPER

Assuming that no post-processing is used, Tone mapping is implemented and applied directly inside the shader.

When rendering in Gamma space, the most noticeable part is that the specular part of the light is finally calculated in the gamma space, resulting in the feeling that the skin color is displaced.

This is to remove the characteristics of Gamma space as much as possible using TONE MAPPER.

Implementation.

//Propertices related of Tone map.
[Header(TONE MAPPER)]//// Neutral tonemapping (Hable/Hejl/Frostbite)
[Toggle] _toggleToneMapper("Tone Mapper" , FLOAT) = 0
_a("Segment A" , Range(0.1, 1)) = 0.2
_b("Segment B" , Range(0.1, 1)) = 0.29
_c("Segment C" , Range(0.1, 1)) = 0.24
_d("Segment D" , Range(0.1, 1)) = 0.272
_e("Segment E" , Range(0.01, 0.1)) = 0.02
_f("Segment F" , Range(0.1, 1)) = 0.3
_WhiteLevel("ToneMappe White Level" , Range(1.3, 5.3)) = 2.3
//====================================================================
//adding to variable for On off toggle
uniform half _toggleToneMapper;
//=====================================================================
// Neutral tonemapping (Hable/Hejl/Frostbite)
// Adding to Neutral tone map function inside shader.
FLOAT3 NeutralCurve(FLOAT3 x, FLOAT a, FLOAT b, FLOAT c, FLOAT d, FLOAT e, FLOAT f)
{
return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) – e / f;
}
FLOAT3 NeutralTonemap(FLOAT3 x)
{
// Tonemap
const FLOAT a = _a;
const FLOAT b = _b;
const FLOAT c = _c;
const FLOAT d = _d;
const FLOAT e = _e;
const FLOAT f = _f;
const FLOAT whiteLevel = _WhiteLevel;
const FLOAT whiteClip = 1;
half3 whiteScale = (1.0).xxx / NeutralCurve(whiteLevel, a, b, c, d, e, f);
x = NeutralCurve(x * whiteScale, a, b, c, d, e, f);
x *= whiteScale;
// Post-curve white point adjustment
x /= whiteClip.xxx;
return x;
}
//=======================================================================================
// Use to if branch with NeutralTonemap function for last output result of finalColor.
if (_toggleToneMapper)
{
finalColor = NeutralTonemap(finalColor);
}
view raw gistfile1.txt hosted with ❤ by GitHub
Tone Map Off.
Tone Map On.

Complete shader code.

Shader "Skin Clip Alpha" {
Properties {
_MainTex ("Albedo(RGB) , Roughness(A)", 2D) = "white" {}
[HDR]_Color ("BaseColor", Color) = (1,1,1,1)
[HideInInspector]_Specular ("Specular", Range(0, 1)) = 0.28
_Roughness ("Roughness", Range(0, 1)) = 0.5
[NoScaleOffset]_SurfaceTangentMap ("Normal Map", 2D) = "bump" {}
_OcclusionStrength ("Occlusion", Range(0, 1)) = 0.8
_Reflection ("Reflection", Range(0, 5)) = 1
[Header(SKIN BRDF)]
[MaterialToggle(_USESKINBRDF)] _UseSKinBRDF("UseSKinBRDF", Float) = 1
[MaterialToggle(_USEBRDFATTEN)] _UseBrdfAtten("Use Skin Brdf Attenuation", Float) = 1
_AttenuationScale("BRDF Attenuation" , Range(0.25,1)) = 0.25
[NoScaleOffset]_SkinBRDF ("Skin BRDF", 2D) = "black" {}
_SkinToneScale ("Skin Tone Scale", Range(0, 1)) = 0.3
_SkinTransColor("Skin Trans Color", Color) = (0,0,0,1)
[NoScaleOffset]_SkinTransMap ("Skin Trans Map(R,G,B) Alpha(A)", 2D) = "white" {}
_BackLightDir("BackLight Dir", Vector) = (0,0,-1,0)
[Header(SubLighting)]
[MaterialToggle(_USESUBLIGHT)] _UseSubLight("Use Sub lighting",Float) = 0
_SubLightScale("Lighting Intensity", Range(1.0, 1.4)) = 1.25
[Header(TONE MAPPER)]//// Neutral tonemapping (Hable/Hejl/Frostbite)
[Toggle] _toggleToneMapper("Tone Mapper" , FLOAT) = 0
_a("Segment A" , Range(0.1, 1)) = 0.2
_b("Segment B" , Range(0.1, 1)) = 0.29
_c("Segment C" , Range(0.1, 1)) = 0.24
_d("Segment D" , Range(0.1, 1)) = 0.272
_e("Segment E" , Range(0.01, 0.1)) = 0.02
_f("Segment F" , Range(0.1, 1)) = 0.3
_WhiteLevel("ToneMappe White Level" , Range(1.3, 5.3)) = 2.3
[Space(5)]
[Header(Alpha)]
_Cutoff("Alpha Cotoff", Range( 0 , 1)) = 1
}
SubShader {
Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout"}
Cull Back
ColorMask RGBA
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define FLOAT half
#define FLOAT2 half2
#define FLOAT3 half3
#define FLOAT4 half4
#define BRDF_TEX 1
#define NONMETAL 1
#include "UnityCG.cginc"
#include "AutoLight.cginc"
#include "Lighting.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma multi_compile_fog
#pragma shader_feature _USESKINBRDF
#pragma shader_feature _USESUBLIGHT
#pragma shader_feature _USEBRDFATTEN
#pragma target 3.0
#pragma multi_compile _ DYNAMIC_POINT_LIGHTS_4
#pragma multi_compile_fwdbase
#include "./Common/JPStandardCoreForward.cginc"
half3 StandardBase( half3 Albedo , half Metallic , half Specular , half Roughness , half3 Emissive , half Occlusion , half Reflection , half3 Normal , float3 WorldPos , half3 ViewDir , half3 LightDir , half3 LightColor , half LightAtten , half3 Ambient , half3 Reflect , float2 LightmapUV , half3 BRDF , half3 BleedAO , half Alpha )
{
FragmentCommonData s;
s.position = WorldPos;
s.viewdir = ViewDir;
s.ambient = Ambient + BleedAO;
s.albedo = JpGammaToLinearSpace(Albedo);
s.alpha = Alpha;
s.metallic = JpGammaToLinearSpace(saturate(Metallic));
s.roughness = JpLinearToGammaSpace(saturate(Roughness));
s.occlusion = JpGammaToLinearSpace(Occlusion);
s.specular = Specular;
s.emissive = JpGammaToLinearSpace(Emissive);
s.normal = Normal;
s.irradiance = Reflection;
s.reflect = Reflect;
s.lightdir = LightDir;
s.lightcolor = LightColor;
s.shadow = LightAtten;
s.lightmapUV.xy = LightmapUV * unity_LightmapST.xy + unity_LightmapST.zw;
#if BRDF_TEX
s.brdf = BRDF;
#endif
return fragForwardBaseInternal(s);
}
uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
uniform sampler2D _SurfaceTangentMap;
uniform half _Roughness;
uniform half _Specular;
uniform half _OcclusionStrength;
uniform half _Reflection;
uniform half4 _Color;
uniform sampler2D _SkinBRDF;
uniform half _SkinToneScale;
uniform half _AttenuationScale;
uniform half _toggleToneMapper;
uniform half _WhiteLevel;
uniform half _a;
uniform half _b;
uniform half _c;
uniform half _d;
uniform half _e;
uniform half _f;
uniform half _Cutoff;
#if _USESKINBRDF
static bool _UseSKinBRDF = true;
#else
static bool _UseSKinBRDF = false;
#endif
#if _USEBRDFATTEN
static bool _UseBrdfAtten = true;
#else
static bool _UseBrdfAtten = false;
#endif
uniform sampler2D _RoughnessMap;
uniform sampler2D _OcclusionMap;
uniform sampler2D _SkinTransMap;
uniform half4 _SkinTransColor;
uniform half4 _BackLightDir;
struct VertexInput {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float2 texcoord0 : TEXCOORD0;
float2 texcoord1 : TEXCOORD1;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0;
float2 uv1 : TEXCOORD1;
float4 posWorld : TEXCOORD2;
FLOAT3 normalDir : TEXCOORD3;
FLOAT3 tangentDir : TEXCOORD4;
FLOAT3 bitangentDir : TEXCOORD5;
LIGHTING_COORDS(6,7)
UNITY_FOG_COORDS(8)
#if defined(LIGHTMAP_ON) || defined(UNITY_SHOULD_SAMPLE_SH)
FLOAT4 ambientOrLightmapUV : TEXCOORD9;
#endif
};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.uv0 = v.texcoord0;
o.uv1 = v.texcoord1;
o.normalDir = UnityObjectToWorldNormal(v.normal);
o.tangentDir = normalize( mul( unity_ObjectToWorld, FLOAT4( v.tangent.xyz, 0.0 ) ).xyz );
o.bitangentDir = normalize(cross(o.normalDir, o.tangentDir)) * (v.tangent.w * unity_WorldTransformParams.w);
o.posWorld = mul(unity_ObjectToWorld, v.vertex);
float3 lightColor = _LightColor0.rgb;
#if UNITY_SHOULD_SAMPLE_SH
FLOAT4 normalWorld = FLOAT4(o.normalDir, 1);
float4 posWorld = o.posWorld;
#ifdef VERTEXLIGHT_ON
// Approximated illumination from non-important point lights
o.ambientOrLightmapUV.rgb = Shade4PointLights(
unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
unity_4LightAtten0, posWorld, normalWorld.xyz);
#endif
#endif
o.pos = UnityObjectToClipPos(v.vertex );
UNITY_TRANSFER_FOG(o,o.pos);
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
// Neutral tonemapping (Hable/Hejl/Frostbite)
FLOAT3 NeutralCurve(FLOAT3 x, FLOAT a, FLOAT b, FLOAT c, FLOAT d, FLOAT e, FLOAT f)
{
return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) – e / f;
}
FLOAT3 NeutralTonemap(FLOAT3 x)
{
// Tonemap
const FLOAT a = _a;
const FLOAT b = _b;
const FLOAT c = _c;
const FLOAT d = _d;
const FLOAT e = _e;
const FLOAT f = _f;
const FLOAT whiteLevel = _WhiteLevel;
const FLOAT whiteClip = 1;
half3 whiteScale = (1.0).xxx / NeutralCurve(whiteLevel, a, b, c, d, e, f);
x = NeutralCurve(x * whiteScale, a, b, c, d, e, f);
x *= whiteScale;
// Post-curve white point adjustment
x /= whiteClip.xxx;
return x;
}
FLOAT4 frag(VertexOutput i) : COLOR
{
i.normalDir = normalize(i.normalDir);
float3x3 tangentTransform = float3x3( i.tangentDir, i.bitangentDir, i.normalDir);
half3 viewDirection = normalize(_WorldSpaceCameraPos.xyz – i.posWorld.xyz);
half4 _SurfaceTangentTex = tex2D(_SurfaceTangentMap,i.uv0);
half3 _SurfaceTangentMap_Local = JP_UnpackNormalRG(_SurfaceTangentTex.xy);
half3 normalT = normalize(_SurfaceTangentMap_Local);
FLOAT3 normalTDirection = mul( normalT, tangentTransform );// Perturbed normals
FLOAT3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
half2 brdfUV = FLOAT2((dot(lightDirection,normalTDirection)*0.5+0.5),(dot(_LightColor0.rgb,half3(0.22,0.707,0.071))*_SkinToneScale));
half2 blendNormalTex = lerp(_SurfaceTangentTex.zw , _SurfaceTangentTex.xy, brdfUV.x);
half3 normalT_Final = normalize(JP_UnpackNormalRG(blendNormalTex.xy));
FLOAT3 normalDirectionFinal = mul( normalT_Final , tangentTransform);
float normalFinalDirection = dot( normalDirectionFinal, lightDirection );
brdfUV.x = normalFinalDirection * 0.5 + 0.5;
half2 brdfUV_Blur = brdfUV.xy;
half ldotn = max(0,dot(lightDirection, normalTDirection));
half3 lightColor = _LightColor0.rgb;
half4 vertexGIAmbient = 0;
#if UNITY_SHOULD_SAMPLE_SH
vertexGIAmbient = i.ambientOrLightmapUV;
#endif
////// Lighting:
//FLOAT attenuation = LIGHT_ATTENUATION(i);
half4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
half3 MainTex_Color = (_MainTex_var.rgb*_Color.rgb);
half _RoughnessMap_var = _MainTex_var.a;
half4 _SkinBRDF_var = tex2D(_SkinBRDF,brdfUV_Blur);// Clamp Wrap Mode
half4 _SkinTransMap_var = tex2D(_SkinTransMap,i.uv0);//This texture value green channel is occlusion map
half inputAlpha = _SkinTransMap_var.a;
clip(inputAlpha – _Cutoff);
half _OcclusionMap_var = 1;
_OcclusionMap_var = _SkinTransMap_var.g;
half3 strength = _SkinTransColor;// Fake Color-Bleeding for AO
half3 colorBleedAO = (pow(abs(_OcclusionMap_var), 1.0f – strength)) * (1-_OcclusionMap_var);
//attenuation *= pow(_SkinBRDF_var , _AttenuationScale);
half attenuation = _UseBrdfAtten?LIGHT_ATTENUATION(i) * (saturate( ( (normalFinalDirection * 0.5 + 0.5) * 2.0) * 2.01.0)) * pow(_SkinBRDF_var , _AttenuationScale ):LIGHT_ATTENUATION(i);
half3 finalColor = StandardBase( MainTex_Color , 0.0 , _Specular , (_RoughnessMap_var*_Roughness) , half3(0,0,0) ,
lerp(1.0,_OcclusionMap_var,_OcclusionStrength) , _Reflection , normalDirectionFinal , i.posWorld.rgb , viewDirection ,
lightDirection , _LightColor0.rgb , attenuation , vertexGIAmbient.rgb , reflect((-1*viewDirection),normalDirectionFinal) , i.uv1 ,
(_UseSKinBRDF ? (_SkinBRDF_var.rgb + (_SkinTransColor.rgb * clamp((_SkinTransMap_var.g * dot((-1 * mul( float4(normalize(_BackLightDir.rgb),0), UNITY_MATRIX_V ).xyz.rgb),normalDirectionFinal)),0,1))) : FLOAT3(ldotn,ldotn,ldotn)) , colorBleedAO , inputAlpha);
if (_toggleToneMapper)
{
finalColor = NeutralTonemap(finalColor);
}
half4 finalRGBA = FLOAT4(finalColor,1);
UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
return finalRGBA;
}
ENDCG
}
Pass {
Name "Meta"
Tags {
"LightMode"="Meta"
}
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#define UNITY_PASS_META 1
#define FLOAT half
#define FLOAT2 half2
#define FLOAT3 half3
#define FLOAT4 half4
#include "UnityCG.cginc"
#include "UnityMetaPass.cginc"
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_shadowcaster
#pragma multi_compile_fog
#pragma target 3.0
uniform sampler2D _MainTex; uniform float4 _MainTex_ST;
uniform half4 _Color;
struct VertexInput {
float4 vertex : POSITION;
float2 texcoord0 : TEXCOORD0;
float2 texcoord1 : TEXCOORD1;
float2 texcoord2 : TEXCOORD2;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float2 uv0 : TEXCOORD0;
};
VertexOutput vert (VertexInput v) {
VertexOutput o = (VertexOutput)0;
o.uv0 = v.texcoord0;
o.pos = UnityMetaVertexPosition(v.vertex, v.texcoord1.xy, v.texcoord2.xy, unity_LightmapST, unity_DynamicLightmapST );
return o;
}
FLOAT4 frag(VertexOutput i) : SV_Target {
UnityMetaInput o;
UNITY_INITIALIZE_OUTPUT( UnityMetaInput, o );
o.Emission = 0;
half4 _MainTex_var = tex2D(_MainTex,TRANSFORM_TEX(i.uv0, _MainTex));
half3 MainTex_Color = (_MainTex_var.rgb*_Color.rgb);
half3 Meta = MainTex_Color;
FLOAT3 diffColor = Meta;
o.Albedo = diffColor;
return UnityMetaFragment( o );
}
ENDCG
}
}
FallBack "Diffuse"
}

Example

Pre integrated skin shader under Gamma space dev. | JP Lee on Patreon

태그:

댓글 남기기

%d 블로거가 이것을 좋아합니다: