OpenGL render obrazka SDL_image

OpenGL render obrazka SDL_image
PM
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 7 lat
  • Postów:35
0

Cześć! Uczę się openGLa od niedawna i przyszło mi się zmierzyć z renderem tekstury. Postanowiłem użyć do tego biblioteki SDL2. Problem polega na tym, że IDE nie pokazuje żadnych błędów związanych z kompilacją, kolor oraz kwadrat również się renderuje. Jedyne czego brakuje to obrazka, który został przeze mnie wybrany.

Do zrobienia VBO, kolorów oraz UV wykorzystałem struktury

Kopiuj
struct GLTexture
{
	GLuint textureID;
	float width, height;
};

struct UV
{
	float u, v;
};

struct Position
{
	float x;
	float y;
};

struct ColorRGBA8
{
	ColorRGBA8() : r(0), g(0), b(0), a(0) { }
	ColorRGBA8(GLubyte R, GLubyte G, GLubyte B, GLubyte A) :
		r(R), g(G), b(B), a(A) { }
	GLubyte r;
	GLubyte g;
	GLubyte b;
	GLubyte a;
};

struct Vertex
{
	Position position;

	ColorRGBA8 color;

	UV uv;

	void setUV(float u, float v)
	{
		uv.u = u;
		uv.v = v;
	}

	void setPosition(float x, float y) 
	{
		position.x = x;
		position.y = y;
	}

	void setColor(GLubyte r, GLubyte g, GLubyte b, GLubyte a) 
	{
		color.r = r;
		color.g = g;
		color.b = b;
		color.a = a;
	}
};

w mainie ustawiłem wszystkie niezbędne rzeczy

Kopiuj
int main(int arg, char*args[])
{
	SDL_Init(SDL_INIT_EVERYTHING);

	SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

	SDL_Window* window = SDL_CreateWindow("window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
	SDL_GLContext context = SDL_GL_CreateContext(window);

	SDL_GL_SetSwapInterval(1);

	glewExperimental = true;

	GLenum result = glewInit();

	std::string vertex = loadFromFile("shader.vert.glsl");
	std::string frag = loadFromFile("shader.frag.glsl");

	GLuint shaderProgram = CreateShaderProgram(vertex.c_str(), frag.c_str());

	GLint uniformUV = glGetUniformLocation(shaderProgram, "mySampler");

	glUseProgram(shaderProgram);

        //Inicjuje kwadrat na pozycji x y i o szerokościach w i h
	InitVBO(1.0, 1.0, -2.0, -2.0);

        // Ładuje teksturę o nazwie ...
	GLTexture texture = LoadTexture("tekstura");

	std::cout << "IN MAIN ID :" << texture.textureID << std::endl;

	SDL_Event *event = new SDL_Event;
	bool quit = false;

	while (!quit && event->type != SDL_QUIT)
	{
		SDL_PollEvent(event);

		glClearDepthf(1.0);

		glUniform1i(uniformUV, 0);

		glClearColor(0.0, 0.0, 0.0, 1.0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_2D, texture.textureID);

		glDrawArrays(GL_TRIANGLES, 0, 6);

		glBindTexture(GL_TEXTURE_2D, 0);
		SDL_GL_SwapWindow(window);
	}

	glDisableVertexAttribArray(0);
	glDisableVertexAttribArray(1);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glDeleteBuffers(1, &vbo);
	glDeleteBuffers(1, &vao);

	return 0;
}

I metodą ładuje teksturę

Kopiuj
GLTexture LoadTexture(std::string textureName)
{
	textureName = textureName + ".png";
	GLTexture texture{};
	SDL_Surface *surface = IMG_Load(textureName.c_str());

	texture.width = surface->w;
	texture.height = surface->h;

	glGenTextures(1, &texture.textureID);
	glBindTexture(GL_TEXTURE_2D, texture.textureID);

	int Format = GL_RGB;

	if (surface->format->BytesPerPixel == 4) {
		Format = GL_RGBA;
	}

	std::cout << "IN LOADTEXTURE ID :" << texture.textureID << std::endl;

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, Format, GL_UNSIGNED_BYTE, surface->pixels);

	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_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

	glGenerateMipmap(GL_TEXTURE_2D);

	glBindTexture(GL_TEXTURE_2D, 0);

	return texture;
}

Inicjacja VBO

Kopiuj

void InitVBO(float x, float y, float w, float h)
{
	Vertex vertex[6];

	vertex[0].setPosition(x + w, y + h);
	vertex[0].setUV(1.0f, 1.0f);

	vertex[1].setPosition(x, y + h);
	vertex[1].setUV(0.0f, 1.0f);

	vertex[2].setPosition(x, y);
	vertex[2].setUV(0.0f, 0.0f);
	
	vertex[3].setPosition(x, y);
	vertex[3].setUV(0.0f, 0.0f);

	vertex[4].setPosition(x + w, y);
	vertex[4].setUV(1.0f, 0.0f);

	vertex[5].setPosition(x + w, y + h);
	vertex[5].setUV(1.0f, 1.0f);

	for (int i = 0; i < 6; ++i)
	{
		vertex[i].setColor(255, 0, 255, 255);
	}

	vertex[1].setColor(0, 0, 255, 255);
	vertex[4].setColor(0, 255, 0, 255);

	glGenBuffers(1, &vbo);
	glBindBuffer(GL_ARRAY_BUFFER, vbo);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW);

	glGenVertexArrays(1, &vao);
	glBindVertexArray(vao);

	glEnableVertexAttribArray(0);
	glEnableVertexAttribArray(1);

	glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
	glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));
	glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, uv));
}

Tak wyglądają shadery

Fragment

Kopiuj
#version 330 core

out vec4 outColor;

in vec4 vertexColor;
in vec2 vertexPos;
in vec2 vertexUV;

uniform sampler2D mySampler;

void main()
{

	vec4 txt = texture(mySampler, vertexUV);
	outColor = txt * vertexColor;
}

I vertex

Kopiuj
#version 330 core

layout (location = 0) in vec2 pos;
layout (location = 1) in vec4 col;
layout (location = 2) in vec2 uv;

out vec2 vertexPos;
out vec4 vertexColor;
out vec2 vertexUV;

void main()
{
	gl_Position = vec4(pos.xy, 0.0, 1.0);
	vertexColor = col;
	vertexPos = pos;
	vertexUV = uv;
}

Efekt końcowy

screenshot-20171223193259.png

obrazek który chciałbym załadować
screenshot-20171223193335.png

Próbowałem załatować jeszcze taki
screenshot-20171223193416.png

to efekt końcowy wyglądał tak, że w ogóle się nic nie pokazywało.

edytowany 2x, ostatnio: PawelMo
CZ
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 lata
  • Postów:231
0
  1. Funkcja InitVBO: wywołanie glBindVertexArray(vao); powinno być przed glBindBuffer(GL_ARRAY_BUFFER, vbo); - z każdym vao stowarzyszone jest vbo, tak jakby vbo było częścią vao.
  2. Przed rysowanie kształtu (glDrawArrays(GL_TRIANGLES, 0, 6);) powinineś zbindować vao.
  3. funkcje glVertexAttribPointer - powinny być poprzedzone zbindowaniem shadera, ale to masz.
  4. rysujesz werteksy w porządku odwrotnym do ruchu wskazówek zegara, (domyślnie chyba jest wyłączone ukrywanie tylnej strony wielokąta, czyli obie strony są rysowane), ale jak nie to możesz ustawić sobie preferencje:
Kopiuj
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glFrontFace(GL_CW);

czyli nie rysujemy tylnej strony wielokąta, zaś przednią stroną jest ta rysowana zgodnie z ruchem wskazówek zegara (GL_CW)

edytowany 1x, ostatnio: czaffik
PM
Nie za bardzo rozumiem o co chodzi z "tylnią" stroną wielokąta.
CZ
wielokąt możesz oglądać z obu stron, np trójkąt ma dwie strony, rysowaną zgodnie z ruchem wskazówek zegara i rysowaną odwrotnie do ruchu wskazówek zegara, za pomocą glFrontFace możesz ustalić która strona wielokąta jest przednia, czy ta rysowana zgodnie z ruchem czy ta druga.
PM
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 7 lat
  • Postów:35
0

Zmieniłem z tym vao. Rysowanie werteksów w innej kolejności raczej nie ma większego znaczenia. Stąd robiłem się uczyłem i kolesiowi działa. Korzystał z innego ładowania tekstur ale to chyba też nie powinno mieć większego znaczenia

edytowany 1x, ostatnio: PawelMo
CZ
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 lata
  • Postów:231
0

Tutaj jedyne co widzę to nie zbindowałeś vao przy tworzeniu vbo, porównaj sobie dobrze kod ze źródła z którego się uczyłeś z tym co masz, to może być kwestia głupiego wywołania funkcji w nieodpowiedniej kolejności.

To mi się jeszcze wydaje wątpliwe:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, Format, GL_UNSIGNED_BYTE, surface->pixels);

  • jeżeli obrazek ma format RGB to 3 parametr też powinien być GL_RGB
edytowany 1x, ostatnio: czaffik
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 18 godzin
0
czaffik napisał(a):
  1. Funkcja InitVBO: wywołanie glBindVertexArray(vao); powinno być przed glBindBuffer(GL_ARRAY_BUFFER, vbo); - z każdym vao stowarzyszone jest vbo, tak jakby vbo było częścią vao

Przeglądam specyfikację i przeglądam i nigdzie nie widzę informacji żeby bindowanie VAO było z w jakikolwiek sposób powiązane z bindowaniem VBO.
Co by znaczyło że trzeba bindować jedno i drugie, w dowolnej kolejności.

funkcje glVertexAttribPointer - powinny być poprzedzone zbindowaniem shadera, ale to masz.

Tego też nie widzę. Zresztą przecież shader można podmieniać w locie, byłoby nielogiczne żeby glVertexAttribPointer był uzależniony od shadera.

PM
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 7 lat
  • Postów:35
0
czaffik napisał(a):

To mi się jeszcze wydaje wątpliwe:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0, Format, GL_UNSIGNED_BYTE, surface->pixels);

  • jeżeli obrazek ma format RGB to 3 parametr też powinien być GL_RGB

Niczego to niestety nie zmienia. Jutro przejrzę wszystko od początku i dam znać.

Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 18 godzin
0

Nie wiem dlaczego ci nie działa — byłoby lepiej gdybyś dał cały program dający się skompilować — ale tu widzę wyciek pamięci:

Kopiuj
    SDL_Surface *surface = IMG_Load(textureName.c_str());

Nigdzie nie zwalniasz tego obrazka. Po wykonaniu glTexImage2D nie jest ci już potrzebny.

PM
Tym się akurat nie martwię na razie, bardziej mnie zastanawia dlaczego to się nie renderuje.
PM
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 7 lat
  • Postów:35
0

https://github.com/DonTweaks/SDL_image-openGL/tree/master Mógłbyś mi też powiedzieć w jaki sposób mam taki błąd szukać. Debuger, debugerem, ale gdzie podstawić breakpoint w takim przypadku, gdzie uv jest ustawione, kolor działa, błędów w kompilacji nie pokazuje... Ustawiłem sobie breakpoint na początku maina i przejechałem po wszystkich funkcjach ale niczego złego nie mogłem zobaczyć. Chyba, że w inny sposób się szuka takich błędów.

edytowany 1x, ostatnio: PawelMo
CZ
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 lata
  • Postów:231
0

@Azarien: Może i nie ma w specyfikacji takiej informacji, ale przed rysowaniem (glDrawArrays, glDrawElements) bindujesz vao (no chyba że to qt), a informacje o werteksach przekazujesz do vbo, więc wydaje się logiczne przypisać te vbo do jakiegoś vao.

Wywołanie glVertexAttribPointer też może być uzależnione bo robię to tak:

Kopiuj
GLint value3 = glGetAttribLocation(program->getID(), "texcoord");
glEnableVertexAttribArray(value3);
glVertexAttribPointer(value3, 2, GL_FLOAT, GL_FALSE, 8*sizeof(float), (void*)(6*sizeof(float)));

No chyba że jest tylko jeden shader, wtedy może nie trzeba pobierać wartości tylko iterować od zera, ale pewniej zrobić tak. (Chociaż jest layout location, może się mylę).

Pomylisz jedną małą rzecz i już ci się nie rysuje.

Odnośnie glVertexAttribArray:

Kopiuj
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, uv));

Czemu masz włączone tylko dwa atrybuty a przekazujesz trzy?

edytowany 4x, ostatnio: czaffik
PM
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 7 lat
  • Postów:35
0

Hm... to mogło powodować błąd, ale już poprawiłem i to samo.

CZ
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 2 lata
  • Postów:231
0

W takim razie: https://pastebin.com/79Vuq4CX - działa, tylko paskudnie wygląda :)
Zmodyfikowałem funkcję InitVBO

Jak zrobię tak:

Kopiuj
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));

glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));

glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, uv));

Też działa.

Jeszcze jedno, jakiego formatu obrazka używasz? Użyłem 512x512.

edytowany 2x, ostatnio: czaffik
Azarien
bo kolejność wywołania glEnableVertexAttribArray i glVertexAttribPointer jest bez znaczenia.
CZ
faktycznie nie ma, ale raczej chodziło o pobranie wartości za pomocą glGetAttribLocation a wpisanie na sztywno z wartości layout location.
Azarien
tak, zgadzam się co go glGetAttribLocation, patrz też mój post na dole.
PM
  • Rejestracja:ponad 7 lat
  • Ostatnio:ponad 7 lat
  • Postów:35
0

Dziękuje. Chodzi wszystko jak marzenie C:

CZ
przydało by się flipImage
PM
Odjąłem 1 od uv.x w shaderze.
CZ
też można, dobry patent
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 18 godzin
1

Jeszcze jedna uwaga - takie coś:

Kopiuj
    GLint uniformTime = glGetUniformLocation(shaderProgram, "time");
    GLint uniformUV = glGetUniformLocation(shaderProgram, "mySampler");

jest bardzo mylące. Jeszcze kilka tych uniformów i przestaniesz ogarniać który jest który.

Lepiej uniformy nazywać jednolicie w shaderze i w C, np. tak:

Kopiuj
    GLint u_time = glGetUniformLocation(shaderProgram, "u_time");
    GLint u_mySampler = glGetUniformLocation(shaderProgram, "u_mySampler");

To samo się tyczy atrybutów:

Kopiuj
layout (location = 0) in vec2 a_pos; // tak samo a_col, a_uv
...
GLint a_pos = glGetAttribLocation(shaderProgram, "a_pos"); // tak samo reszta

glEnableVertexAttribArray(a_pos);
glVertexAttribPointer(a_pos, ...);

tak łatwiej o porządek gdy się tych atrybutów i uniformów zrobi więcej.

edytowany 1x, ostatnio: Azarien
PM
Rozumiem, dzięki, dobry pomysł, na pewno będę korzystał.
Azarien
jeszcze to co w vertex shaderze jest “out” a we fragment shaderze jest “in” to się nazywa varying, i używam prefiksu v_
CZ
nie za bardzo przepadam za tymi prefiksami, jednak mogą ułatwiać identyfikację uniformów i w kodzie C (czy innego języka) i w kodzie shadera.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.