トゥーンとリムライトの合わせ技っぽいやつの備忘録

ピクセルシェーダー↓
```ruby: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でこのように設定する
```ruby: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は光源の座標とモデルの座標の差を正規化したものです

---
描画処理内でモデルを描画するときに
ラムダ式でさっきのピクセルシェーダーを適用する

```ruby:model.cpp
// モデルの描画
m_model->Draw(context, *states, world, view, projection, false, [&]()
				 {
					 context->PSSetShader(m_PS.Get(), nullptr, 0);
				 });
```

:::note warn
参考にする際の注意
　　ここに書いている情報はかなり断片的なので
  　　本当に、あくまで参考程度にとどめておいた方がいいかもです
:::

---
最終的にはこんな感じになるかと思います
---

![画面録画 2024-10-18 033309.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3491315/5b0f34cd-9b60-6806-b50b-1e979ec7575f.gif)
---
こんな感じになれば成功でしょう

まあまだ自分も練習中の身なので
改善の余地は大いにありますね