diff options
| author | KonAki <konaki@anokonaki.org> | 2026-10-11 22:16:09 +0800 |
|---|---|---|
| committer | KonAki <konaki@anokonaki.org> | 2026-10-11 22:16:09 +0800 |
| commit | a4b7011ac9d5ccf012a99bd8a7769fcd45bac53e (patch) | |
| tree | b04f98585b2cd303e7d6e501be6b44ce29e5de49 | |
| parent | 20bbe2731a2d04b6dde65e9f893ad360915a889b (diff) | |
konsofren: kon_lightPass, point and spot lights from the depth buffer
| -rw-r--r-- | kon/konmath.h | 34 | ||||
| -rw-r--r-- | kon/konsofren.h | 115 |
2 files changed, 149 insertions, 0 deletions
diff --git a/kon/konmath.h b/kon/konmath.h index 44f6571..f8aeceb 100644 --- a/kon/konmath.h +++ b/kon/konmath.h @@ -124,6 +124,40 @@ static inline kon_mat4_t kon_mat4Mul(kon_mat4_t a, kon_mat4_t b) { return r; } +/* the matrix that undoes m. returns the identity and sets *ok to 0 if m can't be undone, ok can be NULL */ +static inline kon_mat4_t kon_mat4Inverse(kon_mat4_t a, int *ok) { + const float *m = a.m; + kon_mat4_t r; + float *o = r.m, det; + int i; + + o[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10]; + o[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10]; + o[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9]; + o[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9]; + o[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10]; + o[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10]; + o[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9]; + o[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9]; + o[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6]; + o[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6]; + o[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5]; + o[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5]; + o[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6]; + o[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6]; + o[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5]; + o[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5]; + + det = m[0] * o[0] + m[1] * o[4] + m[2] * o[8] + m[3] * o[12]; + if (det > -1.0e-20f && det < 1.0e-20f) { + if (ok) *ok = 0; + return kon_mat4Identity(); + } + for (i = 0; i < 16; i++) o[i] /= det; + if (ok) *ok = 1; + return r; +} + static inline kon_vec4_t kon_mat4MulVec4(kon_mat4_t m, kon_vec4_t v) { return (kon_vec4_t){ m.m[0] * v.x + m.m[4] * v.y + m.m[8] * v.z + m.m[12] * v.w, diff --git a/kon/konsofren.h b/kon/konsofren.h index 4e29e56..6cca535 100644 --- a/kon/konsofren.h +++ b/kon/konsofren.h @@ -249,6 +249,26 @@ void kon_drawMesh(kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_mat4_t m int kon_drawBillboard(kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_vec3_t position, float width, float height, const kon_image *image, kon_rect_t src, float brightness, kon_renderFlags_t flags); +/*** lights that sit in the world ***/ + +/* a light with a place. with cone 0 it shines all around, otherwise it is a spot light like a flashlight pointing along direction */ +typedef struct kon_pointLight { + kon_vec3_t position; + uint32_t color; /* 0xFFRRGGBB, alpha is ignored */ + float radius; /* it reaches nothing farther than this */ + float intensity; /* 1 is full strength, more than that lights things brighter than they were drawn */ + kon_vec3_t direction; /* spot lights only, the way it points */ + float cone; /* spot lights only, how wide it is from the middle to the edge in radians, 0 for a light that shines all around */ + float soft; /* spot lights only, 0 to 1, how much of the cone fades out at the edge */ +} kon_pointLight_t; + +/* lights what is already drawn, after everything with depth is in and before the screen elements. every pixel that has depth gets + color * (ambient + the light of every light that reaches it). draw the scene with light.ambient 1 and intensity 0 so it still has + its plain colors, this makes it dark and then lights it. it knows where things are but not which way they face, and it has no + shadows: light goes through walls, so keep the radius of a light inside its room. it costs about one pass over the screen plus a bit + for every light that is close. needs the depth buffer, so draw with KON_RENDER_DEPTH */ +void kon_lightPass(kon_framebuffer_t *fb, kon_mat4_t viewProjection, const kon_pointLight_t *lights, int count, float ambient); + /* cube from -1 to 1 with every face mapped to the whole texture */ extern const kon_mesh_t kon_cubeMesh; @@ -1652,6 +1672,101 @@ int kon_drawBillboard(kon_framebuffer_t *fb, kon_mat4_t viewProjection, kon_vec3 return 1; } +/*** light pass ***/ + +typedef struct kon_lightSetup_ { + float x, y, z, radius, invRadius, intensity, r, g, b; + float dx, dy, dz, cosOuter, cosRange; + int spot; +} kon_lightSetup_t; + +void kon_lightPass(kon_framebuffer_t *fb, kon_mat4_t viewProjection, const kon_pointLight_t *lights, int count, float ambient) { + enum { MAX_LIGHTS = 32 }; + kon_lightSetup_t set[MAX_LIGHTS]; + kon_mat4_t inv; + int used = 0, i, ok, px, py; + float ndcStepX, ndcStepY; + + if (!fb || !fb->depth || !lights) return; + inv = kon_mat4Inverse(viewProjection, &ok); + if (!ok) return; + if (ambient < 0.0f) ambient = 0.0f; + + for (i = 0; i < count && used < MAX_LIGHTS; i++) { + const kon_pointLight_t *l = &lights[i]; + kon_lightSetup_t *s = &set[used]; + + if (l->radius <= 0.0f || l->intensity <= 0.0f) continue; + s->x = l->position.x; s->y = l->position.y; s->z = l->position.z; + s->radius = l->radius; + s->invRadius = 1.0f / l->radius; + s->intensity = l->intensity; + s->r = (float)((l->color >> 16) & 255) / 255.0f; + s->g = (float)((l->color >> 8) & 255) / 255.0f; + s->b = (float)(l->color & 255) / 255.0f; + s->spot = l->cone > 0.0f; + if (s->spot) { + float len = sqrtf(l->direction.x * l->direction.x + l->direction.y * l->direction.y + l->direction.z * l->direction.z); + float soft = kon_clamp(l->soft, 0.0f, 1.0f), inner = l->cone * (1.0f - soft); + + if (len < 1.0e-6f) continue; + s->dx = l->direction.x / len; s->dy = l->direction.y / len; s->dz = l->direction.z / len; + s->cosOuter = cosf(l->cone); + s->cosRange = cosf(inner) - s->cosOuter; + if (s->cosRange < 1.0e-4f) s->cosRange = 1.0e-4f; + } + used++; + } + + ndcStepX = 2.0f / (float)fb->width; + ndcStepY = 2.0f / (float)fb->height; + for (py = 0; py < fb->height; py++) { + float ndcY = 1.0f - ((float)py + 0.5f) * ndcStepY; + + for (px = 0; px < fb->width; px++) { + int index = py * fb->width + px; + float z = fb->depth[index], ndcX, wx, wy, wz, ww, level[3], inverseW; + uint32_t c; + int k, r, g, b; + + if (z >= 1.0f) continue; + ndcX = ((float)px + 0.5f) * ndcStepX - 1.0f; + wx = inv.m[0] * ndcX + inv.m[4] * ndcY + inv.m[8] * z + inv.m[12]; + wy = inv.m[1] * ndcX + inv.m[5] * ndcY + inv.m[9] * z + inv.m[13]; + wz = inv.m[2] * ndcX + inv.m[6] * ndcY + inv.m[10] * z + inv.m[14]; + ww = inv.m[3] * ndcX + inv.m[7] * ndcY + inv.m[11] * z + inv.m[15]; + inverseW = 1.0f / ww; + wx *= inverseW; wy *= inverseW; wz *= inverseW; + + level[0] = level[1] = level[2] = ambient; + for (k = 0; k < used; k++) { + const kon_lightSetup_t *s = &set[k]; + float dx = wx - s->x, dy = wy - s->y, dz = wz - s->z, d2 = dx * dx + dy * dy + dz * dz, d, fall, amount; + + if (d2 >= s->radius * s->radius) continue; + d = sqrtf(d2); + fall = 1.0f - d * s->invRadius; + amount = fall * fall * s->intensity; + if (s->spot) { + float along = d > 1.0e-6f ? (dx * s->dx + dy * s->dy + dz * s->dz) / d : 1.0f, edge = (along - s->cosOuter) / s->cosRange; + + if (edge <= 0.0f) continue; + if (edge < 1.0f) amount *= edge * edge * (3.0f - 2.0f * edge); + } + level[0] += amount * s->r; + level[1] += amount * s->g; + level[2] += amount * s->b; + } + + c = fb->data[index]; + r = (int)((float)((c >> 16) & 255) * level[0]); + g = (int)((float)((c >> 8) & 255) * level[1]); + b = (int)((float)(c & 255) * level[2]); + fb->data[index] = 0xFF000000u | (uint32_t)(r > 255 ? 255 : r) << 16 | (uint32_t)(g > 255 ? 255 : g) << 8 | (uint32_t)(b > 255 ? 255 : b); + } + } +} + #endif /* KONSOFREN_3D */ #endif /* end of KONSOFREN_IMPLEMENTATION */ |
