Xna 二维凹凸贴图-单游戏

Xna 二维凹凸贴图-单游戏,xna,monogame,hlsl,bump-mapping,Xna,Monogame,Hlsl,Bump Mapping,感谢您抽出时间查看我的问题 在我第一次尝试游戏时,我正在努力改善海洋。我决定在我的海洋瓷砖上使用凹凸贴图来为水添加一点纹理。为此,我将水平铺绘制到渲染目标,然后在将渲染目标绘制到backbuffer时应用像素着色器 我遇到的问题是,像素着色器似乎偏移或置换了绘制的渲染目标的位置。观察以下两张照片: 此图像是不运行像素着色器的游戏。注意岛屿周围的“浅水区”,这里是纯色。 运行像素着色器后,浅水始终向右偏移。 我正在使用中提供的凹凸贴图。我有一个可能的想法,就是这个凹凸贴图的尺寸与我正在应用

感谢您抽出时间查看我的问题

在我第一次尝试游戏时,我正在努力改善海洋。我决定在我的海洋瓷砖上使用凹凸贴图来为水添加一点纹理。为此,我将水平铺绘制到渲染目标,然后在将渲染目标绘制到backbuffer时应用像素着色器

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


此图像是不运行像素着色器的游戏。注意岛屿周围的“浅水区”,这里是纯色。


运行像素着色器后,浅水始终向右偏移。

我正在使用中提供的凹凸贴图。我有一个可能的想法,就是这个凹凸贴图的尺寸与我正在应用它的渲染目标不匹配。但是,我不完全确定如何创建/调整此凹凸贴图的大小

我的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();

    }
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;
}
有人能看到我的代码有任何问题,或者其他可能导致此偏移量问题的问题吗

非常感谢您的帮助。谢谢

编辑

如果修改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空间中的像素),因此,在光线计算(如反射)后,会将曲面视为比实际更复杂的曲面(请注意,该像素的纹理保持不变)。因此,凹凸贴图根本不会修改海洋瓷砖纹理的位置,而是修改海洋反射的内容(例如,通过更改天空框的采样位置,使天空在水中的反射变形)。您实现它的方式更像是“如果我的屏幕是一个海洋,并反射具有海洋纹理的瓷砖图像会怎么样”

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

也可以按不同的方式(与您现在所做的更为类似)执行此操作-实际上,有多种方法可以执行此操作-但无论哪种方法,您仍然需要从天空纹理中采样最终颜色,而不是从绘制瓷砖的渲染目标中采样。瓷砖中的渲染目标将包含“meta”信息(具体取决于您希望如何操作)。这些信息可以是与天空纹理中的颜色相乘的颜色(创建“有色”水,例如,用于不同的生物群落或模拟日落/日出),或者是一个简单的1或0来告诉是否有海洋,或者是一张每瓦凹凸贴图(允许一次性应用“屏幕全局”和“每个平铺”凹凸贴图。您仍然需要在渲染目标中说“此像素不是海洋,不要为此做任何事情”),或者-如果使用多个渲染目标-所有这些。无论如何,从渲染目标采样的采样位置如果未通过凹凸贴图修改,则只有海洋反射的纹理的采样位置是。这样,海洋也不会发生位移,因为我们根本不接触该采样位置

现在,要创建一个看起来更接近您想要的外观(根据您的图像),您不需要使用凹凸贴图,而是在像素着色器中的采样位置应用一个小的噪波(代码的其余部分不需要更改)。为此,着色器看起来更像这样:

#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();

    }
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;
}
纹理噪声纹理;
采样器2D噪音采样器=采样器\ U状态
{
纹理=;
MipFilter=线性;
MinFilter=线性;
磁滤波器=线性;
地址u=包裹;
地址v=包裹;
};
浮动2噪声补偿;
浮动2噪声功率;
浮动噪声频率;
VertexShaderOutput MainVS(在VertexShaderInput输入中)
{
VertexShaderOutput输出=(VertexShaderOutput)0;
output.Pos=mul(input.Position,WorldViewProjection);
output.Color=input.Color;
返回输出;
}
float4 MainPS(float4位置:SV_位置,float4 color1:COLOR0,float2 texCoord:TEXCOORD0):颜色
{
float4 noise=tex2D(noiseSampler,(texCoord.xy+noiseOffset.xy)*noiseFrequency);
float2偏移=噪声功率*(noise.xy-0.5f)*2.0f;
float4 color=tex2D(水样器,texCoord.xy+offset.xy);
返回颜色;
}
当noisePower(最多)约为屏幕上水平/垂直瓷砖数量的1时,noiseOffset可用于在屏幕上随时间“移动”噪声(应在[-1;1]范围内),noiseFrequency是一个艺术参数(我会从两倍的最大噪波功率开始,然后从那里修改它,使用更高的值使海洋更加扭曲)。这样,瓷砖的边界会扭曲,但在任何方向上都不会移动超过一个瓷砖(感谢noisePower参数)。使用正确的类型也很重要