0

感谢您花时间检查我的问题。

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

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


此图像是没有运行像素着色器的游戏。注意岛屿周围的“浅水”,这里是纯色的。 在此处输入图像描述


随着像素着色器的运行,浅水始终向右偏移。 在此处输入图像描述

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

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

我的monogame draw call看起来像这样:

    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;
}
4

1 回答 1

1

首先,对于您似乎想要做的事情,凹凸贴图实际上是错误的方法:凹凸贴图是关于改变表面法线(基本上“旋转” 3D 空间中的像素),因此遵循光计算(例如反射)将您的表面视为比实际情况更复杂(请注意,该像素的纹理保持在原来的位置)。所以,凹凸贴图根本不会修改海洋瓦片纹理的位置,而是修改海洋反射的东西(例如,通过改变天空盒的采样位置,所以天空在水中的反射会失真) . 您实现它的方式更像是“如果我的屏幕是海洋并且会反射具有海洋纹理的瓷砖图像怎么办”。

如果你真的想使用凹凸贴图,你需要某种大的天空纹理,然后,(不是之后)绘制海洋瓷砖时,你会计算这个天空纹理反射的样本位置(基于位置屏幕上的图块),然后使用凹凸贴图修改该样本位置。一直绘制瓷砖,而不是在将它们绘制到渲染目标之后。

也可以延迟执行此操作(与您现在所做的更相似)-实际上,有多种方法可以这样做-但是无论哪种方式,您仍然需要从天空纹理中采样最终颜色,而不是从你的瓷砖被绘制的渲染目标。您的图块中的渲染目标将包含“元”信息(取决于您希望如何执行此操作)。这些信息可以是与天空纹理颜色相乘的颜色(创建“有色”水,例如,用于不同的生物群落或模拟太阳落山/太阳升起),或者简单的 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 从那,看看什么样的噪音看起来最适合你。

着色器代码的旁注:我尚未测试该代码。只是你知道,并不是说会有很大的错误空间。

编辑:作为侧节点:当然天空纹理实际上不需要看起来像天空;)

于 2019-10-09T16:46:05.770 回答