2D водный шейдер в SFML

Я хочу осуществить алгоритм для 2D водной описанной поверхности здесь и здесь.

Но вместо того, чтобы использовать два международных множества и вычислить на центральном процессоре я хотел бы использовать SFML's sf:: RenderTexture (FBO's в основном) и шейдер GLSL, чтобы управлять всем на GPU. Я хочу использовать SFML, потому что это настолько просто, и я работал с ним прежде, таким образом, я знаю свой путь вокруг этого немного.

Я сделал некоторые значительные успехи до сих пор. Я смог настроить 3 sf:: RenderTextures и пинг-понг между ними правильно (потому что кроме международного множества вы не можете читать и написать тому же самому sf:: RenderTexture в то же время). Я также смог приспособить алгоритм к форме создания области высоты, находящейся в диапазоне-32.767 к 32.767 к диапазону от 0 до 1 (или быть более точен-0.5 к 0.5 для вычисления). Также добавление новых работ ряби некоторым простирается. Таким образом до этого пункта можно на самом деле видеть немного продолжения волн.

Здесь прибывает моя проблема теперь: волны исчезают действительно, действительно быстро и я еще даже не применяю демпфирования. Согласно алгоритму не останавливается рябь, если нет никакого примененного демпфирования. Это даже наоборот. Если бы я применяю "увеличение" взгляд волн близко к тому, на что вы ожидали бы, что они будут похожи (но они все еще исчезают без любого демпфирования, относился к ним). Моя первая мысль была то, что это, потому что я использую плавание в диапазоне 0 - 1 вместо целых чисел, но я только вижу этот являющийся проблемой, если умножение используется, но я только использую дополнение и вычитание.

Вот мой код C++ SFML:

#include 
#include 

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;

}

Пожалуйста, помните, что это - все примерно создание области высоты. Еще нет никакой штриховки воды.

Вы знаете, почему волны исчезают ими сам без демпфирования?

4
nl ja de
Вы находили решение для этого?
добавлено автор Prizoff, источник
I' m жаль алгоритмы объяснены на тех двух страницах: gamedev.net/page/resources/_/technical/…freespace.virgin.net/hugo.elias/graphics/x_water.htm(Iwasn'tabletopostmorethantwolinks,becauseIamnew)
добавлено автор Foaly, источник

2 ответы

Вот некоторые коды "Обработки", который осуществляет тот же самый алгоритм, который вы опубликовали выше, и его демпфирование правильно, я надеюсь, что можно понять некоторые мысли от него:

// codes begin

int Width = 800;
int Height = 600;
int FullSize = 0;
//int Spacing = 10;

int[] source, dest;
PImage bg;

void setup()
{
 //if you want to run these codes by "Processing"
 //please make a picture named "HelloWorld.png"
  bg = loadImage("HelloWorld.png");
  Width = bg.width;
  Height = bg.height;
  FullSize = Width * Height;
  size(Width, Height);
  source = new int[FullSize];
  dest = new int[FullSize];
  for (int i=0; i< FullSize; i++)
    source[i] = dest[i] = 0;
}

void draw()
{
  for (int i=Width; i< FullSize-Width; i++)
  {
   //check for bounds
    int xi = i % Width;
    if ((xi==0) || (xi==Width-1)) continue;

    dest[i] = (
    ((source[i-1]+
      source[i+1]+
      source[i-Width]+
      source[i+Width]) >>1) ) -dest[i];

    int dampFactor = 1000;
    dest[i] -= (dest[i] >> dampFactor);//Damping - Quick divde by 32 (5 bits)
  }

  //image(bg, 0, 0);
  loadPixels();
  for (int i=Width; i< FullSize-Width; i++)
  {
   //check for bounds
    int xi = i % Width;
    if ((xi==0) || (xi==Width-1)) continue;

    int xoffset = dest[i-1] - dest[i+1];
    int yoffset = dest[i-Width] - dest[i+Width];

    int offset = i+xoffset+yoffset*Width;
    if (offset>0 && offset 0 && mouseX < Width && mouseY > 0 && mouseY < Height)
      source[mouseY*Width+mouseX] = (int)random(50, 100); 
}

void mousePressed()
{
  //TODO: make a area pulse value, like a radius circle
   if (mouseX > 0 && mouseX < Width && mouseY > 0 && mouseY < Height)
      source[mouseY*Width+mouseX] = (int)random(50, 100); 
}

// codes end
2
добавлено

Если я читаю код правильно, вы пробуете предыдущую структуру для цветов/высоты структуры и используете четыре соседних pixels/texels, чтобы определить цвет/высоту текущего пикселя.

Поскольку вы вычисляете (вычисление) этих соседей, вы могли бы столкнуться с пропавшими без вести texel, который содержит цвет/высоту, который вы ищете. Это не мог бы быть heighest texel, всего один рядом с ним немного понижают порождение неожиданного демпфирования.

Это - то, где вы делаете не , просто используют дополнение и вычитание:

const float pixelSize = 1.0/textureSize;

При помощи этой стоимости вы могли просто пропустить texel, который вы ищете.

РЕДАКТИРУЮТ

Также: вы насчитываете образцы, таким образом, результатом всегда будут меньше, чем максимальное значение образцов. Таким образом вместо того, чтобы составить в среднем вас мог выбрать максимальное значение. Это могло бы дать странные результаты, но также и дополнительное понимание.

2
добавлено
Вы могли сделать испытательную структуру (так you' ll знают то, чем должен после управлять результат, единственная структура) управляют единственной структурой и отдают структуру к битовому массиву, таким образом, можно исследовать ценности структуры/битового массива. Повторяя это необходимо видеть то, что продолжается. Это - единственный способ, которым я могу вообразить. Решение, которое могло бы обеспечить некоторое понимание, могло состоять в том, чтобы добавить дополнительные образцы. Также: вы насчитываете образцы, таким образом, результатом всегда будут меньше, чем максимальное значение образцов. Таким образом вместо того, чтобы составить в среднем вас мог выбрать максимальное значение. Это могло бы дать странные результаты, но также и дополнительное понимание.
добавлено автор Erno de Weerd, источник
Есть одна вещь, которую необходимо сделать: сделайте вычисление для нескольких пикселей рукой, используя битовые массивы, посмотрите, являются ли результаты тем, что вы ожидали бы от алгоритма. Если они делают, алгоритм неправильный. Если они don' t, внедрение алгоритма могло бы быть неправильным.
добавлено автор Erno de Weerd, источник
Хм, предположите, что texels действительно большой. Теперь, где (0, 0)? это посреди texel или наверху оставлено texel? Если это наверху оставляют, you' ll, вероятно, получают среднее число других texels, у которых есть угол на (0, 0). Легко проверить, добавляя 0.5 * pixelSize , чтобы положение. X и положение. Y (просто предположение) См.: msdn.microsoft.com/en-us/library/windows/desktop/…
добавлено автор Erno de Weerd, источник
нет, теперь вы приспособили размер пикселя. Необходимо приспособить погашение типовых координат.
добавлено автор Erno de Weerd, источник
Да, вы неправы, пиксели равняются все еще 1 / textureSize. Читать это: drilian.com/2008/11/25/…
добавлено автор Erno de Weerd, источник
Я сожалею, но я вне идей теперь...
добавлено автор Erno de Weerd, источник
Я мог быть, и вы могли бы найти больше людей со знанием об этом.
добавлено автор Erno de Weerd, источник
Ничего себе, в первую очередь, спасибо за сумасшедший быстрый ответ! Это на самом деле имеет большой смысл! Таким образом, как я могу удостовериться, что получаю доступ к соседнему texel?
добавлено автор Foaly, источник
Спасибо за наконечник я сделал это. Я загрузил результаты здесь: imgur.com/KN2sUTh (it' s измеренный два, никакая интерполяция) Структура 3 и 5 действительно выглядит странной мне, таким образом, вы были, вероятно, правы. Таким образом, что правильный путь состоит в том, чтобы получить соседний texel в GLSL?
добавлено автор Foaly, источник
Я сделал вычисление вручную на бумаге сетки. Они выглядят немного отличающимися от one' s на битовых массивах я отправил, таким образом, я предполагаю, что внедрение неправильное. Я все еще думаю, что ваша первая идея была, вероятно, правильной, это иногда шаг 1.0 / textureSize doesn' t получают соседний texel и таким образом создают неожиданное демпфирование. Но я don' t знают любой другой путь и haven' t найденный иначе также... Вы могли сказать мне, как это сделано правильно?
добавлено автор Foaly, источник
Хорошо! Я сделал быстрый тест, и использующий плавание константы pixelSize = 1.0 / textureSize + 1.0 / textureSize * 0.5; я добираюсь этот результат. Это все еще doesn' t выглядят правильными и волны don' t проспект распространения больше, но по крайней мере они продолжают идти теперь, все еще делая волнистое движение. Таким образом, я думаю I' m на правильном пути. Но I' m не верный what' s порождение ошибки теперь...
добавлено автор Foaly, источник
Ну, но pixelSize - то, что я использую в качестве погашения. Или я получаю что-то не так здесь?
добавлено автор Foaly, источник
Спасибо за интересную статью! Но право наверху это говорит это it' s не запрашивает OpenGL. Я попробовал position.xy + = pixelSize * 0.5; , но я doesn' t изменяют что-либо...
добавлено автор Foaly, источник
Хорошо! Большое спасибо за всю помощь! Я действительно ценю его! Было бы неуместно задать этот вопрос в gamedev.stackexchange.com потому что я чувствую, что это на самом деле, где это принадлежит.
добавлено автор Foaly, источник
pro.cxx
pro.cxx
3 049 участник(ов)

C/C++ chat 0. Простые вопросы, лабы и о IDE — в чат новичков @supapro 1. Не хамим, не переходим на личности, не вбрасываем утверждения без доказательств 2. No Ads, offtop, flood Объявления о вакансиях и евенты - в лс @AlexFails https://t.me/ProCxx/259155

supapro.cxx
supapro.cxx
1 925 участник(ов)

Чат для тех, кто немного знает C++, простые вопросы по реализации, синтаксису и ide – сюда, а для другого есть: /Главный чат по серьезным вопросам — @ProCxx /Чат по обсуждению всего — @fludpac

C++ Russia
C++ Russia
384 участник(ов)

Сообщество разработчиков C++ в Telegram.

cxx.Дискуссионная
cxx.Дискуссионная
298 участник(ов)

это не двач, общайтесь вежливо; разговор на почти любые темы; Не согласны с баном? В лс @AlexFails, @ivario

C++ для маленьких и тупых
C++ для маленьких и тупых
105 участник(ов)

Лоу левел (по среднему IQ участников) чатик ExtremeCode @extremecode Флудилка @extremecode_rest