[OpenGL] Desafio Matemático

Mi interés por el bajo nivel de la programación hizo que me adentrará en el mundo de cómo construir un motor de videojuegos.
Siendo el centro, bibliotecas cómo sdl, sea la 2 o 3, cómo primer paso (sin contar la base de assembly en z80…). Pero, el tema es OpenGL, gráficos en 3D.

Prácticamente toda la biblioteca depende de usar matrices (que no las estudio en mi carrera de física, no sé por qué no las dan…). Pero, la mayoría de tutoriales, tanto en español cómo inglés, usan GLM.

Con lo cual, desarrollando una función que muestra las matrices:

[a][b][c][d]
[e][f][g][h]
[i][j][k][n]
[q][e][r][t]

Que muestro las matrices, por consola, algo cómo arriba.

Así, al usar las funciones de GLM, podía ver que hacían.

Translate():

[1][0][0][0]
[0][1][0][0]
[0][0][1][0]
[x][y][z][1]

Dónde se puede ver las posiciones que hay que alterar para mover una entidad en el espacio tridimensional.

De la página: La Mecánica Cuántica: La matriz generadora de rotación
Se puede ver en que sectores hay que modificar para rotar a la entidad.
Pero, la matriz es 4x4, entonces es:

[x][x][x][0]
[x][x][x][0]
[x][x][x][0]
[0][0][0][0]

Dónde están las x, sería dónde hacer las operaciones de la imagen.
Aunque esté usa glm: Tutorial 3 : Matrices

Explica cómo es el tema de trasladar y escalar, aunque no la rotación…

Para replicar:

glm::mat4 model = glm::mat4(1.f);

En c:

typedef float (*mat4)[4];
mat4 model = CreateMat4(1.f);

Con lo cual:

typedef float (*mat4)[4];
float (*model)[4] = (float(*)[4])malloc(64);

Para poder ver la estructura interna de la matriz a bajo nivel.
Un puntero a array.

El tema sería, intentar replicar las funciones de:

glm::ortho();
glm::perspective();
glm::lookAt();

Las relacionadas a la “cámara”.

La única que, más o menos tengo:

mat4 ortho(float left, float right, float bottom, float top, float near, float far)
{

	mat4 model = CreateMat4(0.f); // Inicializamos en 0

	model[0][0] = 2.0f / (right - left);
	model[1][1] = 2.0f / (top - bottom);
	model[2][2] = -2.0f / (far - near);

	model[3][0] = - (right + left) / (right - left);
	model[3][1] = - (top + bottom) / (top - bottom);
	model[3][2] = - (far + near) / (far - near);
	model[3][3] = 1.0f;

	return model;
}

El código completo del reemplazo de glm en c:

matrix.h:

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

typedef float (*mat4)[4];

mat4 CreateMat4(float value);
void translate(mat4 model,float x,float y,float z);
void printMat4(const char *name,mat4 model);
mat4 ortho(float left, float right, float bottom, float top, float near, float far);
void multiplyMat4(const mat4 a, const mat4 b, mat4 result);
void ResetMat4(mat4 model);

matrix.c:

#include <mymath.h>

mat4 CreateMat4(float value)
{
	float (*model)[4] = (float(*)[4])malloc(64);
	float *p = &model[0][0];
	for(char i=0; i<16; ++i) *(p+i) = 0.f;
	model[0][0] = value;
	model[1][1] = value;
	model[2][2] = value;
	model[3][3] = value;
	return model;
}

void ResetMat4(mat4 model)
{
	float *p = &model[0][0];
	for(char i=0; i<16; ++i) *(p+i) = 0.f;
	model[0][0] = 1.f;
	model[1][1] = 1.f;
	model[2][2] = 1.f;
	model[3][3] = 1.f;
}

void translate(mat4 model,float x,float y,float z)
{
	float *p = &model[3][0];
	*(p+0) += x;
	*(p+1) += y;
	*(p+2) += z;
}

void printMat4(const char *name,mat4 model)
{
	float *mat4 = &model[0][0];
	puts(name);
	printf("[%.7f] [%.7f] [%.7f] [%.7f]\n",
		*mat4,*(mat4+1),*(mat4+2),*(mat4+3));
	printf("[%.7f] [%.7f] [%.7f] [%.7f]\n",
		*(mat4+4),*(mat4+5),*(mat4+6),*(mat4+7));
	printf("[%.7f] [%.7f] [%.7f] [%.7f]\n",
		*(mat4+8),*(mat4+9),*(mat4+10),*(mat4+11));
	printf("[%.7f] [%.7f] [%.7f] [%.7f]\n",
		*(mat4+12),*(mat4+13),*(mat4+14),*(mat4+15));
	putchar(0x0A);
}

mat4 ortho(float left, float right, float bottom, float top, float near, float far)
{

	mat4 model = CreateMat4(0.f); // Inicializamos en 0

	model[0][0] = 2.0f / (right - left);
	model[1][1] = 2.0f / (top - bottom);
	model[2][2] = -2.0f / (far - near);

	model[3][0] = - (right + left) / (right - left);
	model[3][1] = - (top + bottom) / (top - bottom);
	model[3][2] = - (far + near) / (far - near);
	model[3][3] = 1.0f;

	return model;
}

void _multiplyMat4(const mat4 a,const mat4 b,mat4 result)
{
	float *rta = &result[0][0];
	const float *a_t = &a[0][0];
	const float *b_t = &b[0][0];
	for(int i=0; i<16; i++){
		*(rta+i) = 0.f;
		for(int j=0; j<4; j++)
			*(rta+i) += *(a_t+j) * *(b_t+j);
	}
}

void multiplyMat4(const mat4 a, const mat4 b, mat4 result) {
	for (int row = 0; row < 4; ++row) {
		for (int col = 0; col < 4; ++col) {
			result[row][col] = 0.0f;
			for (int k = 0; k < 4; ++k) {
				result[row][col] += a[row][k] * b[k][col];
			}
		}
	}
}

shader.c:

#include <shader.h>


int sizeFile(FILE *file)
{
	fseek(file,0,SEEK_END);
	long position = ftell(file);
	fseek(file,0,SEEK_SET);
	return (int)position;
}


void GetError(uint shader)
{
	int result;
	int lengthinfo;
	char *infolog;
	glGetShaderiv(shader,GL_COMPILE_STATUS,&result);
	if(result == 0){
		glGetShaderiv(shader,GL_INFO_LOG_LENGTH,&lengthinfo);
		infolog = (char*)malloc(lengthinfo+20);
		glGetShaderInfoLog(shader,lengthinfo,NULL,&infolog[0]);
		printf("[ERROR]: %s\n",infolog);
	}
}

void GetErrorProgram(uint program)
{
	int result;
	int lengthinfo;
	char *infolog;
	glGetProgramiv(program,GL_LINK_STATUS,&result);
	if(result == 0){
		glGetProgramiv(program,GL_INFO_LOG_LENGTH,&lengthinfo);
		infolog = (char*)malloc(lengthinfo+20);
		glGetProgramInfoLog(program,lengthinfo,NULL,&infolog[0]);
		printf("[ERROR]: %s\n",infolog);
	}
}

uint LoadShaders_c(const char *vertex,const char *fragment)
{
	uint program = glCreateProgram();
	uint vertexid = glCreateShader(GL_VERTEX_SHADER);
	uint fragmentid = glCreateShader(GL_FRAGMENT_SHADER);
	FILE *fileVertex = fopen(vertex,"rb");
	FILE *fileFragment = fopen(fragment,"rb");
	int sizeVertex = sizeFile(fileVertex);
	int sizeFragment = sizeFile(fileFragment);
	char *codeVertex = (char*)malloc(sizeVertex+1);
	char *codeFragment = (char*)malloc(sizeFragment+1);
	fread(codeVertex,sizeVertex,1,fileVertex);
	codeVertex[sizeVertex] = '\0';
	fread(codeFragment,sizeFragment,1,fileFragment);
	codeFragment[sizeFragment] = '\0';

	glShaderSource(vertexid,1,(const char**)&codeVertex,NULL);
	glCompileShader(vertexid);
	GetError(vertexid);

	glShaderSource(fragmentid,1,(const char**)&codeFragment,NULL);
	glCompileShader(fragmentid);
	GetError(fragmentid);

	glAttachShader(program,vertexid);
	glAttachShader(program,fragmentid);
	glLinkProgram(program);
	GetErrorProgram(program);

	glDetachShader(program,vertexid);
	glDetachShader(program,fragmentid);

	glDeleteShader(vertexid);
	glDeleteShader(fragmentid);

	free(codeVertex);
	free(codeFragment);
	fclose(fileFragment);
	fclose(fileVertex);
	return program;
}














main.c:

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdint.h>

extern "C"{
#include <shader.h>
#include <mymath.h>
#include <string.h>
}


const float triangle[] = {
	0.0f, 100.0f, 0.0f,
	100.0f, 100.0f, 0.0f,
	50.0f, 0.0f, 0.0f
};



typedef struct{
	uint vao,vbo,program,matrix;
	float x,y,z;
	mat4 MVP;
	char name[7];
}entity;

void destroyEntity(entity *self)
{
	free(self->MVP);
	glDeleteBuffers(1,&self->vbo);
	glDeleteVertexArrays(1,&self->vao);
	glDeleteProgram(self->program);
}

entity *createEntity(const float *model,int size)
{
	entity *initial = (entity*)malloc(sizeof(entity));
	initial->x = 0.f;
	initial->y = 0.f;
	initial->z = 0.f;
	initial->program = LoadShaders_c(
		"res/shaders/vertex.glsl","res/shaders/fragment.glsl");
	initial->matrix = glGetUniformLocation(initial->program,"MVP");
	initial->MVP = CreateMat4(1.f);

	glGenVertexArrays(1,&initial->vao);
	glGenBuffers(1,&initial->vbo);
	glBindVertexArray(initial->vao);

	glBindBuffer(GL_ARRAY_BUFFER,initial->vbo);
	glBufferData(GL_ARRAY_BUFFER,size,model,GL_STATIC_DRAW);
	glEnableVertexAttribArray(0);
	glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,0,(void*)0);

	glBindBuffer(GL_ARRAY_BUFFER,0);
	glBindVertexArray(0);
	return initial;
}

void drawEntity(entity *self,float r,float g,float b)
{
	int color = glGetUniformLocation(self->program,"useColor");
	glUseProgram(self->program);
	glUniform4f(color,r,g,b,1.0f);
	glUniformMatrix4fv(self->matrix,1,GL_FALSE,&self->MVP[0][0]);
	glBindVertexArray(self->vao);
	glDrawArrays(GL_TRIANGLES,0,3);
}

void moveEntity(entity *self,float x,float y,float z,float r = 0.0f)
{
	
	x = (x*0.00156225f)*2.f;
	y = (y*0.002777777778f)*2.f;
	//printf("%s: x: %f y: %f\n", self->name,(self->x*640)/2,(self->y*360)/2);
	
	self->x += x; self->y += y; self->z += z;
	if(self->x >= 2.0f) self->x = 0.0f;
	if(self->y <= -2.0f) self->y = 0.0f;
	//if(self->x >= 540.0f) self->x = 0.0f;
	//if(self->y >= 260.0f) self->y = 0.0f;
	self->matrix = glGetUniformLocation(self->program,"MVP");

	mat4 projection = ortho(0.0f, 640.0f, 360.0f, 0.0f, -1.0f, 1.0f);
	mat4 view = CreateMat4(1.f);
	mat4 model = CreateMat4(1.f);
	translate(model,self->x,self->y,self->z);
	//printMat4(self->name,model);
	
	mat4 temp = CreateMat4(1.f);
	//ResetMat4(self->MVP);
	multiplyMat4(view,model,temp);
	multiplyMat4(projection,temp,self->MVP);
	free(projection);
	free(view);
	free(model);
	free(temp);
}

int main(int argc, char const **argv)
{
	glfwInit();
	glfwWindowHint(GLFW_SAMPLES,4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,0);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GL_TRUE);
	glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
	GLFWwindow *window = glfwCreateWindow(640,360,"My Window",NULL,NULL);
	glfwMakeContextCurrent(window);
	gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);

	glClearColor(1.0f,1.0f,1.0f,0.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);

	entity *player = createEntity((const float*)&triangle,sizeof(triangle));
	entity *enemie = createEntity((const float*)&triangle,sizeof(triangle));
	strcat(player->name,"player\0");
	strcat(enemie->name,"enemie\0");

	do{
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		/* TODO CODE */
		drawEntity(player,0.f,1.f,0.f);
		moveEntity(player,1.f,-1.f,0.f);

		drawEntity(enemie,1.f,0.f,0.f);
		moveEntity(enemie,1.f,0.f,0.f);
		/* CODE END */
		glfwSwapBuffers(window);
		glfwPollEvents();
	}while(glfwGetKey(window,GLFW_KEY_ESCAPE) != GLFW_PRESS
			&& glfwWindowShouldClose(window) == 0);
	free(player);
	free(enemie);
	return 0;
}



Necesitas tener glad.
GLSL:
vertex.glsl:

#version 400 core

layout (location = 0) in vec3 vertexPosition_modelspace;
uniform mat4 MVP;

void main()
{
	gl_Position = MVP * vec4(vertexPosition_modelspace,1);
}


fragment.glsl:

#version 400

out vec4 color;
uniform vec4 useColor;

void main()
{
	color = useColor;
}


4 Me gusta