Programação com OpenGL/Modern OpenGL Tutorial 06: diferenças entre revisões

m
<source> -> <syntaxhighlight> (phab:T237267)
[edição verificada][revisão pendente]
Sem resumo de edição
m (<source> -> <syntaxhighlight> (phab:T237267))
 
 
Ta compilar automaticamente o aplicativo quando você modificar o res_texture.c, coloque ele no Makefile:
<sourcesyntaxhighlight lang="make">
cube.o: res_texture.c
</syntaxhighlight>
</source>
 
== Criando uma textura para o OpenGL buffer ==
Um buffer é basicamente um espaço na memória da placa de vídeo, assim o OpenGL pode acessá-lo rapidamente.
 
<sourcesyntaxhighlight lang="c">
/* Globais */
GLuint texture_id;
GLint uniform_mytexture;
</syntaxhighlight>
</source>
<sourcesyntaxhighlight lang="c">
/* init_resources */
glGenTextures(1, &texture_id);
GL_UNSIGNED_BYTE, // tipo
res_texture.pixel_data);
</syntaxhighlight>
</source>
<sourcesyntaxhighlight lang="c">
/* render */
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture_id);
glUniform1i(uniform_mytexture, /*GL_TEXTURE*/0);
</syntaxhighlight>
</source>
<sourcesyntaxhighlight lang="c">
/* free_resources */
glDeleteTextures(1, &texture_id);
</syntaxhighlight>
</source>
 
== Coordenadas da textura ==
GLint attribute_coord3d, attribute_v_color''', attribute_texcoord''';
 
<sourcesyntaxhighlight lang="c">
/* init_resources */
attribute_name = "texcoord";
return 0;
}
</syntaxhighlight>
</source>
 
Agora, que parte da textura nós mapearemos, para dizer, no canto superior esquerdo da face da frente? Bem isto depende:
 
Para começar enfim, vamos apenas trabalhar com a face frontal. Facil! nós apenas teremos na tela os 2 primeiros triângulos (as 6 primeiras vértices):
<sourcesyntaxhighlight lang="c">
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
</syntaxhighlight>
</source>
 
Assim, as coordenadas da nossa textura estarão entre [0, 1], com o eixo x da esquerda para direita, e o eixo y de baixo para cima:
<sourcesyntaxhighlight lang="c">
/* init_resources */
GLfloat cube_texcoords[] = {
glBindBuffer(GL_ARRAY_BUFFER, vbo_cube_texcoords);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube_texcoords), cube_texcoords, GL_STATIC_DRAW);
</syntaxhighlight>
</source>
<sourcesyntaxhighlight lang="c">
/* onDisplay */
glEnableVertexAttribArray(attribute_texcoord);
0 // deslocamento do primeiro elemento
);
</syntaxhighlight>
</source>
 
Vertex shader:
<sourcesyntaxhighlight lang="glsl">
attribute vec3 coord3d;
attribute vec2 texcoord;
f_texcoord = texcoord;
}
</syntaxhighlight>
</source>
 
Fragment shader:
<sourcesyntaxhighlight lang="glsl">
varying vec2 f_texcoord;
uniform sampler2D mytexture;
gl_FragColor = texture2D(mytexture, f_texcoord);
}
</syntaxhighlight>
</source>
 
[[File:OpenGL_Tutorial_Texture_Flipped.png|thumb|Alguma coisa está errada...]]
 
Revertendo a coordenada da textura é um meio mais fácil para nós, podemos fazer isto no fragment shader:
<sourcesyntaxhighlight lang="glsl">
void main(void) {
vec2 flipped_texcoord = vec2(f_texcoord.x, 1.0 - f_texcoord.y);
gl_FragColor = texture2D(mytexture, flipped_texcoord);
}
</syntaxhighlight>
</source>
 
Certo, tecnicamente nós poderíamos escrever as coordenadas da textura em outra direçõe logo de cara - mas outros aplicativos 3D costumam trabalhar como nós descrevemos.
== Um cubo completo ==
Assim como nós dizemos, vamos especificar vértices independentes para cada face:
<sourcesyntaxhighlight lang="c">
GLfloat cube_vertices[] = {
// frente
1.0, 1.0, 1.0,
};
</syntaxhighlight>
</source>
 
Para cada face, as vértices serão colocadas em sentido anti-horário( Como o espectador esta encarando as faces).
Como consequência, o mapeamento da textura será a mesma em todas as faces:
<sourcesyntaxhighlight lang="cpp">
GLfloat cube_texcoords[2*4*6] = {
// front
for (int i = 1; i < 6; i++)
memcpy(&cube_texcoords[i*4*2], &cube_texcoords[0], 2*4*sizeof(GLfloat));
</syntaxhighlight>
</source>
Aqui nós especificamos o mapeamento para a face da frente, e copiaremos isto nas 5 faces restantes.
 
 
Os elementos do cubo são escritos similarmente, com 2 triângulo como índices(x, x+1, x+2), (x+2,x+3,x):
<sourcesyntaxhighlight lang="c">
GLushort cube_elements[] = {
// frente
int size; glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
glDrawElements(GL_TRIANGLES, size/sizeof(GLushort), GL_UNSIGNED_SHORT, 0);
</syntaxhighlight>
</source>
 
 
[[File:OpenGL_Tutorial_Cube_textured.png|thumb|Voe, cubo, voe!]]
Para ficar mais divertido, e para ver a face inferior, vamos implementar 3 movimentos de rotação mostradas no tutorial flying cube do NeHe´s, no <code>onIdle</code>:
<sourcesyntaxhighlight lang="cpp">
float angle = glutGet(GLUT_ELAPSED_TIME) / 1000.0 * 15; // base 15° per second
glm::mat4 anim = \
glm::rotate(glm::mat4(1.0f), angle*2.0f, glm::vec3(0, 1, 0)) * // Y axis
glm::rotate(glm::mat4(1.0f), angle*4.0f, glm::vec3(0, 0, 1)); // Z axis
</syntaxhighlight>
</source>
 
Está pronto!
 
Para instala-lo:
<sourcesyntaxhighlight lang="bash">
aptitude install libsoil-dev
</syntaxhighlight>
</source>
 
Referencie ele no seu Makefile:
<sourcesyntaxhighlight lang="make">
LDLIBS=-lglut -lSOIL -lGLEW -lGL -lm
</syntaxhighlight>
</source>
 
Uma função de nivel-alto permite que você carregue diretamente para um contexto OpenGL:
<sourcesyntaxhighlight lang="cpp">
glActiveTexture(GL_TEXTURE0);
GLuint texture_id = SOIL_load_OGL_texture
if(texture_id == 0)
cerr << "SOIL loading error: '" << SOIL_last_result() << "' (" << "res_texture.png" << ")" << endl;
</syntaxhighlight>
</source>
 
* O <code>SOIL_FLAG_INVERT_Y</code> intermediá a reversão da coordenada Y como dizemos acima.
 
Note que com este método, você não tem acesso as dimensões da imagem. Para isto, você precisa de uma API de nivel-baixo:
<sourcesyntaxhighlight lang="cpp">
int width, height;
unsigned char* img = SOIL_load_image("res_texture.png", &width, &height, NULL, 0);
glGenTextures(...
...
</syntaxhighlight>
</source>
 
 
251

edições