如何使用计时器在顶点着色器中移动点 [英] How to move points in the vertex shader using a timer

查看:94
本文介绍了如何使用计时器在顶点着色器中移动点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在弄清楚如何使用顶点着色器使用计时器为我的对象设置动画时遇到麻烦.我在窗口中的随机位置上有一堆点.我想做的就是将这些点移动到窗口的中心(即{0.0,0.0}),然后在到达窗口中心的位置停在那里.这是我的顶点着色器代码:

I am having trouble figuring out how to use the vertex shader to animate my objects using a timer. I have a bunch of points located in random locations in the window. What I want to do is move those points to the center of the window (which is {0.0,0.0}) and then stop there once a point reaches the center of the window. This is my code for the vertex shader:

layout(location = 0) in vec2 vertexPos;

uniform mat4 P;
uniform mat4 MV;
uniform float time;

void main() {
    gl_Position = P * MV * vec4(vertexPos, 0.0, 1.0);
}

这将显示所有点在其随机位置.我知道如何将它们移到中心,但是我不知道如何显示实际移到中心的点.

This shows all the points in their random locations. I know how to move them to the center, but I don't know how to show the points actually moving to the center.

推荐答案

使用 lerp 在粒子的初始位置和来源:

Use mix() to lerp between the particle's initial position and the origin:

layout(location = 0) in vec2 vertexPos;

uniform mat4 P;
uniform mat4 MV;
uniform float time;

void main()
{
    vec2 dest( 0.0, 0.0 );
    vec2 curPos = mix( vertexPos, dest, time );
    gl_Position = P * MV * vec4( curPos, 0.0, 1.0 );
}

根据主机计时器,将主机代码中的time0.0更改为1.0.

Vary time from 0.0 to 1.0 in your host code based on a host timer.

编辑:全部:

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>
#include <cstdarg>
#include <vector>
using namespace std;

struct Program
{
    static GLuint Load( const char* shader, ... )
    {
        GLuint prog = glCreateProgram();
        va_list args;
        va_start( args, shader );
        while( shader )
        {
            const GLenum type = va_arg( args, GLenum );
            AttachShader( prog, type, shader );
            shader = va_arg( args, const char* );
        }
        va_end( args );
        glLinkProgram( prog );
        CheckStatus( prog );
        return prog;
    }

private:
    static void CheckStatus( GLuint obj )
    {
        GLint status = GL_FALSE;
        if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
        if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
        if( status == GL_TRUE ) return;
        GLchar log[ 1 << 15 ] = { 0 };
        if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
        if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
        std::cerr << log << std::endl;
        exit( EXIT_FAILURE );
    }

    static void AttachShader( GLuint program, GLenum type, const char* src )
    {
        GLuint shader = glCreateShader( type );
        glShaderSource( shader, 1, &src, NULL );
        glCompileShader( shader );
        CheckStatus( shader );
        glAttachShader( program, shader );
        glDeleteShader( shader );
    }
};

#define GLSL(version, shader) "#version " #version "\n" #shader

const char* vert = GLSL
(
    330 core,
    layout( location = 0 ) in vec2 vertexPos;
    uniform float time;
    void main()
    {
        vec2 dest = vec2( 0.0, 0.0 );
        vec2 curPos = mix( vertexPos, dest, time );
        gl_Position = vec4( curPos, 0.0, 1.0 );
    }
);

const char* frag = GLSL
(
    330 core,
    out vec4 color;
    void main()
    {
        color = vec4( 1.0, 1.0, 1.0, 1.0 );
    }
);

float rnd( const float lo, const float hi )
{
    return lo + ( hi - lo ) * ( rand() / (float)RAND_MAX );
}

GLuint prog = 0;
GLint timeLoc = -1;
void init()
{
    GLuint vao = 0;
    glGenVertexArrays( 1, &vao );
    glBindVertexArray( vao );

    std::vector< float > verts;
    for( size_t i = 0; i < 100; ++i )
    {
        verts.push_back( rnd( -1, 1 ) );
        verts.push_back( rnd( -1, 1 ) );
    }

    GLuint vbo = 0;
    glGenBuffers( 1, &vbo );
    glBindBuffer( GL_ARRAY_BUFFER, vbo );
    glBufferData( GL_ARRAY_BUFFER, sizeof( float ) * verts.size(), &verts[0], GL_STATIC_DRAW );

    glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, 0 );
    glEnableVertexAttribArray( 0 );

    prog = Program::Load
        (
        vert, GL_VERTEX_SHADER,
        frag, GL_FRAGMENT_SHADER,
        NULL
        );
    glUseProgram( prog );
    timeLoc = glGetUniformLocation( prog, "time" );
}

float u = 0.0f;
void timer( int value )
{
    const int duration = 3000;
    static int startTime = glutGet( GLUT_ELAPSED_TIME );
    const int curTime = glutGet( GLUT_ELAPSED_TIME );

    if( curTime > startTime + duration )
    {
        startTime = curTime;
    }

    u  = ( curTime - startTime ) / (float)duration;

    glutTimerFunc( 16, timer, 0 );
    glutPostRedisplay();
}

void display()
{
    glClear( GL_COLOR_BUFFER_BIT );
    glUniform1f( timeLoc, u );
    glDrawArrays( GL_POINTS, 0, 100 );
    glutSwapBuffers();
}

int main(int argc, char **argv)
{
    glutInit( &argc, argv );
    glutInitContextVersion( 3, 3 );
    glutInitContextProfile( GLUT_CORE_PROFILE );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
    glutInitWindowSize( 600, 600 );
    glutCreateWindow( "GLUT" );

    glewExperimental = GL_TRUE;
    glewInit();

    init();

    glutDisplayFunc( display );
    glutTimerFunc( 0, timer, 0 );
    glutMainLoop();
    return 0;
}

这篇关于如何使用计时器在顶点着色器中移动点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆