lmap boundary fixes + opts
parent
b802036590
commit
17dae10084
|
@ -356,6 +356,7 @@ struct lm_context
|
||||||
{
|
{
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
lm_ivec2 writePosition;
|
lm_ivec2 writePosition;
|
||||||
|
int width, height;
|
||||||
lm_ivec2 *toLightmapLocation;
|
lm_ivec2 *toLightmapLocation;
|
||||||
} storage;
|
} storage;
|
||||||
} hemisphere;
|
} hemisphere;
|
||||||
|
@ -616,10 +617,72 @@ static lm_bool lm_findNextConservativeTriangleRasterizerPosition(lm_context *ctx
|
||||||
return lm_findFirstConservativeTriangleRasterizerPosition(ctx);
|
return lm_findFirstConservativeTriangleRasterizerPosition(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lm_integrateHemisphereBatch(lm_context *ctx)
|
static void lm_writeResultsToLightmap(lm_context* ctx)
|
||||||
|
{
|
||||||
|
// do the GPU->CPU transfer of downsampled hemispheres
|
||||||
|
float* hemi = (float*)LM_CALLOC(ctx->hemisphere.storage.width * ctx->hemisphere.storage.height, 4 * sizeof(float));
|
||||||
|
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
||||||
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, hemi);
|
||||||
|
|
||||||
|
// write results to lightmap texture
|
||||||
|
for (int y = 0; y < ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < ctx->hemisphere.storage.width; x++)
|
||||||
|
{
|
||||||
|
int index = y * ctx->hemisphere.storage.width + x;
|
||||||
|
lm_ivec2 lmUV = ctx->hemisphere.storage.toLightmapLocation[index];
|
||||||
|
if (lmUV.x >= 0)
|
||||||
|
{
|
||||||
|
float* c = hemi + index * 4;
|
||||||
|
float validity = c[3];
|
||||||
|
float* lm = ctx->lightmap.data + (lmUV.y * ctx->lightmap.width + lmUV.x) * ctx->lightmap.channels;
|
||||||
|
if (!lm[0] && validity > 0.9)
|
||||||
|
{
|
||||||
|
float scale = 1.0f / validity;
|
||||||
|
switch (ctx->lightmap.channels)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
||||||
|
lm[1] = 1.0f; // do we want to support this format?
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
||||||
|
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
||||||
|
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
||||||
|
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
||||||
|
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
||||||
|
lm[3] = 1.0f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(LM_FALSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LM_DEBUG_INTERPOLATION
|
||||||
|
// set sampled pixel to red in debug output
|
||||||
|
ctx->lightmap.debug[(lmUV.y * ctx->lightmap.width + lmUV.x) * 3 + 0] = 255;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx->hemisphere.storage.toLightmapLocation[index].x = -1; // reset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LM_FREE(hemi);
|
||||||
|
ctx->hemisphere.storage.writePosition = lm_i2(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static lm_bool lm_integrateHemisphereBatch(lm_context *ctx)
|
||||||
{
|
{
|
||||||
if (!ctx->hemisphere.fbHemiIndex)
|
if (!ctx->hemisphere.fbHemiIndex)
|
||||||
return; // nothing to do
|
return LM_FALSE; // nothing to do
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glBindVertexArray(ctx->hemisphere.vao);
|
glBindVertexArray(ctx->hemisphere.vao);
|
||||||
|
@ -687,83 +750,30 @@ static void lm_integrateHemisphereBatch(lm_context *ctx)
|
||||||
{
|
{
|
||||||
int sx = ctx->hemisphere.storage.writePosition.x + x;
|
int sx = ctx->hemisphere.storage.writePosition.x + x;
|
||||||
unsigned int hemiIndex = y * ctx->hemisphere.fbHemiCountX + x;
|
unsigned int hemiIndex = y * ctx->hemisphere.fbHemiCountX + x;
|
||||||
if (hemiIndex >= ctx->hemisphere.fbHemiIndex)
|
ctx->hemisphere.storage.toLightmapLocation[sy * ctx->hemisphere.storage.width + sx] =
|
||||||
ctx->hemisphere.storage.toLightmapLocation[sy * ctx->lightmap.width + sx] = lm_i2(-1, -1);
|
(hemiIndex >= ctx->hemisphere.fbHemiIndex) ?
|
||||||
else
|
lm_i2(-1, -1) :
|
||||||
ctx->hemisphere.storage.toLightmapLocation[sy * ctx->lightmap.width + sx] = ctx->hemisphere.fbHemiToLightmapLocation[hemiIndex];
|
ctx->hemisphere.fbHemiToLightmapLocation[hemiIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lm_bool needWrite = LM_TRUE;
|
||||||
// advance storage texture write position
|
// advance storage texture write position
|
||||||
ctx->hemisphere.storage.writePosition.x += ctx->hemisphere.fbHemiCountX;
|
ctx->hemisphere.storage.writePosition.x += ctx->hemisphere.fbHemiCountX;
|
||||||
if (ctx->hemisphere.storage.writePosition.x + (int)ctx->hemisphere.fbHemiCountX > ctx->lightmap.width)
|
if (ctx->hemisphere.storage.writePosition.x + (int)ctx->hemisphere.fbHemiCountX > ctx->hemisphere.storage.width)
|
||||||
{
|
{
|
||||||
ctx->hemisphere.storage.writePosition.x = 0;
|
ctx->hemisphere.storage.writePosition.x = 0;
|
||||||
|
// storage is full
|
||||||
|
if (ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY >= ctx->hemisphere.storage.height) {
|
||||||
|
lm_writeResultsToLightmap(ctx); // read storage data from gpu memory and write it to the lightmap
|
||||||
|
needWrite = LM_FALSE;
|
||||||
|
} else {
|
||||||
ctx->hemisphere.storage.writePosition.y += ctx->hemisphere.fbHemiCountY;
|
ctx->hemisphere.storage.writePosition.y += ctx->hemisphere.fbHemiCountY;
|
||||||
assert(ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY < ctx->lightmap.height);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->hemisphere.fbHemiIndex = 0;
|
ctx->hemisphere.fbHemiIndex = 0;
|
||||||
}
|
return needWrite;
|
||||||
|
|
||||||
static void lm_writeResultsToLightmap(lm_context *ctx)
|
|
||||||
{
|
|
||||||
// do the GPU->CPU transfer of downsampled hemispheres
|
|
||||||
float *hemi = (float*)LM_CALLOC(ctx->lightmap.width * ctx->lightmap.height, 4 * sizeof(float));
|
|
||||||
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
|
||||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, hemi);
|
|
||||||
|
|
||||||
// write results to lightmap texture
|
|
||||||
for (int y = 0; y < ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < ctx->lightmap.width; x++)
|
|
||||||
{
|
|
||||||
lm_ivec2 lmUV = ctx->hemisphere.storage.toLightmapLocation[y * ctx->lightmap.width + x];
|
|
||||||
if (lmUV.x >= 0)
|
|
||||||
{
|
|
||||||
float *c = hemi + (y * ctx->lightmap.width + x) * 4;
|
|
||||||
float validity = c[3];
|
|
||||||
float *lm = ctx->lightmap.data + (lmUV.y * ctx->lightmap.width + lmUV.x) * ctx->lightmap.channels;
|
|
||||||
if (!lm[0] && validity > 0.9)
|
|
||||||
{
|
|
||||||
float scale = 1.0f / validity;
|
|
||||||
switch (ctx->lightmap.channels)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
|
||||||
lm[1] = 1.0f; // do we want to support this format?
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
|
||||||
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
|
||||||
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
|
||||||
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
|
||||||
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
|
||||||
lm[3] = 1.0f;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(LM_FALSE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef LM_DEBUG_INTERPOLATION
|
|
||||||
// set sampled pixel to red in debug output
|
|
||||||
ctx->lightmap.debug[(lmUV.y * ctx->lightmap.width + lmUV.x) * 3 + 0] = 255;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx->hemisphere.storage.toLightmapLocation[y * ctx->lightmap.width + x].x = -1; // reset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LM_FREE(hemi);
|
|
||||||
ctx->hemisphere.storage.writePosition = lm_i2(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lm_setView(
|
static void lm_setView(
|
||||||
|
@ -1040,6 +1050,7 @@ static void lm_setMeshPosition(lm_context *ctx, unsigned int indicesTriangleBase
|
||||||
// TODO: signed formats
|
// TODO: signed formats
|
||||||
case LM_FLOAT: {
|
case LM_FLOAT: {
|
||||||
n = *(const lm_vec3*)nPtr;
|
n = *(const lm_vec3*)nPtr;
|
||||||
|
n = lm_normalize3(lm_transformNormal(ctx->mesh.normalMatrix, n));
|
||||||
} break;
|
} break;
|
||||||
case LM_NONE: {
|
case LM_NONE: {
|
||||||
n = flatNormal;
|
n = flatNormal;
|
||||||
|
@ -1048,7 +1059,7 @@ static void lm_setMeshPosition(lm_context *ctx, unsigned int indicesTriangleBase
|
||||||
assert(LM_FALSE);
|
assert(LM_FALSE);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
ctx->meshPosition.triangle.n[i] = lm_normalize3(lm_transformNormal(ctx->mesh.normalMatrix, n));
|
ctx->meshPosition.triangle.n[i] = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate area of interest (on lightmap) for conservative rasterization
|
// calculate area of interest (on lightmap) for conservative rasterization
|
||||||
|
@ -1405,16 +1416,13 @@ void lmSetHemisphereWeights(lm_context *ctx, lm_weight_func f, void *userdata)
|
||||||
LM_FREE(weights);
|
LM_FREE(weights);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lmSetTargetLightmap(lm_context *ctx, float *outLightmap, int w, int h, int c)
|
static void lm_initStorage(lm_context *ctx, int w, int h)
|
||||||
{
|
{
|
||||||
ctx->lightmap.data = outLightmap;
|
|
||||||
ctx->lightmap.width = w;
|
|
||||||
ctx->lightmap.height = h;
|
|
||||||
ctx->lightmap.channels = c;
|
|
||||||
|
|
||||||
// allocate storage texture
|
// allocate storage texture
|
||||||
if (!ctx->hemisphere.storage.texture)
|
if (!ctx->hemisphere.storage.texture)
|
||||||
glGenTextures(1, &ctx->hemisphere.storage.texture);
|
glGenTextures(1, &ctx->hemisphere.storage.texture);
|
||||||
|
ctx->hemisphere.storage.width = w;
|
||||||
|
ctx->hemisphere.storage.height = h;
|
||||||
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
@ -1429,6 +1437,18 @@ void lmSetTargetLightmap(lm_context *ctx, float *outLightmap, int w, int h, int
|
||||||
// invalidate all positions
|
// invalidate all positions
|
||||||
for (int i = 0; i < w * h; i++)
|
for (int i = 0; i < w * h; i++)
|
||||||
ctx->hemisphere.storage.toLightmapLocation[i].x = -1;
|
ctx->hemisphere.storage.toLightmapLocation[i].x = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lmSetTargetLightmap(lm_context *ctx, float *outLightmap, int w, int h, int c)
|
||||||
|
{
|
||||||
|
ctx->lightmap.data = outLightmap;
|
||||||
|
ctx->lightmap.width = w;
|
||||||
|
ctx->lightmap.height = h;
|
||||||
|
ctx->lightmap.channels = c;
|
||||||
|
|
||||||
|
unsigned int sw = w > ctx->hemisphere.fbHemiCountX ? w : ctx->hemisphere.fbHemiCountX;
|
||||||
|
unsigned int sh = h > ctx->hemisphere.fbHemiCountY ? h : ctx->hemisphere.fbHemiCountY;
|
||||||
|
lm_initStorage(ctx, sw, sh);
|
||||||
|
|
||||||
#ifdef LM_DEBUG_INTERPOLATION
|
#ifdef LM_DEBUG_INTERPOLATION
|
||||||
if (ctx->lightmap.debug)
|
if (ctx->lightmap.debug)
|
||||||
|
@ -1482,7 +1502,7 @@ lm_bool lmBegin(lm_context *ctx, int* outViewport4, float* outView4x4, float* ou
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // ...and there are no triangles left: finish
|
{ // ...and there are no triangles left: finish
|
||||||
lm_integrateHemisphereBatch(ctx); // integrate and store last batch
|
if (lm_integrateHemisphereBatch(ctx)) // integrate and store last batch
|
||||||
lm_writeResultsToLightmap(ctx); // read storage data from gpu memory and write it to the lightmap
|
lm_writeResultsToLightmap(ctx); // read storage data from gpu memory and write it to the lightmap
|
||||||
|
|
||||||
if (++ctx->meshPosition.pass == ctx->meshPosition.passCount)
|
if (++ctx->meshPosition.pass == ctx->meshPosition.passCount)
|
||||||
|
|
175
engine/v4k
175
engine/v4k
|
@ -329403,6 +329403,7 @@ struct lm_context
|
||||||
{
|
{
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
lm_ivec2 writePosition;
|
lm_ivec2 writePosition;
|
||||||
|
int width, height;
|
||||||
lm_ivec2 *toLightmapLocation;
|
lm_ivec2 *toLightmapLocation;
|
||||||
} storage;
|
} storage;
|
||||||
} hemisphere;
|
} hemisphere;
|
||||||
|
@ -329663,10 +329664,72 @@ static lm_bool lm_findNextConservativeTriangleRasterizerPosition(lm_context *ctx
|
||||||
return lm_findFirstConservativeTriangleRasterizerPosition(ctx);
|
return lm_findFirstConservativeTriangleRasterizerPosition(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lm_integrateHemisphereBatch(lm_context *ctx)
|
static void lm_writeResultsToLightmap(lm_context* ctx)
|
||||||
|
{
|
||||||
|
// do the GPU->CPU transfer of downsampled hemispheres
|
||||||
|
float* hemi = (float*)LM_CALLOC(ctx->hemisphere.storage.width * ctx->hemisphere.storage.height, 4 * sizeof(float));
|
||||||
|
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
||||||
|
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, hemi);
|
||||||
|
|
||||||
|
// write results to lightmap texture
|
||||||
|
for (int y = 0; y < ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < ctx->hemisphere.storage.width; x++)
|
||||||
|
{
|
||||||
|
int index = y * ctx->hemisphere.storage.width + x;
|
||||||
|
lm_ivec2 lmUV = ctx->hemisphere.storage.toLightmapLocation[index];
|
||||||
|
if (lmUV.x >= 0)
|
||||||
|
{
|
||||||
|
float* c = hemi + index * 4;
|
||||||
|
float validity = c[3];
|
||||||
|
float* lm = ctx->lightmap.data + (lmUV.y * ctx->lightmap.width + lmUV.x) * ctx->lightmap.channels;
|
||||||
|
if (!lm[0] && validity > 0.9)
|
||||||
|
{
|
||||||
|
float scale = 1.0f / validity;
|
||||||
|
switch (ctx->lightmap.channels)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
||||||
|
lm[1] = 1.0f; // do we want to support this format?
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
||||||
|
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
||||||
|
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
||||||
|
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
||||||
|
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
||||||
|
lm[3] = 1.0f;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(LM_FALSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LM_DEBUG_INTERPOLATION
|
||||||
|
// set sampled pixel to red in debug output
|
||||||
|
ctx->lightmap.debug[(lmUV.y * ctx->lightmap.width + lmUV.x) * 3 + 0] = 255;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx->hemisphere.storage.toLightmapLocation[index].x = -1; // reset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LM_FREE(hemi);
|
||||||
|
ctx->hemisphere.storage.writePosition = lm_i2(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static lm_bool lm_integrateHemisphereBatch(lm_context *ctx)
|
||||||
{
|
{
|
||||||
if (!ctx->hemisphere.fbHemiIndex)
|
if (!ctx->hemisphere.fbHemiIndex)
|
||||||
return; // nothing to do
|
return LM_FALSE; // nothing to do
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glBindVertexArray(ctx->hemisphere.vao);
|
glBindVertexArray(ctx->hemisphere.vao);
|
||||||
|
@ -329734,83 +329797,30 @@ static void lm_integrateHemisphereBatch(lm_context *ctx)
|
||||||
{
|
{
|
||||||
int sx = ctx->hemisphere.storage.writePosition.x + x;
|
int sx = ctx->hemisphere.storage.writePosition.x + x;
|
||||||
unsigned int hemiIndex = y * ctx->hemisphere.fbHemiCountX + x;
|
unsigned int hemiIndex = y * ctx->hemisphere.fbHemiCountX + x;
|
||||||
if (hemiIndex >= ctx->hemisphere.fbHemiIndex)
|
ctx->hemisphere.storage.toLightmapLocation[sy * ctx->hemisphere.storage.width + sx] =
|
||||||
ctx->hemisphere.storage.toLightmapLocation[sy * ctx->lightmap.width + sx] = lm_i2(-1, -1);
|
(hemiIndex >= ctx->hemisphere.fbHemiIndex) ?
|
||||||
else
|
lm_i2(-1, -1) :
|
||||||
ctx->hemisphere.storage.toLightmapLocation[sy * ctx->lightmap.width + sx] = ctx->hemisphere.fbHemiToLightmapLocation[hemiIndex];
|
ctx->hemisphere.fbHemiToLightmapLocation[hemiIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lm_bool needWrite = LM_TRUE;
|
||||||
// advance storage texture write position
|
// advance storage texture write position
|
||||||
ctx->hemisphere.storage.writePosition.x += ctx->hemisphere.fbHemiCountX;
|
ctx->hemisphere.storage.writePosition.x += ctx->hemisphere.fbHemiCountX;
|
||||||
if (ctx->hemisphere.storage.writePosition.x + (int)ctx->hemisphere.fbHemiCountX > ctx->lightmap.width)
|
if (ctx->hemisphere.storage.writePosition.x + (int)ctx->hemisphere.fbHemiCountX > ctx->hemisphere.storage.width)
|
||||||
{
|
{
|
||||||
ctx->hemisphere.storage.writePosition.x = 0;
|
ctx->hemisphere.storage.writePosition.x = 0;
|
||||||
|
// storage is full
|
||||||
|
if (ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY >= ctx->hemisphere.storage.height) {
|
||||||
|
lm_writeResultsToLightmap(ctx); // read storage data from gpu memory and write it to the lightmap
|
||||||
|
needWrite = LM_FALSE;
|
||||||
|
} else {
|
||||||
ctx->hemisphere.storage.writePosition.y += ctx->hemisphere.fbHemiCountY;
|
ctx->hemisphere.storage.writePosition.y += ctx->hemisphere.fbHemiCountY;
|
||||||
assert(ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY < ctx->lightmap.height);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->hemisphere.fbHemiIndex = 0;
|
ctx->hemisphere.fbHemiIndex = 0;
|
||||||
}
|
return needWrite;
|
||||||
|
|
||||||
static void lm_writeResultsToLightmap(lm_context *ctx)
|
|
||||||
{
|
|
||||||
// do the GPU->CPU transfer of downsampled hemispheres
|
|
||||||
float *hemi = (float*)LM_CALLOC(ctx->lightmap.width * ctx->lightmap.height, 4 * sizeof(float));
|
|
||||||
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
|
||||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, hemi);
|
|
||||||
|
|
||||||
// write results to lightmap texture
|
|
||||||
for (int y = 0; y < ctx->hemisphere.storage.writePosition.y + (int)ctx->hemisphere.fbHemiCountY; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < ctx->lightmap.width; x++)
|
|
||||||
{
|
|
||||||
lm_ivec2 lmUV = ctx->hemisphere.storage.toLightmapLocation[y * ctx->lightmap.width + x];
|
|
||||||
if (lmUV.x >= 0)
|
|
||||||
{
|
|
||||||
float *c = hemi + (y * ctx->lightmap.width + x) * 4;
|
|
||||||
float validity = c[3];
|
|
||||||
float *lm = ctx->lightmap.data + (lmUV.y * ctx->lightmap.width + lmUV.x) * ctx->lightmap.channels;
|
|
||||||
if (!lm[0] && validity > 0.9)
|
|
||||||
{
|
|
||||||
float scale = 1.0f / validity;
|
|
||||||
switch (ctx->lightmap.channels)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
lm[0] = lm_maxf((c[0] + c[1] + c[2]) * scale / 3.0f, FLT_MIN);
|
|
||||||
lm[1] = 1.0f; // do we want to support this format?
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
|
||||||
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
|
||||||
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
lm[0] = lm_maxf(c[0] * scale, FLT_MIN);
|
|
||||||
lm[1] = lm_maxf(c[1] * scale, FLT_MIN);
|
|
||||||
lm[2] = lm_maxf(c[2] * scale, FLT_MIN);
|
|
||||||
lm[3] = 1.0f;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(LM_FALSE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef LM_DEBUG_INTERPOLATION
|
|
||||||
// set sampled pixel to red in debug output
|
|
||||||
ctx->lightmap.debug[(lmUV.y * ctx->lightmap.width + lmUV.x) * 3 + 0] = 255;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx->hemisphere.storage.toLightmapLocation[y * ctx->lightmap.width + x].x = -1; // reset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LM_FREE(hemi);
|
|
||||||
ctx->hemisphere.storage.writePosition = lm_i2(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lm_setView(
|
static void lm_setView(
|
||||||
|
@ -330087,6 +330097,7 @@ static void lm_setMeshPosition(lm_context *ctx, unsigned int indicesTriangleBase
|
||||||
// TODO: signed formats
|
// TODO: signed formats
|
||||||
case LM_FLOAT: {
|
case LM_FLOAT: {
|
||||||
n = *(const lm_vec3*)nPtr;
|
n = *(const lm_vec3*)nPtr;
|
||||||
|
n = lm_normalize3(lm_transformNormal(ctx->mesh.normalMatrix, n));
|
||||||
} break;
|
} break;
|
||||||
case LM_NONE: {
|
case LM_NONE: {
|
||||||
n = flatNormal;
|
n = flatNormal;
|
||||||
|
@ -330095,7 +330106,7 @@ static void lm_setMeshPosition(lm_context *ctx, unsigned int indicesTriangleBase
|
||||||
assert(LM_FALSE);
|
assert(LM_FALSE);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
ctx->meshPosition.triangle.n[i] = lm_normalize3(lm_transformNormal(ctx->mesh.normalMatrix, n));
|
ctx->meshPosition.triangle.n[i] = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculate area of interest (on lightmap) for conservative rasterization
|
// calculate area of interest (on lightmap) for conservative rasterization
|
||||||
|
@ -330452,16 +330463,13 @@ void lmSetHemisphereWeights(lm_context *ctx, lm_weight_func f, void *userdata)
|
||||||
LM_FREE(weights);
|
LM_FREE(weights);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lmSetTargetLightmap(lm_context *ctx, float *outLightmap, int w, int h, int c)
|
static void lm_initStorage(lm_context *ctx, int w, int h)
|
||||||
{
|
{
|
||||||
ctx->lightmap.data = outLightmap;
|
|
||||||
ctx->lightmap.width = w;
|
|
||||||
ctx->lightmap.height = h;
|
|
||||||
ctx->lightmap.channels = c;
|
|
||||||
|
|
||||||
// allocate storage texture
|
// allocate storage texture
|
||||||
if (!ctx->hemisphere.storage.texture)
|
if (!ctx->hemisphere.storage.texture)
|
||||||
glGenTextures(1, &ctx->hemisphere.storage.texture);
|
glGenTextures(1, &ctx->hemisphere.storage.texture);
|
||||||
|
ctx->hemisphere.storage.width = w;
|
||||||
|
ctx->hemisphere.storage.height = h;
|
||||||
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
glBindTexture(GL_TEXTURE_2D, ctx->hemisphere.storage.texture);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
@ -330476,6 +330484,18 @@ void lmSetTargetLightmap(lm_context *ctx, float *outLightmap, int w, int h, int
|
||||||
// invalidate all positions
|
// invalidate all positions
|
||||||
for (int i = 0; i < w * h; i++)
|
for (int i = 0; i < w * h; i++)
|
||||||
ctx->hemisphere.storage.toLightmapLocation[i].x = -1;
|
ctx->hemisphere.storage.toLightmapLocation[i].x = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lmSetTargetLightmap(lm_context *ctx, float *outLightmap, int w, int h, int c)
|
||||||
|
{
|
||||||
|
ctx->lightmap.data = outLightmap;
|
||||||
|
ctx->lightmap.width = w;
|
||||||
|
ctx->lightmap.height = h;
|
||||||
|
ctx->lightmap.channels = c;
|
||||||
|
|
||||||
|
unsigned int sw = w > ctx->hemisphere.fbHemiCountX ? w : ctx->hemisphere.fbHemiCountX;
|
||||||
|
unsigned int sh = h > ctx->hemisphere.fbHemiCountY ? h : ctx->hemisphere.fbHemiCountY;
|
||||||
|
lm_initStorage(ctx, sw, sh);
|
||||||
|
|
||||||
#ifdef LM_DEBUG_INTERPOLATION
|
#ifdef LM_DEBUG_INTERPOLATION
|
||||||
if (ctx->lightmap.debug)
|
if (ctx->lightmap.debug)
|
||||||
|
@ -330529,7 +330549,7 @@ lm_bool lmBegin(lm_context *ctx, int* outViewport4, float* outView4x4, float* ou
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // ...and there are no triangles left: finish
|
{ // ...and there are no triangles left: finish
|
||||||
lm_integrateHemisphereBatch(ctx); // integrate and store last batch
|
if (lm_integrateHemisphereBatch(ctx)) // integrate and store last batch
|
||||||
lm_writeResultsToLightmap(ctx); // read storage data from gpu memory and write it to the lightmap
|
lm_writeResultsToLightmap(ctx); // read storage data from gpu memory and write it to the lightmap
|
||||||
|
|
||||||
if (++ctx->meshPosition.pass == ctx->meshPosition.passCount)
|
if (++ctx->meshPosition.pass == ctx->meshPosition.passCount)
|
||||||
|
@ -330805,7 +330825,6 @@ lm_bool lmImageSaveTGAf(const char *filename, const float *image, int w, int h,
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // LIGHTMAPPER_IMPLEMENTATION
|
#endif // LIGHTMAPPER_IMPLEMENTATION#line 0
|
||||||
#line 0
|
|
||||||
|
|
||||||
#endif // V4K_3RD
|
#endif // V4K_3RD
|
||||||
|
|
Loading…
Reference in New Issue