Browse Source

implement buffer backed lighting uniform structure

main
cinnaboot 5 years ago
parent
commit
54c65d1745
  1. 81
      data/full_lighting.frag
  2. 128
      src/main.cpp
  3. 15
      src/shader.cpp
  4. 20
      src/shader.h
  5. 44
      src/tangerine.cpp
  6. 21
      src/tangerine.h

81
data/full_lighting.frag

@ -6,75 +6,50 @@ in vec2 frag_uv;
out vec4 color;
layout (std140) uniform matrices
{
mat4 view_xform;
mat4 proj_xform;
mat4 normal_xform;
};
uniform mat4 node_xform;
uniform sampler2D sampler;
struct PointLight
{
vec3 pos;
vec3 color;
uint intensity;
};
struct DirectionalLight
{
vec3 direction;
vec3 color;
uint intensity;
};
// FIXME: probably want a buffer-backed UBO for lights in case we have more
// than one shader that does lighting calculations
//uniform PointLight lights[32];
// FIXME: hard-coded values for testing
const DirectionalLight dl1 =
DirectionalLight(vec3(-2, 1, 3), vec3(1,1,1), 1u);
const vec4 ambient_color = vec4(0.1, 0.1, 0.1, 1);
const PointLight pl1 = PointLight(vec3(-20, 10, 30), vec3(1, 1, 1), 800u);
///
const uint NUM_LIGHTS = 32u;
layout (std140) uniform lights
{
uint active_p_lights;
uint buf_size;
uint max_p_lights;
uint active_d_lights;
uint active_p_lights;
uint max_d_lights;
PointLight p_lights[NUM_LIGHTS];
DirectionalLight d_lights[NUM_LIGHTS];
uint active_d_lights;
vec4 pl_positions[NUM_LIGHTS];
vec4 pl_colors[NUM_LIGHTS];
uint pl_intensities[NUM_LIGHTS]; // NOTE: 16 bytes * NUM_LIGHTS
vec4 dl_directions[NUM_LIGHTS]; // FIXME: should be directions
vec4 dl_colors[NUM_LIGHTS];
uint dl_intensities[NUM_LIGHTS]; // NOTE: 16 bytes * NUM_LIGHTS
};
void main()
{
for (uint i = 0u; i < NUM_LIGHTS; i++) {
if (p_lights[i].pos.x > 0)
color.r = 128;
// NOTE: directional lights
vec4 diffuse_color = vec4(0);
for (uint i = 0u; i < active_d_lights; i++) {
vec4 light_direction = normalize(dl_directions[i]);
float diffuse_factor =
clamp(dot(vec4(frag_normal, 1), light_direction), 0, 1);
diffuse_color = diffuse_color +
dl_intensities[i] * diffuse_factor * dl_colors[i];
}
#if 1 // directional light
vec3 light_direction = normalize(dl1.direction);
float diffuse_factor = clamp(dot(frag_normal, light_direction), 0, 1);
vec4 diffuse_color = dl1.intensity * vec4(dl1.color * diffuse_factor, 1);
#else // point light
vec3 light_direction = pl1.pos - frag_pos;
float len = length(light_direction);
light_direction = normalize(light_direction);
float diffuse_factor = dot(frag_normal, light_direction) / pow(len, 2);
diffuse_factor = clamp(diffuse_factor, 0, 1);
vec4 diffuse_color = pl1.intensity * vec4(pl1.color * diffuse_factor, 1);
#endif
//#else // point light
// vec4 light_direction = pl1.pos - frag_pos;
// float len = length(light_direction);
// light_direction = normalize(light_direction);
// float diffuse_factor = dot(frag_normal, light_direction) / pow(len, 2);
// diffuse_factor = clamp(diffuse_factor, 0, 1);
// vec4 diffuse_color = pl1.intensity * vec4(pl1.color * diffuse_factor);
//#endif
color = (ambient_color + diffuse_color) * texture(sampler, frag_uv.st);
}

128
src/main.cpp

@ -4,6 +4,57 @@
#include "tangerine.h"
bool
initLights(RenderState* rs)
{
// NOTE: add a directional light
LightsBuffer* lb = rs->lights_buf;
u32 idx = lb->active_d_lights++;
lb->dl_directions[idx] = glm::vec4(-2, 1, 3, 1);
lb->dl_colors[idx] = glm::vec4(1, 0.8, 0.6, 1);
lb->dl_intensities[idx] = glm::uvec4(1, 0, 0, 0);
// FIXME: we need an interface function to get uniforms by name
GLBuffer* lights_ubo = nullptr;
for (u32 i = 0; i < rs->gl_ctx->num_ubos; i++) {
GLBuffer* ubo = &rs->gl_ctx->uniform_buffers[i];
// FIXME: we need a utilty function for cstring comparison that takes
// into account the length of both strings so we don't match a longer
// string with a matching prefix
if (strncmp(ubo->name, "lights", 8))
lights_ubo = ubo;
}
// FIXME: we need an interface function to update lights
glBufferSubData(lights_ubo->target, 0, lb->buf_size, lb);
// FIXME: this only makes sense for point lights
#if 0
// NOTE: add a debug mesh to view the light source
RenderGroup* debug_group = getFreeRenderGroup(rs);
assert(debug_group);
ShaderProgram* s_debug = getShaderByName("debug", rs->gl_ctx);
assert(s_debug);
initRenderGroup(debug_group, rs->rg_arena, s_debug, 256, "debug_lights");
Entity* e = getFreeEntity(debug_group);
assert(e);
if (!initEntity(e,
rs->gl_ctx,
rs->rg_arena,
&rs->assets.models[0], // tex_cube from loadScene()
s_debug->num_vertex_attribs,
s_debug->attrib_mappings))
{
LOGF(Error, "Error initializing debug entity for light\n");
return false;
}
setEntityPosition(e, glm::vec3(lb->dl_directions[idx]));
#endif
return true;
}
bool
loadScene(RenderState* rs)
{
@ -56,38 +107,10 @@ loadScene(RenderState* rs)
scaleEntity(e, 3);
}
// NOTE: add a point light
PointLight* l1 = &rs->lights[rs->num_lights++];
l1->position = glm::vec3(-20, 10, 30);
l1->color = glm::vec3(1, 1, 1);
l1->intensity = 256;
// NOTE: add a debug mesh to view the light source
RenderGroup* debug_group = getFreeRenderGroup(rs);
assert(debug_group);
ShaderProgram* s_debug = getShaderByName("debug", rs->gl_ctx);
assert(s_debug);
initRenderGroup(debug_group, rs->rg_arena, s_debug, 256, "debug_lights");
for (u32 i = 0; i < rs->num_lights; i++) {
PointLight* l = &rs->lights[i];
Entity* e = getFreeEntity(debug_group);
assert(e);
if (!initEntity(e,
rs->gl_ctx,
rs->rg_arena,
tex_cube,
s_debug->num_vertex_attribs,
s_debug->attrib_mappings))
{
return false;
return initLights(rs);
}
setEntityPosition(e, l->position);
}
return true;
}
#include <glm/gtc/matrix_transform.hpp>
void
render_cb_pre(RenderState* rs)
@ -103,6 +126,45 @@ render_cb_pre(RenderState* rs)
}
}
// NOTE: wiggle camera
static glm::vec3 cam_pos = glm::vec3(0, 0, 50);
static glm::vec3 cam_mov = glm::vec3(0.3, 0, 0);
static glm::vec3 look_pos = glm::vec3(0, 0, 0);
static float direction = -1;
if (cam_pos.x < -20 || cam_pos.x > 20) {
direction *= -1;
cam_mov.x *= direction;
}
cam_pos += cam_mov;
rs->xforms->view_xform = glm::lookAt(cam_pos, look_pos, glm::vec3(0, 1, 0));
#if 1
// TODO: make helper function for getting UBO by name in shader.h
static GLBuffer* xform_ubo = nullptr;
u64 h_search = utilFNV64a_str("matrices");
if (!xform_ubo) {
for (u32 i = 0; i < rs->gl_ctx->num_ubos; i++) {
GLBuffer* buf = &rs->gl_ctx->uniform_buffers[i];
if (buf->name != nullptr) {
u64 hash = utilFNV64a_str(buf->name);
if (hash == h_search)
xform_ubo = buf;
}
}
if (!xform_ubo)
LOGF(Error, "matrices ubo not found\n");
}
updateCameraTransforms(rs->xforms, xform_ubo);
////
#endif
#if 0
for (u32 i = 0; i < rs->num_render_groups; i++) {
RenderGroup& rg = rs->render_groups[i];
@ -114,17 +176,17 @@ render_cb_pre(RenderState* rs)
direction * (float) M_PI / (3 * 60));
}
}
#endif
}
int
main()
{
RenderState* rs = initRenderState();
rs->clear_col = {0.2, 0.2, 0.2, 1};
if (rs) {
if (!loadScene(rs)) {
LOG(Error) << "error loading scene\n";
LOGF(Error, "error loading scene\n");
return 1;
}
@ -134,7 +196,7 @@ main()
return 0;
}
std::cout << "error loading scene\n";
LOGF(Error, "error loading scene\n");
return 1;
}

15
src/shader.cpp

@ -513,18 +513,23 @@ parseUniform(MemoryArena* arena, ShaderProgram* s, u32 uniform_idx)
GLUniform unif = {0};
GLchar unif_name[256] = {0};
GLsizei name_len = 0;
unif.idx = uniform_idx;
glGetActiveUniform(s->prog_id,
uniform_idx,
sizeof(unif_name),
&name_len,
&unif.num_elements,
&unif.data_type,
&unif.uniform_type,
unif_name);
glGetActiveUniformsiv(s->prog_id, 1, &uniform_idx,
GL_UNIFORM_BLOCK_INDEX, &unif.block_idx);
unif.idx = uniform_idx;
glGetActiveUniformsiv(s->prog_id, 1, &uniform_idx, GL_UNIFORM_BLOCK_INDEX,
&unif.block_idx);
glGetActiveUniformsiv(s->prog_id, 1, &uniform_idx, GL_UNIFORM_ARRAY_STRIDE,
&unif.array_stride);
glGetActiveUniformsiv(s->prog_id, 1, &uniform_idx, GL_UNIFORM_OFFSET,
&unif.uniform_offset);
unif.name = arenaCopyCStr(arena, unif_name);
unif.location = glGetUniformLocation(s->prog_id, unif.name);
@ -712,7 +717,7 @@ parseShader(MemoryArena* arena, GLContext* gl_ctx, ShaderProgram* s)
return true;
}
LOGF(Error, "%Error parsing shader\n");
LOGF(Error, "Error parsing shader\n");
return false;
}

20
src/shader.h

@ -17,9 +17,16 @@ struct GLUniform
GLuint idx;
GLint location;
GLint block_idx;
GLenum data_type;
GLint data_size;
GLint num_elements;
GLenum uniform_type; // NOTE: GL_UNSIGNED_INT, GL_FLOAT_VEC4
GLint num_elements; // NOTE: 1 unless uniform is an array of base types
// FIXME: we can't actually get this from opengl introspection API, we have
// to infer it from the uniform type...
GLint data_size; // NOTE: total size in bytes...
GLint array_stride; // NOTE: bytes between array elements
GLint uniform_offset; // NOTE: byte offset from beginning of uniform
char* name;
};
@ -142,13 +149,6 @@ struct GLMesh
struct Animation;
struct PointLight
{
glm::vec3 position;
glm::vec3 color;
u32 intensity;
};
struct Transforms
{
glm::mat4 view_xform;

44
src/tangerine.cpp

@ -10,7 +10,7 @@
bool initGraphics(SDLHandles* handles);
LightsBuffer initLights(MemoryArena* arena, GLContext* gl_ctx, u32 max_lights);
LightsBuffer* initLights(MemoryArena* arena, GLContext* gl_ctx, u32 max_lights);
// interface
@ -290,17 +290,35 @@ initGraphics(SDLHandles* handles)
return handles->window != nullptr;
}
LightsBuffer
LightsBuffer*
initLights(MemoryArena* arena, GLContext* gl_ctx, u32 max_lights)
{
// FIXME: revisit for 'Scene' abstraction
LightsBuffer lights_buf;
lights_buf.active_p_lights = 0;
lights_buf.active_d_lights = 0;
lights_buf.max_p_lights = max_lights;
lights_buf.max_d_lights = max_lights;
lights_buf.p_lights = ARENA_ALLOC(arena, PointLight, max_lights);
lights_buf.d_lights = ARENA_ALLOC(arena, PointLight, max_lights);
// TODO: we need a way to do this automatically somehow
u32 buf_size = 8 * sizeof(u32) // NOTE: 'header'
+ 6 * max_lights * sizeof(glm::vec4); // NOTE: vector arrays
LOGF(Debug, "buf_size: %d\n", buf_size);
LightsBuffer* lb = (LightsBuffer*) ARENA_ALLOC(arena, u8, buf_size);
lb->buf_size = buf_size;
lb->max_p_lights = max_lights;
lb->max_d_lights = max_lights;
// NOTE: set offsets for array pointers
lb->pl_positions = (glm::vec4*) arenaGetAddressOffset(lb, 8 * sizeof(u32));
u32 arr_size = max_lights * sizeof(glm::vec4);
lb->pl_colors =
(glm::vec4*) arenaGetAddressOffset(lb->pl_positions, arr_size);
lb->pl_intensities =
(glm::uvec4*) arenaGetAddressOffset(lb->pl_colors, arr_size);
lb->dl_directions =
(glm::vec4*) arenaGetAddressOffset(lb->pl_intensities, arr_size);
lb->dl_colors =
(glm::vec4*) arenaGetAddressOffset(lb->dl_directions, arr_size);
lb->dl_intensities =
(glm::uvec4*) arenaGetAddressOffset(lb->dl_colors, arr_size);
GLBuffer* lights_ubo = getFreeUBO(gl_ctx);
assert(lights_ubo);
@ -311,20 +329,16 @@ initLights(MemoryArena* arena, GLContext* gl_ctx, u32 max_lights)
assert((GLint) gl_ctx->binding_count < gl_ctx->max_binding_points);
lights_ubo->binding_idx = gl_ctx->binding_count++;
// FIXME: need to pad any vec3s to vec4 to match layout std140
u32 buf_size = sizeof(LightsBuffer)
+ max_lights * sizeof(PointLight)
+ max_lights * sizeof(PointLight);
glGenBuffers(1, &lights_ubo->id);
glBindBuffer(lights_ubo->target, lights_ubo->id);
glBufferData(lights_ubo->target,
buf_size,
&lights_buf,
lb,
GL_DYNAMIC_DRAW);
glBindBufferBase(lights_ubo->target,
lights_ubo->binding_idx,
lights_ubo->id);
return lights_buf;
return lb;
}

21
src/tangerine.h

@ -109,13 +109,22 @@ struct GLClearColor
// NOTE: structure to match the layout of the 'lights' uniform in a shader
struct LightsBuffer
{
u32 active_p_lights;
u32 buf_size;
u32 max_p_lights;
u32 active_d_lights;
u32 active_p_lights;
u32 max_d_lights;
// FIXME: do we need any padding here for layout(std 140)?
PointLight* p_lights;
PointLight* d_lights; // TODO: directional lights
u32 active_d_lights;
// NOTE: padding for std140, vec4 need to be aligned at 16 bytes
u8 padding[12];
glm::vec4* pl_positions;
glm::vec4* pl_colors;
glm::uvec4* pl_intensities;
glm::vec4* dl_directions;
glm::vec4* dl_colors;
glm::uvec4* dl_intensities;
};
struct RenderState
@ -136,7 +145,7 @@ struct RenderState
// could have render groups, lights, camera
// could match up with gltf scene graph where everyting is part of a node
// TODO: will also need other types of lights: directional, spotlight
LightsBuffer lights_buf;
LightsBuffer* lights_buf;
#if 0
u32 num_lights;
u32 max_lights;

Loading…
Cancel
Save