From 5eee29160cd23b98fd892fb05e0c1852dba773e3 Mon Sep 17 00:00:00 2001 From: Alexander Klingenbeck Date: Mon, 19 Jun 2023 18:17:33 +0200 Subject: [PATCH] Add lightmap materials --- .vscode/settings.json | 3 +- src/lightmapper_example.c | 321 ++++---------------------------------- src/rlightmapper.h | 233 +++++++++++++++++++++++++++ 3 files changed, 262 insertions(+), 295 deletions(-) create mode 100644 src/rlightmapper.h diff --git a/.vscode/settings.json b/.vscode/settings.json index 184a5f1..24111ae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,7 @@ "lightmapper.h": "c", "compare": "c", "memory": "c", - "rlgl.h": "c" + "rlgl.h": "c", + "random": "c" } } \ No newline at end of file diff --git a/src/lightmapper_example.c b/src/lightmapper_example.c index 799312e..8c070a3 100644 --- a/src/lightmapper_example.c +++ b/src/lightmapper_example.c @@ -9,9 +9,9 @@ #include #include #include -#define LIGHTMAPPER_IMPLEMENTATION -#define LM_DEBUG_INTERPOLATION -#include "lightmapper.h" + +#define RLIGHTMAPPER_IMPLEMENTATION +#include "rlightmapper.h" typedef struct { @@ -25,281 +25,9 @@ typedef struct GLuint u_intensity; } scene_t; -static void FloatVToMatrix(float *array, struct Matrix *matrix) { - matrix->m0 = array[0]; - matrix->m1 = array[1]; - matrix->m2 = array[2]; - matrix->m3 = array[3]; - matrix->m4 = array[4]; - matrix->m5 = array[5]; - matrix->m6 = array[6]; - matrix->m7 = array[7]; - matrix->m8 = array[8]; - matrix->m9 = array[9]; - matrix->m10 = array[10]; - matrix->m11 = array[11]; - matrix->m12 = array[12]; - matrix->m13 = array[13]; - matrix->m14 = array[14]; - 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); -} - -static Matrix mProjection; -static Matrix mModelview; - -void BeginLightmap() -{ - rlEnableDepthTest(); - rlDisableColorBlend(); - rlDisableBackfaceCulling(); - mProjection = rlGetMatrixProjection(); - mModelview = rlGetMatrixModelview(); -} - -void EndLightmap(){ - //rlDisableDepthTest(); - rlEnableColorBlend(); - rlEnableBackfaceCulling(); - int w = GetScreenWidth() * GetWindowScaleDPI().x; - int h = GetScreenHeight() * GetWindowScaleDPI().y; - rlViewport(0, 0, w, h); - rlDisableFramebuffer(); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - rlSetMatrixModelview(mModelview); - rlSetMatrixProjection(mProjection); -} - -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){ - lm->progress = lmProgress((lm_context *)lm->lm_handle); - lmEnd((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; - im.mipmaps = 1; - return im; -} - -static int bake(scene_t *scene) -{ - lm_context *ctx = lmCreate( - 128, // hemisphere resolution (power of two, max=512) - 0.001f, 100.0f, // zNear, zFar of hemisphere cameras - 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) - // 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. - // tweak this to trade-off between interpolated normals quality and other artifacts (see declaration). - - int w = scene->w, h = scene->h; - float *data = calloc(w * h * 4, sizeof(float)); - lmSetTargetLightmap(ctx, data, w, h, 4); - - Mesh m = scene->raylib_model.meshes[0]; - - lmSetGeometry(ctx, NULL, // no transformation in this example - LM_FLOAT, (unsigned char*)m.vertices, 0, - LM_FLOAT , (unsigned char*)m.normals, 0, - LM_FLOAT, (unsigned char*)m.texcoords, 0, - m.vertexCount, LM_NONE, 0); - - int vp[4]; - float view[16], projection[16]; - double lastUpdateTime = 0.0; - - rlEnableDepthTest(); - rlDisableColorBlend(); - rlDisableBackfaceCulling(); - - // 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)) - { - rlViewport(vp[0], vp[1], vp[2], vp[3]); - - Matrix matView, matProj; - FloatVToMatrix(view, &matView); - FloatVToMatrix(projection, &matProj); - rlSetMatrixModelview(matView); - rlSetMatrixProjection(matProj); - float intensity = 1.0f; - SetShaderValue(scene->shader, scene->u_intensity, &intensity, SHADER_UNIFORM_FLOAT); - drawScene(scene); - - // display progress every second (printf is expensive) - double time = GetTime(); - if (time - lastUpdateTime > 0.05) - { - lastUpdateTime = time; - printf("\r%6.2f%%", lmProgress(ctx) * 100.0f); - fflush(stdout); - } - - lmEnd(ctx); - } - rlDisableDepthTest(); - rlEnableColorBlend(); - rlEnableBackfaceCulling(); - //scene->raylib_model.materials[0].shader = oldShader; - - lmDestroy(ctx); - - // postprocess texture - float *temp = calloc(w * h * 4, sizeof(float)); - for (int i = 0; i < 16; i++) - { - lmImageDilate(data, temp, w, h, 4); - lmImageDilate(temp, data, w, h, 4); - } - lmImageSmooth(data, temp, w, h, 4); - lmImageDilate(temp, data, w, h, 4); - lmImagePower(data, w, h, 4, 1.0f / 2.2f, 0x7); // gamma correct color channels - free(temp); - - unsigned char *tempub = (unsigned char*)calloc(w * h * 4, sizeof(unsigned char)); - lmImageFtoUB(data, tempub, w, h, 4, 1.0f); - Image im; - im.data = tempub; - im.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - im.height = h; - im.width = w; - ExportImage(im,"result.png"); - - // upload result - UnloadTexture(scene->raylib_texture); - Texture texture; - texture.id = rlLoadTexture(tempub, w, h, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8, 1); - texture.width = w; - texture.height = h; - texture.mipmaps = 1; - texture.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; - scene->raylib_texture = texture; - free(tempub); - - scene->raylib_model.materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture; - - // // save result to a file - // if (lmImageSaveTGAf("result.tga", data, w, h, 4, 1.0f)) - // printf("Saved result.tga\n"); - // free(data); - - return 1; + //DrawModel(scene->model2, (Vector3){ -10,10,0.0 }, 3,RAYWHITE); } int main(int argc, char* argv[]) @@ -313,7 +41,7 @@ int main(int argc, char* argv[]) 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 = LoadModel("monkey.obj"); scene.raylib_model.materials[0].shader = scene.shader; scene.model2 = LoadModel("thirdparty/lightmapper/example/cube.obj"); scene.model2.materials[0].shader = scene.shader; @@ -331,32 +59,35 @@ int main(int argc, char* argv[]) camera.projection = CAMERA_PERSPECTIVE; // Camera mode type scene.camera = camera; - Lightmapper lm = LoadLightmapper(scene.w, scene.h, scene.raylib_model.meshes[0], GetDefaultLightmapperConfig()); + LightmapperConfig config = GetDefaultLightmapperConfig(); + config.backgroundColor = (Color){6,0,10}; + //config.hemisphereSize = 512; + Lightmapper lm = LoadLightmapper(scene.w, scene.h, scene.raylib_model.meshes[0], config); + Material lmMat = LoadMaterialLightmapper(BLACK, 0); + Mesh light = GenMeshCube(0.3,0.3, 0.3); + Material lightMaterial = LoadMaterialLightmapper(ORANGE, 1.0f); while (!WindowShouldClose()) { + if(IsMouseButtonDown(MOUSE_BUTTON_LEFT)) + UpdateCamera(&scene.camera, CAMERA_THIRD_PERSON); + if(lm.progress < 1.0f){ double startTime = GetTime(); BeginLightmap(); while(BeginLightmapFragment(&lm)){ - float intensity = 1.0f; - SetShaderValue(scene.shader, scene.u_intensity, &intensity, SHADER_UNIFORM_FLOAT); - drawScene(&scene); + DrawMesh(scene.raylib_model.meshes[0], lmMat, MatrixIdentity()); + DrawMesh(light, lightMaterial, MatrixTranslate(0,1.0,0)); EndLightmapFragment(&lm); // display progress every second (printf is expensive) double time = GetTime(); - if (GetTime() - startTime > 0.03) - { - printf("\r%6.2f%%", lm.progress * 100.0f); - fflush(stdout); - break; - } + if (GetTime() - startTime > 0.03) break; } EndLightmap(); if(lm.progress == 1.0f){ Image img = LoadImageFromLightmapper(lm); - ExportImage(img, "my_result.png"); - //UnloadTexture(scene.raylib_texture); + //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; UnloadLightmapper(lm); @@ -365,11 +96,13 @@ int main(int argc, char* argv[]) BeginDrawing(); ClearBackground(BLUE); - BeginMode3D(scene.camera); - float intensity = 1.0f; - SetShaderValue(scene.shader, scene.u_intensity, &intensity, SHADER_UNIFORM_FLOAT); - drawScene(&scene); - EndMode3D(); + + BeginMode3D(scene.camera); + float intensity = 1.0f; + SetShaderValue(scene.shader, scene.u_intensity, &intensity, SHADER_UNIFORM_FLOAT); + drawScene(&scene); + EndMode3D(); + // printf("%d\n",(int)(lm.progress*GetScreenWidth())); if(lm.progress < 1.0f){ DrawRectangle(0,0,GetScreenWidth(),20, Fade(GREEN,0.5)); diff --git a/src/rlightmapper.h b/src/rlightmapper.h new file mode 100644 index 0000000..13caad2 --- /dev/null +++ b/src/rlightmapper.h @@ -0,0 +1,233 @@ +#ifndef RLIGHTMAPPER_H +#define RLIGHTMAPPER_H + +#include + +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(); +Lightmapper LoadLightmapper(int w, int h, Mesh mesh, LightmapperConfig cfg); +Material LoadMaterialLightmapper(Color emissiveColor, float intensity); +void UnloadLightmapper(Lightmapper lm); +void BeginLightmap(); +void EndLightmap(); +bool BeginLightmapFragment(Lightmapper * lm); +void EndLightmapFragment(Lightmapper * lm); +Image LoadImageFromLightmapper(Lightmapper lm); + + +#endif + +#if defined(RLIGHTMAPPER_IMPLEMENTATION) + +#define LIGHTMAPPER_IMPLEMENTATION +//#define LM_DEBUG_INTERPOLATION +#include "lightmapper.h" + +static const char* fs = +"#version 330\n" +"in vec2 fragTexCoord;\n" +"in vec4 fragColor;\n" +"out vec4 finalColor;\n" +"uniform sampler2D texture0;\n" +"uniform vec4 colDiffuse;\n" +"void main()\n" +"{\n" +" vec4 texelColor = texture(texture0, fragTexCoord);\n" +" texelColor = texelColor * colDiffuse * fragColor * vec4(intensity, intensity, intensity, 1.0);\n" +" finalColor = vec4(texelColor.rgb, (gl_FrontFacing ? 1.0 : 0.0));\n" +"}"; + +const char* vs = "#version 330\n" +"in vec3 vertexPosition;\n" +"in vec2 vertexTexCoord;\n" +"in vec4 vertexColor;\n" +"out vec2 fragTexCoord;\n" +"out vec4 fragColor;\n" +"uniform mat4 mvp;\n" +"void main()\n" +"{\n" +" fragTexCoord = vertexTexCoord;\n" +" fragColor = vertexColor;\n" +" gl_Position = mvp * vec4(vertexPosition, 1.0);\n" +"}"; + +static void FloatVToMatrix(float *array, struct Matrix *matrix) { + matrix->m0 = array[0]; + matrix->m1 = array[1]; + matrix->m2 = array[2]; + matrix->m3 = array[3]; + matrix->m4 = array[4]; + matrix->m5 = array[5]; + matrix->m6 = array[6]; + matrix->m7 = array[7]; + matrix->m8 = array[8]; + matrix->m9 = array[9]; + matrix->m10 = array[10]; + matrix->m11 = array[11]; + matrix->m12 = array[12]; + matrix->m13 = array[13]; + matrix->m14 = array[14]; + matrix->m15 = array[15]; +} + +LightmapperConfig GetDefaultLightmapperConfig(){ + return (LightmapperConfig){ + 64, 0.001f, 100.0f, WHITE, 2, 0.01f, 0.0f + }; +} + +static Shader defaultShader; + +Material LoadMaterialLightmapper(Color emissiveColor, float emissiveIntensity) +{ + if(defaultShader.id == 0) defaultShader = LoadShaderFromMemory(vs, fs); + + Material mat = LoadMaterialDefault(); + mat.shader = defaultShader; + mat.maps[MATERIAL_MAP_DIFFUSE].color = emissiveColor; // Diffuse color + //mat.params[0] = emissiveIntensity; + return mat; +} + + +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); +} + +static Matrix mProjection; +static Matrix mModelview; + +void BeginLightmap() +{ + rlEnableDepthTest(); + rlDisableColorBlend(); + rlDisableBackfaceCulling(); + mProjection = rlGetMatrixProjection(); + mModelview = rlGetMatrixModelview(); +} + +void EndLightmap(){ + //rlDisableDepthTest(); + rlEnableColorBlend(); + rlEnableBackfaceCulling(); + int w = GetScreenWidth() * GetWindowScaleDPI().x; + int h = GetScreenHeight() * GetWindowScaleDPI().y; + rlViewport(0, 0, w, h); + rlDisableFramebuffer(); + glUseProgram(0); + glBindTexture(GL_TEXTURE_2D, 0); + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + glBindVertexArray(0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + rlSetMatrixModelview(mModelview); + rlSetMatrixProjection(mProjection); +} + +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); + } else { + lm->progress = 1.0f; + } + return (bool)status; +} + +void EndLightmapFragment(Lightmapper * lm){ + lm->progress = lmProgress((lm_context *)lm->lm_handle); + lmEnd((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; + im.mipmaps = 1; + return im; +} +#endif \ No newline at end of file