gpt4 book ai didi

c++ - SFML 中的二维水着色器

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:55:19 37 4
gpt4 key购买 nike

我想为描述的 2D 水面实现算法 herehere .

但我不想使用两个 int 数组并在 CPU 上进行计算,而是使用 SFML 的 sf::RenderTexture(基本上是 FBO)和一个 GLSL 着色器在 GPU 上运行所有内容。我想使用 SFML,因为它非常简单,而且我以前使用过它,所以我对它略有了解。

到目前为止,我已经取得了一些不错的进展。我能够正确设置 3 个 sf::RenderTextures 和它们之间的乒乓球(因为除了 int 数组你不能读写相同的 sf::RenderTexture同时)。我还能够将高度字段创建形式的算法调整为 -32.767 到 32.767 范围内的范围 0 到 1(或者更精确的计算 -0.5 到 0.5)。还可以在一定程度上添加新的涟漪效果。所以到目前为止,您实际上可以看到一些波浪正在发生。

现在我的问题来了:波浪消失得非常非常快,我什至还没有应用任何阻尼。根据该算法,如果没有应用阻尼,则纹波不会停止。甚至相反。如果我应用“放大”,波浪看起来接近您期望的样子(但它们仍然消失,没有应用任何阻尼)。我的第一个想法是,这是因为我在 0 - 1 范围内使用 float 而不是整数,但我只在使用乘法时才看到这是一个问题,但我只使用加法和减法。

这是我的 SFML C++ 代码:

#include <SFML/Graphics.hpp>
#include <iostream>

int main()
{
sf::RenderWindow window(sf::VideoMode(1000, 1000), "SFML works!");
window.setFramerateLimit(12);

sf::RenderTexture buffers[3];
buffers[0].create(500, 500);
buffers[1].create(500, 500);
buffers[2].create(500, 500);
sf::RenderTexture* firstBuffer = buffers;
sf::RenderTexture* secondBuffer = &buffers[1];
sf::RenderTexture* finalBuffer = &buffers[2];

firstBuffer->clear(sf::Color(128, 128, 128));
secondBuffer->clear(sf::Color(128, 128, 128));
finalBuffer->clear(sf::Color(128, 128, 128));

sf::Shader waterHeightmapShader;
waterHeightmapShader.loadFromFile("waterHeightmapShader.glsl", sf::Shader::Fragment);

sf::Sprite spritefirst;
spritefirst.setPosition(0, 0);
spritefirst.setTexture(firstBuffer->getTexture());

sf::Sprite spritesecond;
spritesecond.setPosition(500, 0);
spritesecond.setTexture(secondBuffer->getTexture());

sf::Sprite spritefinal;
spritefinal.setPosition(0, 500);
spritefinal.setTexture(finalBuffer->getTexture());

while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
window.close();

if(event.type == sf::Event::KeyReleased && event.key.code == sf::Keyboard::Escape)
window.close();
}


waterHeightmapShader.setParameter("mousePosition", sf::Vector2f(-1.f, -1.f));
// if mouse button is pressed add new ripples
if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sf::Vector2i mousePosition = sf::Mouse::getPosition(window);
if(mousePosition.x < 500 && mousePosition.y < 500)
{
sf::Vector2f mouse(mousePosition);

mouse.x /= 500.f;
mouse.y /= 500.f;

mouse.y = 1 - mouse.y;


std::cout << mouse.x << " " << mouse.y << std::endl;

waterHeightmapShader.setParameter("mousePosition", mouse);
}
}


waterHeightmapShader.setParameter("textureTwoFramesAgo", firstBuffer->getTexture());
waterHeightmapShader.setParameter("textureOneFrameAgo", secondBuffer->getTexture());

// create the heightmap
secondBuffer->display();
finalBuffer->clear(sf::Color(128, 128, 128));
finalBuffer->draw(sf::Sprite(secondBuffer->getTexture()), &waterHeightmapShader);
finalBuffer->display();


spritefirst.setTexture(firstBuffer->getTexture());
spritesecond.setTexture(secondBuffer->getTexture());
spritefinal.setTexture(finalBuffer->getTexture());

window.clear();
window.draw(spritefirst);
window.draw(spritesecond);
window.draw(spritefinal);
window.display();

// swap the buffers around, first becomes second, second becomes third and third becomes first
sf::RenderTexture* swapper = firstBuffer;
firstBuffer = secondBuffer;
secondBuffer = finalBuffer;
finalBuffer = swapper;
}

return 0;
}

这是我的 GLSL 着色器代码:

uniform sampler2D textureTwoFramesAgo;
uniform sampler2D textureOneFrameAgo;
uniform vec2 mousePosition;

const float textureSize = 500.0;
const float pixelSize = 1.0 / textureSize;

void main()
{
// pixels position
vec2 position = gl_TexCoord[0].st;

vec4 finalColor = ((texture2D(textureOneFrameAgo, vec2(position.x - pixelSize, position.y)) +
texture2D(textureOneFrameAgo, vec2(position.x + pixelSize, position.y)) +
texture2D(textureOneFrameAgo, vec2(position.x, position.y + pixelSize)) +
texture2D(textureOneFrameAgo, vec2(position.x, position.y - pixelSize)) - 2.0) / 2) -
(texture2D(textureTwoFramesAgo, position) - 0.5);

// damping
// finalColor.rgb *= 1.9; // <---- uncomment this for the "amplifiction" ie. to see the waves better
finalColor.rgb += 0.5;

// add new ripples
if(mousePosition.x > 0.0)
{
if(distance(position, mousePosition) < pixelSize * 5)
{
finalColor = vec4(0.9, 0.9, 0.9, 1.0);
}
}

gl_FragColor = finalColor;

}

请记住,这只是关于高度场的创建。还没有水的阴影。

你知道为什么波会在没有阻尼的情况下自行消失吗?

最佳答案

如果我正确地阅读了代码,您将对前一帧的纹理颜色/高度进行采样,并使用四个相邻的像素/纹素来确定当前像素的颜色/高度。

当您计算(缩放)这些邻居时,您可能会错过包含您正在寻找的颜色/高度的纹素。它可能不是最高的纹理元素,只是旁边的一个稍微低一点,导致意外的阻尼。

这是您只使用加法和减法的地方:

const float pixelSize = 1.0 / textureSize;

通过使用这个值,您可能会错过您正在寻找的纹素。

编辑

此外:您正在对样本进行平均,因此结果将始终小于样本的最大值。因此,您可以选择最大值而不是取平均值。这可能会产生奇怪的结果,但也会产生额外的洞察力。

关于c++ - SFML 中的二维水着色器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14579610/

37 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com