ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

【openGLES3.0编程指南笔记-11】粒子系统

2021-06-13 23:01:57  阅读:174  来源: 互联网

标签:粒子系统 openGLES3.0 10000 userData float myesContext 11 GL rand


目录

概述

粒子的属性:

寿命 a_lifetime

开始位置 a_startPosition

结束位置 a_endPosition

中心位置 u_centerPosition

颜色 u_color随机生成

时间 u_time持续一秒钟

1000个粒子,在1秒钟的时间,从开始位置,线性移动到结束位置。

1. 初始化粒子的位置

int Init(MYESContext *myesContext)
{
    myUserData *userData = (myUserData *)myesContext->userData;
    int i;

    char vShaderStr[] =
            "#version 300 es \n"
            "uniform float u_time; \n"
            "uniform vec3 u_centerPosition; \n"
            "layout(location = 0) in float a_lifetime; \n"
            "layout(location = 1) in float a_startPosition; \n"
            "layout(location = 2) in vec3 a_endPosition; \n"
            "out float v_lifetime; \n"
            "void main() \n"
            "{ \n"
            "   if ( u_time <= a_lifetime ) \n"
            "   {   \n"
        // 这个是线性插值
            "       gl_Position.xyz = a_startPosition + (u_time * a_endPosition); \n"
        // 移动中心位置
            "       gl_Position.xyz += u_centerPosition; \n"
            "       gl_Position.w = 1.0;    \n"
            "   } \n"
            "   else \n"
            "   { \n"
            "       gl_Position = vec4(-1000, -1000, 0, 0); \n"
            "   } \n"
            "   v_lifetime = 1.0 - (u_time / a_lifetime); \n"
            "   v_lifetime = clamp(v_lifetime, 0.0, 1.0); \n"
            "   gl_PointSize  = (v_lifetime * v_lifetime) * 40.0; \n"
            "}";
// 颜色
    char fShaderStr[] =
            "#version 300 es \n"
            "precision mediump float; \n"
            "uniform vec4 u_color; \n"
            "in float v_lifetime; \n"
            "layout(location = 0) out vec4 fragColor; \n"
            "uniform sampler2D s_texture; \n"
            "void main() \n"
            "{ \n"
            "   vec4 texColor; \n"
            "   texColor = texture(s_texture, gl_PointCoord); \n"
        // 乘于一个纹理的值
            "   fragColor = vec4(u_color) * texColor; \n"
        // 透明度根据时间,逐渐变暗
            "   fragColor.a *= v_lifetime; \n"
            "} \n";

    userData->programObject = myesLoadProgram(vShaderStr, fShaderStr);
    userData->timeLoc = glGetUniformLocation(userData->programObject, "u_time");
    userData->centerPositionLoc = glGetUniformLocation(userData->programObject, "u_centerPosition");
    userData->colorLoc = glGetUniformLocation(userData->programObject, "u_color");
    userData->samplerLoc = glGetUniformLocation(userData->programObject, "s_texture");

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    srand(0);
    for (i = 0; i < NUM_PARTICLES; i++)
    {
        float *praticleData = &userData->particleData[i*PARTICLE_SIZE];
        // 取余10000,是将数据控制到10000以内,0-1之间,寿命a_lifetime
        (*praticleData++) = ((float)(rand()%10000)/10000.0f);
// -1到1之间,粒子的开始位置
        (*praticleData++) = ((float)(rand()%10000)/5000.0f) - 1.0f;
        (*praticleData++) = ((float)(rand()%10000)/5000.0f) - 1.0f;
        (*praticleData++) = ((float)(rand()%10000)/5000.0f) - 1.0f;
// -0.125-0之间,粒子的最终位置
        (*praticleData++) = ((float)(rand()%10000)/40000.0f) - 0.125f;
        (*praticleData++) = ((float)(rand()%10000)/40000.0f) - 0.125f;
        (*praticleData++) = ((float)(rand()%10000)/40000.0f) - 0.125f;
    }
    userData->time = 1.0f;
    userData->textureId = LoadTexture(myesContext->platformData, "smoke.tga");
    if (userData->textureId <= 0) {
        return GL_FALSE;
    }

    return GL_TRUE;
}

2. 更新粒子的位置和颜色

void Update(MYESContext *myesContext, float deltaTime)
{
    myUserData *userData = (myUserData *)myesContext->userData;

    userData->time += deltaTime;
    glUseProgram(userData->programObject);
    // 要1秒之后才更新
    if (userData->time >= 1.0f)
    {
        float centerPos[3];
        float color[4];
        userData->time = 0.0f;
        // 中心位置,-0.5 到 0.5
        centerPos[0] = ((float) (rand()%10000) / 10000.0f) - 0.5f;
        centerPos[1] = ((float) (rand()%10000) / 10000.0f) - 0.5f;
        centerPos[2] = ((float) (rand()%10000) / 10000.0f) - 0.5f;

        glUniform3fv(userData->centerPositionLoc, 1, &centerPos[0]);
// 颜色,0.5到1.0
        color[0] = ((float) (rand() % 10000) / 20000.0f) + 0.5f;
        color[1] = ((float) (rand() % 10000) / 20000.0f) + 0.5f;
        color[2] = ((float) (rand() % 10000) / 20000.0f) + 0.5f;
        color[3] = 0.5;

        glUniform4fv(userData->colorLoc, 1, &color[0]);
    }

    glUniform1f(userData->timeLoc, userData->time);
}

源码解析

#include "esUtil.h"
#include <stdlib.h>
#include <math.h>

#define NUM_PARTICLES 1000
#define PARTICLE_SIZE 7

#define ATTRIBUTE_LIFETIME_LOCATION 0
#define ATTRIBUTE_STARTPOSITION_LOCATION 1
#define ATTRIBUTE_ENDPOSITION_LOCATION 2
typedef struct
{
    GLuint programObject;
    GLint timeLoc;
    GLint colorLoc;
    GLuint centerPositionLoc;
    GLint samplerLoc;
    GLuint textureId;
    float particleData[NUM_PARTICLES*PARTICLE_SIZE];
    float time;
} myUserData;
GLuint LoadTexture(void *ioContext, char *fileName)
{
    int width, height;
    char *buffer = esLoadTGA(ioContext, fileName, &width, &height);
    GLuint texId;

    if (buffer == NULL) {
        esLogMessage("Error loading (%s) image.\n", fileName);
        return 0;
    }

    glGenTextures(1, &texId);
    glBindTexture(GL_TEXTURE_2D, texId);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    free(buffer);
    return texId;
}
int Init(MYESContext *myesContext)
{
    myUserData *userData = (myUserData *)myesContext->userData;
    int i;

    char vShaderStr[] =
            "#version 300 es \n"
            "uniform float u_time; \n"
            "uniform vec3 u_centerPosition; \n"
        // 寿命
            "layout(location = 0) in float a_lifetime; \n"
        // 粒子开始位置
            "layout(location = 1) in float a_startPosition; \n"
        // 粒子结束位置
            "layout(location = 2) in vec3 a_endPosition; \n"
            "out float v_lifetime; \n"
            "void main() \n"
            "{ \n"
            "   if ( u_time <= a_lifetime ) \n"
            "   {   \n"
            "       gl_Position.xyz = a_startPosition + (u_time * a_endPosition); \n"
            "       gl_Position.xyz += u_centerPosition; \n"
            "       gl_Position.w = 1.0;    \n"
            "   } \n"
            "   else \n"
            "   { \n"
            "       gl_Position = vec4(-1000, -1000, 0, 0); \n"
            "   } \n"
            "   v_lifetime = 1.0 - (u_time / a_lifetime); \n"
            "   v_lifetime = clamp(v_lifetime, 0.0, 1.0); \n"
            "   gl_PointSize  = (v_lifetime * v_lifetime) * 40.0; \n"
            "}";

    char fShaderStr[] =
            "#version 300 es \n"
            "precision mediump float; \n"
            "uniform vec4 u_color; \n"
            "in float v_lifetime; \n"
            "layout(location = 0) out vec4 fragColor; \n"
            "uniform sampler2D s_texture; \n"
            "void main() \n"
            "{ \n"
            "   vec4 texColor; \n"
            "   texColor = texture(s_texture, gl_PointCoord); \n"
            "   fragColor = vec4(u_color) * texColor; \n"
            "   fragColor.a *= v_lifetime; \n"
            "} \n";

    userData->programObject = myesLoadProgram(vShaderStr, fShaderStr);
    userData->timeLoc = glGetUniformLocation(userData->programObject, "u_time");
    userData->centerPositionLoc = glGetUniformLocation(userData->programObject, "u_centerPosition");
    userData->colorLoc = glGetUniformLocation(userData->programObject, "u_color");
    userData->samplerLoc = glGetUniformLocation(userData->programObject, "s_texture");

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    srand(0);
    for (i = 0; i < NUM_PARTICLES; i++)
    {
        float *praticleData = &userData->particleData[i*PARTICLE_SIZE];
        (*praticleData++) = ((float)(rand()%10000)/10000.0f);

        (*praticleData++) = ((float)(rand()%10000)/5000.0f) - 1.0f;
        (*praticleData++) = ((float)(rand()%10000)/5000.0f) - 1.0f;
        (*praticleData++) = ((float)(rand()%10000)/5000.0f) - 1.0f;

        (*praticleData++) = ((float)(rand()%10000)/40000.0f) - 0.125f;
        (*praticleData++) = ((float)(rand()%10000)/40000.0f) - 0.125f;
        (*praticleData++) = ((float)(rand()%10000)/40000.0f) - 0.125f;
    }
    userData->time = 1.0f;
    userData->textureId = LoadTexture(myesContext->platformData, "smoke.tga");
    if (userData->textureId <= 0) {
        return GL_FALSE;
    }

    return GL_TRUE;
}
void Update(MYESContext *myesContext, float deltaTime)
{
    myUserData *userData = (myUserData *)myesContext->userData;

    userData->time += deltaTime;
    glUseProgram(userData->programObject);
    if (userData->time >= 1.0f)
    {
        float centerPos[3];
        float color[4];
        userData->time = 0.0f;
        centerPos[0] = ((float) (rand()%10000) / 10000.0f) - 0.5f;
        centerPos[1] = ((float) (rand()%10000) / 10000.0f) - 0.5f;
        centerPos[2] = ((float) (rand()%10000) / 10000.0f) - 0.5f;

        glUniform3fv(userData->centerPositionLoc, 1, &centerPos[0]);

        color[0] = ((float) (rand() % 10000) / 20000.0f) + 0.5f;
        color[1] = ((float) (rand() % 10000) / 20000.0f) + 0.5f;
        color[2] = ((float) (rand() % 10000) / 20000.0f) + 0.5f;
        color[3] = 0.5;

        glUniform4fv(userData->colorLoc, 1, &color[0]);
    }

    glUniform1f(userData->timeLoc, userData->time);
}
void Draw(MYESContext *myesContext)
{
    myUserData *userData = (myUserData *) myesContext->userData;
    glViewport(0, 0, myesContext->width, myesContext->height);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(userData->programObject);
    glVertexAttribPointer(ATTRIBUTE_LIFETIME_LOCATION, 1, GL_FLOAT,
            GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat), userData->particleData);
    glVertexAttribPointer(ATTRIBUTE_ENDPOSITION_LOCATION, 3, GL_FLOAT,
                          GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat), &userData->particleData[1]);
    glVertexAttribPointer(ATTRIBUTE_STARTPOSITION_LOCATION, 3, GL_FLOAT,
                          GL_FALSE, PARTICLE_SIZE * sizeof(GLfloat), &userData->particleData[4]);

    glEnableVertexAttribArray(ATTRIBUTE_LIFETIME_LOCATION);
    glEnableVertexAttribArray(ATTRIBUTE_ENDPOSITION_LOCATION);
    glEnableVertexAttribArray(ATTRIBUTE_STARTPOSITION_LOCATION);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, userData->textureId);
    glUniform1i(userData->samplerLoc, 0);
    glDrawArrays(GL_POINTS, 0, NUM_PARTICLES);
}
void ShutDown(MYESContext *myesContext)
{
    myUserData *userData = (myUserData *)myesContext->userData;
    glDeleteTextures(1, &userData->textureId);
    glDeleteProgram(userData->programObject);
}
int myesMain(MYESContext *myesContext)
{
    myesContext->userData = (myUserData *)malloc(sizeof(myUserData));
    myesCreateWindow(myesContext, "PaticleSystem", 640, 480, MY_ES_WINDOW_RGB);
    if (!Init(myesContext)) {
        return GL_FALSE;
    }
    esRegisterDrawFunc(myesContext, Draw);
    esRegisterUpdateFunc(myesContext, Update);
    esRegisterShutdownFunc(myesContext, ShutDown);

    return GL_TRUE;
}

效果图

image

标签:粒子系统,openGLES3.0,10000,userData,float,myesContext,11,GL,rand
来源: https://www.cnblogs.com/pyjetson/p/14881469.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有