Xna 二维凹凸贴图-单游戏
感谢您抽出时间查看我的问题 在我第一次尝试游戏时,我正在努力改善海洋。我决定在我的海洋瓷砖上使用凹凸贴图来为水添加一点纹理。为此,我将水平铺绘制到渲染目标,然后在将渲染目标绘制到backbuffer时应用像素着色器 我遇到的问题是,像素着色器似乎偏移或置换了绘制的渲染目标的位置。观察以下两张照片:Xna 二维凹凸贴图-单游戏,xna,monogame,hlsl,bump-mapping,Xna,Monogame,Hlsl,Bump Mapping,感谢您抽出时间查看我的问题 在我第一次尝试游戏时,我正在努力改善海洋。我决定在我的海洋瓷砖上使用凹凸贴图来为水添加一点纹理。为此,我将水平铺绘制到渲染目标,然后在将渲染目标绘制到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参数)。使用正确的类型也很重要