[2D凹凸映射-Monogame

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[2D凹凸映射-Monogame相关的知识,希望对你有一定的参考价值。

感谢您抽出宝贵时间检查我的问题。

我在尝试游戏时正在努力改善海洋。我决定对我的海洋瓷砖使用凹凸贴图,为水中添加一些纹理。为此,我将水瓦片绘制到renderTarget,然后在将渲染目标绘制到后缓冲区时应用像素着色器。

我遇到的问题是像素着色器似乎偏移或置换了绘制的渲染目标的位置。观察这两张照片:


此图像是不运行像素着色器的游戏。注意岛周围的“ 浅水”,这是纯色。enter image description here


运行像素着色器后,浅水将始终向右偏移。enter image description here

我正在使用riemers novice bump mapping中提供的凹凸贴图。我可能想到的是此凹凸贴图的尺寸与我要对其应用的渲染目标不匹配。但是,我不确定要如何创建/调整凹凸图的大小。

我的HLSL像素着色器看起来像这样:

#if OPENGL
    #define SV_POSITION POSITION
    #define VS_SHADERMODEL vs_3_0
    #define PS_SHADERMODEL ps_3_0
#else
    #define VS_SHADERMODEL vs_4_0_level_9_1
    #define PS_SHADERMODEL ps_4_0_level_9_1
#endif

matrix WorldViewProjection;
float xWaveLength;
float xWaveHeight;

texture bumpMap;
sampler2D bumpSampler = sampler_state
{
    Texture = <bumpMap>;
};

texture water;
sampler2D waterSampler = sampler_state
{
    Texture = <water>;
};
// MAG,MIN,MIRRR SETTINGS? SEE RIEMERS

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float2 TextureCords : TEXCOORD;
    float4 Color : COLOR0;
};

struct VertexShaderOutput
{
    float4 Pos : SV_POSITION;
    float2 BumpMapSamplingPos : TEXCOORD2;
    float4 Color : COLOR0;
};

VertexShaderOutput MainVS(in VertexShaderInput input)
{
    VertexShaderOutput output = (VertexShaderOutput)0;

    output.BumpMapSamplingPos = input.TextureCords/xWaveLength;
    output.Pos = mul(input.Position, WorldViewProjection);
    output.Color = input.Color;

    return output;
}

float4 MainPS(float4 pos : SV_POSITION, float4 color1 : COLOR0, float2 texCoord : TEXCOORD0) : COLOR
{
    float4 bumpColor = tex2D(bumpSampler, texCoord.xy);
    //get offset 
    float2 perturbation = xWaveHeight * (bumpColor.rg - 0.5f)*2.0f;

    //apply offset to coordinates in original texture
    float2 currentCoords = texCoord.xy;
    float2 perturbatedTexCoords = currentCoords + perturbation;

    //return the perturbed values
    float4 color = tex2D(waterSampler, perturbatedTexCoords);
    return color;
}

technique oceanRipple
{
    pass P0
    {
        //VertexShader = compile VS_SHADERMODEL MainVS();
        PixelShader = compile PS_SHADERMODEL MainPS();
    }
};

我的单人游戏抽奖电话看起来像这样:

    public void DrawMap(SpriteBatch sbWorld, SpriteBatch sbStatic, RenderTarget2D worldScene, GameTime gameTime)
    {

        // Set Water RenderTarget
        _graphics.SetRenderTarget(waterScene);
        _graphics.Clear(Color.CornflowerBlue);
        sbWorld.Begin(_cam, SpriteSortMode.Texture);
        foreach (var t in BoundingBoxLocations.OceanTileLocationList)
        {
            TilePiece tile = (TilePiece)t;
            tile.DrawTile(sbWorld);
        }
        sbWorld.End();

        // set up gamescene draw
        _graphics.SetRenderTarget(worldScene);
        _graphics.Clear(Color.PeachPuff);

        // water
        sbWorld.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
        oceanRippleEffect.Parameters["bumpMap"].SetValue(waterBumpMap);
        oceanRippleEffect.Parameters["water"].SetValue(waterScene);
        //oceanRippleEffect.Parameters["xWaveLength"].SetValue(3f);
        oceanRippleEffect.Parameters["xWaveHeight"].SetValue(0.3f);
        ExecuteTechnique("oceanRipple");
        sbWorld.Draw(waterScene, Vector2.Zero, Color.White);
        sbWorld.End();

        // land
        sbWorld.Begin(_cam, SpriteSortMode.Texture);
        foreach (var t in BoundingBoxLocations.LandTileLocationList)
        {
            TilePiece tile = (TilePiece)t;
            tile.DrawTile(sbWorld);
        }
        sbWorld.End();

    }

任何人都可以看到我的代码有任何问题,否则可能导致此偏移问题?

非常感谢您的帮助。谢谢!

编辑

如果修改xWaveHeight着色器参数,它将更改偏移量的显示位置。值为0不会偏移,但不会应用凹凸贴图。有什么办法解决吗?

我知道偏移是由像素着色器的摄动引起的,但是我想知道是否有一种方法可以在保留凹凸贴图的同时撤消该偏移。在链接的riemer教程中,包含了一个顶点着色器。我不确定是否需要此方法,但是当我将顶点着色器包括在该技术中并将像素着色器修改为以下内容时,则不会绘制水。

float4 MainPS(in VertexShaderOutput output) : COLOR
{
    float4 bumpColor = tex2D(bumpSampler, output.BumpMapSamplingPos.xy);
    //get offset 
    float2 perturbation = xWaveHeight * (bumpColor.rg - 0.5f)*2.0f;

    //apply offset to coordinates in original texture
    float2 currentCoords = output.BumpMapSamplingPos.xy;
    float2 perturbatedTexCoords = currentCoords + perturbation;

    //return the perturbed values
    float4 color = tex2D(waterSampler, perturbatedTexCoords);
    return color;
}
答案

首先,对于您似乎想做的事情,凹凸贴图实际上是错误的方法:凹凸贴图是关于更改表面法线(基本上是“旋转” 3D空间中的像素),因此请遵循光计算(例如(例如反射)看到的表面要比实际上复杂得多(请注意,该像素的纹理会保留在原处)。因此,凹凸贴图将根本不修改海洋瓷砖纹理的位置,但修改海洋reflected的内容(例如,通过更改天空盒的样本位置,因此水中的天空变形了)。实现的方式更像是“如果我的屏幕是海洋,并且会反射具有海洋纹理的图块,该怎么办”。

如果您确实要使用凹凸贴图,则需要某种大的天空纹理,然后,while(不是在绘制海洋瓷砖之后),您将计算此天空反射的样本位置纹理(基于屏幕上图块的位置),然后使用凹凸贴图修改该样本位置。所有while都绘制图块,而不是将它们绘制到渲染目标之后。

也可以按照不同的方式进行此操作(与您现在正在执行的操作类似)-实际上,有多种方法可以这样做-但无论哪种方式,您仍需要从天空纹理中采样最终的颜色,不是从渲染目标绘制您的图块。瓦片中的渲染目标将改为包含“元”信息(取决于您要执行此操作的精确程度)。这些信息可以是颜色乘以天空纹理的颜色(例如创建“有色”水,例如用于不同的生物或模拟日落/日出),也可以是简单的1或0来指示是否存在是任何海洋,还是每块凹凸图(您将允许一次性应用“屏幕全局”和“每块”凹凸图)。您仍然需要一种方式来表示“此像素不是海洋,则不要在“渲染目标”中为此做任何事情),或者-如果您使用多个渲染目标,则一次全部完成。无论如何,可以通过凹凸贴图修改要从渲染目标中采样的采样位置,而只有海洋反射的纹理的采样位置可以修改。这样一来,海洋也就不会移位,因为我们根本没有接触到该样本位置。现在,要创建与您想要的外观更相似(根据您的图像)的外观,您将不使用凹凸贴图,而是对像素着色器中的样本位置施加少量噪点(其余代码无需更改)。为此,您的着色器将更像这样:

texture noiseTexture; sampler2D noiseSampler = sampler_state { Texture = <noiseTexture>; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; AddressU = Wrap; AddressV = Wrap; }; float2 noiseOffset; float2 noisePower; float noiseFrequency; VertexShaderOutput MainVS(in VertexShaderInput input) { VertexShaderOutput output = (VertexShaderOutput)0; output.Pos = mul(input.Position, WorldViewProjection); output.Color = input.Color; return output; } float4 MainPS(float4 pos : SV_POSITION, float4 color1 : COLOR0, float2 texCoord : TEXCOORD0) : COLOR { float4 noise = tex2D(noiseSampler, (texCoord.xy + noiseOffset.xy) * noiseFrequency); float2 offset = noisePower * (noise.xy - 0.5f) * 2.0f; float4 color = tex2D(waterSampler, texCoord.xy + offset.xy); return color; }

noisePower最多(约为)。屏幕上水平/垂直图块的数量为1,noiseOffset可用于随时间在屏幕上“移动”噪声(应在[-1; 1]范围内),并且noiseFrequency是一个艺术参数(我会从最大噪声功率的两倍开始,然后从那里进行修改,更高的值会使海洋更失真。这样,图块的边界就会变形,但在任何方向上移动的幅度都不能超过一个图块(由于noisePower参数)。在这里使用正确的噪声纹理也很重要:白噪声,蓝噪声,可能是由窦波建立的“不是真的噪声”纹理等。重要的是每个像素的“平均值”值大约为0.5,因此不会发生整体位移,并且值在纹理中分布良好。 Appart由此可见,哪种噪音最适合您。 

着色器代码的注释:我尚未测试该代码。只是您知道,并不是错误的余地很大。

以上是关于[2D凹凸映射-Monogame的主要内容,如果未能解决你的问题,请参考以下文章

在monogame中克隆和绘制对象

XNA (MonoGame) 世界空间和物体运动

标题对象位置与MonoGame位置不匹配

无法理解在 monogame/xna 中“发布”代码的工作原理

OpenGL、GLSL 片段着色器无法读取 Sampler2D 纹理

使用 Xamarin 的简单 2D 游戏