gpt4 book ai didi

colors - C#/XNA/HLSL - 在 2D Sprite 上应用像素着色器会影响同一渲染目标上的其他 Sprite

转载 作者:行者123 更新时间:2023-12-02 00:14:05 28 4
gpt4 key购买 nike

背景信息

我刚刚开始学习 HLSL,并决定通过编写一个简单的 2D XNA 4.0 弹幕游戏来测试我从互联网上学到的知识。

我编写了一个像素着色器来更改项目符号的颜色。

想法是这样的:子弹的原始纹理主要是黑色、白色和红色。在我的像素着色器的帮助下,子弹可以变得更加丰富多彩。

Idea

但是,我不确定着色器如何以及何时应用于 XNA 4.0 中的 spriteBatch,以及何时结束。这可能是问题的原因。XNA 3.x 中有 pass.begin() 和 pass.end(),但 XNA 4.0 中的 pass.apply() 让我感到困惑。

另外,我也是第一次使用renderTarget。这可能会导致问题。

症状

它有效,但前提是项目符号列表中存在相同颜色的项目符号。如果渲染不同颜色的子弹,则会产生错误的颜色。

看起来像素着色器没有应用在子弹纹理上,而是应用在包含所有渲染子弹的renderTarget上。

举个例子: Screenshot这里我有一些红色子弹和蓝色子弹。最后创建的子弹是蓝色的。看起来像素着色器在红色的基础上添加了蓝色,使它们变成蓝紫色。

如果我连续创建子弹,红色子弹将会在红色和蓝紫色之间切换。 (我相信蓝色的也在切换,但不明显。)

代码

由于我是 HLSL 新手,所以我真的不知道我必须提供什么。以下是我相信或不知道是否与问题相关的所有事情。

C# - 敌人子弹(或只是子弹):

protected SpriteBatch spriteBatch;
protected Texture2D texture;
protected Effect colorEffect;
protected Color bulletColor;
... // And some unrelated variables

public EnemyBullet(SpriteBatch spriteBatch, Texture2D texture, Effect colorEffect, BulletType bulletType, (and other data, like velocity)
{
this.spriteBatch = spriteBatch;
this.texture = texture;
this.colorEffect = colorEffect;
if(bulletType == BulletType.ARROW_S)
{
bulletColor = Color.Red; // The bullet will be either red
}
else
{
bulletColor = Color.Blue; // or blue.
}
}

public void Update()
{
... // Update positions and other properties, but not the color.
}

public void Draw()
{
colorEffect.Parameters["DestColor"].SetValue(bulletColor.ToVector4());
int l = colorEffect.CurrentTechnique.Passes.Count();
for (int i = 0; i < l; i++)
{
colorEffect.CurrentTechnique.Passes[i].Apply();
spriteBatch.Draw(texture, Position, sourceRectangle, Color.White, (float)Math.PI - rotation_randian, origin, Scale, SpriteEffects.None, 0.0f);
}
}

C# - 项目符号管理器:

private Texture2D bulletTexture;

private List<EnemyBullet> enemyBullets;
private const int ENEMY_BULLET_CAPACITY = 10000;

private RenderTarget2D bulletsRenderTarget;

private Effect colorEffect;

...

public EnemyBulletManager()
{
enemyBullets = new List<EnemyBullet>(ENEMY_BULLET_CAPACITY);
}

public void LoadContent(ContentManager content, SpriteBatch spriteBatch)
{
bulletTexture = content.Load<Texture2D>(@"Textures\arrow_red2");

bulletsRenderTarget = new RenderTarget2D(spriteBatch.GraphicsDevice, spriteBatch.GraphicsDevice.PresentationParameters.BackBufferWidth, spriteBatch.GraphicsDevice.PresentationParameters.BackBufferHeight, false, SurfaceFormat.Color, DepthFormat.None);

colorEffect = content.Load<Effect>(@"Effects\ColorTransform");
colorEffect.Parameters["ColorMap"].SetValue(bulletTexture);
}

public void Update()
{
int l = enemyBullets.Count();
for (int i = 0; i < l; i++)
{
if (enemyBullets[i].IsAlive)
{
enemyBullets[i].Update();
}
else
{
enemyBullets.RemoveAt(i);
i--;
l--;
}
}
}

// This function is called before Draw()
public void PreDraw()
{
// spriteBatch.Begin() is called outside this class, for reference:
// spriteBatch.Begin(SpriteSortMode.Immediate, null);

spriteBatch.GraphicsDevice.SetRenderTarget(bulletsRenderTarget);
spriteBatch.GraphicsDevice.Clear(Color.Transparent);

int l = enemyBullets.Count();
for (int i = 0; i < l; i++)
{
if (enemyBullets[i].IsAlive)
{
enemyBullets[i].Draw();
}
}

spriteBatch.GraphicsDevice.SetRenderTarget(null);
}

public void Draw()
{
// Before this function is called,
// GraphicsDevice.Clear(Color.Black);
// is called outside.

spriteBatch.Draw(bulletsRenderTarget, Vector2.Zero, Color.White);

// spriteBatch.End();
}

// This function will be responsible for creating new bullets.
public EnemyBullet CreateBullet(EnemyBullet.BulletType bulletType, ...)
{
EnemyBullet eb = new EnemyBullet(spriteBatch, bulletTexture, colorEffect, bulletType, ...);
enemyBullets.Add(eb);
return eb;
}

HLSL - 效果\ColorTransform.fx

float4 DestColor;

texture2D ColorMap;
sampler2D ColorMapSampler = sampler_state
{
Texture = <ColorMap>;
};

struct PixelShaderInput
{
float2 TexCoord : TEXCOORD0;
};

float4 PixelShaderFunction(PixelShaderInput input) : COLOR0
{
float4 srcRGBA = tex2D(ColorMapSampler, input.TexCoord);

float fmax = max(srcRGBA.r, max(srcRGBA.g, srcRGBA.b));
float fmin = min(srcRGBA.r, min(srcRGBA.g, srcRGBA.b));
float delta = fmax - fmin;

float4 originalDestColor = float4(1, 0, 0, 1);
float4 deltaDestColor = originalDestColor - DestColor;

float4 finalRGBA = srcRGBA - (deltaDestColor * delta);

return finalRGBA;
}

technique Technique1
{
pass ColorTransform
{
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}

如果有人能帮助解决问题,我将不胜感激。 (或者优化我的着色器。我对 HLSL 真的知之甚少。)

最佳答案

在 XNA 4 中,您应该将效果直接传递到 SpriteBatch,如 Shawn Hargreaves' Blog 中所述。 .

也就是说,在我看来问题是,将子弹渲染到 bulletsRenderTarget 后,然后使用相同的 spriteBatch 绘制该 RenderTarget,最后一个效果仍然有效。这可以解释为什么整个图像被漆成蓝色。

一种解决方案是使用 SpriteBatch 的两次 Begin()/End() 遍,一次有效果,另一次没有效果。或者一开始就不使用单独的 RenderTarget,这在这种情况下似乎毫无意义。

我也是像素着色器的初学者,所以,只是我的 2c。

关于colors - C#/XNA/HLSL - 在 2D Sprite 上应用像素着色器会影响同一渲染目标上的其他 Sprite ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10863909/

28 4 0
文章推荐: java - Struts2如何将Set从 View 绑定(bind)回 Controller