在 Direct3D11 中模拟 Direct3D9 固定功能管道

问题描述 投票:0回答:2

我们的软件目前使用 Direct3D9 中的固定功能管道,为用户提供一种轻松编写脚本的方式,将灯光和对象放入简单的场景中。我们允许定向光、点光源和聚光灯。我正在尝试将我们转移到 Direct3D11,但我希望它尽可能接近 Direct3D9 固定功能管道作为基线。我们可以稍后添加诸如每像素照明之类的东西。我对着色器编码是全新的,尽管我已经从事 C++ 多年,但我感觉不适合我。我想知道是否有 DX11 支持的着色器可以完美模拟 DX9 固定功能管道提供的照明。我已经在 FixedFuncEMUFX11 中看到了旧的点光仿真示例,我将尝试使用它作为基础,但我只知道我没有尽可能有效地执行此操作,并且正确的数学聚光灯模拟超出了我的能力范围。是否有任何开源软件可以模拟固定功能管道,或者包含 DirectX11/10 的定向光、点光源和聚光灯实现?我想我所需要的只是 .fx 或 .hlsl 文件。即使达到 8 个光源也没关系。

我目前正在使用 DirectXTK 作为正确 DirectX11 编程的指南,但如果有更好的编码标准,我很乐意看到行业标准 DirectX11 渲染引擎编程方法的示例。感谢您提供的任何建议。

c++ shader directx-11 directx-9 lighting
2个回答
4
投票

对于 Direct3D 11 的基本渲染,DirectX Tool Kit 内置着色器基于 XNA Game Studio 4,它提供了一组良好的基本功能,包括定向照明和每像素照明。它们设计用于与所有Direct3D功能级别硬件配合使用,因此它们不会实现聚光灯之类的功能,而这些功能可以通过更现代的硬件轻松完成。

FixedFuncEMU11 示例是旧 DirectX SDK 的 FixedFuncEMU Direct3D 10 示例的 Direct3D 11 端口。着色器对于理解各种 Direct3D 9 特定的固定功能管道很有用,但不涵盖“标准”内容,例如在 HLSL 中实现标准照明模型。另请注意,此示例使用 Direct3D 11 的效果系统,该系统有其自己的问题。不过,它对于查看还是很有用的:

  • 固定功能转换管道
  • 固定功能照明管线
  • 阿尔法测试
  • 用户剪辑平面
  • 像素雾
  • Gouraud 和平面阴影模式
  • 投影纹理查找(texldp)
  • 多重纹理
  • D3DFILL_POINT 填充模式
  • 屏幕空间UI渲染

您可能想尝试一些旧的 Direct3D 9 时代的 HLSL 着色器编程介绍。虽然与 Direct3D 11 不是 100% 兼容,但它们非常接近,而且 HLSL 本身也基本相同。例如,我找到了这篇文章

还有许多优秀的 Direct3D 11 书籍,所有这些书籍都涵盖了 HLSL 着色器,因为 Direct3D 11 中没有固定功能管道。请参阅书籍推荐了解一些详细信息和注释,因为其中一些书籍是在 DirectX SDK 发布之前编写的退休了。特别是,您应该查看 Varcholik 的 Real-Time 3D Rendering with DirectX and HLSL,因为它主要关注 HLSL 创作。


2
投票

对于通过在 hlsl 中搜索固定功能管道仿真而来到这里的任何人,这几乎正是我所寻找的:http://www.3dgep.com/texturing-lighting-directx-11/那里的着色器并不是非常优化,但是是为了清晰起见而编写的,并且对于 hlsl 初学者来说是一个很好的介绍。几乎没有什么多余的东西需要筛选,以便准确地了解正在发生的事情以及让场景运行的最低限度。聚光灯并不是 DX9 的 FFP 聚光灯的精确复制,但它很容易修改成这样。

#define MAX_LIGHTS 8

// Light types.
#define DIRECTIONAL_LIGHT 0
#define POINT_LIGHT 1
#define SPOT_LIGHT 2

Texture2D Texture : register(t0);
sampler Sampler : register(s0);

struct _Material
{
    float4  Emissive;       // 16 bytes
    //----------------------------------- (16 byte boundary)
    float4  Ambient;        // 16 bytes
    //------------------------------------(16 byte boundary)
    float4  Diffuse;        // 16 bytes
    //----------------------------------- (16 byte boundary)
    float4  Specular;       // 16 bytes
    //----------------------------------- (16 byte boundary)
    float   SpecularPower;  // 4 bytes
    bool    UseTexture;     // 4 bytes
    float2  Padding;        // 8 bytes
    //----------------------------------- (16 byte boundary)
};  // Total:               // 80 bytes ( 5 * 16 )

cbuffer MaterialProperties : register(b0)
{
    _Material Material;
};

struct Light
{
    float4      Position;               // 16 bytes
    //----------------------------------- (16 byte boundary)
    float4      Direction;              // 16 bytes
    //----------------------------------- (16 byte boundary)
    float4      Color;                  // 16 bytes
    //----------------------------------- (16 byte boundary)
    float       SpotAngle;              // 4 bytes
    float       ConstantAttenuation;    // 4 bytes
    float       LinearAttenuation;      // 4 bytes
    float       QuadraticAttenuation;   // 4 bytes
    //----------------------------------- (16 byte boundary)
    int         LightType;              // 4 bytes
    bool        Enabled;                // 4 bytes
    int2        Padding;                // 8 bytes
    //----------------------------------- (16 byte boundary)
};  // Total:                           // 80 bytes (5 * 16 byte boundary)

cbuffer LightProperties : register(b1)
{
    float4 EyePosition;                 // 16 bytes
    //----------------------------------- (16 byte boundary)
    float4 GlobalAmbient;               // 16 bytes
    //----------------------------------- (16 byte boundary)
    Light Lights[MAX_LIGHTS];           // 80 * 8 = 640 bytes
};  // Total:                           // 672 bytes (42 * 16 byte boundary)

float4 DoDiffuse( Light light, float3 L, float3 N )
{
    float NdotL = max( 0, dot( N, L ) );
    return light.Color * NdotL;
}

float4 DoSpecular( Light light, float3 V, float3 L, float3 N )
{
    // Phong lighting.
    float3 R = normalize( reflect( -L, N ) );
    float RdotV = max( 0, dot( R, V ) );

    // Blinn-Phong lighting
    float3 H = normalize( L + V );
    float NdotH = max( 0, dot( N, H ) );

    return light.Color * pow( RdotV, Material.SpecularPower );
}

float DoAttenuation( Light light, float d )
{
    return 1.0f / ( light.ConstantAttenuation + light.LinearAttenuation * d + light.QuadraticAttenuation * d * d );
}

struct LightingResult
{
    float4 Diffuse;
    float4 Specular;
};

LightingResult DoPointLight( Light light, float3 V, float4 P, float3 N )
{
    LightingResult result;

    float3 L = ( light.Position - P ).xyz;
    float distance = length(L);
    L = L / distance;

    float attenuation = DoAttenuation( light, distance );

    result.Diffuse = DoDiffuse( light, L, N ) * attenuation;
    result.Specular = DoSpecular( light, V, L, N ) * attenuation;

    return result;
}

LightingResult DoDirectionalLight( Light light, float3 V, float4 P, float3 N )
{
    LightingResult result;

    float3 L = -light.Direction.xyz;

    result.Diffuse = DoDiffuse( light, L, N );
    result.Specular = DoSpecular( light, V, L, N );

    return result;
}

float DoSpotCone( Light light, float3 L )
{
    float spotMinAngle = cos( light.SpotAngle );
    float spotMaxAngle = ( spotMinAngle + 1.0f ) / 2.0f;
    float cosAngle = dot( light.Direction.xyz, L );
    return smoothstep( spotMinAngle, spotMaxAngle, cosAngle ); 
}

LightingResult DoSpotLight( Light light, float3 V, float4 P, float3 N )
{
    LightingResult result;

    float3 L = ( light.Position - P ).xyz;
    float distance = length(L);
    L = L / distance;

    float attenuation = DoAttenuation( light, distance );
    float spotIntensity = DoSpotCone( light, -L );

    result.Diffuse = DoDiffuse( light, L, N ) * attenuation * spotIntensity;
    result.Specular = DoSpecular( light, V, L, N ) * attenuation * spotIntensity;

    return result;
}

LightingResult ComputeLighting( float4 P, float3 N )
{
    float3 V = normalize( EyePosition - P ).xyz;

    LightingResult totalResult = { {0, 0, 0, 0}, {0, 0, 0, 0} };

    [unroll]
    for( int i = 0; i < MAX_LIGHTS; ++i )
    {
        LightingResult result = { {0, 0, 0, 0}, {0, 0, 0, 0} };

        if ( !Lights[i].Enabled ) continue;

        switch( Lights[i].LightType )
        {
        case DIRECTIONAL_LIGHT:
            {
                result = DoDirectionalLight( Lights[i], V, P, N );
            }
            break;
        case POINT_LIGHT: 
            {
                result = DoPointLight( Lights[i], V, P, N );
            }
            break;
        case SPOT_LIGHT:
            {
                result = DoSpotLight( Lights[i], V, P, N );
            }
            break;
        }
        totalResult.Diffuse += result.Diffuse;
        totalResult.Specular += result.Specular;
    }

    totalResult.Diffuse = saturate(totalResult.Diffuse);
    totalResult.Specular = saturate(totalResult.Specular);

    return totalResult;
}

struct PixelShaderInput
{
    float4 PositionWS   : TEXCOORD1;
    float3 NormalWS     : TEXCOORD2;
    float2 TexCoord     : TEXCOORD0;
};

float4 TexturedLitPixelShader( PixelShaderInput IN ) : SV_TARGET
{
    LightingResult lit = ComputeLighting( IN.PositionWS, normalize(IN.NormalWS) );

    float4 emissive = Material.Emissive;
    float4 ambient = Material.Ambient * GlobalAmbient;
    float4 diffuse = Material.Diffuse * lit.Diffuse;
    float4 specular = Material.Specular * lit.Specular;

    float4 texColor = { 1, 1, 1, 1 };

    if ( Material.UseTexture )
    {
        texColor = Texture.Sample( Sampler, IN.TexCoord );
    }

    float4 finalColor = ( emissive + ambient + diffuse + specular ) * texColor;

    return finalColor;
}
© www.soinside.com 2019 - 2024. All rights reserved.