DirectX11(五)

简单Shader,使用了Effect框架

//方向光源
struct DirectionalLight
{
    float4 Ambient;    //环境光
    float4 Diffuse;    //散射光
    float4 Specular;   //镜面光
    float3 Direction;  //方向
    float Pad;         //只用于字节对齐
};

struct Material
{
    float4 Ambient;     //环境系数
    float4 Diffuse;     //散射系数
    float4 Specular;    //镜面光系数 w = 高光因子
    float4 Reflect;
};

//计算方向光光强
void ComputeDirectionalLight(Material mat, DirectionalLight light, float3 normal, float3 toEye,
    out float4 ambient, out float4 diffuse, out float4 spec)

{
    //初始化
    ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
    diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
    spec = float4(0.0f, 0.0f, 0.0f, 0.0f);

    //环境光
    ambient = mat.Ambient * light.Ambient;

    //光的反向量
    float3 antiLightVec = -light.Direction;
    //光与法线的夹角
    float diffuseFactor = dot(antiLightVec, normal);
    if (diffuseFactor > 0)
    {
        //散射光
        diffuse = diffuseFactor * mat.Diffuse * light.Diffuse;

        //镜面光
        float3 vReflect = reflect(-antiLightVec, normal);
        float specFactor = pow(max(dot(vReflect, toEye), 0.0f), mat.Specular.w);
        spec = specFactor * mat.Specular * light.Specular;
    }

}
#include "LightHelper.fx"

//帧常量缓冲
cbuffer cbPerFrame
{
    //光源
    DirectionalLight gDirLights[3];
    //视点
    float3 gEyePosW;
    float gFogStart;
    float gFogRange;
    float4 gFogColor;
};

//对象常量缓冲
cbuffer cbPerObject
{
    //世界变换
    float4x4 gWorld;
    //世界的逆转置变换,用于法线
    float4x4 gWorldInvTranspose;
    //世界相机投影变换
    float4x4 gWorldViewProj;
    //纹理变换
    float4x4 gTexTransform;
    //材质
    Material gMaterial;
};
//纹理图
Texture2D gDiffuseMap;

//采样状态
SamplerState samAnisotropic
{
    //各向异性过滤
    Filter = ANISOTROPIC;   
    MaxAnisotropy = 4;
    //寻址方式
    AddressU = WRAP;
    AddressV = WRAP;
};
struct VertexIn
{
    //本地坐标
    float3 PosL         : POSITION;
    //本地法线
    float3 NormalL      : NORMAL;
    //纹理坐标
    float2 Tex          : TEXCOORD;
};

struct VertexOut
{
    //世界坐标
    float3 PosW         : POSITION;
    //世界法线
    float3 NormalW      : NORMAL;
    //齐次坐标
    float4 PosH         : SV_POSITION;
    //纹理
    float2 Tex          : TEXCOORD;
};

VertexOut VS(VertexIn vIn)
{
    VertexOut vOut;
    //本地坐标转为世界坐标
    vOut.PosW = mul(float4(vIn.PosL, 1.0f), gWorld).xyz;
    //本地法线转为世界法线
    vOut.NormalW = mul(vIn.NormalL, (float3x3)gWorldInvTranspose);
    //齐次坐标
    vOut.PosH = mul(float4(vIn.PosL, 1.0f), gWorldViewProj);
    //纹理坐标
    vOut.Tex = mul(float4(vIn.Tex, 0.0f, 1.0f), gTexTransform).xy;
    return vOut;
}

float4 PS(VertexOut vOut):SV_Target
{
    //插值的法线可能没有归一化
    vOut.NormalW = normalize(vOut.NormalW);

    //到视点的向量
    float3 toEye = gEyePosW - vOut.PosW;
    //距离
    float distToEye = length(toEye);
    //归一化
    toEye = normalize(toEye);

    //默认纹理颜色
    float4 texColor = float4(1, 1, 1, 1);
    texColor = gDiffuseMap.Sample(samAnisotropic, vOut.Tex);
    clip(texColor.a - 0.1f);

    //计算光照
    float4 litColor = texColor;
    //初始化光照
    float4 ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
    float4 diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
    float4 spec = float4(0.0f, 0.0f, 0.0f, 0.0f);
    for (int i = 0; i < 3; i++)
    {
        float4 A, D, S;
        ComputeDirectionalLight(gMaterial, gDirLights[i], vOut.NormalW, toEye,
            A, D, S);

        ambient += A;
        diffuse += D;
        spec += S;
    }

    litColor = texColor*(ambient + diffuse) + spec;

    //雾效
    float fogLerp = saturate((distToEye - gFogStart) / gFogRange);
    litColor = lerp(litColor, gFogColor, fogLerp);

    //Alpha
    litColor.a = gMaterial.Diffuse.a * texColor.a;

    return litColor;
}

technique11 Tech
{
    pass P0
    {
        SetVertexShader(CompileShader(vs_5_0, VS()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_5_0, PS()));
    }
};

效果图:
这里写图片描述
项目Github地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值