一、粗糙度贴图的概念
粗糙度贴图是一种用于增强3D模型表现力的技术,是指在建模过程中,通过在模型表面增加一层颜色或者灰度纹理贴图,来模拟物体表面的微小凹凸不平,从而增加物体表面的细节和真实感。
常见的粗糙度贴图包括:反射率贴图、法线贴图、置换贴图、高光贴图等。
二、粗糙度贴图的种类和应用
1、反射率贴图
反射率贴图用于影响物体表面的反射度,比如镜面反射。
下面是一段实现反射率贴图的代码示例:
float4 ReflectanceMapPS(PSInput input) : SV_Target { float4 diffuse = texDiffuse.Sample(ss, input.TexCoord); float3 normal = texNormal.Sample(ss, input.TexCoord).rgb * 2 - 1; float3 specular = pow(max(dot(normal, eyeVector), 0), shininess) * texSpecular.Sample(ss, input.TexCoord).rgb; return float4((diffuse.rgb + emissive.rgb) * ambient.rgb + diffuse.rgb * lightColor.rgb + specular * lightColor.rgb, texDiffuse.Sample(ss, input.TexCoord).a); }
2、法线贴图
法线贴图是一种用来模拟3D模型表面细节的技术,通过在模型表面以纹理的方式存储法线向量,来增强物体表面的细节感。
下面是一段实现法线贴图的代码示例:
float3 NormalMapPS(PSInput input) : SV_Target { float3 normal = texNormal.Sample(ss, input.TexCoord).rgb * 2 - 1; float3 tangent = normalize(tangentVector - input.WorldNormal * dot(tangentVector, input.WorldNormal)); float3 bitangent = cross(input.WorldNormal, tangent) * tangent.w; float3x3 tbn = float3x3(tangent, bitangent, input.WorldNormal); normal = normalize(mul(normal, tbn)); return normal * 0.5f + 0.5f; }
3、置换贴图
置换贴图是一种用于模拟物体表面几何细节的技术,通过将几何信息存储在纹理中,并在运行时将几何信息应用到模型中,增加模型表面的凹凸感。
下面是一段实现置换贴图的代码示例:
float4 DisplacementMapPS(PSInput input) : SV_Target { float4 pos = mul(float4(input.WorldPos, 1), viewProj); pos /= pos.w; float3 normal = texNormal.Sample(ss, input.TexCoord).rgb * 2 - 1; float height = texHeight.Sample(ss, input.TexCoord).r; float3x3 tbn = float3x3(input.WorldTangent, input.WorldBinormal, input.WorldNormal); float4 offset = float4(normal * height * displacementScale, 0); offset = mul(offset, tbn); pos.xyz += offset.xyz; return texDiffuse.Sample(ss, input.TexCoord); }
4、高光贴图
高光贴图用于模拟3D模型表面的高亮反射,增加物体表面的反射感。
下面是一段实现高光贴图的代码示例:
float4 SpecularMapPS(PSInput input) : SV_Target { float3 normal = texNormal.Sample(ss, input.TexCoord).rgb * 2 - 1; float3 reflection = normalize(reflect(-lightVector, normal)); float specular = pow(saturate(dot(reflection, eyeVector)), shininess) * texSpecular.Sample(ss, input.TexCoord).r; return float4(specular, specular, specular, 1); }
三、粗糙度贴图的优化
1、压缩纹理
在使用粗糙度贴图的时候,可以采用压缩纹理的方式来减小纹理资源的体积,从而节省显存和提高加载速度。
下面是一段实现压缩纹理的代码示例:
D3DX11CreateTextureFromFile(device, L"texture.dds", NULL, NULL, &texture, NULL); D3DX11CreateShaderResourceViewFromFile(device, L"texture.dds", NULL, NULL, &textureSRV, NULL);
2、使用MipMaps
MipMaps可以用来处理粗糙度贴图的采样问题,在远处使用低分辨率的MipMap,近处使用高分辨率的MipMap,从而避免了远处纹理变得模糊,近处纹理变得失真的问题。
下面是一段使用MipMaps的代码示例:
D3DX11CreateTextureFromFile(device, L"texture.dds", NULL, NULL, &texture, NULL); D3DX11CreateShaderResourceViewFromFile(device, L"texture.dds", NULL, NULL, &textureSRV, NULL); D3D11_SAMPLER_DESC samplerDesc; samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; samplerDesc.MinLOD = 0; samplerDesc.MaxLOD = D3D11_FLOAT32_MAX; device->CreateSamplerState(&samplerDesc, &samplerState); context->PSSetSamplers(0, 1, &samplerState);
3、使用纹理阵列
纹理阵列可以用来存储多个纹理,在顶点/像素着色器中使用数组下标进行访问,从而避免了频繁地在GPU和CPU之间切换纹理。此外,纹理阵列还可以用于实现环境贴图等效果。
下面是一段实现纹理阵列的代码示例:
D3DX11CreateTextureFromFile(device, L"textureArray.dds", NULL, NULL, &textureArray, NULL); D3DX11CreateShaderResourceViewFromFile(device, L"textureArray.dds", NULL, NULL, &textureArraySRV, NULL); context->PSSetShaderResources(0, 1, &textureArraySRV);
4、使用GPU实现采样
使用GPU实现纹理采样可以避免在CPU和GPU之间频繁地拷贝纹理数据,从而提高渲染效率。
下面是一段使用GPU实现纹理采样的代码示例:
Texture2D tex : register(t0); SamplerState samp : register(s0); cbuffer ConstantBuffer : register(b0) { float4x4 worldViewProj; }; struct VS_INPUT { float3 pos : POSITION; float3 norm : NORMAL; float2 texCoord : TEXCOORD; }; struct PS_INPUT { float4 pos : SV_POSITION; float3 norm : NORMAL; float2 texCoord : TEXCOORD; }; PS_INPUT main(VS_INPUT input) { PS_INPUT output; output.pos = mul(worldViewProj, float4(input.pos, 1.0f)); output.norm = input.norm; output.texCoord = input.texCoord; return output; } float4 main(PS_INPUT input) : SV_TARGET { return tex.Sample(samp, input.texCoord); }
四、结语
粗糙度贴图是一项非常重要的技术,可以大大增强3D模型的表现力,让模型更真实、更细致。希望通过这篇文章的介绍,能够对粗糙度贴图技术有更深入的了解,同时也希望大家在实际的开发中能够充分应用这项技术,为游戏的画面质量提升做出自己的贡献。