XNA 4.0像素着色器3.0精确纹理查找/示例问题

我被困在试图解决这个问题。 我原来有一些着色器是为XNA 3.1编写的,但在转换到XNA 4.0之后,由于指令计数,stream控制问题等原因,它们将不再编译,而且我无法获得重写的版本。

这是全2D的,使用着色器模型3.0,HLSL,使用C#中的XNA 4.0框架,以及SpriteBatch进行绘制。

algorithm/目标:


我需要做的是传递一个浅色的纹理到着色器。 这包含一个灰度预先点亮的纹理,我只是使用添加剂混合与给定的纹理来添加基本的照明。 现在我有大约120个特定的RGB值,我希望着色器忽略,不添加照明颜色,只是返回input的颜色。

在XNA 3.1中这工作:

最初,我将这些特定的忽略颜色硬编码为着色器本身内部的一个大型int3数组,并对每个像素采样绘图纹理,乘以255,并将其舍入,并将结果与​​int3数组中的每种颜色进行比较。 如果我find了一个匹配,只要返回采样的graphics纹理颜色,否则在相同的位置添加照明纹理颜色。

升级到XNA 4.0后,着色器将不再编译。

新的方法无法工作:

所以,我决定尝试使用预处理纹理来存储我的忽略颜色,并将其传递给着色器,以用作查找表,而不是循环通过着色器中的数组。 要做到这一点,我需要检查一个R,G,B值,并确定是否该颜色应该忽略,或点燃。

256x256x256纹理在某些卡片上会太大,因为我只需要编码〜120种颜色,所以我试图用颜色的R和G值作为纹理的X和Y坐标来代替256×256纹理,并将可能的蓝色值打包到该颜色的所有四个分量中。

因此,在着色器中,我对当前的像素颜色进行采样,使用该颜色的R和G值作为位置对“忽略纹理”进行采样。 然后,将像素的蓝色值与返回的忽略颜色的每个RGBA值进行比较,以查看是否有任何组件位于蓝色值的某个阈值内。 如果是这样,那么一场比赛,我忽略了颜色。

理论上似乎没有问题,但无法正常工作。

我知道一个问题,未使用的位置的默认颜色值可能会给误报,但我知道这不是主要问题。 蓝色的阴影不被忽视,总的来说,它看起来很乱。 我认为它与采样/过滤,但我不知道。

如果有人有任何建议或更好的方式来做到这一点,而不修改所有的艺术等,我将不胜感激!

这里是大部分着色器和相关的代码。 像素着色器也使用3.0顶点着色器。 如果我只是将input颜色从没有做任何事情的阴影中传回来,所有东西都可以正确绘制。 照明纹理很好,忽略纹理具有正确的值。 我使用SurfaceFormat.Color构建了Ignore纹理。

我想也许这是新的XNA 4变化的预乘alpha的问题,但我改变了纹理处理器不预乘,和SpriteBatch非预乘,这没有我想象的效果。 也许是一个纹理过滤问题,所以我试着将所有的采样器MinFilter,MagFilter等设置为NONE,但是这给了一个编译器错误。 设置他们为POINT工作,但给出了不同的结果。

像素着色器:

1 sampler TextureSampler : register(s0); 2 float4x4 MatrixTransform : register(c0); 3 4 texture IgnoreTex; 5 sampler IgnoreSampler = sampler_state { 6 Texture = <IgnoreTex>; 7 }; 8 9 float ignoreThreshold = 0.03; 10 11 float4 PSTileLighting(PS_INPUT input) : COLOR 12 { 13 float4 lightBase = tex2Dlod(BaseSampler, float4(input.lightCoord, 0, 0)); 14 float4 tileBase = tex2Dlod(TextureSampler, float4(input.texCoord, 0, 0)); 15 16 float4 ret; 17 bool found = false; 18 int testx, testy, testz; 19 20 testx = round(tileBase.r * 255); 21 testy = round(tileBase.g * 255); 22 23 float2 lookupPos = float2(tileBase.r, tileBase.g); 24 float4 lookupResult = tex2Dlod(IgnoreSampler, float4(lookupPos, 0, 0)); 25 26 float rTest = abs(lookupResult.r - tileBase.b); 27 float gTest = abs(lookupResult.g - tileBase.b); 28 float bTest = abs(lookupResult.b - tileBase.b); 29 float aTest = abs(lookupResult.a - tileBase.b); 30 31 if((rTest < ignoreThreshold) 32 || (gTest < ignoreThreshold) 33 || (bTest < ignoreThreshold) 34 || (aTest < ignoreThreshold)) 35 { 36 // ignore color 37 ret = tileBase; 38 } 39 else 40 { 41 // lighting 42 ret = float4(2*tileBase.rgb*lightBase.rgb, tileBase.a); 43 } 44 45 return ret; 46 } 

这个代码调用了这个方法:(第一次尝试所有将效果传递给spritebatch的组合,在after,之前等等)

 1 Engine.GraphicsDevice.SetRenderTarget(background); 2 3 Engine.GraphicsDevice.Viewport = SectionViewport; 4 Engine.GraphicsDevice.Clear(Color.Transparent); 5 6 Map.TilesEffect.CurrentTechnique = Map.TilesEffect.Techniques["TileLighting"]; 7 8 Vector2 viewportSize = new Vector2(SectionViewport.Width, SectionViewport.Height); 9 viewport.SetValue(viewportSize); 10 matrixTransform.SetValue(transform); 11 ignoreTexture.SetValue(IgnoreColors.RegularIgnoreTexture); 12 13 Engine.SpriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied, null, null, null); 14 15 Map.TilesEffect.CurrentTechnique.Passes[0].Apply(); 16 DrawTiles(tileLayer, 0, 5, bounds, Color.White); 17 18 Engine.SpriteBatch.End(); 

如果我填充硬编码的int3数组,并且只循环它的一个子集来传递指令数量限制,它可以正常工作,但在这个纹理中查找值似乎根本不起作用。 我得到不一致的结果。 我曾尝试各种组合的纹理坐标从字节转换为0 … 1漂浮与奇数的结果,不同的阈值,但没有任何作品。 我只是想我的原始值检查!