提交 d47805b1 编写于 作者: GamebabyRockSun_QQ's avatar GamebabyRockSun_QQ

添加27号示例,并修正WIC工具库中的bug

上级 05fe7479
......@@ -210,12 +210,7 @@
</FxCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\Shader\HDR_COLOR_CONV.hlsli">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</None>
<None Include="..\Shader\0-1 HDR_COLOR_CONV.hlsli" />
<None Include="Shader\GRS_PBR_Function.hlsli">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
......
......@@ -64,7 +64,7 @@
<None Include="Shader\GRS_Scene_CB_Def.hlsli">
<Filter>Shader</Filter>
</None>
<None Include="..\Shader\HDR_COLOR_CONV.hlsli">
<None Include="..\Shader\0-1 HDR_COLOR_CONV.hlsli">
<Filter>Shader</Filter>
</None>
</ItemGroup>
......
#include "HDR_COLOR_CONV.hlsli"
#include "0-1 HDR_COLOR_CONV.hlsli"
#include "GRS_PBR_Function.hlsli"
Texture2D g_txHDR : register(t0);
......
#include "GRS_Scene_CB_Def.hlsli"
#include "GRS_PBR_Function.hlsli"
#include "HDR_COLOR_CONV.hlsli"
#include "0-1 HDR_COLOR_CONV.hlsli"
SamplerState g_sapLinear : register(s0);
TextureCube g_texSpecularCubemap : register(t0);
......
#include "HDR_COLOR_CONV.hlsli"
#include "0-1 HDR_COLOR_CONV.hlsli"
#include "GRS_Scene_CB_Def.hlsli"
Texture2D g_Texture2DArray[] : register(t0);
......
#include "HDR_COLOR_CONV.hlsli"
#include "0-1 HDR_COLOR_CONV.hlsli"
#include "GRS_Scene_CB_Def.hlsli"
#include "GRS_PBR_Function.hlsli"
......
......@@ -21,7 +21,6 @@ float4 PSMain(ST_GRS_HLSL_PS_INPUT stPSInput) : SV_TARGET
// ط
float3 N = g_texNormal.Sample(g_sapLinear, stPSInput.m_v2UV).xyz;
N = 2.0f * N - 1.0f;
//N.y = -N.y; // for Opengl Normal Map Texture
N = normalize(N);
float3x3 mxTBN= { stPSInput.m_v3WTangent , stPSInput.m_v3WBitangent, stPSInput.m_v3WNormal };
......
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="源文件">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="头文件">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="资源文件">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Shader">
<UniqueIdentifier>{a483a90b-a366-49f3-96e1-68b3e46aa6a4}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="27-IBL-With-Material-Texture.cpp">
<Filter>源文件</Filter>
</ClCompile>
<ClCompile Include="..\Commons\GRS_Assimp_Loader.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="Shader\0-2 GRS_PBR_Function.hlsli">
<Filter>Shader</Filter>
</None>
<None Include="Shader\0-3 GRS_Scene_CB_Def.hlsli">
<Filter>Shader</Filter>
</None>
<None Include="..\Shader\0-1 HDR_COLOR_CONV.hlsli">
<Filter>Shader</Filter>
</None>
</ItemGroup>
<ItemGroup>
<FxCompile Include="Shader\1-1 GRS_6Times_HDR_2_Cubemap_VS.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\1-2 GRS_1Times_GS_HDR_2_CubeMap_VS_GS.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\1-3 GRS_HDR_Spherical_Map_2_Cubemap_PS.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\2-1 GRS_IBL_Diffuse_Irradiance_Convolution_With_Integration_PS.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\2-2 GRS_IBL_Diffuse_Irradiance_Convolution_With_Monte_Carlo_PS.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\3-1 GRS_IBL_Specular_Pre_Integration_PS.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\3-2 GRS_IBL_BRDF_Integration_LUT.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\4-1 GRS_PBR_IBL_VS_Multi_Instance.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\4-2 GRS_PBR_IBL_PS_Texture.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\5-1 GRS_SkyBox_With_Spherical_Map.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\5-2 GRS_SkyBox_With_CubeMap.hlsl">
<Filter>Shader</Filter>
</FxCompile>
<FxCompile Include="Shader\6-1 GRS_Quad_With_Dynamic_Index_Multi_Instance.hlsl">
<Filter>Shader</Filter>
</FxCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\Commons\GRS_Assimp_Loader.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
</Project>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
\ No newline at end of file
#define PI 3.14159265359
#define TWO_PI 6.28318530718
#define FOUR_PI 12.56637061436
#define FOUR_PI2 39.47841760436
#define INV_PI 0.31830988618
#define INV_TWO_PI 0.15915494309
#define INV_FOUR_PI 0.07957747155
#define HALF_PI 1.57079632679
#define INV_HALF_PI 0.636619772367
float RadicalInverse_VdC(uint bits)
{
bits = (bits << 16u) | (bits >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
}
float2 Hammersley(uint i, uint N)
{
return float2(float(i) / float(N), RadicalInverse_VdC(i));
}
// 等距柱状投影 转换到 Cube Map 的纹理坐标系
// 下面这段直接来自OpenGL的教程
//static const float2 invAtan = float2(0.1591, 0.3183);
//
//float2 SampleSphericalMap(float3 v)
//{
// //float2 v2UV = float2(atan(v.z/v.x), asin(v.y));
// float2 v2UV = float2(atan2(v.z, v.x), asin(v.y));
// v2UV *= invAtan;
// v2UV += 0.5;
// return v2UV;
//}
// 下面这个是修正后的HLSL版本
float2 SampleSphericalMap(float3 coord)
{
float theta = acos(coord.y);
float phi = atan2(coord.x, coord.z);
phi += (phi < 0) ? 2 * PI : 0;
float u = phi * 0.1591f;
float v = theta * 0.3183f;
return float2(u, v);
}
float DistributionGGX(float3 N, float3 H, float roughness)
{
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0f);
float NdotH2 = NdotH * NdotH;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0f) + 1.0f);
denom = PI * denom * denom;
return nom / denom;
}
float GeometrySchlickGGX_DirectLight(float NdotV, float roughness)
{// Point Light Versions
float r = (roughness + 1.0);
float k = (r * r) / 8.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
float GeometrySchlickGGX_IBL(float NdotV, float roughness)
{// IBL Versions
float a = roughness;
float k = (a * a) / 2.0f;
float nom = NdotV;
float denom = NdotV * (1.0f - k) + k;
return nom / denom;
}
float GeometrySmith_DirectLight(float NdotV,float NdotL, float roughness)
{
float ggx2 = GeometrySchlickGGX_DirectLight(NdotV, roughness);
float ggx1 = GeometrySchlickGGX_DirectLight(NdotL, roughness);
return ggx1 * ggx2;
}
float GeometrySmith_IBL(float NdotV,float NdotL, float roughness)
{
float ggx2 = GeometrySchlickGGX_IBL(NdotV, roughness);
float ggx1 = GeometrySchlickGGX_IBL(NdotL, roughness);
return ggx1 * ggx2;
}
float3 FresnelSchlick(float cosTheta, float3 F0)
{
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
float3 FresnelSchlickRoughness(float cosTheta, float3 F0, float roughness)
{
return F0 + (max(float3(1.0 - roughness, 1.0 - roughness, 1.0 - roughness), F0) - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
}
float3 ImportanceSampleGGX(float2 Xi, float3 N, float roughness)
{
float a = roughness * roughness;
float phi = 2.0f * PI * Xi.x;
float cosTheta = sqrt((1.0f - Xi.y) / (1.0f + (a * a - 1.0f) * Xi.y));
float sinTheta = sqrt(1.0f - cosTheta * cosTheta);
float3 H;
H.x = cos(phi) * sinTheta;
H.y = sin(phi) * sinTheta;
H.z = cosTheta;
float3 up = abs(N.z) < 0.999 ? float3(0.0f, 0.0f, 1.0f) : float3(1.0f, 0.0f, 0.0f);
float3 tangent = normalize(cross(up, N));
float3 bitangent = cross(N, tangent);
float3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
return normalize(sampleVec);
}
\ No newline at end of file
#define GRS_CUBE_MAP_FACE_CNT 6
#define GRS_LIGHT_COUNT 4
cbuffer CB_GRS_SCENE_MATRIX : register(b0)
{
matrix g_mxWorld;
matrix g_mxView;
matrix g_mxProj;
matrix g_mxWorldView;
matrix g_mxWVP;
matrix g_mxInvWVP;
matrix g_mxVP;
matrix g_mxInvVP;
};
cbuffer CB_GRS_GS_VIEW_MATRIX : register(b1)
{
matrix g_mxGSCubeView[GRS_CUBE_MAP_FACE_CNT]; // View matrices for cube map rendering
};
// Camera
cbuffer CB_GRS_SCENE_CAMERA : register(b2)
{
float4 g_v4EyePos;
float4 g_v4LookAt;
float4 g_v4UpDir ;
}
// lights
cbuffer CB_GRS_SCENE_LIGHTS : register(b3)
{
float4 g_v4LightPos[GRS_LIGHT_COUNT];
float4 g_v4LightColors[GRS_LIGHT_COUNT];
};
// Material
// 以下这些材质参数主要用于生成预积分贴图,与场景中物体表面材质没有关系
cbuffer CB_GRS_PBR_MATERIAL : register(b4)
{
float g_fMetallic; // 金属度
float g_fRoughness; // 粗糙度
float g_fAO; // 环境遮挡系数
float4 g_v4Albedo; // 反射率
};
cbuffer CB_GRS_MODEL_DATA : register(b5)
{
matrix g_mxModel2World;
};
\ No newline at end of file
#include "0-3 GRS_Scene_CB_Def.hlsli"
struct ST_GRS_HLSL_VS_IN
{
float4 m_v4LPos : POSITION; // Model Local position
};
struct ST_GRS_HLSL_VS_OUT
{
float4 m_v4HPos : SV_POSITION; // Projection coord
float4 m_v4WPos : POSITION; // World position
};
ST_GRS_HLSL_VS_OUT VSMain(ST_GRS_HLSL_VS_IN stVSInput)
{
ST_GRS_HLSL_VS_OUT stVSOutput;
stVSOutput.m_v4WPos = stVSInput.m_v4LPos;
// 从模型空间转换到世界坐标系
stVSOutput.m_v4HPos = mul(stVSInput.m_v4LPos, g_mxWVP);
return stVSOutput;
}
#include "0-3 GRS_Scene_CB_Def.hlsli"
struct ST_GRS_HLSL_VS_IN
{
float4 m_v4LPos : POSITION; // Model Local position
};
struct ST_GRS_HLSL_GS_IN
{
float4 m_v4WPos : SV_POSITION; // World position
};
struct ST_GRS_HLSL_GS_OUT
{
float4 m_v4HPos : SV_POSITION; // Projection coord
float4 m_v4WPos : POSITION; // World position
uint RTIndex : SV_RenderTargetArrayIndex;// Render Target Array Index
};
ST_GRS_HLSL_GS_IN VSMain(ST_GRS_HLSL_VS_IN stVSInput)
{
ST_GRS_HLSL_GS_IN stVSOutput;
// 从模型空间转换到世界坐标系
stVSOutput.m_v4WPos = mul(stVSInput.m_v4LPos, g_mxWorld);
return stVSOutput;
}
[maxvertexcount(18)]
void GSMain(triangle ST_GRS_HLSL_GS_IN stGSInput[3], inout TriangleStream<ST_GRS_HLSL_GS_OUT> CubeMapStream)
{
for ( int f = 0; f < GRS_CUBE_MAP_FACE_CNT; ++ f )
{
ST_GRS_HLSL_GS_OUT stGSOutput;
stGSOutput.RTIndex = f; //设定输出的缓冲索引
for (int v = 0; v < 3; v++)
{
// 下面的乘积是可以优化的,可以提前在 CPP 中 将6个View矩阵分别先与Projection矩阵相乘,再传入Shader
// 当然因为这里是固定的Cube
stGSOutput.m_v4WPos = stGSInput[v].m_v4WPos;
stGSOutput.m_v4HPos = mul(stGSInput[v].m_v4WPos, g_mxGSCubeView[f]);
stGSOutput.m_v4HPos = mul(stGSOutput.m_v4HPos, g_mxProj);
CubeMapStream.Append(stGSOutput);
}
CubeMapStream.RestartStrip();
}
}
\ No newline at end of file
#include "0-2 GRS_PBR_Function.hlsli"
Texture2D g_txHDR : register(t0);
SamplerState g_smpLinear : register(s0);
struct ST_GRS_HLSL_PS_IN
{
float4 m_v4HPos : SV_POSITION; // Projection coord
float4 m_v4WPos : POSITION; // World position
};
float4 PSMain(ST_GRS_HLSL_PS_IN stPSInput) : SV_Target
{
float2 v2UV = SampleSphericalMap(normalize(stPSInput.m_v4WPos.xyz));
return float4(g_txHDR.Sample(g_smpLinear, v2UV).rgb, 1.0f);
}
#include "0-2 GRS_PBR_Function.hlsli"
TextureCube g_texHDREnvCubemap : register(t0);
SamplerState g_sapLinear : register(s0);
struct ST_GRS_HLSL_PS_INPUT
{
float4 m_v4HPos : SV_POSITION;
float3 m_v4WPos : POSITION;
};
float4 PSMain(ST_GRS_HLSL_PS_INPUT pin):SV_Target
{
float3 N = normalize(pin.m_v4WPos.xyz);
float3 irradiance = float3(0.0f, 0.0f, 0.0f);
float3 up = float3(0.0f, 1.0f, 0.0f);
//float3 right = normalize(cross(N, up));
float3 right = normalize(cross(up, N));
up = normalize(cross(N, right));
//up = normalize(cross(right,N));
N = normalize(cross(right,up));
float nrSamples = 0.0f;
float deltaPhi = (2.0f * PI) / 180.0f;
float deltaTheta = (0.5f * PI) / 90.0f;
// 卷积运算,直接翻译自公式
for (float phi = 0.0f; phi < 2.0f * PI; phi += deltaPhi)
{
for (float theta = 0.0f; theta < 0.5f * PI; theta += deltaTheta)
{
// 球坐标转换到笛卡尔坐标(切空间)
float3 tangentSample = float3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
// 切空间转换到世界坐标空间
float3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N;
//float3 sampleVec = right;
irradiance += (g_texHDREnvCubemap.Sample(g_sapLinear, sampleVec).xyz * cos(theta) * sin(theta));
nrSamples += 1.0f;
}
}
irradiance = PI * irradiance * (1.0 / float(2 * nrSamples));
return float4(irradiance, 1.0f);
}
\ No newline at end of file
#include "0-2 GRS_PBR_Function.hlsli"
TextureCube g_texHDREnvCubemap : register(t0);
SamplerState g_sapLinear : register(s0);
struct ST_GRS_HLSL_PS_INPUT
{
float4 m_v4HPos : SV_POSITION;
float3 m_v4WPos : POSITION;
};
float4 PSMain(ST_GRS_HLSL_PS_INPUT stPSInput) :SV_Target
{
float3 N = normalize(stPSInput.m_v4WPos.xyz);
float3 irradiance = float3(0.0f,0.0f,0.0f);
// 计算切空间
float3 Up = float3(0.0f, 1.0f, 0.0f);
float fdot = dot(Up, N);
if ((1.0 - fdot) > 1e-6)
{
Up = float3(1.0f, 0.0f, 0.0f);
}
float3 Right = normalize(cross(Up, N));
Up = normalize(cross(N, Right));
N = normalize(cross(Right, Up));
float theta = 0.0f;
float phi = 0.0f;
float2 Xi;
float3 L;
const uint SAMPLE_NUM = 4096u;
for (uint i = 0u; i < SAMPLE_NUM; i++)
{
// 产生均匀分布随机数
Xi = Hammersley(i, SAMPLE_NUM);
// 根据 CDF 反函数计算指定分布的随机变量
phi = TWO_PI * Xi.x;
theta = asin(sqrt(Xi.y));
// 球坐标转换到笛卡尔坐标(切空间)
L = float3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta));
// 切空间转换到世界坐标空间
L = L.x * Right + L.y * Up + L.z * N;
// 采样求和统计入射辐照度
irradiance += g_texHDREnvCubemap.Sample(g_sapLinear, L).xyz;
}
// 取平均得到最终结果
irradiance *= 1.0 / float(SAMPLE_NUM);
return float4(irradiance,1.0f);
}
\ No newline at end of file
#include "0-2 GRS_PBR_Function.hlsli"
#include "0-3 GRS_Scene_CB_Def.hlsli"
TextureCube g_texHDREnvCubemap : register(t0);
SamplerState g_sapLinear : register(s0);
struct ST_GRS_HLSL_PS_INPUT
{
float4 m_v4HPos : SV_POSITION;
float3 m_v4WPos : POSITION;
};
float4 PSMain(ST_GRS_HLSL_PS_INPUT pin) : SV_Target
{
float3 N = normalize(pin.m_v4WPos.xyz);
float3 R = N;
float3 V = R;
uint SAMPLE_COUNT = 4096u;
float3 prefilteredColor = float3(0.0f, 0.0f, 0.0f);
float totalWeight = 0.0f;
for (uint i = 0; i < SAMPLE_COUNT; ++i)
{
// 生成均匀分布的无偏序列(Hammersley)
float2 Xi = Hammersley(i, SAMPLE_COUNT);
// 进行有偏的重要性采样
float3 H = ImportanceSampleGGX(Xi, N, g_fRoughness);
//float3 H = ImportanceSampleGGX(Xi, N, 0.1f);
float3 L = normalize(2.0f * dot(V, H) * H - V);
float NdotL = max(dot(N, L), 0.0f);
if ( NdotL > 0.0f )
{
//float D = DistributionGGX(N, H, roughness);
//float NdotH = max(dot(N, H), 0.0);
//float HdotV = max(dot(H, V), 0.0);
//float pdf = D * NdotH / (4.0 * HdotV) + 0.0001;
//float resolution = 512.0; // resolution of source cubemap (per face)
//float saTexel = 4.0 * PI / (6.0 * resolution * resolution);
//float saSample = 1.0 / (float(SAMPLE_COUNT) * pdf + 0.0001);
//float mipLevel = roughness == 0.0 ? 0.0 : 0.5 * log2(saSample / saTexel);
//prefilteredColor += textureLod(g_texHDREnvCubemap, L, mipLevel).rgb * NdotL;
//totalWeight += NdotL;
prefilteredColor += g_texHDREnvCubemap.Sample(g_sapLinear, L).rgb * NdotL;
totalWeight += NdotL;
}
}
prefilteredColor = prefilteredColor / totalWeight;
return float4(prefilteredColor, 1.0f);
}
\ No newline at end of file
#include "0-2 GRS_PBR_Function.hlsli"
struct ST_GRS_HLSL_VS_IN
{
float4 m_v4LPos : POSITION;
float2 m_v2UV : TEXCOORD;
};
struct ST_GRS_HLSL_VS_OUT
{
float4 m_v4HPos : SV_POSITION;
float2 m_v2UV : TEXCOORD;
};
ST_GRS_HLSL_VS_OUT VSMain(ST_GRS_HLSL_VS_IN stVSIn)
{
ST_GRS_HLSL_VS_OUT stVSOut = (ST_GRS_HLSL_VS_OUT)0.0f;
stVSOut.m_v2UV = stVSIn.m_v2UV;
//to clip space
stVSOut.m_v4HPos = stVSIn.m_v4LPos;
return stVSOut;
}
float2 IntegrateBRDF(float NdotV, float roughness)
{
float3 V;
V.x = sqrt(1.0f - NdotV * NdotV);
V.y = 0.0f;
V.z = NdotV;
float A = 0.0f;
float B = 0.0f;
float3 N = float3(0.0f, 0.0f, 1.0f);
uint SAMPLE_COUNT = 1024;
for (uint i = 0; i < SAMPLE_COUNT; ++i)
{
float2 Xi = Hammersley(i, SAMPLE_COUNT);
float3 H = ImportanceSampleGGX(Xi, N, roughness);
float3 L = normalize(2.0 * dot(V, H) * H - V);
float NdotL = max(L.z, 0.0);
float NdotH = max(H.z, 0.0);
float VdotH = max(dot(V, H), 0.0);
if (NdotL > 0.0)
{
float G = GeometrySmith_IBL( NdotV , NdotL , roughness);
float G_Vis = ( G * VdotH ) / ( NdotH * NdotV );
float Fc = pow(1.0 - VdotH, 5.0);
A += (1.0 - Fc) * G_Vis;
B += Fc * G_Vis;
}
}
A /= float(SAMPLE_COUNT);
B /= float(SAMPLE_COUNT);
return float2(A, B);
}
float2 PSMain(ST_GRS_HLSL_VS_OUT pin) :SV_TARGET
{
return IntegrateBRDF(pin.m_v2UV.x, pin.m_v2UV.y);
}
\ No newline at end of file
// Multi-Instance PBR IBL Vertex Shader
#include "0-3 GRS_Scene_CB_Def.hlsli"
struct ST_GRS_HLSL_PBR_VS_INPUT
{
float4 m_v4LPos : POSITION;
float4 m_v4LNormal : NORMAL;
float2 m_v2UV : TEXCOORD;
};
struct ST_GRS_HLSL_PBR_PS_INPUT
{
float4 m_v4HPos : SV_POSITION;
float4 m_v4WPos : POSITION;
float4 m_v4WNormal : NORMAL;
float2 m_v2UV : TEXCOORD;
};
SamplerState g_sapLinear : register(s0);
Texture2D g_texDisplacement : register(t2, space1); // 位移贴图(高度图)
ST_GRS_HLSL_PBR_PS_INPUT VSMain(ST_GRS_HLSL_PBR_VS_INPUT stVSInput)
{
ST_GRS_HLSL_PBR_PS_INPUT stVSOutput;
// 根据位移贴图直接改变物体外形,更好的做法是使用 Tesselation
float fDis = (g_texDisplacement.SampleLevel(g_sapLinear, stVSInput.m_v2UV, 0.0f).r * 0.1f);
stVSInput.m_v4LPos += fDis * normalize(stVSInput.m_v4LNormal);
// 局部坐标转换到世界空间和裁剪空间
stVSOutput.m_v4WPos = mul(stVSInput.m_v4LPos, g_mxModel2World);
stVSOutput.m_v4WPos = mul(stVSOutput.m_v4WPos, g_mxWorld);
stVSOutput.m_v4HPos = mul(stVSOutput.m_v4WPos, g_mxVP);
// 法线先变换到世界坐标系中,再进行世界坐标变换;
stVSInput.m_v4LNormal.w = 0.0f;
stVSOutput.m_v4WNormal = mul(stVSInput.m_v4LNormal, g_mxModel2World);
stVSOutput.m_v4WNormal = normalize(mul(stVSOutput.m_v4WNormal, g_mxWorld));
stVSOutput.m_v2UV = stVSInput.m_v2UV;
return stVSOutput;
}
\ No newline at end of file
#include "0-3 GRS_Scene_CB_Def.hlsli"
#include "0-2 GRS_PBR_Function.hlsli"
#include "0-1 HDR_COLOR_CONV.hlsli"
SamplerState g_sapLinear : register(s0);
// IBL Lights
TextureCube g_texSpecularCubemap : register(t0, space0); // 镜面反射
TextureCube g_texDiffuseCubemap : register(t1, space0); // 漫反射光照
Texture2D g_texLut : register(t2, space0); // BRDF LUT
// PBR Material
Texture2D g_texAlbedo : register(t0, space1); // 基础反射率(Base Color or Albedo)
Texture2D g_texNormal : register(t1, space1); // 法线
Texture2D g_texDisplacement : register(t2, space1); // 位移贴图(高度图)
Texture2D g_texMetalness : register(t3, space1); // 金属度
Texture2D g_texRoughness : register(t4, space1); // 粗糙度
Texture2D g_texAO : register(t5, space1); // AO
struct ST_GRS_HLSL_PBR_PS_INPUT
{
// Per Vertex Data
float4 m_v4HPos : SV_POSITION;
float4 m_v4WPos : POSITION;
float4 m_v4WNormal : NORMAL;
float2 m_v2UV : TEXCOORD;
};
float3 CalcNewNormal(float2 v2UV, float3 v3Pos, float3 v3OldNormal/*ST_GRS_HLSL_VS_OUTPUT stPSInput*/)
{
float fDisplacementScale = 0.1f;
// 水平方向uv的增量
float2 v2UVdx = ddx_fine(v2UV);
// 垂直方向uv的增量
float2 v2UVdy = ddy_fine(v2UV);
// 当前置换距离
float fHeight = g_texDisplacement.Sample(g_sapLinear, v2UV).r;
// 水平方向下一个像素点的置换距离
float fHx = g_texDisplacement.Sample(g_sapLinear, v2UV + v2UVdx).r;
// 垂直方向下一个像素点的置换距离
float fHy = g_texDisplacement.Sample(g_sapLinear, v2UV + v2UVdy).r;
// 水平方向置换增量
float fHdx = (fHx - fHeight) * fDisplacementScale;
// 垂直方向置换增量
float fHdy = (fHy - fHeight) * fDisplacementScale;
// 水平方向顶点坐标增量,作为切线
float3 v3Tangent = ddx_fine(v3Pos.xyz);
// 垂直方向顶点坐标增量,作为副切线
float3 v3BinTangent = ddy_fine(v3Pos.xyz);
// 到这里为止,其实已经可以用 v3Tangent 差乘 v3BinTangent 来得到 v3NewNormal 了
// 但是会发现 v3NewNormal 并不平滑,用来计算光照会出现硬边
// 解决办法是使用从 vertex shader 传过来的 normal 来进行纠正,顶点上的 normal 是平滑的
// corss 部分就是用平滑的 normal 来重新计算新的 v3Tangent
// 后面加法是使用置换增量来对其进行扰动
float3 v3NewTangent = cross(v3BinTangent, v3OldNormal) + v3OldNormal * fHdx;
// 同理
float3 v3NewBinTangent = cross(v3OldNormal, v3Tangent) + v3OldNormal * fHdy;
// 最终得到平滑的 v3NewNormal
float3 v3NewNormal = cross(v3NewTangent, v3NewBinTangent);
v3NewNormal = normalize(v3NewNormal);
// 这里就可以使用这个 v3NewNormal 参与光照计算了
return v3NewNormal;
}
float4 PSMain(ST_GRS_HLSL_PBR_PS_INPUT stPSInput) : SV_TARGET
{
float3 v3Albedo = g_texAlbedo.Sample(g_sapLinear, stPSInput.m_v2UV).rgb;
float3 N = g_texNormal.Sample(g_sapLinear, stPSInput.m_v2UV).xyz;
float fMetallic = g_texMetalness.Sample(g_sapLinear, stPSInput.m_v2UV).r;
float fRoughness = g_texRoughness.Sample(g_sapLinear, stPSInput.m_v2UV).r;
float fAO = g_texAO.Sample(g_sapLinear, stPSInput.m_v2UV).r;
// 法线贴图中取得的法线的标准解算
N = 2.0f * N - 1.0f;
N = normalize(N);
// 计算切空间
float3 up = float3(0.0f, 1.0f, 0.0f);
if (dot(up, stPSInput.m_v4WNormal.xyz) < 1e-6)
{
up = float3(1.0f, 0.0f, 0.0f);
}
float3 right = normalize(cross(up, stPSInput.m_v4WNormal.xyz));
up = cross(stPSInput.m_v4WNormal.xyz, right);
// 重新计算逐像素法线
N = right * N.x + up * N.y + stPSInput.m_v4WNormal.xyz * N.z;
//N = CalcNewNormal(stPSInput.m_v2UV, stPSInput.m_v4WPos.xyz, N);
//return float4(N, 1.0f);
//return float4(v3Albedo, 1.0f);
//return float4(fMetallic, 0.0f, 0.0f, 1.0f);
//return float4(fRoughness, 0.0f, 0.0f, 1.0f);
//return float4(fAO, 0.0f, 0.0f, 1.0f);
// 颜色转换到线性空间(纹理颜色空间本身就是线性空间时,不需要这个转换)
//v3Albedo = SRGBToLinear(v3Albedo);
float3 V = normalize(g_v4EyePos.xyz - stPSInput.m_v4WPos.xyz); // 视向量
float3 R = reflect(-V, N); // 视向量的镜面反射向量
float3 F0 = float3(0.04f, 0.04f, 0.04f);
F0 = lerp(F0, v3Albedo, fMetallic);
float3 Lo = float3(0.0f,0.0f,0.0f);
float NdotV = max(dot(N, V), 0.0f);
// 首先按照之前的样子计算直接光照的效果
for (int i = 0; i < GRS_LIGHT_COUNT; ++i)
{
// 计算点光源的照射
// 因为是多实例渲染,所以对每个光源做下位置变换,这样相当于每个实例有了自己的光源
// 注意这不是标准操作,一定要注意正式的代码中不要这样做
float4 v4LightWorldPos = mul(g_v4LightPos[i], g_mxWorld);
float3 L = v4LightWorldPos.xyz - stPSInput.m_v4WPos.xyz; // 入射光线
float distance = length(L);
float attenuation = 1.0 / (distance * distance);
float3 radiance = g_v4LightColors[i].rgb * attenuation; // 距离平方反比衰减
L = normalize(L);
float3 H = normalize(V + L); // 视向量与光线向量的中间向量
float NdotL = max(dot(N, L), 0.0f);
// Cook-Torrance BRDF
float NDF = DistributionGGX(N, H, fRoughness);
float G = GeometrySmith_DirectLight(NdotV ,NdotL , fRoughness);
float3 F = FresnelSchlick(NdotV , F0);
float3 numerator = NDF * G * F;
float denominator = 4.0 * NdotV * NdotL + 0.0001; // + 0.0001 to prevent divide by zero
float3 specular = numerator / denominator;
float3 kS = F;
float3 kD = float3(1.0f,1.0f,1.0f) - kS;
kD *= 1.0 - fMetallic;
Lo += (kD * v3Albedo / PI + specular) * radiance * NdotL; // note that we already multiplied the BRDF by the Fresnel (kS) so we won't multiply by kS again
}
// 接着开始利用前面的预积分结果计算IBL光照的效果
// 根据粗糙度插值计算菲涅尔系数(与直接光照的菲涅尔系数计算方法不同)
float3 F = FresnelSchlickRoughness(NdotV, F0, fRoughness);
float3 kS = F;
float3 kD = 1.0 - kS;
kD *= (1.0 - fMetallic); // 简单但非常重要的计算步骤,表达了纯金属是没有漫反射的
// IBL漫反射环境光部分
float3 irradiance = g_texDiffuseCubemap.Sample(g_sapLinear, N).rgb;
float3 diffuse = irradiance * v3Albedo;
float fCubeWidth = 0.0f;
float fCubeHeight = 0.0f;
float fCubeMapLevels = 0.0f;
// 获取 CubeMap 的 Max Maplevels
g_texSpecularCubemap.GetDimensions(0, fCubeWidth, fCubeHeight, fCubeMapLevels);
// IBL镜面反射环境光部分
float3 prefilteredColor = g_texSpecularCubemap.SampleLevel(g_sapLinear, R, fRoughness * fCubeMapLevels).rgb;
float2 brdf = g_texLut.Sample(g_sapLinear, float2(NdotV, fRoughness)).rg;
float3 specular = prefilteredColor * (F0 * brdf.x + brdf.y);
// IBL 光照合成
float3 ambient = (kD * diffuse + specular) * fAO;
// 直接光照 + IBL光照
float3 color = ambient + Lo;
//return float4(color, 1.0f);
// Gamma
return float4(LinearToSRGB(color),1.0f);
}
\ No newline at end of file
#include "0-1 HDR_COLOR_CONV.hlsli"
#include "0-2 GRS_PBR_Function.hlsli"
#include "0-3 GRS_Scene_CB_Def.hlsli"
Texture2D g_txSphericalMap : register(t0);
SamplerState g_smpLinear : register(s0);
struct ST_GRS_HLSL_VS_IN
{
float4 m_v4LPos : POSITION;
};
struct ST_GRS_HLSL_PS_IN
{
float4 m_v4LPos : SV_POSITION;
float4 m_v4PPos : TEXCOORD0;
};
ST_GRS_HLSL_PS_IN SkyboxVS(ST_GRS_HLSL_VS_IN stVSInput)
{
ST_GRS_HLSL_PS_IN stVSOutput;
stVSOutput.m_v4LPos = stVSInput.m_v4LPos;
stVSOutput.m_v4PPos = normalize(mul(stVSInput.m_v4LPos, g_mxInvVP));
return stVSOutput;
}
float4 SkyboxPS(ST_GRS_HLSL_PS_IN stPSInput) : SV_TARGET
{
float2 v2UV = SampleSphericalMap(normalize(stPSInput.m_v4PPos.xyz));
return float4(g_txSphericalMap.Sample(g_smpLinear, v2UV).rgb,1.0f);
}
#include "0-1 HDR_COLOR_CONV.hlsli"
#include "0-3 GRS_Scene_CB_Def.hlsli"
TextureCube g_txCubeMap : register(t0);
SamplerState g_smpLinear : register(s0);
struct ST_GRS_HLSL_VS_IN
{
float4 m_v4LPos : POSITION;
};
struct ST_GRS_HLSL_PS_IN
{
float4 m_v4LPos : SV_POSITION;
float4 m_v4PPos : TEXCOORD0;
};
ST_GRS_HLSL_PS_IN SkyboxVS(ST_GRS_HLSL_VS_IN stVSInput)
{
ST_GRS_HLSL_PS_IN stVSOutput;
stVSOutput.m_v4LPos = stVSInput.m_v4LPos;
stVSOutput.m_v4PPos = normalize(mul(stVSInput.m_v4LPos, g_mxInvVP));
return stVSOutput;
}
float4 SkyboxPS(ST_GRS_HLSL_PS_IN stPSInput) : SV_TARGET
{
float3 v3SRGBColor = LinearToSRGB(g_txCubeMap.Sample(g_smpLinear, stPSInput.m_v4PPos.xyz).rgb);
return float4(v3SRGBColor,1.0f);
}
#include "0-1 HDR_COLOR_CONV.hlsli"
#include "0-3 GRS_Scene_CB_Def.hlsli"
Texture2D g_Texture2DArray[] : register(t0);
SamplerState g_smpLinear : register(s0);
struct ST_GRS_HLSL_VS_IN
{
float4 m_v4LPosition : POSITION;
float4 m_v4Color : COLOR0;
float2 m_v2UV : TEXCOORD;
float4x4 m_mxQuad2World : WORLD;
uint m_nTextureIndex : COLOR1;
};
struct ST_GRS_HLSL_PS_IN
{
float4 m_v4Position : SV_POSITION;
float4 m_v4Color : COLOR0;
float2 m_v2UV : TEXCOORD;
uint m_nTextureIndex : COLOR1;
};
ST_GRS_HLSL_PS_IN VSMain( ST_GRS_HLSL_VS_IN stVSInput )
{
ST_GRS_HLSL_PS_IN stVSOutput;
stVSOutput.m_v4Position = mul(stVSInput.m_v4LPosition, stVSInput.m_mxQuad2World);
// 下面两句是二选一,一般2D渲染的时候 World 和 View 矩阵都取了单位矩阵,但不排除特殊情况,所以一般还是乘以MVP综合矩阵
//stVSOutput.m_v4Position = mul(stVSOutput.m_v4Position, g_mxProj);
stVSOutput.m_v4Position = mul(stVSOutput.m_v4Position, g_mxWVP);
stVSOutput.m_v4Color = stVSInput.m_v4Color;
stVSOutput.m_v2UV = stVSInput.m_v2UV;
stVSOutput.m_nTextureIndex = stVSInput.m_nTextureIndex;
return stVSOutput;
}
float4 PSMain(ST_GRS_HLSL_PS_IN stPSInput) : SV_TARGET
{
//float3 v3SRGBColor
//= LinearToSRGB(g_Texture2DArray[stPSInput.m_nTextureIndex].Sample(g_smpLinear, stPSInput.m_v2UV).rgb);
//return float4(v3SRGBColor,1.0f);
return float4(g_Texture2DArray[stPSInput.m_nTextureIndex].Sample(g_smpLinear, stPSInput.m_v2UV).rgb,1.0f);
}
These texture files were created by FreePBR.com and may be used freely in your video games and 3d work at no cost. They may not however be redistributed on other websites or anywhere else other than FreePBR.com. We think that is more than fair. :) We also would greatly appreciate it if some sorrt of credit was given if you do indeed use these textures in a published game. Other than that, keep on creating and have fun. :)
\ No newline at end of file
[.ShellClassInfo]
InfoTip=This folder is shared online.
IconFile=C:\Program Files\Google\Drive\googledrivesync.exe
IconIndex=16
\ No newline at end of file
此差异已折叠。
......@@ -5,9 +5,12 @@
#include <wincodec.h> //for WIC
#include <d3d12.h> //for d3d12
#include <wrl.h> //添加WTL支持 方便使用COM
#include <atlexcept.h>
#include "GRS_Def.h"
#include "GRS_Mem.h"
using namespace ATL;
using namespace Microsoft;
using namespace Microsoft::WRL;
......@@ -61,6 +64,8 @@ static WICConvert g_WICConvert[] =
{ GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
{ GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
//// 2021-06-12
//{ GUID_WICPixelFormat8bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM
{ GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT
{ GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT
......@@ -137,7 +142,7 @@ __inline BOOL WICLoadImageFromFile(LPCWSTR pszTextureFile
, UINT& nTextureH
, UINT& nPicRowPitch
, BYTE*& pbImageData
, size_t& szBufferSize )
, size_t& szBufferSize)
{
BOOL bRet = TRUE;
try
......@@ -174,43 +179,36 @@ __inline BOOL WICLoadImageFromFile(LPCWSTR pszTextureFile
WICPixelFormatGUID wpf = {};
//获取WIC图片格式
GRS_THROW_IF_FAILED(pIWICFrame->GetPixelFormat(&wpf));
GUID tgFormat = {};
//通过第一道转换之后获取DXGI的等价格式
if (GetTargetPixelFormat(&wpf, &tgFormat))
{
emTextureFormat = GetDXGIFormatFromPixelFormat(&tgFormat);
}
// 尝试是否可以直接使用
emTextureFormat = GetDXGIFormatFromPixelFormat(&wpf);
GUID tgFormat = { wpf };
if (DXGI_FORMAT_UNKNOWN == emTextureFormat)
{// 不支持的图片格式 目前退出了事
// 一般 在实际的引擎当中都会提供纹理格式转换工具,
{// 直接不支持的图片格式 尝试一下兼容性转换
// 一般在实际的引擎当中都会提供纹理格式转换工具,
// 图片都需要提前转换好,所以不会出现不支持的现象
AtlThrow(S_FALSE);
}
if (!InlineIsEqualGUID(wpf, tgFormat))
{// 这个判断很重要,如果原WIC格式不是直接能转换为DXGI格式的图片时
// 我们需要做的就是转换图片格式为能够直接对应DXGI格式的形式
//创建图片格式转换器
ComPtr<IWICFormatConverter> pIConverter;
GRS_THROW_IF_FAILED(pIWICFactory->CreateFormatConverter(&pIConverter));
//初始化一个图片转换器,实际也就是将图片数据进行了格式转换
GRS_THROW_IF_FAILED(pIConverter->Initialize(
pIWICFrame.Get(), // 输入原图片数据
tgFormat, // 指定待转换的目标格式
WICBitmapDitherTypeNone, // 指定位图是否有调色板,现代都是真彩位图,不用调色板,所以为None
NULL, // 指定调色板指针
0.f, // 指定Alpha阀值
WICBitmapPaletteTypeCustom // 调色板类型,实际没有使用,所以指定为Custom
));
// 调用QueryInterface方法获得对象的位图数据源接口
GRS_THROW_IF_FAILED(pIConverter.As(&pIBMP));
//通过第一道转换之后获取DXGI的等价格式
if (GetTargetPixelFormat(&wpf, &tgFormat))
{
emTextureFormat = GetDXGIFormatFromPixelFormat(&tgFormat);
ComPtr<IWICFormatConverter> pIConverter;
GRS_THROW_IF_FAILED(pIWICFactory->CreateFormatConverter(&pIConverter));
//初始化一个图片转换器,实际也就是将图片数据进行了格式转换
GRS_THROW_IF_FAILED(pIConverter->Initialize(
pIWICFrame.Get(), // 输入原图片数据
tgFormat, // 指定待转换的目标格式
WICBitmapDitherTypeNone, // 指定位图是否有调色板,现代都是真彩位图,不用调色板,所以为None
NULL, // 指定调色板指针
0.f, // 指定Alpha阀值
WICBitmapPaletteTypeCustom // 调色板类型,实际没有使用,所以指定为Custom
));
// 调用QueryInterface方法获得对象的位图数据源接口
GRS_THROW_IF_FAILED(pIConverter.As(&pIBMP));
}
}
else
{
//图片数据格式不需要转换,直接获取其位图数据源接口
//获取位图数据源接口
GRS_THROW_IF_FAILED(pIWICFrame.As(&pIBMP));
}
//获得图片大小(单位:像素)
......@@ -251,7 +249,7 @@ __inline BOOL WICLoadImageFromFile(LPCWSTR pszTextureFile
GRS_THROW_IF_FAILED(pIBMP->CopyPixels(nullptr
, nPicRowPitch
, static_cast<UINT>(szImageBuffer)
, pbPicData) );
, pbPicData));
pbImageData = pbPicData;
szBufferSize = szImageBuffer;
......
......@@ -55,6 +55,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "25-IBL-MultiInstance-Sphere
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "26-Normal-Map-And-Tangent-Space", "26-Normal-Map-And-Tangent-Space\26-Normal-Map-And-Tangent-Space.vcxproj", "{469021D1-DAEC-4EFB-8A1E-A148A1E4EF20}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "27-IBL-With-Material-Texture", "27-IBL-With-Material-Texture\27-IBL-With-Material-Texture.vcxproj", "{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
......@@ -377,6 +379,18 @@ Global
{469021D1-DAEC-4EFB-8A1E-A148A1E4EF20}.Release|x64.Build.0 = Release|x64
{469021D1-DAEC-4EFB-8A1E-A148A1E4EF20}.Release|x86.ActiveCfg = Release|Win32
{469021D1-DAEC-4EFB-8A1E-A148A1E4EF20}.Release|x86.Build.0 = Release|Win32
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Debug|x64.ActiveCfg = Debug|x64
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Debug|x64.Build.0 = Debug|x64
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Debug|x86.ActiveCfg = Debug|Win32
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Debug|x86.Build.0 = Debug|Win32
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Profile|x64.ActiveCfg = Debug|x64
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Profile|x64.Build.0 = Debug|x64
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Profile|x86.ActiveCfg = Debug|Win32
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Profile|x86.Build.0 = Debug|Win32
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Release|x64.ActiveCfg = Release|x64
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Release|x64.Build.0 = Release|x64
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Release|x86.ActiveCfg = Release|Win32
{5CB8B4F5-1BF1-475D-B0A0-83BE20E30061}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......
{
"name": "GRSD3D12Sample",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册