Add lightmapper integration for raylib

This commit is contained in:
Alexander Klingenbeck 2023-06-18 16:13:39 +02:00
parent 75b8f12e9b
commit 3e28803a58
6 changed files with 274 additions and 4493 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ result.tga
lightmapper_example lightmapper_example
lightmapper_example.exe lightmapper_example.exe
result.png result.png
monkey.obj

View File

@ -0,0 +1,13 @@
#version 330
in vec2 fragTexCoord;
in vec4 fragColor;
out vec4 finalColor;
uniform sampler2D texture0;
uniform vec4 colDiffuse;
uniform float intensity;
void main()
{
vec4 texelColor = texture(texture0, fragTexCoord);
texelColor = texelColor*colDiffuse*fragColor*vec4(intensity, intensity, intensity, 1.0);
finalColor = vec4(texelColor.rgb, (gl_FrontFacing ? 1.0 : 0.0));
}

View File

@ -0,0 +1,13 @@
#version 330
in vec3 vertexPosition;
in vec2 vertexTexCoord;
in vec4 vertexColor;
out vec2 fragTexCoord;
out vec4 fragColor;
uniform mat4 mvp;
void main()
{
fragTexCoord = vertexTexCoord;
fragColor = vertexColor;
gl_Position = mvp*vec4(vertexPosition, 1.0);
}

40
cube.obj Normal file
View File

@ -0,0 +1,40 @@
# Blender v3.1.2 OBJ File: ''
# www.blender.org
mtllib cube.mtl
o Cube
v 1.000000 1.000000 -1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 1.000000 -1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 1.000000
vt 0.625000 0.500000
vt 0.875000 0.500000
vt 0.875000 0.750000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.125000 0.500000
vt 0.375000 0.500000
vt 0.125000 0.750000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 -1.0000 0.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
usemtl Material
s off
f 1/1/1 5/2/1 7/3/1 3/4/1
f 4/5/2 3/4/2 7/6/2 8/7/2
f 8/8/3 7/9/3 5/10/3 6/11/3
f 6/12/4 2/13/4 4/5/4 8/14/4
f 2/13/5 1/1/5 3/4/5 4/5/5
f 6/11/6 5/10/6 1/1/6 2/13/6

4398
monkey.obj

File diff suppressed because it is too large Load Diff

View File

@ -13,33 +13,19 @@
#define LM_DEBUG_INTERPOLATION #define LM_DEBUG_INTERPOLATION
#include "lightmapper.h" #include "lightmapper.h"
#ifndef M_PI // even with _USE_MATH_DEFINES not always available
#define M_PI 3.14159265358979323846
#endif
typedef struct {
float p[3];
float t[2];
} vertex_t;
typedef struct typedef struct
{ {
//GLuint program; //Shader raylib_shader;
Shader raylib_shader;
GLint u_lightmap;
GLint u_mvp;
Texture raylib_texture; Texture raylib_texture;
//GLuint lightmap;
int w, h; int w, h;
Model raylib_model; Model raylib_model;
Model model2;
Camera camera; Camera camera;
Shader shader;
GLuint u_intensity;
} scene_t; } scene_t;
static int initScene(scene_t *scene); static void FloatVToMatrix(float *array, struct Matrix *matrix) {
static void drawScene(scene_t *scene, float *view, float *projection);
static void destroyScene(scene_t *scene);
static void convertArrayToStruct(float *array, struct Matrix *matrix) {
matrix->m0 = array[0]; matrix->m0 = array[0];
matrix->m1 = array[1]; matrix->m1 = array[1];
matrix->m2 = array[2]; matrix->m2 = array[2];
@ -58,12 +44,149 @@ static void convertArrayToStruct(float *array, struct Matrix *matrix) {
matrix->m15 = array[15]; matrix->m15 = array[15];
} }
static void drawScene(scene_t *scene){
DrawModel(scene->raylib_model, (Vector3){ 0,0,0 }, 1, WHITE);
DrawModel(scene->model2, (Vector3){ -1,0.3,0.0 }, 0.05, RED);
}
typedef struct Lightmapper {
void * lm_handle;
float * data;
int w;
int h;
float progress;
} Lightmapper;
typedef struct LightmapperConfig {
int hemisphereSize;
float zNear;
float zFar;
Color backgroundColor;
int interpolationPasses;
float interpolationThreshold;
float cameraToSurfaceDistanceModifier;
} LightmapperConfig;
LightmapperConfig GetDefaultLightmapperConfig(){
return (LightmapperConfig){
64, 0.001f, 100.0f, WHITE, 2, 0.01f, 0.0f
};
}
Lightmapper LoadLightmapper(int w, int h, Mesh mesh, LightmapperConfig cfg){
Lightmapper lm = {0};
lm_context* ctx = lm.lm_handle = lmCreate(cfg.hemisphereSize, cfg.zNear, cfg.zFar,
cfg.backgroundColor.r / (float)255, cfg.backgroundColor.g / (float)255, cfg.backgroundColor.b / (float)255,
cfg.interpolationPasses, cfg.interpolationThreshold, cfg.cameraToSurfaceDistanceModifier);
if(ctx == NULL){
TraceLog(LOG_ERROR, "Unable to create lightmapper. Init failed.");
goto RETURN;
}
lm.w = w;
lm.h = h;
float *data = lm.data = calloc(w * h * 4, sizeof(float));
lmSetTargetLightmap(ctx, data, w, h, 4);
const void* indices = NULL;
lm_type indicesType = LM_NONE;
int count = mesh.vertexCount;
if(mesh.indices != NULL){
indices = mesh.indices;
indicesType = LM_UNSIGNED_SHORT;
count = mesh.triangleCount * 3;
}
lmSetGeometry(ctx, NULL,
LM_FLOAT, (unsigned char*)mesh.vertices, 0,
LM_FLOAT , (unsigned char*)mesh.normals, 0,
LM_FLOAT, (unsigned char*)mesh.texcoords, 0,
count, indicesType, indices);
RETURN:
return lm;
}
void UnloadLightmapper(Lightmapper lm){
free(lm.data);
lmDestroy((lm_context *)lm.lm_handle);
}
void BeginLightmap()
{
rlEnableDepthTest();
rlDisableColorBlend();
rlDisableBackfaceCulling();
}
void EndLightmap(){
rlDisableDepthTest();
rlEnableColorBlend();
rlEnableBackfaceCulling();
}
static int vp[4];
static float view[16], projection[16];
static Matrix matView, matProj;
bool BeginLightmapFragment(Lightmapper * lm){
lm_bool status = lmBegin((lm_context *)lm->lm_handle, vp, view, projection);
if(status){
rlViewport(vp[0], vp[1], vp[2], vp[3]);
FloatVToMatrix(view, &matView);
FloatVToMatrix(projection, &matProj);
rlSetMatrixModelview(matView);
rlSetMatrixProjection(matProj);
//float intensity = 1.0f;
//SetShaderValue(scene->shader, scene->u_intensity, &intensity, SHADER_UNIFORM_FLOAT);
} else {
lm->progress = 1.0f;
}
return (bool)status;
}
void EndLightmapFragment(Lightmapper * lm){
lmEnd((lm_context *)lm->lm_handle);
lm->progress = lmProgress((lm_context *)lm->lm_handle);
}
Image LoadImageFromLightmapper(Lightmapper lm){
Image im = { 0 };
if(lm.progress < 1.0f){
TraceLog(LOG_ERROR, "Lightmapping is not finished");
return im;
}
// postprocess texture
float *temp = calloc(lm.w * lm.h * 4, sizeof(float));
for (int i = 0; i < 16; i++)
{
lmImageDilate(lm.data, temp, lm.w, lm.h, 4);
lmImageDilate(temp, lm.data, lm.w, lm.h, 4);
}
lmImageSmooth(lm.data, temp, lm.w, lm.h, 4);
lmImageDilate(temp, lm.data, lm.w, lm.h, 4);
lmImagePower(lm.data, lm.w, lm.h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels
free(temp);
unsigned char *tempub = (unsigned char*)calloc(lm.w * lm.h * 4, sizeof(unsigned char));
lmImageFtoUB(lm.data, tempub, lm.w, lm.h, 4, 1.0f);
im.data = tempub;
im.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
im.height = lm.w;
im.width = lm.h;
return im;
}
static int bake(scene_t *scene) static int bake(scene_t *scene)
{ {
lm_context *ctx = lmCreate( lm_context *ctx = lmCreate(
64, // hemisphere resolution (power of two, max=512) 128, // hemisphere resolution (power of two, max=512)
0.001f, 100.0f, // zNear, zFar of hemisphere cameras 0.001f, 100.0f, // zNear, zFar of hemisphere cameras
0.1f, 0.15f, 0.5f, // background color (white for ambient occlusion) 1.0f, 1.0f, 1.0f, // background color (white for ambient occlusion)
2, 0.01f, // lightmap interpolation threshold (small differences are interpolated rather than sampled) 2, 0.01f, // lightmap interpolation threshold (small differences are interpolated rather than sampled)
// check debug_interpolation.tga for an overview of sampled (red) vs interpolated (green) pixels. // check debug_interpolation.tga for an overview of sampled (red) vs interpolated (green) pixels.
0.0f); // modifier for camera-to-surface distance for hemisphere rendering. 0.0f); // modifier for camera-to-surface distance for hemisphere rendering.
@ -87,22 +210,24 @@ static int bake(scene_t *scene)
rlEnableDepthTest(); rlEnableDepthTest();
rlDisableColorBlend(); rlDisableColorBlend();
Shader oldShader = scene->raylib_model.materials[0].shader; rlDisableBackfaceCulling();
scene->raylib_model.materials[0].shader = scene->raylib_shader;
scene->raylib_model.materials[0].maps[0].texture = scene->raylib_texture; // TODO: Write (gl_FrontFacing ? 1.0 : 0.0) to the alpha channel in custom shader
//Shader oldShader = scene->raylib_model.materials[0].shader;
//scene->raylib_model.materials[0].shader = scene->raylib_shader;
while (lmBegin(ctx, vp, view, projection)) while (lmBegin(ctx, vp, view, projection))
{ {
// render to lightmapper framebuffer
rlViewport(vp[0], vp[1], vp[2], vp[3]); rlViewport(vp[0], vp[1], vp[2], vp[3]);
Matrix matView, matProj; Matrix matView, matProj;
convertArrayToStruct(view, &matView); FloatVToMatrix(view, &matView);
convertArrayToStruct(projection, &matProj); FloatVToMatrix(projection, &matProj);
rlSetMatrixModelview(matView); rlSetMatrixModelview(matView);
rlSetMatrixProjection(matProj); rlSetMatrixProjection(matProj);
float intensity = 1.0f;
DrawModel(scene->raylib_model, (Vector3){ 0,0,0 }, 1, WHITE); SetShaderValue(scene->shader, scene->u_intensity, &intensity, SHADER_UNIFORM_FLOAT);
drawScene(scene);
// display progress every second (printf is expensive) // display progress every second (printf is expensive)
double time = GetTime(); double time = GetTime();
@ -117,7 +242,8 @@ static int bake(scene_t *scene)
} }
rlDisableDepthTest(); rlDisableDepthTest();
rlEnableColorBlend(); rlEnableColorBlend();
scene->raylib_model.materials[0].shader = oldShader; rlEnableBackfaceCulling();
//scene->raylib_model.materials[0].shader = oldShader;
lmDestroy(ctx); lmDestroy(ctx);
@ -170,8 +296,53 @@ int main(int argc, char* argv[])
InitWindow(1024,768,"Test"); InitWindow(1024,768,"Test");
scene_t scene = {0}; scene_t scene = {0};
initScene(&scene);
scene.shader = LoadShader("assets/shaders/glsl330/default.vs","assets/shaders/glsl330/default.fs");
scene.u_intensity = GetShaderLocation(scene.shader, "intensity");
// load mesh
scene.raylib_model = LoadModel("thirdparty/lightmapper/example/gazebo.obj");
scene.raylib_model.materials[0].shader = scene.shader;
scene.model2 = LoadModel("thirdparty/lightmapper/example/cube.obj");
scene.model2.materials[0].shader = scene.shader;
scene.w = 512;
scene.h = 512;
scene.raylib_texture = LoadTextureFromImage(GenImageColor(1,1,BLACK));
scene.raylib_model.materials[0].maps[0].texture = scene.raylib_texture;
Camera camera = { 0 };
camera.position = (Vector3){ 0.0f, 0.5f, 1.5f }; // Camera position
camera.target = (Vector3){ 0.0f, 0.35f, 0.0f }; // Camera looking at point
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
camera.fovy = 45.0f; // Camera field-of-view Y
camera.projection = CAMERA_PERSPECTIVE; // Camera mode type
scene.camera = camera;
bake(&scene); bake(&scene);
// Lightmapper lm = LoadLightmapper(scene.w, scene.h, scene.raylib_model.meshes[0], GetDefaultLightmapperConfig());
// double lastUpdateTime = 0;
// BeginLightmap();
// while(BeginLightmapFragment(&lm)){
// float intensity = 1.0f;
// SetShaderValue(scene.shader, scene.u_intensity, &intensity, SHADER_UNIFORM_FLOAT);
// drawScene(&scene);
// EndLightmapFragment(&lm);
// // display progress every second (printf is expensive)
// double time = GetTime();
// if (time - lastUpdateTime > 0.05)
// {
// lastUpdateTime = time;
// printf("\r%6.2f%%", lm.progress * 100.0f);
// fflush(stdout);
// }
// }
// EndLightmap();
// Image img = LoadImageFromLightmapper(lm);
// //ExportImage(img, "my_result.png");
// UnloadTexture(scene.raylib_texture);
// scene.raylib_texture = LoadTextureFromImage(img);
// scene.raylib_model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = scene.raylib_texture;
while (!WindowShouldClose()) while (!WindowShouldClose())
{ {
@ -183,74 +354,15 @@ int main(int argc, char* argv[])
BeginDrawing(); BeginDrawing();
BeginMode3D(scene.camera); BeginMode3D(scene.camera);
ClearBackground(BLUE); ClearBackground(BLUE);
DrawModel(scene.raylib_model, (Vector3) {0.0f,0.0f,0.0f}, 1, WHITE); float intensity = 1.0f;
SetShaderValue(scene.shader, scene.u_intensity, &intensity, SHADER_UNIFORM_FLOAT);
drawScene(&scene);
EndMode3D(); EndMode3D();
EndDrawing(); EndDrawing();
} }
destroyScene(&scene); UnloadModel(scene.raylib_model);
UnloadTexture(scene.raylib_texture);
CloseWindow(); CloseWindow();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int initScene(scene_t *scene)
{
// load mesh
scene->raylib_model = LoadModel("thirdparty/lightmapper/example/gazebo.obj");
Mesh m = scene->raylib_model.meshes[0];
if(m.normals != NULL) puts("Has normals");
if(m.texcoords != NULL) puts("Has texcoords");
if(m.texcoords2 != NULL) puts("Has texcoords2");
if(m.indices != NULL) puts("Has indices");
scene->w = 512;
scene->h = 512;
scene->raylib_texture = LoadTextureFromImage(GenImageColor(1,1,BLACK));
// load shader
const char *vp =
"#version 150 core\n"
"in vec3 vertexPosition;\n"
"in vec2 vertexTexCoord;\n"
"uniform mat4 mvp;\n"
"out vec2 v_texcoord;\n"
"void main()\n"
"{\n"
"gl_Position = mvp * vec4(vertexPosition, 1.0);\n"
"v_texcoord = vertexTexCoord;\n"
"}\n";
const char *fp =
"#version 150 core\n"
"in vec2 v_texcoord;\n"
"uniform sampler2D texture0;\n"
"out vec4 o_color;\n"
"void main()\n"
"{\n"
"o_color = vec4(texture(texture0, v_texcoord).rgb, gl_FrontFacing ? 1.0 : 0.0);\n"
"}\n";
scene->raylib_shader = LoadShaderFromMemory(vp, fp);
scene->u_lightmap = rlGetLocationUniform(scene->raylib_shader.id, "texture0");
scene->u_mvp = rlGetLocationUniform(scene->raylib_shader.id, "mvp");
Camera camera = { 0 };
camera.position = (Vector3){ 1.0f, 0.5f, 1.0f }; // Camera position
camera.target = (Vector3){ 0.0f, 0.35f, 0.0f }; // Camera looking at point
camera.up = (Vector3){ 0.0f, 1.0f, 0.0f }; // Camera up vector (rotation towards target)
camera.fovy = 45.0f; // Camera field-of-view Y
camera.projection = CAMERA_PERSPECTIVE; // Camera mode type
scene->camera = camera;
return 1;
}
static void destroyScene(scene_t *scene)
{
UnloadModel(scene->raylib_model);
UnloadTexture(scene->raylib_texture);
UnloadShader(scene->raylib_shader);
}