SFML/GLSL – Pulsate of objects when rotating the camera

  3d, c++, glsl, sfml

I have small 3d scene (only one sphere and light) created with shaders and sfml library. The problem is that the smaller the object and the farther from it you are, when the camera rotates, it begins to pulsate/ripple (changing in size, becoming larger or smaller).
I may have made a mistake in calculating the rotation matrix, but all sources use just such formulas. Confused and I don’t know what else could be the reason.

c++ code

int main() {
    int w = 1920;
    int h = 1080;
    int mouseX = w / 2;
    int mouseY = h / 2;
    float mouseSensitivity = 3.0f;
    float speed = 0.1f;
    bool mouseHidden = true;
    bool wasdUD[6] = { false, false, false, false, false, false };
    sf::Vector3f pos = sf::Vector3f(-5.0f, 0.0f, 0.0f);
    sf::Clock clock;

    sf::RenderWindow window(sf::VideoMode(w, h), "Ray tracing", sf::Style::Titlebar | sf::Style::Close);
    window.setFramerateLimit(60);
    window.setMouseCursorVisible(false);

    sf::RenderTexture emptyTexture;
    emptyTexture.create(w, h);
    sf::Sprite emptySprite = sf::Sprite(emptyTexture.getTexture());
    sf::Shader shader;
    shader.loadFromFile("OutputShader.frag", sf::Shader::Fragment);
    shader.setUniform("u_resolution", sf::Vector2f(w, h));

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed) {
                window.close();
            } else if (event.type == sf::Event::MouseMoved) {
                if (mouseHidden) {
                    mouseX += event.mouseMove.x - w / 2;
                    mouseY += event.mouseMove.y - h / 2;
                    sf::Mouse::setPosition(sf::Vector2i(w / 2, h / 2), window);
                }
            } else if (event.type == sf::Event::MouseButtonPressed) {
                window.setMouseCursorVisible(false);
                mouseHidden = true;
            } else if (event.type == sf::Event::KeyPressed) {
                if (event.key.code == sf::Keyboard::Escape) {
                    window.setMouseCursorVisible(true);
                    mouseHidden = false;
                } else if (event.key.code == sf::Keyboard::W) wasdUD[0] = true;
                else if (event.key.code == sf::Keyboard::A) wasdUD[1] = true;
                else if (event.key.code == sf::Keyboard::S) wasdUD[2] = true;
                else if (event.key.code == sf::Keyboard::D) wasdUD[3] = true;
                else if (event.key.code == sf::Keyboard::Space) wasdUD[4] = true;
                else if (event.key.code == sf::Keyboard::LShift) wasdUD[5] = true;
            } else if (event.type == sf::Event::KeyReleased) {
                if (event.key.code == sf::Keyboard::W) wasdUD[0] = false;
                else if (event.key.code == sf::Keyboard::A) wasdUD[1] = false;
                else if (event.key.code == sf::Keyboard::S) wasdUD[2] = false;
                else if (event.key.code == sf::Keyboard::D) wasdUD[3] = false;
                else if (event.key.code == sf::Keyboard::Space) wasdUD[4] = false;
                else if (event.key.code == sf::Keyboard::LShift) wasdUD[5] = false;
            }
        } if (mouseHidden) {
            float mx = ((float)mouseX / w - 0.5f) * mouseSensitivity;
            float my = ((float)mouseY / h - 0.5f) * mouseSensitivity;
            sf::Vector3f dir = sf::Vector3f(0.0f, 0.0f, 0.0f);
            sf::Vector3f dirTemp;
            if (wasdUD[0]) dir = sf::Vector3f(1.0f, 0.0f, 0.0f);
            else if (wasdUD[2]) dir = sf::Vector3f(-1.0f, 0.0f, 0.0f);
            if (wasdUD[1]) dir += sf::Vector3f(0.0f, -1.0f, 0.0f);
            else if (wasdUD[3]) dir += sf::Vector3f(0.0f, 1.0f, 0.0f);
            dirTemp.z = dir.z * cos(-my) - dir.x * sin(-my);
            dirTemp.x = dir.z * sin(-my) + dir.x * cos(-my);
            dirTemp.y = dir.y;
            dir.x = dirTemp.x * cos(mx) - dirTemp.y * sin(mx);
            dir.y = dirTemp.x * sin(mx) + dirTemp.y * cos(mx);
            dir.z = dirTemp.z;
            pos += dir * speed;
            if (wasdUD[4]) pos.z -= speed;
            else if (wasdUD[5]) pos.z += speed;
            shader.setUniform("u_pos", pos);
            shader.setUniform("u_mouse", sf::Vector2f(mx, my));
            shader.setUniform("u_time", clock.getElapsedTime().asSeconds());
        }
        window.draw(emptySprite, &shader);
        window.display();
    }
    return 0;
}

shader code

#version 130

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform vec3 u_pos;
uniform float u_time;

const float MAX_DIST = 99999.0;

mat2 rotate(float a) {
    float s = sin(a);
    float c = cos(a);
    return mat2(c, -s, s, c);
}

vec2 sphIntersect(in vec3 ro, in vec3 rd, float ra) {
    float b = dot(ro, rd);
    float c = dot(ro, ro) - ra * ra;
    float h = b * b - c;
    if(h < 0.0) return vec2(-1.0);
    h = sqrt(h);
    return vec2(-b - h, -b + h);
}

vec3 castRay(vec3 ro, vec3 rd) {
    vec2 minIt = vec2(MAX_DIST);
    vec2 it;
    vec3 n;
    vec3 spherePos = vec3(0.0, -1.0, 0.0);
    it = sphIntersect(ro - spherePos, rd, 1.0);

    if(it.x > 0.0 && it.x < minIt.x) {
        minIt = it;
        vec3 itPos = ro + rd * it.x;
        n = itPos - spherePos;
    }

    if(minIt.x == MAX_DIST) return vec3(0.0);
    vec3 light = normalize(vec3(-0.5, 0.75, -1.0));
    float diffuse = max(0.0, dot(light, n)) * 0.5 + 0.1;
    float specular = max(0.0, pow(dot(reflect(rd, n), light), 32.0));
    vec3 col = vec3(diffuse + specular);
    return col;
}

void main() {
    vec2 uv = (gl_TexCoord[0].xy - 0.5) * u_resolution / u_resolution.y;
    vec3 rayOrigin = u_pos;
    vec3 rayDirection = normalize(vec3(1.0, uv));
    rayDirection.zx *= rotate(-u_mouse.y);
    rayDirection.xy *= rotate(u_mouse.x);
    vec3 col = castRay(rayOrigin, rayDirection);
    gl_FragColor = vec4(col, 1.0);
}

Source: Windows Questions C++

LEAVE A COMMENT