0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2024-10-20

ピクセルシェーダー↓

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);
				 });

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


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

画面録画 2024-10-18 033309.gif

こんな感じになれば成功でしょう

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?