summaryrefslogtreecommitdiff
path: root/pbr/2.1.2.ibl_irradiance/ibl_irradiance.c
blob: e6f13901dc862451cb64a268de92516cdcabc921 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "common.h"

int main(void)
{
	state_t state = init_state(1600, 800);

	init_glfw(&state);
	init_gl();
	glDepthFunc(GL_LEQUAL);

	/* meshes */
	Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj");
	Mesh *sphere = mesh_load_obj(state.arena, "../../data/models/sphere.obj");
	Mesh *quad = mesh_gen_quad(state.arena);

	/* shaders */
	add_shader("pbr.vert",        "pbr.frag",        0);
	add_shader("hdr.vert",        "hdr.frag",        0);
	add_shader("cubemap.vert",    "cubemap.frag",    0);
	add_shader("background.vert", "background.frag", 0);
	add_shader("convolution.vert", "convolution.frag", 0);

	light_t lights[4] = {
		{{-10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}},
		{{-5.0f,  0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}},
		{{ 5.0f,  0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}},
		{{ 10.0f, 0.0f, 20.0f}, {300.0f, 300.0f, 300.0f}},
	};

	/* textures */
	U32 hdr_texture = load_hdr_texture("../../data/textures/loigerwiesen.hdr");;

	/* framebuffers */
	U32 hdr_fbo, hdr_colorbuffer, hdr_rbo;
	glGenFramebuffers(1, &hdr_fbo);
	glGenTextures(1, &hdr_colorbuffer);
	glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, state.width, state.height, 0, GL_RGBA, GL_FLOAT, 0);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glGenRenderbuffers(1, &hdr_rbo);
	glBindRenderbuffer(GL_RENDERBUFFER, hdr_rbo);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, state.width, state.height);
	glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo);
	glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, hdr_colorbuffer, 0);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdr_rbo);
	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
		die("failed to create framebuffer");
	glBindRenderbuffer(GL_RENDERBUFFER, 0);
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	U32 capture_fbo, capture_rbo;
	glGenFramebuffers(1, &capture_fbo);
	glGenRenderbuffers(1, &capture_rbo);
	glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo);
	glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512);
	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, capture_rbo);
	if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
		die("failed to create framebuffer");
	glBindRenderbuffer(GL_RENDERBUFFER, 0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	U32 cubemap;
	glGenTextures(1, &cubemap);
	glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
	for (U32 i = 0; i < 6; i++)
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, 0);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

	MAT4 capture_projection = perspective(90.0f, 1.0f, 0.1f, 10.0f);
	V3F capture_origin = {0};
	MAT4 capture_views[6] = {
		look_at(capture_origin, v3f( 1.0f,  0.0f,  0.0f), v3f(0.0f, -1.0f,  0.0f)),
		look_at(capture_origin, v3f(-1.0f,  0.0f,  0.0f), v3f(0.0f, -1.0f,  0.0f)),
		look_at(capture_origin, v3f( 0.0f,  1.0f,  0.0f), v3f(0.0f,  0.0f,  1.0f)),
		look_at(capture_origin, v3f( 0.0f, -1.0f,  0.0f), v3f(0.0f,  0.0f, -1.0f)),
		look_at(capture_origin, v3f( 0.0f,  0.0f,  1.0f), v3f(0.0f, -1.0f,  0.0f)),
		look_at(capture_origin, v3f( 0.0f,  0.0f, -1.0f), v3f(0.0f, -1.0f,  0.0f)),
	};

	glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo);
	U32 shader = find_shader("cubemap");
	if (!shader) die("waht");
	glUseProgram(shader);
	shader_set_mat4fv(shader, "projection", capture_projection);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, hdr_texture);

	glViewport(0, 0, 512, 512);
	for (U32 i = 0; i < 6; i++) {
		shader_set_mat4fv(shader, "view", capture_views[i]);
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemap, 0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		mesh_draw(cube);
	}
	glUseProgram(0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	U32 irradiance_map;
	glGenTextures(1, &irradiance_map);
	glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance_map);
	for (U32 i = 0; i < 6; i++)
		glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, 0);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

	glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo);
	glBindRenderbuffer(GL_RENDERBUFFER, capture_rbo);
	glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32);
	glBindRenderbuffer(GL_RENDERBUFFER, 0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	glBindFramebuffer(GL_FRAMEBUFFER, capture_fbo);
	shader = find_shader("convolution");
	glUseProgram(shader);
	shader_set_mat4fv(shader, "projection", capture_projection);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_CUBE_MAP, cubemap);
	glViewport(0, 0, 32, 32);
	for (U32 i = 0; i < 6; i++) {
		shader_set_mat4fv(shader, "view", capture_views[i]);
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradiance_map, 0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		mesh_draw(cube);
	}
	glUseProgram(0);
	glBindFramebuffer(GL_FRAMEBUFFER, 0);

	glViewport(0, 0, state.width, state.height);

	F32 time = 0;

	while (!glfwWindowShouldClose(state.window)) {
		handle_glfw_events(state.window, &state.input);
		F32 dt = lock_framerate(60);
		fps_info(dt, 10);

		/* update */
		update_camera_first_person(&state.camera, &state.input, dt, 2.0f);
		F32 limit = 4.0f;
		for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++)
			lights[i].position.y = sinf(time + i) * limit;
		time += dt;

		/* render */
		F32 ar = (F32)state.width / (F32)state.height;
		MAT4 projection = camera_persp(state.camera, ar);
		MAT4 view = get_view_matrix(&state.camera);

		glClearColor(0.16f, 0.16f, 0.16f, 1.0f);

		glBindFramebuffer(GL_FRAMEBUFFER, hdr_fbo);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		shader = find_shader("pbr");
		glUseProgram(shader);
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance_map);
		shader_set_mat4fv(shader, "projection", projection);
		shader_set_mat4fv(shader, "view", view);
		shader_set_3fv(shader, "camera", state.camera.pos);
		shader_set_3fv(shader, "color", v3f(0.04, 0.04, 0.04));
		shader_set_1f(shader, "ao", 1.0f);
		for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) {
			char str[512];
			snprintf(str, 512, "lights[%d].position", i);
			shader_set_3fv(shader, str, lights[i].position);
			snprintf(str, 512, "lights[%d].color", i);
			shader_set_3fv(shader, str, lights[i].color);
		}
		S32 rows = 7;
		S32 cols = 7;
		F32 offset = 3.0f;
		for (S32 row = 0; row < rows; row++) {
			shader_set_1f(shader, "metallic", (F32)row / (F32)rows);
			for (S32 col = 0; col < cols; col++) {
				shader_set_1f(shader, "roughness", clamp(0.05f, (F32)col / (F32)cols, 1.0f));
				V3F pos = {(col - cols / 2.0f) * offset, (row - rows / 2.0f) * offset, 0.0f};
				MAT4 model = mat4_make_translate(pos);
				shader_set_mat4fv(shader, "model", model);
				mesh_draw(sphere);
			}
		}

		for (U32 i = 0; i < (sizeof(lights) / sizeof(lights[0])); i++) {
			MAT4 model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f));
			model = mat4_translate(model, lights[i].position);
			shader_set_mat4fv(shader, "model", model);
			mesh_draw(sphere);
		}

		glUseProgram(0);

		shader = find_shader("background");
		glUseProgram(shader);
		shader_set_mat4fv(shader, "projection", projection);
		shader_set_mat4fv(shader, "view", view);
		glActiveTexture(GL_TEXTURE0);
		glBindTexture(GL_TEXTURE_CUBE_MAP, irradiance_map);
		mesh_draw(cube);
		glUseProgram(0);

		glBindFramebuffer(GL_FRAMEBUFFER, 0);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		shader = find_shader("hdr");
		if (!shader) die("failed to find hdr shader!");
		glUseProgram(shader);
		glBindTexture(GL_TEXTURE_2D, hdr_colorbuffer);
		shader_set_mat4fv(shader, "model", mat4_identity());
		mesh_draw(quad);
		glUseProgram(0);

		glfwSwapBuffers(state.window);
	}

	return 0;
}