Add image textures

This commit is contained in:
Jean-Michel Gorius 2022-11-13 16:35:37 +01:00
parent fc35055466
commit 391aa6240e
8 changed files with 8009 additions and 40 deletions

View File

@ -5,3 +5,4 @@ C implementation of the [*Ray tracing in one week-end*](https://raytracing.githu
## Examples
![Ray tracing in one week-end book cover](examples/book-cover.png)
![Earth](examples/earth.png)

BIN
assets/earthmap.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

BIN
examples/earth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

7897
external/stb_image.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -192,7 +192,7 @@ bool hittable_list_bounding_box(const HittableList *list, double time_start,
}
static void get_sphere_uv(Point3 p, double *u, double *v) {
double theta = acos(-p.x);
double theta = acos(-p.y);
double phi = atan2(-p.z, p.x) + M_PI;
*u = phi / (2 * M_PI);
*v = theta / M_PI;

25
main.c
View File

@ -19,8 +19,9 @@
#define SCENE_RANDOM 0
#define SCENE_TWO_SPHERES 1
#define SCENE_TWO_PERLIN_SPHERES 2
#define SCENE_EARTH 3
#define SCENE_SELECT SCENE_TWO_PERLIN_SPHERES
#define SCENE_SELECT SCENE_EARTH
static Color ray_color(Ray r, const Hittable *world, int depth) {
if (depth <= 0)
@ -143,6 +144,14 @@ static Hittable *two_perlin_spheres(Arena *arena) {
return world;
}
static Hittable *earth(Arena *arena) {
Texture *earth_texture = texture_create_image("assets/earthmap.jpg", arena);
Material *earth_surface = material_create_lambertian(earth_texture, arena);
Hittable *globe = hittable_create_sphere((Point3){0.0, 0.0, 0.0}, 2.0,
earth_surface, arena);
return globe;
}
int main(void) {
srand(42);
@ -158,14 +167,14 @@ int main(void) {
/* Image parameters */
const double aspect_ratio = 16.0 / 9.0;
const int image_width = 400;
const int image_width = 1200;
const int image_height = (int)(image_width / aspect_ratio);
const int samples_per_pixel = 100;
const int samples_per_pixel = 500;
const int max_depth = 50;
/* World */
Point3 look_from = {13.0, 2.0, 3.0};
Point3 look_from = {0.0, 0.0, 1.0};
Point3 look_at = {0.0, 0.0, 0.0};
double vfov = 40.0;
double aperture = 0.0;
@ -189,6 +198,11 @@ int main(void) {
look_from = (Point3){13.0, 2.0, 3.0};
look_at = (Point3){0.0, 0.0, 0.0};
vfov = 20.0;
#elif SCENE_SELECT == SCENE_EARTH
world = earth(&arena);
look_from = (Point3){13.0, 2.0, 3.0};
look_at = (Point3){0.0, 0.0, 0.0};
vfov = 20.0;
#endif
Vec3 up = {0.0, 1.0, 0.0};
@ -232,3 +246,6 @@ int main(void) {
#include "texture.c"
#include "utils.c"
#include "vec3.c"
#define STB_IMAGE_IMPLEMENTATION
#include "external/stb_image.h"

108
texture.c
View File

@ -1,9 +1,17 @@
#include "texture.h"
#include "arena.h"
#include "color.h"
#include "external/stb_image.h"
#include "perlin.h"
#include "utils.h"
#include <math.h>
#include <stdlib.h>
#define DEBUG_COLOR \
(Color) { 1.0, 0.0, 1.0 }
static const int image_bytes_per_pixel = 3;
Texture *texture_create_solid_color(Color value, Arena *arena) {
Texture *result = arena_alloc(arena, sizeof(Texture));
@ -22,6 +30,13 @@ Texture *texture_create_checker(const Texture *odd, const Texture *even,
return result;
}
Texture *texture_create_checker_solid_color(Color odd, Color even, double size,
Arena *arena) {
Texture *odd_texture = texture_create_solid_color(odd, arena);
Texture *even_texture = texture_create_solid_color(even, arena);
return texture_create_checker(odd_texture, even_texture, size, arena);
}
Texture *texture_create_perlin_noise(double scale, int point_count,
Arena *arena) {
Texture *result = arena_alloc(arena, sizeof(Texture));
@ -31,11 +46,68 @@ Texture *texture_create_perlin_noise(double scale, int point_count,
return result;
}
Texture *texture_create_checker_solid_color(Color odd, Color even, double size,
Arena *arena) {
Texture *odd_texture = texture_create_solid_color(odd, arena);
Texture *even_texture = texture_create_solid_color(even, arena);
return texture_create_checker(odd_texture, even_texture, size, arena);
Texture *texture_create_image(const char *filename, Arena *arena) {
Texture *result = arena_alloc(arena, sizeof(Texture));
result->type = TEXTURE_IMAGE;
int components_per_pixel = image_bytes_per_pixel;
result->image.data =
stbi_load(filename, &result->image.width, &result->image.height,
&components_per_pixel, components_per_pixel);
if (!result->image.data) {
fprintf(stderr, "Failed to load texture from image file %s\n", filename);
result->image.width = result->image.height = 0;
}
result->image.bytes_per_scanline =
image_bytes_per_pixel * result->image.width;
return result;
}
static Color image_value(const ImageTexture *image, double u, double v) {
if (!image->data)
return DEBUG_COLOR;
u = clamp(u, 0.0, 1.0);
v = 1.0 - clamp(v, 0.0, 1.0);
int i = u * image->width;
int j = v * image->height;
if (i >= image->width)
i = image->width - 1;
if (j >= image->height)
j = image->height - 1;
const double color_scale = 1.0 / 255.0;
const unsigned char *pixel =
image->data + j * image->bytes_per_scanline + i * image_bytes_per_pixel;
return (Color){color_scale * pixel[0], color_scale * pixel[1],
color_scale * pixel[2]};
}
static Color solid_color_value(const SolidColor *solid_color) {
return solid_color->value;
}
static Color checker_value(const CheckerTexture *checker, double u, double v,
Point3 p) {
double sines = sin(checker->size * p.x) * sin(checker->size * p.y) *
sin(checker->size * p.z);
if (sines < 0.0)
return texture_value(checker->odd, u, v, p);
return texture_value(checker->even, u, v, p);
}
static Color perlin_value(const PerlinNoiseTexture *perlin, Point3 p) {
double noise_value =
0.5 *
(1.0 + sin(perlin->scale * p.z +
10 * perlin_turbulence(perlin->data, p,
PERLIN_DEFAULT_TURBULENCE_DEPTH)));
return color_mul_const(noise_value, (Color){1.0, 1.0, 1.0});
}
Color texture_value(const Texture *texture, double u, double v, Point3 p) {
@ -46,28 +118,8 @@ Color texture_value(const Texture *texture, double u, double v, Point3 p) {
return checker_value(&texture->checker, u, v, p);
case TEXTURE_PERLIN_NOISE:
return perlin_value(&texture->noise, p);
case TEXTURE_IMAGE:
return image_value(&texture->image, u, v);
}
return (Color){0.0, 0.0, 0.0};
}
Color solid_color_value(const SolidColor *solid_color) {
return solid_color->value;
}
Color checker_value(const CheckerTexture *checker, double u, double v,
Point3 p) {
double sines = sin(checker->size * p.x) * sin(checker->size * p.y) *
sin(checker->size * p.z);
if (sines < 0.0)
return texture_value(checker->odd, u, v, p);
return texture_value(checker->even, u, v, p);
}
Color perlin_value(const PerlinNoiseTexture *perlin, Point3 p) {
double noise_value =
0.5 *
(1.0 + sin(perlin->scale * p.z +
10 * perlin_turbulence(perlin->data, p,
PERLIN_DEFAULT_TURBULENCE_DEPTH)));
return color_mul_const(noise_value, (Color){1.0, 1.0, 1.0});
return DEBUG_COLOR;
}

View File

@ -10,6 +10,7 @@ typedef enum TextureType {
TEXTURE_SOLID_COLOR,
TEXTURE_CHECKER,
TEXTURE_PERLIN_NOISE,
TEXTURE_IMAGE,
} TextureType;
typedef struct Texture Texture;
@ -29,12 +30,19 @@ typedef struct PerlinNoiseTexture {
double scale;
} PerlinNoiseTexture;
typedef struct ImageTexture {
unsigned char *data;
int width, height;
int bytes_per_scanline;
} ImageTexture;
struct Texture {
TextureType type;
union {
SolidColor solid_color;
CheckerTexture checker;
PerlinNoiseTexture noise;
ImageTexture image;
};
};
@ -45,14 +53,8 @@ Texture *texture_create_checker_solid_color(Color odd, Color even, double size,
Arena *arena);
Texture *texture_create_perlin_noise(double scale, int point_count,
Arena *arena);
Texture *texture_create_image(const char *filename, Arena *arena);
Color texture_value(const Texture *texture, double u, double v, Point3 p);
Color solid_color_value(const SolidColor *solid_color);
Color checker_value(const CheckerTexture *checker, double u, double v,
Point3 p);
Color perlin_value(const PerlinNoiseTexture *perlin, Point3 p);
#endif /* INCLUDED_TEXTURE_H */