Add Perlin noise
This commit is contained in:
parent
20a77499bc
commit
8400ea96aa
4
color.c
4
color.c
@ -12,6 +12,10 @@ Color color_mul(Color c1, Color c2) {
|
|||||||
return (Color){c1.r * c2.r, c1.g * c2.g, c1.b * c2.b};
|
return (Color){c1.r * c2.r, c1.g * c2.g, c1.b * c2.b};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color color_mul_const(double t, Color c) {
|
||||||
|
return (Color){t * c.r, t * c.g, t * c.b};
|
||||||
|
}
|
||||||
|
|
||||||
Color color_random(void) {
|
Color color_random(void) {
|
||||||
return (Color){random_double_in_range(0.0, 1.0),
|
return (Color){random_double_in_range(0.0, 1.0),
|
||||||
random_double_in_range(0.0, 1.0),
|
random_double_in_range(0.0, 1.0),
|
||||||
|
|||||||
1
color.h
1
color.h
@ -9,6 +9,7 @@ typedef struct Color {
|
|||||||
|
|
||||||
Color color_add(Color c1, Color c2);
|
Color color_add(Color c1, Color c2);
|
||||||
Color color_mul(Color c1, Color c2);
|
Color color_mul(Color c1, Color c2);
|
||||||
|
Color color_mul_const(double t, Color c);
|
||||||
|
|
||||||
Color color_random(void);
|
Color color_random(void);
|
||||||
Color color_random_in_range(double min, double max);
|
Color color_random_in_range(double min, double max);
|
||||||
|
|||||||
31
main.c
31
main.c
@ -9,6 +9,7 @@
|
|||||||
#include "color.h"
|
#include "color.h"
|
||||||
#include "hittable.h"
|
#include "hittable.h"
|
||||||
#include "material.h"
|
#include "material.h"
|
||||||
|
#include "perlin.h"
|
||||||
#include "point3.h"
|
#include "point3.h"
|
||||||
#include "ray.h"
|
#include "ray.h"
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
@ -17,8 +18,9 @@
|
|||||||
|
|
||||||
#define SCENE_RANDOM 0
|
#define SCENE_RANDOM 0
|
||||||
#define SCENE_TWO_SPHERES 1
|
#define SCENE_TWO_SPHERES 1
|
||||||
|
#define SCENE_TWO_PERLIN_SPHERES 2
|
||||||
|
|
||||||
#define SCENE_SELECT SCENE_TWO_SPHERES
|
#define SCENE_SELECT SCENE_TWO_PERLIN_SPHERES
|
||||||
|
|
||||||
static Color ray_color(Ray r, const Hittable *world, int depth) {
|
static Color ray_color(Ray r, const Hittable *world, int depth) {
|
||||||
if (depth <= 0)
|
if (depth <= 0)
|
||||||
@ -120,6 +122,27 @@ static Hittable *two_spheres(Arena *arena) {
|
|||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Hittable *two_perlin_spheres(Arena *arena) {
|
||||||
|
Hittable *world = hittable_create_hittable_list(arena);
|
||||||
|
|
||||||
|
Texture *perlin_texture =
|
||||||
|
texture_create_perlin_noise(4.0, PERLIN_DEFAULT_POINT_COUNT, arena);
|
||||||
|
hittable_list_add(
|
||||||
|
&world->list,
|
||||||
|
hittable_create_sphere((Point3){0.0, -1000.0, 0.0}, 1000.0,
|
||||||
|
material_create_lambertian(perlin_texture, arena),
|
||||||
|
arena),
|
||||||
|
arena);
|
||||||
|
hittable_list_add(
|
||||||
|
&world->list,
|
||||||
|
hittable_create_sphere((Point3){0.0, 2.0, 0.0}, 2.0,
|
||||||
|
material_create_lambertian(perlin_texture, arena),
|
||||||
|
arena),
|
||||||
|
arena);
|
||||||
|
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
srand(42);
|
srand(42);
|
||||||
|
|
||||||
@ -161,6 +184,11 @@ int main(void) {
|
|||||||
look_from = (Point3){13.0, 2.0, 3.0};
|
look_from = (Point3){13.0, 2.0, 3.0};
|
||||||
look_at = (Point3){0.0, 0.0, 0.0};
|
look_at = (Point3){0.0, 0.0, 0.0};
|
||||||
vfov = 20.0;
|
vfov = 20.0;
|
||||||
|
#elif SCENE_SELECT == SCENE_TWO_PERLIN_SPHERES
|
||||||
|
world = two_perlin_spheres(&arena);
|
||||||
|
look_from = (Point3){13.0, 2.0, 3.0};
|
||||||
|
look_at = (Point3){0.0, 0.0, 0.0};
|
||||||
|
vfov = 20.0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Vec3 up = {0.0, 1.0, 0.0};
|
Vec3 up = {0.0, 1.0, 0.0};
|
||||||
@ -198,6 +226,7 @@ int main(void) {
|
|||||||
#include "color.c"
|
#include "color.c"
|
||||||
#include "hittable.c"
|
#include "hittable.c"
|
||||||
#include "material.c"
|
#include "material.c"
|
||||||
|
#include "perlin.c"
|
||||||
#include "point3.c"
|
#include "point3.c"
|
||||||
#include "ray.c"
|
#include "ray.c"
|
||||||
#include "texture.c"
|
#include "texture.c"
|
||||||
|
|||||||
86
perlin.c
Normal file
86
perlin.c
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#include "perlin.h"
|
||||||
|
#include "arena.h"
|
||||||
|
#include "utils.h"
|
||||||
|
#include "vec3.h"
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
struct PerlinData {
|
||||||
|
Vec3 *random_vectors;
|
||||||
|
int *perm_x;
|
||||||
|
int *perm_y;
|
||||||
|
int *perm_z;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void permute(int *p, int n) {
|
||||||
|
for (int i = n - 1; i > 0; --i) {
|
||||||
|
int target = random_int_in_range(0, i);
|
||||||
|
int tmp = p[i];
|
||||||
|
p[i] = p[target];
|
||||||
|
p[target] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int *perlin_generate_perm(int point_count, Arena *arena) {
|
||||||
|
int *p = arena_alloc(arena, point_count * sizeof(int));
|
||||||
|
|
||||||
|
for (int i = 0; i < point_count; ++i)
|
||||||
|
p[i] = i;
|
||||||
|
permute(p, point_count);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
PerlinData *perlin_init(int point_count, Arena *arena) {
|
||||||
|
PerlinData *data = arena_alloc(arena, sizeof(PerlinData));
|
||||||
|
data->random_vectors = arena_alloc(arena, point_count * sizeof(Vec3));
|
||||||
|
for (int i = 0; i < point_count; ++i)
|
||||||
|
data->random_vectors[i] = vec3_normalize(vec3_random_in_range(-1.0, 1.0));
|
||||||
|
|
||||||
|
data->perm_x = perlin_generate_perm(point_count, arena);
|
||||||
|
data->perm_y = perlin_generate_perm(point_count, arena);
|
||||||
|
data->perm_z = perlin_generate_perm(point_count, arena);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double perlin_interp(const Vec3 c[2][2][2], double u, double v,
|
||||||
|
double w) {
|
||||||
|
double uu = u * u * (3 - 2 * u);
|
||||||
|
double vv = v * v * (3 - 2 * v);
|
||||||
|
double ww = w * w * (3 - 2 * w);
|
||||||
|
double accum = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
for (int j = 0; j < 2; ++j) {
|
||||||
|
for (int k = 0; k < 2; ++k) {
|
||||||
|
Vec3 weight_v = {u - i, v - j, w - k};
|
||||||
|
accum += (i * uu + (1 - i) * (1 - uu)) * (j * vv + (1 - j) * (1 - vv)) *
|
||||||
|
(k * ww + (1 - k) * (1 - ww)) * vec3_dot(c[i][j][k], weight_v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return accum;
|
||||||
|
}
|
||||||
|
|
||||||
|
double perlin_noise(const PerlinData *data, Point3 p) {
|
||||||
|
double u = p.x - floor(p.x);
|
||||||
|
double v = p.y - floor(p.y);
|
||||||
|
double w = p.z - floor(p.z);
|
||||||
|
|
||||||
|
int i = (int)floor(p.x);
|
||||||
|
int j = (int)floor(p.y);
|
||||||
|
int k = (int)floor(p.z);
|
||||||
|
|
||||||
|
Vec3 c[2][2][2] = {0};
|
||||||
|
for (int di = 0; di < 2; ++di) {
|
||||||
|
for (int dj = 0; dj < 2; ++dj) {
|
||||||
|
for (int dk = 0; dk < 2; ++dk) {
|
||||||
|
c[di][dj][dk] = data->random_vectors[data->perm_x[(i + di) & 0xff] ^
|
||||||
|
data->perm_y[(j + dj) & 0xff] ^
|
||||||
|
data->perm_z[(k + dk) & 0xff]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return perlin_interp(c, u, v, w);
|
||||||
|
}
|
||||||
14
perlin.h
Normal file
14
perlin.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef INCLUDED_PERLIN_H
|
||||||
|
#define INCLUDED_PERLIN_H
|
||||||
|
|
||||||
|
#include "arena.h"
|
||||||
|
#include "point3.h"
|
||||||
|
|
||||||
|
#define PERLIN_DEFAULT_POINT_COUNT 256
|
||||||
|
|
||||||
|
typedef struct PerlinData PerlinData;
|
||||||
|
|
||||||
|
PerlinData *perlin_init(int point_count, Arena *arena);
|
||||||
|
double perlin_noise(const PerlinData *data, Point3 p);
|
||||||
|
|
||||||
|
#endif /* INCLUDED_PERLIN_H */
|
||||||
27
texture.c
27
texture.c
@ -1,5 +1,7 @@
|
|||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
#include "arena.h"
|
#include "arena.h"
|
||||||
|
#include "color.h"
|
||||||
|
#include "perlin.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
@ -20,6 +22,15 @@ Texture *texture_create_checker(const Texture *odd, const Texture *even,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Texture *texture_create_perlin_noise(double scale, int point_count,
|
||||||
|
Arena *arena) {
|
||||||
|
Texture *result = arena_alloc(arena, sizeof(Texture));
|
||||||
|
result->type = TEXTURE_PERLIN_NOISE;
|
||||||
|
result->noise.data = perlin_init(point_count, arena);
|
||||||
|
result->noise.scale = scale;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Texture *texture_create_checker_solid_color(Color odd, Color even, double size,
|
Texture *texture_create_checker_solid_color(Color odd, Color even, double size,
|
||||||
Arena *arena) {
|
Arena *arena) {
|
||||||
Texture *odd_texture = texture_create_solid_color(odd, arena);
|
Texture *odd_texture = texture_create_solid_color(odd, arena);
|
||||||
@ -30,16 +41,16 @@ Texture *texture_create_checker_solid_color(Color odd, Color even, double size,
|
|||||||
Color texture_value(const Texture *texture, double u, double v, Point3 p) {
|
Color texture_value(const Texture *texture, double u, double v, Point3 p) {
|
||||||
switch (texture->type) {
|
switch (texture->type) {
|
||||||
case TEXTURE_SOLID_COLOR:
|
case TEXTURE_SOLID_COLOR:
|
||||||
return solid_color_value(&texture->solid_color, u, v, p);
|
return solid_color_value(&texture->solid_color);
|
||||||
case TEXTURE_CHECKER:
|
case TEXTURE_CHECKER:
|
||||||
return checker_value(&texture->checker, u, v, p);
|
return checker_value(&texture->checker, u, v, p);
|
||||||
|
case TEXTURE_PERLIN_NOISE:
|
||||||
|
return perlin_value(&texture->noise, p);
|
||||||
}
|
}
|
||||||
return (Color){0.0, 0.0, 0.0};
|
return (Color){0.0, 0.0, 0.0};
|
||||||
}
|
}
|
||||||
|
|
||||||
Color solid_color_value(const SolidColor *solid_color, double u, double v,
|
Color solid_color_value(const SolidColor *solid_color) {
|
||||||
Point3 p) {
|
|
||||||
(void)u, (void)v, (void)p;
|
|
||||||
return solid_color->value;
|
return solid_color->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,3 +62,11 @@ Color checker_value(const CheckerTexture *checker, double u, double v,
|
|||||||
return texture_value(checker->odd, u, v, p);
|
return texture_value(checker->odd, u, v, p);
|
||||||
return texture_value(checker->even, 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 + perlin_noise(perlin->data, (Point3){perlin->scale * p.x,
|
||||||
|
perlin->scale * p.y,
|
||||||
|
perlin->scale * p.z}));
|
||||||
|
return color_mul_const(noise_value, (Color){1.0, 1.0, 1.0});
|
||||||
|
}
|
||||||
|
|||||||
15
texture.h
15
texture.h
@ -3,11 +3,13 @@
|
|||||||
|
|
||||||
#include "arena.h"
|
#include "arena.h"
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
|
#include "perlin.h"
|
||||||
#include "point3.h"
|
#include "point3.h"
|
||||||
|
|
||||||
typedef enum TextureType {
|
typedef enum TextureType {
|
||||||
TEXTURE_SOLID_COLOR,
|
TEXTURE_SOLID_COLOR,
|
||||||
TEXTURE_CHECKER,
|
TEXTURE_CHECKER,
|
||||||
|
TEXTURE_PERLIN_NOISE,
|
||||||
} TextureType;
|
} TextureType;
|
||||||
|
|
||||||
typedef struct Texture Texture;
|
typedef struct Texture Texture;
|
||||||
@ -22,11 +24,17 @@ typedef struct CheckerTexture {
|
|||||||
double size;
|
double size;
|
||||||
} CheckerTexture;
|
} CheckerTexture;
|
||||||
|
|
||||||
|
typedef struct PerlinNoiseTexture {
|
||||||
|
const PerlinData *data;
|
||||||
|
double scale;
|
||||||
|
} PerlinNoiseTexture;
|
||||||
|
|
||||||
struct Texture {
|
struct Texture {
|
||||||
TextureType type;
|
TextureType type;
|
||||||
union {
|
union {
|
||||||
SolidColor solid_color;
|
SolidColor solid_color;
|
||||||
CheckerTexture checker;
|
CheckerTexture checker;
|
||||||
|
PerlinNoiseTexture noise;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,13 +43,16 @@ Texture *texture_create_checker(const Texture *odd, const Texture *even,
|
|||||||
double size, Arena *arena);
|
double size, Arena *arena);
|
||||||
Texture *texture_create_checker_solid_color(Color odd, Color even, double size,
|
Texture *texture_create_checker_solid_color(Color odd, Color even, double size,
|
||||||
Arena *arena);
|
Arena *arena);
|
||||||
|
Texture *texture_create_perlin_noise(double scale, int point_count,
|
||||||
|
Arena *arena);
|
||||||
|
|
||||||
Color texture_value(const Texture *texture, double u, double v, Point3 p);
|
Color texture_value(const Texture *texture, double u, double v, Point3 p);
|
||||||
|
|
||||||
Color solid_color_value(const SolidColor *solid_color, double u, double v,
|
Color solid_color_value(const SolidColor *solid_color);
|
||||||
Point3 p);
|
|
||||||
|
|
||||||
Color checker_value(const CheckerTexture *checker, double u, double v,
|
Color checker_value(const CheckerTexture *checker, double u, double v,
|
||||||
Point3 p);
|
Point3 p);
|
||||||
|
|
||||||
|
Color perlin_value(const PerlinNoiseTexture *perlin, Point3 p);
|
||||||
|
|
||||||
#endif /* INCLUDED_TEXTURE_H */
|
#endif /* INCLUDED_TEXTURE_H */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user