LoginSignup
4
5

More than 5 years have passed since last update.

MMDモデルを使用したデスクトップユーティリティの開発 その7 色表現

Last updated at Posted at 2016-10-01

前: その6
次: その8

ディフューズ・スペキュラ光など、色の表現を追加する。
トゥーンシェーダ、スフィアマッピングを導入する。

マテリアルから必要な情報を取り出し、適切なテクスチャ座標の計算を行うことで、質感の表現ができます。
今回のソースはこちら

effect.fx
matrix World;
matrix View;
matrix Projection;
float3 ambientLight;
float4 matDiffuse;
float4 matAmbient;
float4 matSpecular;
float matAlpha;
float matSpecularity;
float3 lightDir;
float3 eyePos;
Texture2D normalTexture;
SamplerState normalSampler {};
Texture2D toonTexture;
SamplerState toonSampler {};
Texture2D sphTexture;
SamplerState sphSampler {};
Texture2D spaTexture;
SamplerState spaSampler {};
bool tex;
bool ton;
bool sph;
bool spa;
bool edge;

struct Vertexes {
    float4 position : SV_Position;
    float4 normal : NORMAL;
    float2 uv : TEXCOORD;
};

struct OutVert {
    float4 position : SV_Position;
    float2 uv : TEXCOORD;
    float4 diffuse : COLOR0;
    float3 specular : COLOR1;
    float2 toonCoord : TEXCOORD1;
    float2 sphereCoord : TEXCOORD2;
};

struct Colors {
    float3 diffuse;
    float3 specular;
    float2 toonCoord;
};

Colors CalcLight(float3 E, float3 N) {
    Colors col = (Colors)0;

    col.diffuse = ambientLight;
    col.specular = 0;

    float3 L = normalize(-lightDir);
    float3 H = normalize(E + L);
    float2 prt = lit(dot(N, L), dot(N, H), matSpecularity).yz;
    col.specular += ambientLight * prt.y;

    col.diffuse *= matDiffuse.rgb;
    col.diffuse += matAmbient.rgb;
    col.diffuse = saturate(col.diffuse);
    col.specular *= matSpecular.rgb;

    col.toonCoord.x = clamp(0.5f - dot(normalize(N), normalize(E)) * 0.5f, 0, 1);
    col.toonCoord.y = clamp(0.5f - dot(normalize(N), normalize(L)) * 0.5f, 0, 1);

    return col;
}

OutVert myVertexShader(Vertexes input) {
    OutVert output = (OutVert)0;

    float4 posW = mul(input.position, World);
    float4 pos = mul(posW, View);
    pos = mul(pos, Projection);
    output.position = pos;
    output.uv = input.uv;

    float3 N = normalize(mul(input.normal, World)).xyz;
    float3 subEye = eyePos - posW.xyz;
    float3 E = normalize(subEye);
    Colors light = CalcLight(E, N);

    output.diffuse = float4(light.diffuse.rgb, matAlpha);
    output.specular = light.specular;

    output.toonCoord = light.toonCoord;
    output.sphereCoord = float2(input.normal.x / 2 + 0.5f, input.normal.y / 2 + 0.5f);

    return output;
}

float4 myPixelShader(OutVert input) : SV_Target {
    float4 color = normalTexture.Sample(normalSampler, input.uv) * input.diffuse + float4(input.specular.rgb, 0);
    if (sph) {
        color.rgb *= sphTexture.Sample(sphSampler, input.sphereCoord).rgb;
    }
    if (spa) {
        color.rgb += spaTexture.Sample(spaSampler, input.sphereCoord).rgb;
    }
    if (ton) {
        color.rgb *= toonTexture.Sample(toonSampler, input.toonCoord).rgb;
    }

    return color;
}

technique10 myTechnique {
    pass myPass {
        SetVertexShader(CompileShader(vs_5_0, myVertexShader()));
        SetPixelShader(CompileShader(ps_5_0, myPixelShader()));
    }
}

cirno.png

さいごに

調べながら色々ためしてみたのですが、なかなか思うようにはいかなかったため、シェーダ部分は色々なところからの寄せ集めです。

次回は、PMX読み込み・表示に取り掛かる予定です。

4
5
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
4
5