Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[SDL2 OpenGles2 GLSL] - blending czyli mieszanie tekstur

Ostatnio zmodyfikowano 2024-02-08 23:09
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
[SDL2 OpenGles2 GLSL] - blending czyli mieszanie tekstur
» 2023-02-08 13:42:46

Blending Tekstur

C++ SDL opengles2 GLSL

Witam!
Oto moj program, ktory pobiera dwie tekstury i rysuje albo jedna z nich, albo dwie zblendowane. Wyglada to calkiem niezle moim zdaniem, kod jest czytelny. Nie chcialbym tego zepsuc wiec .. jak zrobic rysowanie tekstur tak azeby z jednej gladko przeszlo w druga? Myslalem o czyms takim jak stworzenie maski - gradientu z czerni w biel. Ale jak zrobic taki gradient pod dowolnym katem?

Wejscie:


Rezultat programu:


Kod programu:

C/C++
// program rysujacy dwie rozne tekstury
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_opengles2.h>
#include<iostream>
using namespace std;

#include "math.cpp"

SDL_Window * window;

GLuint vTextureShader;
GLuint fTextureShader;
GLuint vDoubleTextureShader;
GLuint fDoubleTextureShader;

GLuint textureProgram;
GLuint doubleTextureProgram;

GLuint textures[ 2 ];
static GLfloat vertexes[ 6 ];

// SHADERS //////////////////////////////////////////////////////
const char * vTextureSource =
"attribute vec4 position;\n"
"attribute vec2 texcoord;\n"
"varying vec2 Texcoord;\n"
"void main()\n"
"{\n"
"gl_Position = position;\n"
"Texcoord = texcoord;\n"
"}\n"
;

const char * fTextureSource =
"precision mediump float;\n"
"uniform sampler2D texture;\n"
"varying vec2 Texcoord;\n"
"void main()\n"
"{\n"
"gl_FragColor = texture2D(texture, Texcoord);\n"
"}\n"
;

const char * fDoubleTextureSource =
"precision mediump float;\n"
"uniform sampler2D texture1;\n"
"uniform sampler2D texture2;\n"
"varying vec2 Texcoord;\n"
"void main()\n"
"{\n"
"vec4 color1 = texture2D(texture1, Texcoord);\n"
"vec4 color2 = texture2D(texture2, Texcoord);\n"
"gl_FragColor = color1*0.5 + color2*0.5;\n"
"}\n"
;

void initSDL()
{
   
//program graphics init
   
SDL_Init( SDL_INIT_EVERYTHING );
   
// We use OpenGL ES 2.0
   
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 2 );
   
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 0 );
   
   
// We want at least 8 bits per color
   
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
   
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
   
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
   
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
   
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 8 );
   
   
SDL_DisplayMode DM;
   
SDL_GetCurrentDisplayMode( 0, & DM );
   
   
window = SDL_CreateWindow(
   
"Load PNG x2 and draw textures",
   
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
   
int( DM.w ), int( DM.h ),
   
SDL_WINDOW_SHOWN |
   
SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN );
   
cout << "created window size is a [" << DM.w << "x" << DM.h << "]\n";
   
SDL_GL_CreateContext( window );
}

void initShaders()
{
   
vTextureShader = glCreateShader( GL_VERTEX_SHADER );
   
fTextureShader = glCreateShader( GL_FRAGMENT_SHADER );
   
vDoubleTextureShader = glCreateShader( GL_VERTEX_SHADER );
   
fDoubleTextureShader = glCreateShader( GL_FRAGMENT_SHADER );
   
   
glShaderSource( vTextureShader, 1, & vTextureSource, NULL );
   
glShaderSource( fTextureShader, 1, & fTextureSource, NULL );
   
glShaderSource( vDoubleTextureShader, 1, & vTextureSource, NULL );
   
glShaderSource( fDoubleTextureShader, 1, & fDoubleTextureSource, NULL );
   
   
glCompileShader( vTextureShader );
   
glCompileShader( fTextureShader );
   
glCompileShader( vDoubleTextureShader );
   
glCompileShader( fDoubleTextureShader );
   
   
textureProgram = glCreateProgram();
   
glAttachShader( textureProgram, vTextureShader );
   
glAttachShader( textureProgram, fTextureShader );
   
   
doubleTextureProgram = glCreateProgram();
   
glAttachShader( doubleTextureProgram, vDoubleTextureShader );
   
glAttachShader( doubleTextureProgram, fDoubleTextureShader );
   
   
glLinkProgram( textureProgram );
   
glLinkProgram( doubleTextureProgram );
}

void setVertexes( vec2f screenSize, vec2f v1, vec2f v2, vec2f v3 )
{
   
vertexes[ 0 ] = v1.x /( screenSize.x / 2.f );
   
vertexes[ 1 ] = v1.y /( screenSize.y / 2.f );
   
vertexes[ 2 ] = v2.x /( screenSize.x / 2.f );
   
vertexes[ 3 ] = v2.y /( screenSize.y / 2.f );
   
vertexes[ 4 ] = v3.x /( screenSize.x / 2.f );
   
vertexes[ 5 ] = v3.y /( screenSize.y / 2.f );
}

void drawTriangle( vec2f screenSize, vec2f v1, vec2f v2, vec2f v3, GLuint texture )
{
   
glUseProgram( textureProgram );
   
setVertexes( screenSize, v1, v2, v3 );
   
   
// add array [vertexes] to edit position
   
GLint position = glGetAttribLocation( textureProgram, "position" );
   
glEnableVertexAttribArray( position );
   
glVertexAttribPointer( position, 2, GL_FLOAT, GL_FALSE, 0, vertexes );
   
   
GLint texcoord = glGetAttribLocation( textureProgram, "texcoord" );
   
glEnableVertexAttribArray( texcoord );
   
glVertexAttribPointer( texcoord, 2, GL_FLOAT, GL_FALSE, 0, vertexes );
   
   
glActiveTexture( GL_TEXTURE0 );
   
glBindTexture( GL_TEXTURE_2D, texture );
   
   
// get the sampler2D from shaders
   
GLint textureUniform = glGetUniformLocation( textureProgram, "texture" );
   
glUniform1i( textureUniform, 0 ); // texture from shader = GL_TEXTURE0
   
   
glDrawArrays( GL_TRIANGLES, 0, 4 );
}

void drawTriangle( vec2f screenSize, vec2f v1, vec2f v2, vec2f v3, GLuint tex1, GLuint tex2 )
{
   
glUseProgram( doubleTextureProgram );
   
setVertexes( screenSize, v1, v2, v3 );
   
   
// add array [vertexes] to edit position
   
GLint position = glGetAttribLocation( doubleTextureProgram, "position" );
   
glEnableVertexAttribArray( position );
   
glVertexAttribPointer( position, 2, GL_FLOAT, GL_FALSE, 0, vertexes );
   
   
GLint texcoord = glGetAttribLocation( doubleTextureProgram, "texcoord" );
   
glEnableVertexAttribArray( texcoord );
   
glVertexAttribPointer( texcoord, 2, GL_FLOAT, GL_FALSE, 0, vertexes );
   
   
// TEXTURE 0  
   
glActiveTexture( GL_TEXTURE0 );
   
glBindTexture( GL_TEXTURE_2D, tex1 );
   
GLint textureUniform1 = glGetUniformLocation( doubleTextureProgram, "texture1" );
   
glUniform1i( textureUniform1, 0 ); // texture from shader = GL_TEXTURE0
   
    // TEXTURE 1  
   
glActiveTexture( GL_TEXTURE1 );
   
glBindTexture( GL_TEXTURE_2D, tex2 );
   
GLint textureUniform2 = glGetUniformLocation( doubleTextureProgram, "texture2" );
   
glUniform1i( textureUniform2, 1 ); // texture from shader = GL_TEXTURE1
   
   
glDrawArrays( GL_TRIANGLES, 0, 4 );
}

void loadTexture( GLuint & texture, const char * path )
{
   
SDL_Surface * img = IMG_Load( path );
   
if( img == NULL )
   
{
       
cout << "error load texture: " << path << "\n";
       
return;
   
}
   
   
glGenTextures( 1, & texture );
   
glBindTexture( GL_TEXTURE_2D, texture );
   
   
// now set parameters of texture // texture must be repeat when end of tex
   
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
   
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
   
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
   
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
   
   
// now set the pixels to texture
   
glTexImage2D(
   
GL_TEXTURE_2D, 0, GL_RGBA, img->w, img->h,
   
0, GL_RGBA, GL_UNSIGNED_BYTE,
   
img->pixels );
   
   
cout << "load texture: " << path << "\n";
}

void loadTextures()
{
   
loadTexture( textures[ 0 ], "obraz1.png" );
   
loadTexture( textures[ 1 ], "obraz2.png" );
}

int main()
{
   
initSDL();
   
initShaders();
   
loadTextures();
   
   
vec2f screen, v1, v2, v3, v4;
   
float side = 1024;
   
screen = vec2f( 2640, 1200 );
   
v1 = vec2f( - side / 2, side / 2 );
   
v2 = vec2f( side / 2, side / 2 );
   
v3 = vec2f( side / 2, - side / 2 );
   
v4 = vec2f( - side / 2, - side / 2 );
   
   
while( true )
   
{
       
// clear screen
       
glClearColor( 0.125f, 0.125f, 0.125f, 1.0f );
       
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
       
       
drawTriangle( screen, v1, v2, v3, textures[ 0 ] ); // draw normal texture
       
drawTriangle( screen, v1, v3, v4, textures[ 0 ], textures[ 1 ] ); // draw blend textures
       
        // draw submit
       
SDL_GL_SwapWindow( window );
   
}
   
return 0;
}

Maska przykladowa:
P-179943
pekfos
» 2023-02-08 17:01:02
Obróć maskę w Gimpie? Nie wiadomo jakiego rodzaju rozwiązania oczekujesz.
P-179944
tBane
Temat założony przez niniejszego użytkownika
» 2023-02-08 17:07:10
otoz wolalbym tego uniknac, zalozmy ze chcialbym zmienic wymiary trojkatow np. rozciagnac je w poziomie i nadal chcialbym uzyskac gladkie przejscie z jednej tekstury do drugiej. potrzebuje wygenerowac maske gradientu tylko nie mam pojecia jak sie za to zabrac.

A zreszta latwiej bedzie wytlumaczyc tak:
https://cpp0x.pl/forum/temat/?id=28787

W tej gre pola sa niby-szesciokatami tzn. nie sa pelnymi szesciokatami, tzn nie maja bokow rownej dlugosci. Szukam sposobu na zblendowanie dwoch tekstur w "mostku" tzn. prostokacie ktory znajduje sie pomiedzy dwoma szesciokatami :D
P-179945
pekfos
» 2023-02-08 17:28:03
Gradienty (interpolacje) są wbudowane, od tego jest varying. Na podstawie Texcoord.x możesz obliczyć gradient w fragment shaderze, ale kąty są ograniczone przez wierzchołki. Żeby mieć dowolną maskę, oblicz wartość dla każdego piksela na podstawie jego współrzędnych i załaduj wynik jako teksturę. Dalej to już matematyka.
P-179947
tBane
Temat założony przez niniejszego użytkownika
» 2023-02-08 17:34:23
Ano wlasnie nie wiem jak.
Wiem ze dla tych 45 stopni mozna zrobic.

if( x < fX )
    maska[x][y] = textureSizeX/2 - (fX-x)/(textureSizeX/2)

ale dla innego przypadku? poza tym bylby to dobry algorytm na przyszlosc ;)
P-179948
pekfos
» 2023-02-08 17:57:39
Możesz na przykład obrócić układ współrzędnych o jakiś kąt i użyć nowej współrzędnej X do wyznaczenia koloru. Któreś 2 rogi obrazu będą miały skrajne wartości, więc oblicz je najpierw żeby potem móc umieścić wszystko we właściwym zakresie.

https://en.wikipedia.org/wiki/Rotation_matrix
Tego typu operacje są wspierane dość dobrze w GLSL, więc powinno się dać łatwo zrobić to w locie z poziomu shadera. Przy czym interesująca jest tylko jedna współrzędna, więc nie ma co ciągnąć do roboty całej macierzy.
P-179949
tBane
Temat założony przez niniejszego użytkownika
» 2023-02-08 18:01:58
eh.. a liczylem na cos prostego z funkcja liniowa 0-180 stopni.
sprobuje to zrozumiec, moze sie uda. a jak znajde rozwiazanie z funkcja liniowa to sie podziele.
P-179950
pekfos
» 2023-02-08 19:09:08
W jakimkolwiek problemie z jakimś dowolnym kątem, trygonometria to zwykle jest te proste rozwiązanie.
C/C++
float x2 = x * cos( alfa ) - y * sin( alfa ); // obrót
float norm =( x2 - min ) /( max - min ); // normalizacja do [0, 1]
uint8_t color = 255 * norm * norm; // gradient kwadratowy wygląda bardziej jak ten przykład
P-179951
« 1 »
  Strona 1 z 1