Search code examples
c++graphicsrenderinginterpolationsfml

Cosine interpolation Rendering as Linear Interpolation


I am trying to create different interpolation methods between points. So far I have got Linear interpolation Down, but my Cosine interpolation seems to be rendering as linear, so I have something very wrong. I am using C++ to code and SFML to render

My linear interpolation function is:

sf::Vector2f game::linearInterpolate(sf::Vector2f a, sf::Vector2f b, float randN) {
        return sf::Vector2f(a.x * (1 - randN) + b.x * randN,
            a.y * (1 - randN) + b.y * randN);
}

where a is the point to interpolate from and b is the point to interpolate to, and randN is a random number. for those unfamiliar with sfml, the vector2f is just a vector of two floats, which are the coordinates of the pixel to draw

My cosine interpolation function. I think something is wrong here, as it seems to be returning linear interpolation function coordinates, but the math is correct from every resource I have seen(I think)

sf::Vector2f game::cosineInterpolate(sf::Vector2f a, sf::Vector2f b, float randN) {
    float ft = randN * 3.1415927f;
    float f = (1 - cos(ft)) * 0.5f;

    return sf::Vector2f(a.x * (1-f) + b.x * f,
        a.y * (1 - f) + b.y * f);
    
}

which was found from this tutorial: https://web.archive.org/web/20160530124230/http://freespace.virgin.net/hugo.elias/models/m_perlin.htm

My function to draw the pixels is:

//For each point to interpolate between:
    for (sf::Vector2f &l : this->noiseSpots) {
        
        //How many pixels between each point:
        for (unsigned long xScreen = 0; xScreen < 1000; xScreen++) {
            //random number between 0 and one
            float r = this->rand01();
            
            //calculate points to draw
            sf::Vector2f lInterpolatedVec = linearInterpolate(l, this->noiseSpots.at(a + 1), r);
            sf::Vector2f coInterpolatedVec = cosineInterpolate(l, this->noiseSpots.at(a + 1), r);

            //draw linear interpolated graph
            this->graph.setPixel(lInterpolatedVec.x, lInterpolatedVec.y, sf::Color(255, 255, 255));
            //draw cosine interpolated graph
            this->graph.setPixel(coInterpolatedVec.x, coInterpolatedVec.y, sf::Color(255, 0, 0));
        }
        if (a < fidelity-1) { a++; }else{};
    }

noiseSpots is a vector of each spot to interpolate between, and fidelity is the number of those spots.

I think I may need to put my cosine function call outside of the pixel drawing loop but am unsure how to implement this.

PS: before anyone asks, for some reason std::next is not working to access my next element in my vector, so I am using this workaround with a starting out as 0 and increasing each iteration which is why there is that sorta ugly this->noiseSpots.at(a + 1)

An example of my linear interpolation as requested by molbdino:

An example of my linear interpolation as requested by molbdino

And an example of my "Cosine" interpolation:

And an example of my "Cosine" interpolation

Edit: Ok so I have fully narrowed it down to the cosine interpolation function, as I can get curved lines by replacing 1 or more of the f values with randN, but I still am unsure why I cant get the damn cosine interpolation working


Solution

  • Ok so turns out I'm an idiot, LEARN FROM MY MISTAKE BEFORE YOU SPEND DAYS TRYING TO FIX THIS YOURSELF.

    DO NOT INTERPOLATE ON BOTH AXIS:

    sf::Vector2f game::cosineInterpolate(sf::Vector2f a, sf::Vector2f b, float randN) {
        float ft = randN * 3.1415927f;
        float f = (1 - cos(ft)) * 0.5f;
    
        return sf::Vector2f(a.x * (1-f) + b.x * f,
            a.y * (1 - f) + b.y * f);
        
    }
    

    Should be:

    sf::Vector2f game::cosineInterpolate(sf::Vector2f a, sf::Vector2f b, float randN) {
        float ft = randN * 3.1415927f;
        float f = (1 - cos(ft)) * 0.5f;
    
        return sf::Vector2f(a.x * (1-randN) + b.x * randN,
            a.y * (1 - f) + b.y * f);
        
    }
    

    if you do that on the x axis not the Y you get cosine waves in the opposite direction. If you do BOTH (like I was), the waves cancel out and you just get a straight line.