Udało się ale ... ale każdy płatek to oddzielny obiekt więc optymalizacja leży..
const char * snowflake_vertex_shader_source = R"(
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texcoords;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
out vec2 TexCoords;
out vec4 FragPosition;
void main()
{
TexCoords = texcoords;
FragPosition = view * model * vec4(position, 1.0);
gl_Position = projection * FragPosition;
}
)";
const char * snowflake_fragment_shader_source = R"(
#version 330 core
in vec2 TexCoords;
in vec4 FragPosition;
uniform sampler2D tex; // Tekstura
uniform vec3 fogColor;
uniform float fogStart;
uniform float fogEnd;
out vec4 FragColor;
void main()
{
// Obliczenie współczynnika mgły
float fogFactor = (fogEnd - abs(FragPosition.z)) / (fogEnd - fogStart);
fogFactor = clamp(fogFactor, 0.0, 1.0);
// Pobranie koloru tekstury
vec3 texColor = texture(tex, TexCoords).rgb;
// Finalny kolor z uwzględnieniem mgły
FragColor = vec4(mix(fogColor, texColor, fogFactor), 1.0);
}
)";
std::random_device rd;
std::mt19937 generator = std::mt19937( rd() );
glm::vec3 generateFallingSnowFlakePosition( glm::vec3 rect_position, glm::vec3 rect_size ) {
glm::vec3 pos;
std::uniform_real_distribution < > dis;
dis = std::uniform_real_distribution < >( rect_position.x - rect_size.x / 2.0f, rect_position.x + rect_size.x / 2.0f );
pos.x = rect_position.x + dis( generator );
dis = std::uniform_real_distribution < >( 0, rect_position.y + rect_size.y / 2.0f );
pos.y = rect_position.y + dis( generator );
dis = std::uniform_real_distribution < >( rect_position.z - rect_size.z / 2.0f, rect_position.z + rect_size.z / 2.0f );
pos.z = rect_position.z + dis( generator );
return pos;
}
class Snowflake {
public:
unsigned int VAO; unsigned int vertices_buffer; Transform transform;
std::vector < float > vertices;
float speed = 0.1f;
Program * prog;
unsigned int tex;
Snowflake() {
transform.position = glm::vec3( 0 );
transform.scale = glm::vec3( 1 );
tex = 0;
prog = nullptr;
vertices = {
- 0.1f, - 0.1f, 0.0f, 0.0f, 0.0f,
0.1f, - 0.1f, 0.0f, 1.0f, 0.0f,
- 0.1f, 0.1f, 0.0f, 0.0f, 1.0f,
0.1f, - 0.1f, 0.0f, 1.0f, 0.0f,
0.1f, 0.1f, 0.0f, 1.0f, 1.0f,
- 0.1f, 0.1f, 0.0f, 0.0f, 1.0f
};
glGenVertexArrays( 1, & VAO );
glGenBuffers( 1, & vertices_buffer );
glBindVertexArray( VAO );
glBindBuffer( GL_ARRAY_BUFFER, vertices_buffer );
glBufferData( GL_ARRAY_BUFFER, vertices.size() * sizeof( float ), vertices.data(), GL_STATIC_DRAW );
glEnableVertexAttribArray( 0 );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof( float ),( void * ) 0 );
glEnableVertexAttribArray( 1 );
glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof( float ),( void * )( 3 * sizeof( float ) ) );
glBindVertexArray( 0 );
}
void setPosition( glm::vec3 position ) {
transform.setPosition( position );
}
void setProgram( Program * program ) {
prog = program;
}
void setTexture( unsigned int & texture ) {
tex = texture;
}
void update( glm::vec3 rect_position, glm::vec3 rect_size ) {
transform.position.y -= 0.01f;
if( transform.position.y < 0 ) {
transform.setPosition( generateFallingSnowFlakePosition( rect_position, rect_size ) );
}
}
void draw( Camera * cam ) {
glUseProgram( prog->shader_program );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, tex );
glUniform1i( glGetUniformLocation( prog->shader_program, "tex" ), 0 );
glUniform3f( glGetUniformLocation( prog->shader_program, "fogColor" ), 0.25f, 0.25f, 0.25f );
glUniform1f( glGetUniformLocation( prog->shader_program, "fogStart" ), 1.0f );
glUniform1f( glGetUniformLocation( prog->shader_program, "fogEnd" ), 15.0f );
glm::mat4 view = cam->GetViewMatrix();
glm::mat4 projection = glm::perspective( glm::radians( 45.0f ), 800.0f / 600.0f, 0.1f, 100.0f );
glm::mat4 model = glm::mat4( 1.0f );
model = glm::translate( model, transform.position );
model = glm::rotate( model, glm::radians( transform.rotation.x ), glm::vec3( 1.0f, 0.0f, 0.0f ) );
model = glm::rotate( model, glm::radians( transform.rotation.y ), glm::vec3( 0.0f, 1.0f, 0.0f ) );
model = glm::rotate( model, glm::radians( transform.rotation.z ), glm::vec3( 0.0f, 0.0f, 1.0f ) );
model = glm::scale( model, transform.scale );
glUniformMatrix4fv( glGetUniformLocation( prog->shader_program, "projection" ), 1, GL_FALSE, & projection[ 0 ][ 0 ] );
glUniformMatrix4fv( glGetUniformLocation( prog->shader_program, "view" ), 1, GL_FALSE, & view[ 0 ][ 0 ] );
glUniformMatrix4fv( glGetUniformLocation( prog->shader_program, "model" ), 1, GL_FALSE, & model[ 0 ][ 0 ] );
glPointSize( 10.0f );
glBindVertexArray( VAO );
glDrawArrays( GL_TRIANGLES, 0, vertices.size() / 5 );
glBindVertexArray( 0 );
}
};
class SnowStorm {
public:
glm::vec3 rect_position;
glm::vec3 rect_size;
short snowflakes_count;
std::vector < Snowflake * > snowflakes;
int texture_width, texture_height, texture_nrChannels;
unsigned int texture;
SnowStorm( Program * program ) {
rect_position = glm::vec3( 0, 20, 0 );
rect_size = glm::vec3( 15, 5, 15 );
snowflakes_count = 1000;
loadTexture( "textures/snowflake.png" );
for( short i = 0; i < snowflakes_count; i++ ) {
Snowflake * snow = new Snowflake();
glm::vec3 position = generateFallingSnowFlakePosition( rect_position, rect_size );
snow->setProgram( program );
snow->setTexture( texture );
snow->setPosition( position );
snowflakes.push_back( snow );
}
}
~SnowStorm() {
for( auto & snow: snowflakes ) {
delete snow;
}
snowflakes.clear();
}
void loadTexture( std::string texture_pathfile ) {
glGenTextures( 1, & texture );
glBindTexture( GL_TEXTURE_2D, texture );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
stbi_set_flip_vertically_on_load( true );
unsigned char * data = stbi_load( texture_pathfile.c_str(), & texture_width, & texture_height, & texture_nrChannels, 0 );
if( data ) {
GLenum format =( texture_nrChannels == 4 ) ? GL_RGBA
: GL_RGB;
glTexImage2D( GL_TEXTURE_2D, 0, format, texture_width, texture_height, 0, format, GL_UNSIGNED_BYTE, data );
glGenerateMipmap( GL_TEXTURE_2D );
stbi_image_free( data );
}
else {
std::cout << "Failed to load texture: " << texture_pathfile << "\n";
}
glBindTexture( GL_TEXTURE_2D, 0 ); }
void update() {
for( auto & snow: snowflakes ) {
snow->update( rect_position, rect_size );
}
}
void draw( Camera * cam ) {
for( auto & snow: snowflakes ) {
snow->draw( cam );
}
}
};