|
// 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 2
|
|
#define SHADING_MODEL 2 // 1:MMD 2:Phong with Fresnel
|
|
//#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 ndotl = clamp(dot( normal, light ), 0.0f, 1.0f);
|
|
float ndotv = clamp(dot( normal, view ), 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;
|
|
//return float4(texCoord, 0, 1);
|
|
[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.
|
|
[branch]
|
|
if ( g_toonFileEnabled == 1 ) {
|
|
#if SHADING_MODEL == 1
|
|
// Toon without self-shadowing material method.
|
|
color *= SampleColorTexture(g_toonTex, ToonTextureSampler, float2(0.0f, 0.5f - ndotl * 0.5f));
|
|
#else
|
|
comp = (1.0f - ndotv) * tempSpecularColor + ndotl;
|
|
float4 ToonTex = SampleColorTexture(g_toonTex, ToonTextureSampler, float2(0.0f, 1.0f));
|
|
color.a *= ToonTex.a;
|
|
shadowColor.rgb *= ToonTex.rgb;
|
|
#endif
|
|
}
|
|
}
|
|
comp = saturate(comp);
|
|
//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);
|
|
}
|