Creating a SIN wave in OpenGL

Discussion in 'General Programming Support' started by BANANAMAN, Jun 4, 2012.

  1. BANANAMAN

    BANANAMAN Resident Star Battle Expert.

    Ratings:
    +153 / 0 / -0
    So I'm trying to create a sin wave that moves in OpenGL and so far I've gotten around 35 line segments to move up and down due to their Y value being determined by continuous computation as the program runs. Thing is how do I make it so that the Y value for each line to increase at different rates such as theta 1 = theta,theta 2 = theta + 10,and so on....until it creates a sin wave.

    Code:
    #include <stdio.h>
    #include <conio.h>
    #include "GlutStarter.h"
    //Add this to use the sine function
    #include <math.h>
     
    void Render();
    double ConvertToRadian(double DegreeValue);
     
    double t = 0.0;    //time or angle for the sine function
     
    int main(int argc, char** argv)
    {
        StartGlut(&argc, argv, "GL Simulation Environment",
            Render, Render, 0,0,0,0,0,0,0,0);
     
        return 0;
    }
     
    double ConvertToRadian(double DegreeValue)
    {
        double pi = 3.14159;
        double RadianValue = DegreeValue * (pi/180.0);
        return RadianValue;
    }
     
    void Render()
    {
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
     
        //compute the height of the platform
        double y = 5 * sin(ConvertToRadian(t));    //t is for time
        t++;
        if (t>=360.0) t = 0.0;
     
        //Render the platform using:
        //Computed value
        //Line
        glBegin(GL_LINES);
        for(int x = -1.0;x < 36;x++)
        {
            glVertex3d(x, y, 0.0);
        }
        glEnd();
     
        glutSwapBuffers();
    }
    Is it also possible to build up from this code a simple gravity simulation?
     
  2. s3rius

    s3rius Linux is only free if your time is worthless.

    Ratings:
    +128 / 0 / -0
    Can you specify what you want to do?

    As I understood it you have something like that
    [​IMG]

    And you want something like that
    [​IMG]

    So, you want to smooth out the lines?
     
  3. UnknowVector

    UnknowVector I come from the net ... My format, Vector.

    Ratings:
    +144 / 0 / -0
    No; he doesn't have a waveform at all. He has a series of 36 co-linear line segments that go up and down as one, with their height given by a sine wave. Rather boring really. We can fix that though. :)

    Here's your typical sine wave in the (x, y) plane: y = 5sin((x) * pi). It sits on the x-axis stretching left and right and goes up and down as you walk along the axis. If you stand still you don't go anywhere, i.e. the wave is not animated. If you introduce a new variable, t for time, like this y = 5sin((x + t) * pi) then the wave will start undulating. All you need to do is sample that function at 37 points (x, 5sin((x + t) * pi)) and plot the line segments in between them and you will have your wave drawn nicely on screen.

    (Note: I'm multiplying by pi inside the sin function so the wavelength is an integer (2), instead of an irrational number (2pi), which makes things a bit simpler.)

    Now you say you want a gravity simulation, and I see you are referring to the line segments as "platforms". You want the wave to be solid then? So things can stand on top of it, and move along the hills sort of like a boat on a stormy sea or something?

    One approach is to use the same method above, but instead of rendering the line segments, use them in collision detection routines.

    Another (better, I think) approach would be to test whether or not your boat/unit/whatever is above or below the wave with some simple mathematics. Say you have a boat, and it's position is (xpos, ypos). If ypos is less than 5sin((xpos + t) * pi) then the boat is BELOW the wave, if it's greater than 5sin((xpos + t) * pi) then it is ABOVE the wave. If on one frame the boat is below and the next it is above, then the boat passed through the wave and you need to correct this.

    It might help you to know what direction the wave is moving at that point and that time. The sine wave will hit its maximum value (5) when (xpos+t)%2 is 1/2 and it's minimum value (-5) when (xpos+t)%2 is 3/2. If (xpos+t)%2 is between 1/2 and 3/2 then the wave is moving DOWN. If (xpos+t)%2 is below 1/2 or above 3/2 then the wave is moving UP. If a boat passes downwards through the wave when the wave is moving up, then the wave should hit it rather hard, and maybe send it flying or something.

    (% is modulo.)

    (You can also determine which direction the wave is moving by examining the derivative of 5sin((xpos + t) * pi) with respect to t, which is 5(pi)cos((xpos + t) * pi). If the derivative is negative, the wave is moving down, if it is positive the wave is moving up.)

    Hope some of this is useful, post back if anything is confusing or you need more help.
     
    • Like Like x 1
  4. BANANAMAN

    BANANAMAN Resident Star Battle Expert.

    Ratings:
    +153 / 0 / -0
    That was rather interesting to figure out. Now I'm wondering how I could turn this 36 co-linear line segments that look like a single line into a grid that stretches along the x and z axis.

    The math portion I can easily understand. The real problem I'm tackling with is loop logic management Like where do I put this computation? This loop that draws a line? etc.
     
  5. UnknowVector

    UnknowVector I come from the net ... My format, Vector.

    Ratings:
    +144 / 0 / -0
    You're writing in a pure procedural style, so if you can follow the math you should be able to follow the code. Try describing the exact math you would use.

    Will your grid be moving up and down like a grate of solid metal bars, where every piece of metal moves together? (So, just like what you had at the beginning, but instead you would have a bunch of copies of that line laid parallel to each other, and a bunch more copies laid perpendicular, creating a grid.)

    Metal grate, imagine this tied to a rope and being raised and lowered from a roof:
    [​IMG]

    Or will it be undulating like the ocean? There are plenty of different waveforms you can create here: (Note, Wolfram Alpha won't do animations, so these versions of the waves are frozen (no variable t).)

    5sin((sqrt(x^2 + z^2) + t) * pi) = 5sin((distance_from_origin + t) * pi):
    http://www.wolframalpha.com/input/?i=5sin(sqrt(x^2+++z^2)+*+pi)

    5sin((x + z + t) * pi):
    http://www.wolframalpha.com/input/?i=5sin((x+z)+*+pi)

    You can imagine those not as surfaces, but as a grid of lines laid across the surfaces, that would give you an undulating grid. The technical name for those lines would be traces. The wireframe you can see in the wolfram alpha images is just the combination of the function's traces along the x and z axii.

    (These are pretty standard textbook examples for functions of two variables, I have NO idea why I can't find better pictures of them online.)

    As an example, say you were just trying to make the metal grate like thing that moves up and down. You can use two calls to glVertex3d to draw any individual line in the grid (even if it isn't parallel to the axii). Just create and draw one line for each bar in your grate. If you want the grate to move up and down, just make sure to choose a y-coordinate for each end point by evaluating one of the sine functions.

    If you want the grate to undulate then you will basically need to do exactly what you did for the 1-dimensional case, except you will use a new function (of variables x, z, and t) to define the height of the wave. Also, instead of just sampling a series of points along the x-axis, you will need to either sample a series of points along a series of lines parallel to the x-axis and a series of points along a series of lines parallel to the z-axis (i.e. sample along the traces), OR, switch over to rendering the result as a surface instead of a grid of lines (i.e. the colored part of wolfram alpha's drawings.) I haven't used OpenGL so I can't point you to what part of the API would help, but I suspect you would want to sample a bunch of points spread out all over the xz plane, then use those sample points as the vertices of a bunch of triangles in a mesh and have OpenGL draw the triangles for you.

    Note, the derivative with respect to t doesn't really change much with these new functions. Sine still changes to cosine, the pi still pops out, and everything else is the same as before you differentiate.

    5(pi)cos((sqrt(x^2 + z^2) + t) * pi)

    5(pi)cos((x + z + t) * pi)
     
  6. BANANAMAN

    BANANAMAN Resident Star Battle Expert.

    Ratings:
    +153 / 0 / -0
    That last explanation fried my brain.

    Can you explain it in a different view point?

    Edit:This is the current code snippet I have that renders 36 lines that move in a wave every frame.

    Code:
    glBegin(GL_LINES);
    amp=0.0;
    t=0.0;
    for (double x=-36.0; x<=36.0; x++)
    {
    double y = amp * sin( (ba+t)*DTRF );
    glVertex3d(x, y, 0.0);
    t+=10.0;
    amp+=0.2;
    }
    glEnd();
    
    What it does is that before the for loop starts it sets the time and amp variables to 0 before entering the loop. When the for loop begins it'll will first calculate the value of y then draw a line,iterate the time by 10 and amp by 0.2 it will do this until there are 36 lines moving along the y axis in varying heights thus simulating a wave.

    What I need is that how do I modify this so it draws a grid along the x and z axis whose lines move the same.
     
  7. Sevion

    Sevion The DIY Ninja

    Ratings:
    +423 / 0 / -0
    Okay, BANANAMAN. I made a little demo code that draws a grid and a Sine wave that oscillates. I've commented the code so you can understand how it works.

    I did it in Win32 C++ because I'm trying to learn it, but the important parts should be clear to you:

    Code:
    /********************************************************************
        created:    2012/06/14
        created:    14:6:2012  9:52
        filename:    c:\Users\Sevion\documents\visual studio 2010\Projects\Sin Wave\Sin Wave\sinwave.cpp
        file path:    c:\Users\Sevion\documents\visual studio 2010\Projects\Sin Wave\Sin Wave
        file base:    sinwave
        file ext:    cpp
        author:        Sevion
     
        purpose:    Sine Wave demonstration
    *********************************************************************/
     
    #define _USE_MATH_DEFINES
    #include <windows.h>
    #include <Math.h>
    #include <wingdi.h>
     
    #define WINDOW_WIDTH 640
    #define WINDOW_HEIGHT 480
     
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
     
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    {
        static TCHAR szAppName[] = TEXT("SineWave");
        HWND        hwnd;
        MSG          msg;
        WNDCLASSEX  wndclassex = {0};
        wndclassex.cbSize        = sizeof(WNDCLASSEX);
        wndclassex.style        = CS_HREDRAW | CS_VREDRAW;
        wndclassex.lpfnWndProc  = WndProc;
        wndclassex.cbClsExtra    = 0;
        wndclassex.cbWndExtra    = 0;
        wndclassex.hInstance    = hInstance;
        wndclassex.hIcon        = LoadIcon (NULL, IDI_APPLICATION);
        wndclassex.hCursor      = LoadCursor (NULL, IDC_ARROW);
        wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
        wndclassex.lpszMenuName  = NULL;
        wndclassex.lpszClassName = szAppName;
        wndclassex.hIconSm      = wndclassex.hIcon;
     
        if (!RegisterClassEx (&wndclassex))
        {
            MessageBox (NULL, "RegisterClassEx failed!", szAppName, MB_ICONERROR);
            return 0;
        }
        hwnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW,
                              szAppName,
                              "Sine Wave Demonstration",
                              WS_OVERLAPPED|WS_SYSMENU|WS_MINIMIZEBOX,
                              CW_USEDEFAULT,
                              CW_USEDEFAULT,
                              WINDOW_WIDTH,
                              WINDOW_HEIGHT,
                              NULL,
                              NULL,
                              hInstance,
                              NULL);
                           
        ShowWindow (hwnd, iCmdShow);
        UpdateWindow (hwnd);
     
        SetTimer(hwnd, 9001, 1, NULL);
     
        while (GetMessage (&msg, NULL, 0, 0))
        {
            TranslateMessage (&msg);
            DispatchMessage (&msg);
        }
        return msg.wParam;
    }
     
    double startingAngle = 0;
     
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        RECT rc;
        GetClientRect(hwnd, &rc);
        int width = rc.right - rc.left;
        int height = rc.bottom - rc.top;
        int edge = 50;
        double angle = 0;
        double d = 0;
        HDC hdc;
        PAINTSTRUCT ps;
        switch (message)
        {
        case WM_CREATE:
            return (0);
     
        case WM_TIMER:
            InvalidateRect(hwnd, &rc, true);
            UpdateWindow(hwnd);
            return (0);
         
        case WM_PAINT:
            hdc = BeginPaint (hwnd, &ps);
            // SINE WAVE STARTS HERE
            // DRAW GRID
            MoveToEx(hdc, edge, height / 2, NULL);
            LineTo(hdc, width - edge, height / 2);
            MoveToEx(hdc, width / 2, edge, NULL);
            LineTo(hdc, width / 2, height - edge);
            for (int i = 0; i <= 21; i++)
            {
                // Draw notches on the x-axis
                MoveToEx(hdc, (int)((width - 2.0 * edge) / 21.0 * i + edge), (int)(height / 2.0 + 5.0), NULL);
                LineTo(hdc, (int)((width - 2.0 * edge) / 21.0 * i + edge), (int)(height / 2.0 - 5.0));
                // Draw notches on the y-axis
                MoveToEx(hdc, (int)(width / 2.0 + 5.0 - 1), (int)((height - 2 * edge) / 21.0 * i + edge), NULL);
                LineTo(hdc, (int)(width / 2.0 - 5.0 - 1), (int)((height - 2 * edge) / 21.0 * i + edge));
            }
            // END GRID
            // DRAW WAVE
            angle = startingAngle;
            while (angle - startingAngle <= 8 * M_PI)
            {
                // Moves the initial point to the origin (center). First iteration will end up being (width/2, height/2)
                MoveToEx(hdc, (int)(width / 2 + 50 * sin(angle)), (int)(height - edge - 200 * (angle - startingAngle) / M_PI * (height - 2 * edge) / 1600), NULL);
                // Draw the line to a point defined PI/200 Radians over.
                LineTo(hdc, (int)(width / 2 + 50 * sin(angle + M_PI / 200)), (int)(height - edge - 200 * ((angle - startingAngle) + M_PI / 200) / M_PI * (height - 2 * edge) / 1600));
                // Increment by PI / 200, this gives us 1600 iterations (line segments) to smooth out the sine wave
                angle += M_PI / 200;
            }
            // Make the next sine wave start at a different angle so it seems to "move"
            startingAngle += M_PI / 25;
            // END WAVE
            // END OF SINE WAVE DRAW
            EndPaint (hwnd, &ps);
            return (0);
         
        case WM_DESTROY:
            PostQuitMessage (0);
            return (0);
        }
        return DefWindowProc (hwnd, message, wParam, lParam);
    }
    
    If you have questions, just ask me, though I prefer not to use Facebook chat. I despise it.

    I'm not really sure I'm following what you mean by making a grid that follows this line.

    Can you draw a picture in Paint or another program to show us what you mean?
     

    Attached Files:

  8. BANANAMAN

    BANANAMAN Resident Star Battle Expert.

    Ratings:
    +153 / 0 / -0
    Well It should be something like this...

    Note:The lines shouldn't wiggle or move along the x and z axis
     

    Attached Files:

  9. BANANAMAN

    BANANAMAN Resident Star Battle Expert.

    Ratings:
    +153 / 0 / -0
    Bump:I managed to make a grid move /undulate with waves that move along the x and z axis. Problem is that the lines tend to move separately messing up the grid.

    Code:
    #include <stdio.h>
    #include <conio.h>
    #include "GlutStarter.h"
    #include <math.h>
    #include <glut.h>
     
    void Render();
    //#define DTRF (3.14.159/180);
    double t = 0.0;
    double ba = 0.0;
    double WaveHeight = 1.2;
     
    double ConvertToRadian(double DegreeValue);
    int main(int argc, char** argv)
    {
    StartGlut(&argc, argv, "GL Simulation Environment",
    Render, Render,0,0,0,0,0,0,0,0);
     
    return 0;
     
    }
    double ConvertToRadian(double DegreeValue)
    {
        double pi = 3.14159;
        double RadianValue = DegreeValue * (pi/180.0);
        return RadianValue;
    }
     
     
     
    void Render()
    {
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    //
    glPushMatrix();
    for (float z1 = -5;z1 <= 5;z1+= 0.5)
    {
       
    glBegin(GL_LINE_STRIP);
        for (double x1=-5;x1<=5;x1+=0.5)
        {
        double y1 = WaveHeight * sin(ConvertToRadian(((t+(x1*10)))*2));
        glVertex3d(x1,y1,z1);
        }
    glEnd();
    }
    for (float x2 = -5;x2 <= 5;x2 += 0.5)
    {
       
        glBegin(GL_LINE_STRIP);
        for (double z2 = -5;z2<=5;z2+=0.5)
        {
        double y2 = WaveHeight * sin(ConvertToRadian(((t+(z2*10)))*2));
        glVertex3d(x2,y2,z2);
        }
    glEnd();
    }
    t+=0.5;
    ba+=0.5;
    glPopMatrix();
    ////-------------------------------------------------
    glutSwapBuffers();
    }
    Is there anyway to fix this while still having waves move along the x and z axis?
     
  10. Sevion

    Sevion The DIY Ninja

    Ratings:
    +423 / 0 / -0
    You need to make each starting point match with the perpendicular wave. From there, each wave should match with all of the rest.

    Play with the "startingAngle" concept.
     
  11. BANANAMAN

    BANANAMAN Resident Star Battle Expert.

    Ratings:
    +153 / 0 / -0
    i'm not entirely sure I follow.
     

Share This Page