Shader 使用纹理图集时HLSL颜色溢出
我正在用C#/XNA做一个游戏。我目前正在处理将用于地形的着色器。为了提高速度和效率,我使用了纹理图集,但我在瓷砖之间遇到纹理/颜色出血: 我在FXComposer和我的游戏中都得到了这种效果。这是我的着色器:Shader 使用纹理图集时HLSL颜色溢出,shader,textures,hlsl,atlas,Shader,Textures,Hlsl,Atlas,我正在用C#/XNA做一个游戏。我目前正在处理将用于地形的着色器。为了提高速度和效率,我使用了纹理图集,但我在瓷砖之间遇到纹理/颜色出血: 我在FXComposer和我的游戏中都得到了这种效果。这是我的着色器: //----------------------------------------------------------------------------- // InstancedModel.fx // // Microsoft XNA Community Game Platfor
//-----------------------------------------------------------------------------
// InstancedModel.fx
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
// Camera settings.
float4x4 World : World < string UIWidget="None"; >;
float4x4 View : View < string UIWidget="None"; >;
float4x4 Projection : Projection < string UIWidget="None"; >;
// This sampler uses a simple Lambert lighting model.
float3 LightDirection = normalize(float3(-1, -1, -1));
float3 DiffuseLight = 1.25;
float3 AmbientLight = 0.25;
float TextureSide = 0; //0 = top, 1 = side, 2 = bottom
float2 TextureCoord;
texture Texture;
float2 TextureSize = 2.0;
sampler Sampler = sampler_state
{
Texture = (Texture);
MinFilter = Linear;
MipFilter = Linear;
MagFilter = Linear;
AddressU = Clamp;
AddressV = Clamp;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float2 TextureCoordinate : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Color : COLOR0;
float2 TextureCoordinate : TEXCOORD0;
};
// Vertex shader helper function shared between the two techniques.
VertexShaderOutput VertexShaderCommon(VertexShaderInput input, float4x4 instanceTransform, float2 atlasCoord, float4 colour)
{
VertexShaderOutput output;
// Apply the world and camera matrices to compute the output position.
float4 worldPosition = mul(input.Position, instanceTransform);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
// Compute lighting, using a simple Lambert model.
float3 worldNormal = mul(input.Normal, instanceTransform);
float diffuseAmount = max(-dot(worldNormal, LightDirection), 0);
float3 lightingResult = saturate(diffuseAmount * DiffuseLight + AmbientLight);
output.Color = float4(lightingResult, 1);
output.Color = output.Color * colour;
//calculate texture coords
float2 InputTextureCoords = input.TextureCoordinate;// / TextureSize;
float2 InputAtlasCoords = atlasCoord;// / TextureSize;
float2 textCoordsActual = InputTextureCoords + InputAtlasCoords;
output.TextureCoordinate = textCoordsActual;
return output;
}
// Hardware instancing reads the per-instance world transform from a secondary vertex stream.
VertexShaderOutput HardwareInstancingVertexShader(VertexShaderInput input,
float4x4 instanceTransform : BLENDWEIGHT,
float2 atlasCoord1 : TEXCOORD1, float2 atlasCoord2 : TEXCOORD2, float2 atlasCoord3 : TEXCOORD3,
float4 colour : COLOR1)
{
float2 atlasCoord = atlasCoord1;
if (TextureSide == 1)
{
atlasCoord = atlasCoord1;
}
if (TextureSide == 2)
{
atlasCoord = atlasCoord2;
}
else if (TextureSide == 3)
{
atlasCoord = atlasCoord3;
}
return VertexShaderCommon(input, mul(World, transpose(instanceTransform)), atlasCoord, colour);
}
// When instancing is disabled we take the world transform from an effect parameter.
VertexShaderOutput NoInstancingVertexShader(VertexShaderInput input,
float4x4 instanceTransform : BLENDWEIGHT,
float2 atlasCoord1 : TEXCOORD1, float2 atlasCoord2 : TEXCOORD2, float2 atlasCoord3 : TEXCOORD3,
float4 colour : COLOR1)
{
return VertexShaderCommon(input, World, TextureCoord, float4(1,1,1,1));
}
float2 HalfPixileCorrectedCoords(float2 coords)
{
float u = (coords.x) / TextureSize;
float v = (coords.y) / TextureSize;
return float2(u, v);
}
// Both techniques share this same pixel shader.
float4 PixelShaderFunction(VertexShaderOutput input,
float2 atlasCoord1 : TEXCOORD1) : COLOR00
{
float2 outputTextureCoords = HalfPixileCorrectedCoords(input.TextureCoordinate);
return tex2D(Sampler, outputTextureCoords) * input.Color;
}
// Hardware instancing technique.
technique HardwareInstancing
{
pass Pass1
{
VertexShader = compile vs_3_0 HardwareInstancingVertexShader();
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}
// For rendering without instancing.
technique NoInstancing
{
pass Pass1
{
VertexShader = compile vs_3_0 NoInstancingVertexShader();
PixelShader = compile ps_3_0 PixelShaderFunction();
}
}
//-----------------------------------------------------------------------------
//InstancedModel.fx
//
//微软XNA社区游戏平台
//版权所有(C)微软公司。版权所有。
//-----------------------------------------------------------------------------
//相机设置。
float4x4世界:世界;
float4x4视图:视图;
float4x4投影:投影;
//此采样器使用简单的Lambert照明模型。
float3 LightDirection=normalize(float3(-1,-1,-1));
float3漫射光=1.25;
float3环境光=0.25;
float-TextureSide=0//0=顶部,1=侧面,2=底部
浮动2纹理命令;
纹理;
float2-TextureSize=2.0;
采样器采样器=采样器状态
{
纹理=(纹理);
MinFilter=线性;
MipFilter=线性;
磁滤波器=线性;
地址U=夹具;
地址V=钳位;
};
结构VertexShaderInput
{
浮动4位置:位置0;
float3 Normal:NORMAL0;
float2纹理坐标:TEXCOORD0;
};
结构VertexShaderOutput
{
浮动4位置:位置0;
float4颜色:COLOR0;
float2纹理坐标:TEXCOORD0;
};
//顶点着色器辅助函数在两种技术之间共享。
VertexShaderOutput VertexShaderCommon(VertexShaderInput输入、浮点4x4实例转换、浮点2 Atlascord、浮点4颜色)
{
VertexShaderOutput输出;
//应用世界和摄影机矩阵来计算输出位置。
float4 worldPosition=mul(input.Position,instanceTransform);
float4 viewPosition=mul(世界位置,视图);
输出位置=mul(视图位置、投影);
//使用简单的Lambert模型计算照明。
float3 worldNormal=mul(input.Normal,instanceTransform);
浮动扩散量=最大值(-dot(世界法线,光照方向),0);
float3 lightingResult=饱和(扩散量*扩散光+环境光);
output.Color=float4(lightingResult,1);
output.Color=output.Color*Color;
//计算纹理坐标
float2 InputTextureCoords=input.TextureCoords;///TextureSize;
float2 InputAtlasCoords=Atlascord;///TextureSize;
float2 textCoordsActual=inputExtureCoords+inputAtlasoords;
output.texturecoordinal=textCoordsActual;
返回输出;
}
//硬件实例从次顶点流读取每个实例的世界变换。
VertexShader输出硬件安装VertexShader(VertexShaderInput输入,
float4x4实例转换:混合重量,
浮动2大西洋城1:TEXCOORD1,浮动2大西洋城2:TEXCOORD2,浮动2大西洋城3:TEXCOORD3,
浮动4颜色:彩色1)
{
float2 atlasCoord=atlasCoord1;
如果(TextureSide==1)
{
Atlascord=Atlascord1;
}
如果(TextureSide==2)
{
Atlascord=Atlascord2;
}
else if(TextureSide==3)
{
Atlascord=Atlascord3;
}
返回VertexShaderCommon(输入,mul(世界,转置(instanceTransform)),Atlascord,颜色);
}
//禁用实例化时,我们从效果参数获取世界变换。
VertexShaderOutput无安装VertexShader(VertexShaderInput,
float4x4实例转换:混合重量,
浮动2大西洋城1:TEXCOORD1,浮动2大西洋城2:TEXCOORD2,浮动2大西洋城3:TEXCOORD3,
浮动4颜色:彩色1)
{
返回VertexShaderCommon(输入、世界、纹理命令、浮点4(1,1,1,1));
}
浮动2半像素校正坐标(浮动2坐标)
{
float u=(coords.x)/TextureSize;
float v=(coords.y)/TextureSize;
返回浮点数2(u,v);
}
//这两种技术共享相同的像素着色器。
float4像素着色器函数(VertexShaderOutput输入,
浮动2 Atlascord1:TEXCOORD1:COLOR00
{
float2 outputExtureCoords=HalfPixileCorrectedCoords(input.textureCoords);
返回tex2D(采样器,输出exturecoords)*输入.Color;
}
//硬件实例技术。
技术硬件安装
{
通行证1
{
VertexShader=编译vs_3_0硬件安装VertexShader();
PixelShader=编译ps_3_0 PixelShaderFunction();
}
}
//用于渲染而不实例化。
安装技术
{
通行证1
{
VertexShader=编译vs_3_0 NoInstanceVertexShader();
PixelShader=编译ps_3_0 PixelShaderFunction();
}
}
我的FX Composer HLSL配置文件:
以及使用以下工具的测试atlas im:
(因为我需要更多的声誉,所以不能发布,也许我可以在后续发布?)
我对此做了很多阅读,似乎我要么需要进行“半像素校正”,要么在图集中指定纹理的边缘包裹像素。这两种我都试过了,但都没有成功
问题:
如何解决我遇到的像素出血问题?如果您想使用atlas获得漂亮的无缝平铺纹理,您必须创建一个比预期大4倍的纹理(即(2 x宽度)x(2 x高度)) 更具体地说,地图集中的每个瓷砖应如下所示: 整个瓷砖应重复两次,从其中心(u,v)开始 (u,v)是atlas纹理中瓷砖的坐标 但是,在纹理生成时,此平铺应使用的坐标
rw = tile_width / atlas_width
rh = tile_height / atlas_height
u0 = u + 0.5 * rw
v0 = v + 0.5 * rh
u1 = u0 + rw
v1 = v0 + rh