Skip to content

Commit

Permalink
Add 2x upsampling and mild filter pass to generated emissive texture
Browse files Browse the repository at this point in the history
Makes them look a bit less blocky.
  • Loading branch information
res2k committed Jul 24, 2021
1 parent 910badd commit 48ae8e9
Showing 1 changed file with 148 additions and 9 deletions.
157 changes: 148 additions & 9 deletions src/refresh/vkpt/textures.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,102 @@ static void filter_float_image(float* pixels, int num_comps, const float kernel[
filter_one_dimension_float(pixels, num_comps, kernel, kernel_size, height, width, 1, width);
}

struct bilerp_s
{
int current_output_row;
float *current_input_data;
float *next_input_data;
float *output_data;
};

static void bilerp_init(struct bilerp_s* bilerp, int input_w)
{
bilerp->current_output_row = -1;
bilerp->current_input_data = IMG_AllocPixels(input_w * sizeof(float) * 3);
bilerp->next_input_data = IMG_AllocPixels(input_w * sizeof(float) * 3);
bilerp->output_data = IMG_AllocPixels(input_w * 2 * sizeof(float) * 3);
}

static void bilerp_free(struct bilerp_s* bilerp)
{
Z_Free(bilerp->current_input_data);
Z_Free(bilerp->next_input_data);
Z_Free(bilerp->output_data);
}

static inline void _bilerp_get_next_output_line(struct bilerp_s *bilerp, const float** output_line, const float* next_input, int input_w)
{
if(bilerp->current_output_row == -1) {
memcpy(bilerp->next_input_data, next_input, input_w * sizeof(float) * 3);
bilerp->current_output_row = 0;
}

if((bilerp->current_output_row & 1) == 0) {
// Even output line: use input lines
// Swap next_input_data into current_input_data
float *tmp = bilerp->next_input_data;
bilerp->next_input_data = bilerp->current_input_data;
bilerp->current_input_data = tmp;
} else {
// Odd output line: interpolate between input lines
float *color_dest = bilerp->next_input_data;
memcpy(bilerp->next_input_data, next_input, input_w * sizeof(float) * 3);

float *color_ptr = bilerp->current_input_data;
float *next_color_ptr = bilerp->next_input_data;
for (int x = 0; x < input_w; x++) {
color_ptr[0] = (color_ptr[0] + next_color_ptr[0]) * 0.5f;
color_ptr[1] = (color_ptr[1] + next_color_ptr[1]) * 0.5f;
color_ptr[2] = (color_ptr[2] + next_color_ptr[2]) * 0.5f;
color_ptr += 3;
next_color_ptr += 3;
}
}

float *out_ptr = bilerp->output_data;
float color[3];
const float* color_ptr = bilerp->current_input_data;
for (int out_x = 0; out_x < input_w * 2 - 1; out_x++) {
if((out_x & 1) == 0) {
// Even output row: direct value
memcpy(color, color_ptr, 3 * sizeof(float));
} else {
// Odd output row: interpolate between colors
color_ptr += 3;
color[0] = (color[0] + color_ptr[0]) * 0.5f;
color[1] = (color[1] + color_ptr[1]) * 0.5f;
color[2] = (color[2] + color_ptr[2]) * 0.5f;
}
memcpy(out_ptr, color, 3 * sizeof(float));
out_ptr += 3;
}

// Last row: interpolate between last and first pixel
color[0] = (color_ptr[0] + bilerp->current_input_data[0]) * 0.5f;
color[1] = (color_ptr[1] + bilerp->current_input_data[1]) * 0.5f;
color[2] = (color_ptr[2] + bilerp->current_input_data[2]) * 0.5f;
memcpy(out_ptr, color, 3 * sizeof(float));

*output_line = bilerp->output_data;

bilerp->current_output_row++;
}

static inline void bilerp_get_next_output_line_from_rgb_f32(struct bilerp_s *bilerp, const float** output_line, const float* input_data, int input_w, int input_h)
{
const float *next_input = NULL;
if (bilerp->current_output_row == -1) {
next_input = input_data;
} else if ((bilerp->current_output_row & 1) != 0) {
int in_y = (bilerp->current_output_row + 1) >> 1;
// Wraparound last line
if(in_y >= input_h)
in_y = 0;
next_input = input_data + in_y * input_w * 3;
}
_bilerp_get_next_output_line(bilerp, output_line, next_input, input_w);
}

// Fake an emissive texture from a diffuse texture by using pixels brighter than a certain amount
static void apply_fake_emissive_threshold(image_t *image)
{
Expand Down Expand Up @@ -677,7 +773,11 @@ static void apply_fake_emissive_threshold(image_t *image)
// ...and use it to normalize max luminance to 1
float lum_scale = max_lum > 0 ? 1.0f / max_lum : 1.0f;

// Combine blurred "bright" mask with original image (to retain some colorization)
/* Combine blurred "bright" mask with original image (to retain some colorization).
Produce float output for upsampling pass */
float *final = IMG_AllocPixels(w * h * 3 * sizeof(float));

float *out_final = final;
current_bright_mask = bright_mask;
byte *current_img_pixel = image->pix_data;
for (int y = 0; y < h; y++) {
Expand All @@ -694,20 +794,59 @@ static void apply_fake_emissive_threshold(image_t *image)
float src_lum = LUMINANCE(color_img[0], color_img[1], color_img[2]);
src_lum *= src_lum;
float scale = *current_bright_mask * src_lum * lum_scale;
color_img[0] *= scale;
color_img[1] *= scale;
color_img[2] *= scale;

current_img_pixel[0] = encode_srgb(color_img[0]);
current_img_pixel[1] = encode_srgb(color_img[1]);
current_img_pixel[2] = encode_srgb(color_img[2]);
out_final[0] = color_img[0] * scale;
out_final[1] = color_img[1] * scale;
out_final[2] = color_img[2] * scale;

out_final += 3;
current_bright_mask++;
current_img_pixel += 4;
}
}

Z_Free(bright_mask);

// Interpolate final image to 2x size, apply a mild filter, to have it look less blocky
int width_2x = w * 2;
int height_2x = h * 2;
float *final_2x = IMG_AllocPixels(width_2x * height_2x * 3 * sizeof(float));

struct bilerp_s bilerp_final;
bilerp_init(&bilerp_final, w);
float *out_final_2x = final_2x;
for (int out_y = 0; out_y < height_2x; out_y++) {
float *img_line;
bilerp_get_next_output_line_from_rgb_f32(&bilerp_final, &img_line, final, w, h);
memcpy(out_final_2x, img_line, width_2x * 3 * sizeof(float));
out_final_2x += width_2x * 3;
}
bilerp_free(&bilerp_final);
Z_Free(final);

const float filter_final[] = { 0.157731, 0.684538, 0.157731 };
filter_float_image(final_2x, 3, filter_final, sizeof(filter_final) / sizeof(filter_final[0]), width_2x, height_2x);

// Final -> SRGB
int new_size = width_2x * height_2x * 4;
Z_Free(image->pix_data);
image->pix_data = IMG_AllocPixels(new_size);
image->upload_width = width_2x;
image->upload_height = height_2x;

float* current_pixel = final_2x;
byte *out_pixel = image->pix_data;
for (int y = 0; y < height_2x; y++) {
for (int x = 0; x < width_2x; x++) {
out_pixel[0] = encode_srgb(current_pixel[0]);
out_pixel[1] = encode_srgb(current_pixel[1]);
out_pixel[2] = encode_srgb(current_pixel[2]);
out_pixel[3] = 255;

current_pixel += 3;
out_pixel += 4;
}
}

Z_Free(final_2x);
}

image_t *vkpt_fake_emissive_texture(image_t *image)
Expand Down

0 comments on commit 48ae8e9

Please sign in to comment.