【问题标题】:Stop spray and stay in its position停止喷涂并保持原位
【发布时间】:2019-05-18 21:35:29
【问题描述】:
// #include loads up library files, the order can matter
// generally load glut.h last
#include <stdio.h>  // this library is for standard input and output
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "glut.h"// this library is for glut the OpenGL Utility Toolkit

//this defines a constant for the array size
#define SPRAYSIZE 500

// the properties of a spray particle are defined in a struct 
struct sprayParticle {
    float x = 0; // current position  x
    float y = 0; // current position  y
    float startx = 0; // birth position  x
    float starty = 0; // birth position y
    int startTime; // a birthtime in frames when it will be born
    int startRange = 100; // the maximum time at which a birth can happen
    bool started = false; // tracks whether the particle has benn born or not
    float speed = 0.1;
    float radius;
    float startxd = 0; // starting direction vector x value
    float startyd = 0; // startingdirection vestor y value
    float xd = 0;  //  current direction vector x value
    float yd = 0;  // current direction vector x value
    float alpha = 1.0; // transparency
};

int winWidth = 1000, winHeight = 1000;
int counter = 0;
time_t t;
sprayParticle spray[SPRAYSIZE];

float angle = 90; // the angle of the spray: 0 degrees is to the left, 
// 90 degrees straight up, 180 to the right etc
float sprayWidth = 30;// the width of the spray in degrees
float sprayCenterX, sprayCenterY;
//variables for spray colour, set once per spray
float fr = 1; float fg = 1;  float fb = 1;
// the gravity vector
float gx = 0;
float gy = -0.0005;
// the position of thepartcle ystem emitter, wher the rocket should be drawn
float rocketstartx = winWidth - 100, rocketstarty = winHeight - 100;

void init() {
    glClearColor(0.0, 0.0, 0.0, 0.0); // set what colour you want the background to be
    glMatrixMode(GL_PROJECTION); // set the matrix mode, we will look at this later
    gluOrtho2D(0.0, winWidth, 0.0, winHeight);
}

void circle(double radius, double xc, double yc) {
    int i;
    double angle = 2 * 3.1415 / 20; // circle is drawn using 20 line.
    double circle_xy[40][2];
    circle_xy[0][0] = radius + xc;
    circle_xy[0][1] = yc;
    glBegin(GL_POLYGON);
    for (i = 1; i < 20; i++) {
        circle_xy[i][0] = radius * cos(i *angle) + xc;
        circle_xy[i][1] = radius * sin(i * angle) + yc;
        glVertex2f(circle_xy[i - 1][0], circle_xy[i - 1][1]);
        glVertex2f(circle_xy[i][0], circle_xy[i][1]);
    }
    glEnd();
}

void normalise(int i) {
    float mag;
    mag = sqrt((spray[i].xd*spray[i].xd) + (spray[i].yd*spray[i].yd));
    spray[i].xd = spray[i].xd / mag;
    spray[i].yd = spray[i].yd / mag;
}

// we calculate the direction vector of the current particle from the global 
variable angle and spread
void setDirectionVector(int i) {
    float minAngle, maxAngle, range, newangle;
    double newAngleInRadians; // variable 
    int rangeInt;
    minAngle = angle - (sprayWidth / 2.0); // calc the minimum angle the particle could move along
    maxAngle = angle + (sprayWidth / 2.0); // calc the maximum angle
    range = maxAngle - minAngle;
    rangeInt = (int)(range*100.0);
    newangle = minAngle + ((float)(rand() % rangeInt) / 100.0); // generate a random angle between mi and max angles
    newAngleInRadians = (double)(newangle / 360.0)*(2 * 3.1415); // convert it to radians
    spray[i].xd = (float)cos(newAngleInRadians);// calc the diection vector x value
    spray[i].yd = (float)sin(newAngleInRadians);// calc the diection vector y value
}

void initspray() {
    for (int i = 0; i < SPRAYSIZE; i++) {
        spray[i].x = winWidth / 2; // set current start x position
        spray[i].y = 100;// set current start y position
        spray[i].startx = spray[i].x; spray[i].starty = spray[i].y;// set start x and y position
        spray[i].speed = 0.1 + (float)(rand() % 150) / 1000.0;// speed is 0.1 to 0.25
        spray[i].startTime = rand() % spray[i].startRange;// set birth time
        spray[i].radius = (float)(rand() % 15); // random radius
        setDirectionVector(i);// set the current direction vector
        spray[i].startxd = spray[i].xd; spray[i].startyd = spray[i].yd; // set start direction vector to current
    }
    // set colour of spray 
    fr = 0.5 + (float)(rand() % 500) / 1000.0;
    fg = 0.5 + (float)(rand() % 500) / 1000.0;
    fb = 0.5 + (float)(rand() % 500) / 1000.0;
}

void drawsprayParticle(int i) {
    glLineWidth(2);
    if (!spray[i].started) {
        if (counter == spray[i].startTime) {
            spray[i].started = true;
        }
    }
    if (spray[i].started) {
        glColor4f(fr, fg, fb, spray[i].alpha); // white particiles
        circle(spray[i].radius, spray[i].x, spray[i].y);
        spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
        spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
        // this produces a direction vector that is a little longer than 1
        spray[i].yd = spray[i].yd + gy;
        // so the normalise the vector to make length 1
        normalise(i);
        // reduce transparency
        spray[i].alpha -= 0.00015;
    }
    if (spray[i].x<0 || spray[i].x>winWidth + 500 || spray[i].y<0 || spray[i].y>winHeight) {
        spray[i].x = spray[i].startx; spray[i].y = spray[i].starty; //rocketstartx
        spray[i].xd = spray[i].startxd; spray[i].yd = spray[i].startyd;
        spray[i].alpha = 1.0;
    }
}

void drawspray() {
    // draw each spray particle 
    for (int i = 0; i < SPRAYSIZE; i++) {
        drawsprayParticle(i);
    }
    // increment rocket position
    rocketstartx += 0.2;
    // if the rocket is oof the screen more nad 500 pixels to the right the rest it to 0
    if (rocketstartx > winWidth + 500) { rocketstartx = 0; }
    counter++;
}

// This is the display function it is called when ever you want to draw something
void display() {
    glClear(GL_COLOR_BUFFER_BIT); // clear the screen using the background colour
    glColor3f(1.0, 1.0, 1.0); // set colour to white
    drawspray();
    glFlush(); // force all drawing to finish   
}

// This is the idle function it is called whenever the program is idle
void idle() {
    display();
}

// As with many programming languages the main() function is the entry point for execution of the program
int main(int argc, char** argv) {
    srand((unsigned)time(&t));
    // initialise first spray work
    initspray();
    glutInit(&argc, argv);  //perform the GLUT initialization
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); // more initialisation
    glutInitWindowSize(winWidth, winHeight); // set window position
    glutInitWindowPosition(0, 0); // set window size
    glutCreateWindow("Fire"); // create a display with a given caption for the title bar
    glEnable(GL_BLEND); //Enable blending.
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    init(); // call init function defined above
    glutIdleFunc(idle); //  define what function to call when the program is idle
    glutDisplayFunc(display); // define what function to call to draw 
    glutMainLoop();
    // this line exits the program
    return 0;
}

上面的原始代码通常会创建一个将粒子喷射到整个屏幕的喷泉,但我已经更改了喷射的大小和范围,所以我可以创建一个火焰。问题是我无法阻止粒子的扩散并且它一直在向上移动。我希望它保持在原来的位置。

它是这样工作的:

这就是我希望它的工作方式:

【问题讨论】:

    标签: c++ visual-studio opengl


    【解决方案1】:

    用公式

    spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
    spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
    

    点到它的原点的距离线性增加。您必须按时间降低速度才能平稳地接近极限位置。

    例如

    spray[i].speed *= 0.9992f;
    

    当然,当点在其原点“重新启动”时,您必须保持速度 (spray[i].speed)。如果该点的速度或该点的 alpha 值低于阈值,则该点也必须“重新启动”:

    void drawsprayParticle(int i) {
        glLineWidth(2);
        if (!spray[i].started) {
            if (counter == spray[i].startTime) {
                spray[i].started = true;
            }
        }
    
        if (spray[i].started) {
            glColor4f(fr, fg, fb, spray[i].alpha); // white particles
            circle(spray[i].radius, spray[i].x, spray[i].y);
            spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
            spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
            // this produces a direction vector that is a little longer than 1
            spray[i].yd = spray[i].yd + gy;
            // so the normalize the vector to make length 1
            normalise(i);
            // reduce transparency
            spray[i].alpha -= 0.0003;
            spray[i].speed *= 0.9992f;
        }
    
        if ( spray[i].x<0 || spray[i].x>winWidth + 500 ||
             spray[i].y<0 || spray[i].y>winHeight ||
             spray[i].alpha < 1.0f/256.0f ||
             spray[i].speed < 0.04f ) {
    
            spray[i].x = spray[i].startx; spray[i].y = spray[i].starty; 
            spray[i].xd = spray[i].startxd; spray[i].yd = spray[i].startyd;
            spray[i].alpha = 1.0;
            spray[i].speed = 0.1 + (float)(rand() % 150) / 1000.0;
        }
    }
    

    这是一种经验算法,因此您必须使用这些值来获得您需要的效果。

    另外我增加了起始范围:int startRange = 1300;

    预览:

    【讨论】:

    • 如何移动喷雾粒子?
    • @Muddy 在Display() 的开头使用glTranslate ---- glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(offsetx, offsety, 0.0f);
    • offsetx, offsety 未定义
    • @Muddy 当然是的,因为你必须定义它。这是粒子的位移,您可以动态更改偏移量以移动粒子。使用glTranslatef(100.0f, 0.0f, 0.0f); 看看会发生什么。
    • 哦,是的,我明白你的意思了。对不起,我没有用我的大脑。当您将其命名为 offset, offsety 时,我感到很困惑
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多