Add image textures
This commit is contained in:
parent
fc35055466
commit
391aa6240e
@ -5,3 +5,4 @@ C implementation of the [*Ray tracing in one week-end*](https://raytracing.githu
|
||||
## Examples
|
||||
|
||||

|
||||

|
||||
|
||||
BIN
assets/earthmap.jpg
Normal file
BIN
assets/earthmap.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 158 KiB |
BIN
examples/earth.png
Normal file
BIN
examples/earth.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 320 KiB |
7897
external/stb_image.h
vendored
Normal file
7897
external/stb_image.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
25
main.c
@ -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
108
texture.c
@ -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;
|
||||
}
|
||||
|
||||
16
texture.h
16
texture.h
@ -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 */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user