プロジェクト

プロフィール

ヘルプ

タスク #40 » mmd.hlsl

修正ファイル最新版 - みょうじ, 2020/04/16 11:41

 
// BSD license
//
//Copyright( c ) 2019, lena antler(猫のしもべ), less
//All rights reserved.
//
//Redistribution and use in source and binary forms, with or without
//modification, are permitted provided that the following conditions are met :
//
//1. Redistributions of source code must retain the above copyright notice,
//this list of conditions and the following disclaimer.
//2. Redistributions in binary form must reproduce the above copyright notice,
//this list of conditions and the following disclaimer in the documentation
//and / or other materials provided with the distribution.
//
//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
//( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
//( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//The views and conclusions contained in the software and documentation are those
//of the authors and should not be interpreted as representing official policies,
//either expressed or implied, of the FreeBSD Project.
//
//------------------------------------------------------------------------------
//
// MMDモデル(pmd/pmx/x)を表示するためのシェーダー。だと思うヨ。
//
//------------------------------------------------------------------------------

// 基本ルート署名定義
//
// t0:toonテクスチャ
// t1:sphereテクスチャ
// t2:材質テクスチャ
// t3:追加テクスチャ1
// t4:追加テクスチャ2
// t5:追加テクスチャ3
// t6:セルフ影マップ
//
// b0:wvp行列やライトなどのシーン属性
// b1:マテリアル個別の属性
//
// s0:ANISOTROPIC/Wrapサンプラー。
// s1:ANISOTROPIC/Clampサンプラー。
// s2:MIN_MAG_MIP_LINEAR/Wrapサンプラー。
// s3:MIN_MAG_MIP_LINEAR/Clampサンプラー。
// s4:MIN_MAG_MIP_POINT/Wrapサンプラー。
// s5:MIN_MAG_MIP_POINT/Clampサンプラー。
// s6:COMPARISON ANISOTROPIC/Wrapサンプラー。
// s7:COMPARISON ANISOTROPIC/Clampサンプラー。
// s8:COMPARISON MIN_MAG_MIP_LINEAR/Wrapサンプラー。
// s9:COMPARISON MIN_MAG_MIP_LINEAR/Clampサンプラー。
// s10:COMPARISON MIN_MAG_MIP_POINT/Wrapサンプラー。
// s11:COMPARISON MIN_MAG_MIP_POINT/Clampサンプラー。
//------------------------------------------------------------------------------
//

//------------------------------------------------------------------------------
// Shader behavior.
//------------------------------------------------------------------------------
//#define SOFTWARE_PCF 1
#define SHADING_MODEL 1 // 1:MMD 2:Phong with Fresnel
//#define BINALIZE_SHADOW_FILTER 0.25
//#define LENEAR_WORKFLOW

//------------------------------------------------------------------------------
// シーン属性
//------------------------------------------------------------------------------
cbuffer cbScene : register(b0)
{
float4x4 g_wvp;
float4x4 g_viewMatrix;
float4x4 g_projectionMatrix;
float4x4 g_viewProjectionMatrix;

float3 g_cameraPos;
float3 g_cameraCenter;
float3 g_cameraUp;
float3 g_cameraDirection;
float g_fov;

float4x4 g_lwvp;
float4x4 g_groundShadowWvp;
float4 g_groundShadowColor;
float3 g_lightDirection;
float3 g_lightColor;
float g_lightRange;
float g_near;
float g_far;
uint g_shadowBufferSize;
};

//------------------------------------------------------------------------------
// マテリアル属性
//------------------------------------------------------------------------------

#define NND_SPHERE_DISABLED (0) // スフィア無効(排他)
#define NND_SPHERE_MULTIPLICATION (1) // 加算スフィアが有効(排他)
#define NND_SPHERE_ADDTION (2) // 乗算スフィアが有効(排他)

cbuffer cbMaterial : register(b1)
{
float4 g_diffuse;
float3 g_specular;
float g_shininess;
float3 g_ambient;

uint g_uvCount;

uint g_toonFileEnabled;
uint g_sphereFlag;
uint g_edgeEnabled;
float g_edgeSize;
float4 g_edgeColor;
uint g_groundShadowEnabled;
uint g_shadowCastEnabled;
uint g_shadowRecvEnabled;
uint g_doubleSided;
};


//------------------------------------------------------------------------------
// Outer parameter.
//------------------------------------------------------------------------------
Texture2D g_toonTex : register(t0);
Texture2D g_sphereTex : register(t1);
Texture2D g_materialTex[4] : register(t2);
Texture2D g_shadowTex : register(t6);
Texture2D g_extraTex[4] : register(t7);

SamplerState g_wrapAnisotropicSampler : register(s0);
SamplerState g_clampAnisotropicSampler : register(s1);
SamplerState g_wrapLinerSampler : register(s2);
SamplerState g_clampLinerSampler : register(s3);
SamplerState g_wrapPointSampler : register(s4);
SamplerState g_clampPointSampler : register(s5);

SamplerComparisonState g_wrapComparisonAnisotropicSampler : register(s6);
SamplerComparisonState g_clampComparisonAnisotropicSampler : register(s7);
SamplerComparisonState g_wrapComparisonLinerSampler : register(s8);
SamplerComparisonState g_clampComparisonLinerSampler : register(s9);
SamplerComparisonState g_wrapComparisonPointSampler : register(s10);
SamplerComparisonState g_clampComparisonPointSampler : register(s11);

struct VSInput
{
float3 position : NND_POSITION;
float3 normal : NND_NORMAL;
float2 uv[4] : NND_TEXCOORD;
float edgeBias : NND_EDGEBIAS;
};

// カラーマップ用のWRAP-Sampler
#define ColorTextureSampler g_wrapAnisotropicSampler

// Toonマップ用のCLAMP-Sampler
#define ToonTextureSampler g_clampAnisotropicSampler

// Sphereマップ用のCLAMP-Sampler(分ける必要は無いかも知れないが一応分けておく)
#define SphereTextureSampler g_clampAnisotropicSampler

// シャドウマップ用のサンプラー
#define ShadowMapTextureSampler g_clampLinerSampler
#define SoftShadowMapTextureSampler g_clampComparisonLinerSampler

// トゥーン度合いを調整する定数。小さいほど影が伸びてグラデーションが出る。
// トゥーンテクスチャの解像度次第で影の出方が変わる。16以上は差が出ないと思われる。
//
// 3 MMDと同じ色合い
#define ToonFactor 3

static float3 lightDiffuse = float3(0.0f, 0.0f, 0.0f);
static float3 lightAmbient = g_lightColor;
static float3 lightSpecular = g_lightColor;
static float4 materialDiffuseColor = g_diffuse;
static float3 materialAmbientColor = g_diffuse.rgb;
static float3 materialSpecularColor = g_specular;
static float4 diffuseColor = materialDiffuseColor * float4(lightDiffuse, 1.0f);
static float3 ambientColor = saturate( materialAmbientColor * g_lightColor + g_ambient );
static float3 specularColor = materialSpecularColor * g_lightColor;
static float shadowTexStemp = 1.0f / g_shadowBufferSize;

//------------------------------------------------------------------------------
// Functions.
//------------------------------------------------------------------------------
// Texture sample for linearize workflow.
float4 SampleColorTexture(Texture2D textureObject, SamplerState state, float2 uv)
{
#ifdef LENEAR_WORKFLOW
return pow(textureObject.Sample(state, uv), 2.2f);
#else
return textureObject.Sample(state, uv);
#endif
}

// Linearize color.
float3 Linearize(float3 color)
{
#ifdef LENEAR_WORKFLOW
return pow(color, 2.2f);
#else
return color;
#endif
}

// Unlinearize color.
float3 Unlinearize(float3 color)
{
#ifdef LENEAR_WORKFLOW
return pow(color, 0.454545f);
#else
return color;
#endif
}

//------------------------------------------------------------------------------
// マテリアル描画用
//------------------------------------------------------------------------------

struct PSInput
{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float2 sphereUv : TEXCOORD2;
float3 view : TEXCOORD3;
float4 zCalcTex : TEXCOORD4;
float4 color : COLOR0;
float3 shadowColor : COLOR1;
};

PSInput VSMain( VSInput input )
{
PSInput result;

result.position = mul( float4(input.position, 1.0f), g_wvp );
//result.position = mul( float4(input.position, 1.0f), g_groundShadowWvp );

result.normal = normalize( input.normal );

// For normal offset shadows.
result.zCalcTex = mul( float4(input.position + result.normal * g_lightRange / 1000, 1.0f), g_lwvp );

result.view = g_cameraPos - input.position;

result.color.rgb = Linearize(ambientColor);
result.shadowColor = result.color.rgb;
float3 diffuse = Linearize(diffuseColor.rgb);
if ( g_toonFileEnabled == 1 ) {
result.color.rgb += max( 0.0f, dot( input.normal, -g_lightDirection ) ) * diffuse;
}
result.color.a = diffuseColor.a;
result.color.rgb = saturate( result.color.rgb );

result.uv = input.uv[0];

result.sphereUv = float2(0.0f, 0.0f);
if ( g_sphereFlag != NND_SPHERE_DISABLED ) {
float2 normalWv = mul( result.normal, (float3x3)g_viewMatrix ).xy;
result.sphereUv = normalWv * float2(0.5f, -0.5f) + 0.5f;
}

return result;
}

float4 PSMain( PSInput input ) : SV_TARGET
{
//return float4(0.5f + 0.5f * input.normal, 1.0f );
//return float4(input.normal, 1.0 );

// For now, let's normalize values we don't know is normalized.
float3 normal = normalize( input.normal );
float3 light = -g_lightDirection;
float3 view = normalize( input.view );

// ------------------------------------------------------------
// Material color.
// ------------------------------------------------------------
// Specular color.
float3 tempSpecularColor = Linearize(specularColor);
float3 halfVec = normalize( view + light );
float3 specular = pow( max( 0.0f, dot( halfVec, normal ) ), g_shininess ) * tempSpecularColor;

float ndotlFull = dot( normal, light );
float ndotv = clamp(dot( normal, view ), 0.0f, 1.0f);
float ndotl = clamp(ndotlFull, 0.0f, 1.0f);

// Base color.
float4 color = input.color;
float3 shadowColor = input.shadowColor;
// Texture mapping.
[branch]
if ( 0 < g_uvCount ) {
float4 texColor = SampleColorTexture(g_materialTex[0], ColorTextureSampler, input.uv);
color *= texColor;
shadowColor *= texColor.rgb;
}
// Sphere mapping.
[branch]
if ( g_sphereFlag != NND_SPHERE_DISABLED ) {
float4 sphereTexColor = SampleColorTexture(g_sphereTex, SphereTextureSampler, input.sphereUv);
[branch]
if ( g_sphereFlag == NND_SPHERE_ADDTION ) {
color.rgb += sphereTexColor.rgb;
shadowColor += sphereTexColor.rgb;
}
else {
color.rgb *= sphereTexColor.rgb;
shadowColor *= sphereTexColor.rgb;
}
color.a *= sphereTexColor.a;
}

// Add specular.
// Specular appears only light side.
color.rgb += specular;

// ------------------------------------------------------------
// Self shadowing.
// ------------------------------------------------------------
float3 comp = 1.0f;
[branch]
if (g_shadowRecvEnabled == 1) {
float depth = input.zCalcTex.z / input.zCalcTex.w;
float2 texCoord;
texCoord.x = (1.0f + input.zCalcTex.x / input.zCalcTex.w) * 0.5f;
texCoord.y = (1.0f - input.zCalcTex.y / input.zCalcTex.w) * 0.5f;

[branch]
if ( any( saturate( texCoord ) != texCoord ) ) {
// Out of shadow map square.
} else {
comp = 0.0f;
float bias = 0.005f * clamp(tan(acos(ndotl)), 0.0f, 0.01f);
#ifdef SOFTWARE_PCF
[loop]
for (int loopY = -SOFTWARE_PCF; loopY <= SOFTWARE_PCF; ++loopY) {
[loop]
for (int loopX = -SOFTWARE_PCF; loopX <= SOFTWARE_PCF; ++loopX) {
comp += g_shadowTex.SampleCmpLevelZero(SoftShadowMapTextureSampler, float2(loopX, loopY) * shadowTexStemp + texCoord, depth);
}
}
comp /= (SOFTWARE_PCF * 2 + 1) * (SOFTWARE_PCF * 2 + 1);
#else
comp += g_shadowTex.SampleCmpLevelZero(SoftShadowMapTextureSampler, texCoord, depth);
// comp += g_shadowTex.SampleCmpLevelZero(SoftShadowMapTextureSampler, texCoord, depth);
#endif
}
comp = clamp(comp, 0.0f, 1.0f);

// ------------------------------------------------------------
// Toon(lut) mapping.
// ------------------------------------------------------------
[branch]
if ( g_toonFileEnabled == 1 ) {
float4 ToonTex = SampleColorTexture(g_toonTex, ToonTextureSampler, float2(0.0f, 1.0f));
#if SHADING_MODEL == 1
comp = min(saturate(ndotl * ToonFactor), comp);
#else
// Without toon mapping.
comp = (1.0f - ndotv) * tempSpecularColor + ndotl * comp;
#endif
color.a *= ToonTex.a;
shadowColor.rgb *= ToonTex.rgb;
}
} else {
// No shadow receiver material.
float4 ToonTex = 1.0f;
[branch]
if ( g_toonFileEnabled == 1 ) {
#if SHADING_MODEL == 1
// Toon without self-shadowing material method.
ToonTex = SampleColorTexture(g_toonTex, ToonTextureSampler, float2(0.0f, 0.5f - ndotlFull * 0.5f));
color *= ToonTex;
#else
comp = (1.0f - ndotv) * tempSpecularColor + ndotl;
ToonTex = SampleColorTexture(g_toonTex, ToonTextureSampler, float2(0.0f, 1.0f));
color.a *= ToonTex.a;
#endif
shadowColor.rgb *= ToonTex.rgb;
}
}
comp = saturate(comp);
#ifdef BINALIZE_SHADOW_FILTER
comp = step(BINALIZE_SHADOW_FILTER, comp);
#endif
[branch]
if (color.a == 0) discard;
//return float4(Unlinearize(comp), color.a);

color.rgb = lerp(shadowColor, color.rgb, comp);

color.rgb = Unlinearize(color.rgb);

return color;
}


//------------------------------------------------------------------------------
// エッジ描画用
//------------------------------------------------------------------------------

struct PSEdgeInput
{
float4 position : SV_POSITION;
float4 color : COLOR;
};

PSEdgeInput VSEdgeMain( VSInput input )
{
PSEdgeInput result;

float3 eye = g_cameraPos - input.position;
//float distance = length( eye ) / (g_far - g_near);
float distance = length( eye ) / 1000;
float3 tempNormal = mul( normalize( float3(input.normal.xy, 0) ), (float3x3)g_wvp );
float edgeWeigt = 5.0f * g_edgeSize * input.edgeBias * distance * (degrees( g_fov ) / 180);
float3 pos = input.position + input.normal * edgeWeigt;
result.position = mul( float4(pos, 1.0f), g_wvp );
result.color = g_edgeColor;


return result;
}

float4 PSEdgeMain( PSEdgeInput input ) : SV_TARGET
{
//return float4(0.0f, 0.0f, 0.0f, 0.0f);
return input.color;
}


//------------------------------------------------------------------------------
// セルフ影描画用
//------------------------------------------------------------------------------

struct PSShadowInput
{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
float alpha : COLOR;
};

PSShadowInput VSShadowMain( VSInput input )
{
PSShadowInput result;
result.position = mul( float4(input.position, 1.0f), g_lwvp );
result.alpha = diffuseColor.a;
result.uv = input.uv[0];
return result;
}

float4 PSShadowMain( PSShadowInput input ) : SV_TARGET
{
if (g_shadowCastEnabled == 0) {
discard;
}
[branch]
if ( 0 < g_uvCount ) {
float alpha = input.alpha * g_materialTex[0].Sample( ColorTextureSampler, input.uv ).a;
clip(alpha < 0.1f ? -1 : 1);
}
return float4(0.0f, 0.0f, 0.0f, 1.0f);
}


//------------------------------------------------------------------------------
// 地面影描画用
//------------------------------------------------------------------------------

struct PSGroundShadowInput
{
float4 position : SV_POSITION;
};

PSGroundShadowInput VSGroundShadowMain( VSInput input )
{
PSGroundShadowInput result;
result.position = mul( float4(input.position, 1.0f), g_groundShadowWvp );
return result;
}

float4 PSGroundShadowMain( PSGroundShadowInput input ) : SV_TARGET
{
[branch]
if ( g_groundShadowEnabled == 0 ) {
discard;
}
return float4(g_groundShadowColor.rgb, 1.0f);
}
    (1-1/1)