ピクセルシェーダー↓
PS.hlsl
Texture2D<float4> Texture : register(t0);
sampler Sampler : register(s0);
cbuffer Parameters : register(b0)
{
float4 DiffuseColor : packoffset(c0);
float3 EmissiveColor : packoffset(c1);
float3 SpecularColor : packoffset(c2);
float SpecularPower : packoffset(c2.w);
float3 LightDirection[3] : packoffset(c3);
float3 LightDiffuseColor[3] : packoffset(c6);
float3 LightSpecularColor[3] : packoffset(c9);
float3 EyePosition : packoffset(c12);
float3 FogColor : packoffset(c13);
float4 FogVector : packoffset(c14);
float4x4 World : packoffset(c15);
float3x3 WorldInverseTranspose : packoffset(c19);
float4x4 WorldViewProj : packoffset(c22);
};
struct PSInput
{
float2 TexCoord : TEXCOORD0;
float4 PositionWS : TEXCOORD1;
float3 NormalWS : TEXCOORD2;
float4 Diffuse : COLOR0;
};
float4 main(PSInput input) : SV_Target0
{
// 法線とライト方向の計算
float3 normal = normalize(input.NormalWS);
float3 toLight = normalize(-LightDirection[0]);
float NdotL = dot(normal, toLight);
// カメラ方向との角度を使って輪郭線を強調
float3 toEye = normalize(EyePosition - input.PositionWS.xyz);
float edgeFactor = saturate(dot(normal, toEye)); // カメラと法線の角度による境界検出
edgeFactor = pow(1.0f - edgeFactor, 2.0f); // 輪郭線を強調
// トゥーンシェーディング:3段階の明るさ設定
float toonLightAmount = 0.1f + step(0.4f, NdotL) * 0.4f +
step(0.7f, NdotL) * 0.5f;
// 輪郭線の強調度合い
float edgeAmount = 2.5f;
// ディフューズの計算(輪郭線強調を適用)
float3 diffuse = (toonLightAmount + edgeFactor * edgeAmount) *
(LightDiffuseColor[0] * DiffuseColor.rgb + EmissiveColor);
// より強調されたスペキュラの計算
float3 halfVector = normalize(toLight + toEye);
float NdotH = dot(normal, halfVector);
float3 specular = pow(saturate(NdotH), SpecularPower * 2.0f) * LightSpecularColor[0];
// テクスチャカラーの取得
float4 textureColor = Texture.Sample(Sampler, input.TexCoord);
// トゥーン風に色を合成
return float4(textureColor.rgb * diffuse + specular, DiffuseColor.a);
}
これをコンパイルして
C++側の更新処理内で
モデルのUpdateEffectsでこのように設定する
model.cpp
m_model->UpdateEffects([&](IEffect* effect)
{
auto basicEffect = dynamic_cast<BasicEffect*>(effect);
if (basicEffect)
{
basicEffect->SetLightingEnabled(true);
basicEffect->SetLightEnabled(0, true);
basicEffect->SetLightDirection(0, -lightDirection);
basicEffect->SetSpecularPower(50);
basicEffect->SetPerPixelLighting(true);
basicEffect->SetTextureEnabled(true);
basicEffect->SetVertexColorEnabled(false);
basicEffect->SetFogEnabled(false);
}
});
lightDirectionは光源の座標とモデルの座標の差を正規化したものです
描画処理内でモデルを描画するときに
ラムダ式でさっきのピクセルシェーダーを適用する
model.cpp
// モデルの描画
m_model->Draw(context, *states, world, view, projection, false, [&]()
{
context->PSSetShader(m_PS.Get(), nullptr, 0);
});
参考にする際の注意
ここに書いている情報はかなり断片的なので
本当に、あくまで参考程度にとどめておいた方がいいかもです
最終的にはこんな感じになるかと思います
こんな感じになれば成功でしょう
まあまだ自分も練習中の身なので
改善の余地は大いにありますね