Skip to content

Commit 6c9164f

Browse files
GDBobbykarnkaul
andauthored
3rd, 4th dimension, Post Processing (#5)
### Post Processor post processing class, named Processor, allows for some additional default post-processing. Custom Post Processing can still be done using Noise::at The post processor class functionality is completely optional, and will not have any runtime cost if not required A few of the default post-processing methods : * Billowy * Rigid * Hybrid Multi-Fractal * Turbulent * Basic ### 3rd dimension Generates perlin noise given 3 dimensional coordinates. Included is an example that creates an obj file point cloud. The example uses the Processor class, with the hybrid multi-fractal post-processing functionality. ### 4th dimension 4th dimension support is there, but no viable example is currently known. --------- Co-authored-by: Karn Kaul <[email protected]>
1 parent 78b6eb2 commit 6c9164f

22 files changed

+1027
-8
lines changed

examples/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
add_subdirectory(histogram)
22
add_subdirectory(texture2d)
3+
add_subdirectory(point-cloud)

examples/common/argument_parsing.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <noiz/noise2.hpp>
2-
31
#include <charconv>
42
#include <format>
53
#include <iostream>

examples/point-cloud/CMakeLists.txt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
project(noiz-point-cloud)
2+
3+
add_executable(${PROJECT_NAME})
4+
5+
target_link_libraries(${PROJECT_NAME} PRIVATE
6+
noiz::noiz-lib
7+
noiz::noiz-compile-options
8+
)
9+
10+
target_sources(${PROJECT_NAME} PRIVATE
11+
pointcloud.cpp
12+
)
13+
14+
target_include_directories(${PROJECT_NAME} PRIVATE
15+
../common
16+
)

examples/point-cloud/pointcloud.cpp

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#include <noiz/noise3.hpp>
2+
#include <noiz/processing.hpp>
3+
4+
#include <argument_parsing.hpp>
5+
6+
7+
#include <charconv>
8+
#include <filesystem>
9+
#include <format>
10+
#include <iostream>
11+
#include <vector>
12+
#include <fstream>
13+
14+
constexpr int32_t constant_base_resolution = 128;
15+
constexpr int32_t constant_max_resolution_factor = 32;
16+
17+
struct Config {
18+
noiz::Seed seed{noiz::detail::Generator::make_random_seed()};
19+
noiz::GridExtent3 grid_extent{constant_base_resolution, constant_base_resolution, constant_base_resolution}; // NOLINT
20+
float step{0.1f}; // NOLINT
21+
int image_size_factor{1};
22+
23+
// syntax: [count] [step]
24+
auto parse_args(Args args) -> bool {
25+
if (!args.next_as(step, "step")) { return false; }
26+
if (!args.next_as(image_size_factor, "image_size_factor")) { return false; }
27+
if (image_size_factor < 0 || image_size_factor > constant_max_resolution_factor) {
28+
std::cerr << std::format("invalid image size factor: '{}'\n", image_size_factor);
29+
return false;
30+
}
31+
if (!args.args.empty()) {
32+
return false;
33+
}
34+
grid_extent.x *= image_size_factor;
35+
grid_extent.y *= image_size_factor;
36+
grid_extent.z *= image_size_factor;
37+
return true;
38+
}
39+
};
40+
41+
// pulls noise from noiz::lib, writes a pixel to ppm file
42+
class Point_Cloud {
43+
public:
44+
explicit Point_Cloud(int image_size_factor) : image_size{static_cast<uint16_t>(constant_base_resolution * image_size_factor)} {}
45+
46+
void build_and_write_object_with_noise(noiz::Noise3f& noise, float const& step) const {
47+
48+
std::ofstream out_file{"hybrid_multifractal_noise.obj", std::ios::binary};
49+
50+
float vertex_z;
51+
float vertex_y;
52+
53+
noiz::Processor3f noise_processor{noise};
54+
55+
for(int z = 0; z < image_size; z++){
56+
vertex_z = (static_cast<float>(z) / static_cast<float>(image_size)) - 0.5f;
57+
58+
for (int y = 0; y < image_size; y++) {
59+
vertex_y = (static_cast<float>(y) / static_cast<float>(image_size)) - 0.5f;
60+
for(int x = 0; x < image_size; x++) {
61+
// add noise at point
62+
//raw noise
63+
#if 0 //raw noise
64+
const float noise_value = noise.at(noiz::Vec3f{.x = static_cast<float>(x) * step, .y = static_cast<float>(y) * step, .z = static_cast<float>(z) * step});
65+
if(noise_value > 0.0f){ //this should render a half of the points with raw noise
66+
67+
//no point in assigning x here? just write it directly to
68+
out_file << "v " << ((static_cast<float>(x) / static_cast<float>(image_size)) - 0.5f) << " " << vertex_y << " " << vertex_z << '\n';
69+
}
70+
#else //hybrid multi fractal noise
71+
const float noise_value = noise_processor.hybrid_multi_fractal_processing(
72+
noiz::Vec3f{.x = static_cast<float>(x) * step, .y = static_cast<float>(y) * step, .z = static_cast<float>(z) * step}
73+
);
74+
if(noise_value > 2.0f){ //this should render a half of the points with hmf noise
75+
76+
//no point in assigning x here? just write it directly to
77+
out_file << std::format("v {} {} {} '\n", (static_cast<float>(x) / static_cast<float>(image_size)) - 0.5f, vertex_y, vertex_z);
78+
//out_file << "v " << ((static_cast<float>(x) / static_cast<float>(image_size)) - 0.5f) << " " << vertex_y << " " << vertex_z << '\n';
79+
}
80+
#endif
81+
}
82+
}
83+
}
84+
out_file.close();
85+
}
86+
87+
private:
88+
uint16_t image_size;
89+
};
90+
91+
auto main(int argc, char** argv) -> int {
92+
auto config = Config{};
93+
94+
// skip exe name (argv[0])
95+
auto const args = Args{std::span{argv, static_cast<std::size_t>(argc)}.subspan(1)};
96+
97+
// handle --help
98+
if (!args.args.empty() && args.args.front() == std::string_view{"--help"}) {
99+
std::cout << std::format("Usage: {} [step(=0.1)] [image_size_factor(=1)]\n", std::filesystem::path{*argv}.stem().string());
100+
std::cout << "\t output image resolution is 128x128, with each dimension multiplied by image_size_factor, maximum scaling factor is 32[image size of 4096]" << std::endl;
101+
return EXIT_SUCCESS;
102+
}
103+
104+
// parse args, if any
105+
if (!config.parse_args(args)) {
106+
std::cout << args.args.front() << std::endl;
107+
return EXIT_FAILURE;
108+
}
109+
110+
111+
auto noise = noiz::Noise3f{noiz::Seed{config.seed}, config.grid_extent};
112+
113+
// build and write noise to image
114+
auto point_cloud = Point_Cloud{config.image_size_factor};
115+
point_cloud.build_and_write_object_with_noise(noise, config.step);
116+
}

noiz/CMakeLists.txt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,25 @@ target_sources(${PROJECT_NAME} PUBLIC FILE_SET HEADERS BASE_DIRS include FILES
1313
include/noiz/noise2.hpp
1414
include/noiz/seed.hpp
1515
include/noiz/vec2.hpp
16-
)
16+
17+
18+
include/noiz/detail/data3.hpp
19+
include/noiz/detail/grid3.hpp
20+
21+
include/noiz/cell3.hpp
22+
include/noiz/index3.hpp
23+
include/noiz/noise3.hpp
24+
include/noiz/vec3.hpp
25+
26+
27+
include/noiz/detail/data4.hpp
28+
include/noiz/detail/grid4.hpp
29+
30+
include/noiz/cell4.hpp
31+
include/noiz/index4.hpp
32+
include/noiz/noise4.hpp
33+
include/noiz/vec4.hpp
34+
)
1735

1836
target_include_directories(${PROJECT_NAME} INTERFACE
1937
include

noiz/include/noiz/cell3.hpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
#include <span>
3+
#include "index3.hpp"
4+
#include "vec3.hpp"
5+
6+
namespace noiz {
7+
template <std::floating_point Type>
8+
struct Corner3 {
9+
Vec3<Type> location{};
10+
Vec3<Type> gradient{};
11+
};
12+
13+
template <typename Type>
14+
struct TCell3 {
15+
Type left_top_front{};
16+
Type right_top_front{};
17+
Type left_bottom_front{};
18+
Type right_bottom_front{};
19+
20+
Type left_top_back{};
21+
Type right_top_back{};
22+
Type left_bottom_back{};
23+
Type right_bottom_back{};
24+
};
25+
26+
template <std::floating_point Type>
27+
using Cell3 = TCell3<Vec3<Type>>;
28+
29+
template <std::floating_point Type>
30+
using CornerCell3 = TCell3<Corner3<Type>>;
31+
} // namespace noiz

noiz/include/noiz/cell4.hpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
#include <span>
3+
#include "index4.hpp"
4+
#include "vec4.hpp"
5+
6+
namespace noiz {
7+
template <std::floating_point Type>
8+
struct Corner4 {
9+
Vec4<Type> location{};
10+
Vec4<Type> gradient{};
11+
};
12+
13+
template <typename Type>
14+
struct TCell4 {
15+
//16 is 2^4
16+
std::array<Type, 16> corners{};
17+
};
18+
19+
template <std::floating_point Type>
20+
using Cell4 = TCell4<Vec4<Type>>;
21+
22+
template <std::floating_point Type>
23+
using CornerCell4 = TCell4<Corner4<Type>>;
24+
} // namespace noiz

noiz/include/noiz/detail/data3.hpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#pragma once
2+
#include "generator.hpp"
3+
#include "grid3.hpp"
4+
5+
namespace noiz::detail {
6+
template <std::floating_point Type>
7+
auto make_populated_grid(Index3 const grid_extent, Seed seed = Generator::make_random_seed()) -> Grid3<Type> {
8+
auto ret = make_grid3<Type>(grid_extent);
9+
auto generator = Generator{seed};
10+
for (auto& corner : ret.corners) { generator.next(corner.gradient); }
11+
return ret;
12+
}
13+
14+
template <std::floating_point Type>
15+
constexpr auto compute_offsets(CornerCell3<Type> const& corner, Vec3<Type> const point) -> Cell3<Type> {
16+
return Cell3<Type>{
17+
.left_top_front = point - corner.left_top_front.location,
18+
.right_top_front = point - corner.right_top_front.location,
19+
.left_bottom_front = point - corner.left_bottom_front.location,
20+
.right_bottom_front = point - corner.right_bottom_front.location,
21+
.left_top_back = point - corner.left_top_back.location,
22+
.right_top_back = point - corner.right_top_back.location,
23+
.left_bottom_back = point - corner.left_bottom_back.location,
24+
.right_bottom_back = point - corner.right_bottom_back.location,
25+
};
26+
}
27+
28+
template <std::floating_point Type>
29+
constexpr auto compute_dot_products(CornerCell3<Type> const& corner, Cell3<Type> const& offset) -> TCell3<Type> {
30+
return TCell3<Type>{
31+
.left_top_front = dot(corner.left_top_front.gradient, offset.left_top_front),
32+
.right_top_front = dot(corner.right_top_front.gradient, offset.right_top_front),
33+
.left_bottom_front = dot(corner.left_bottom_front.gradient, offset.left_bottom_front),
34+
.right_bottom_front = dot(corner.right_bottom_front.gradient, offset.right_bottom_front),
35+
36+
.left_top_back = dot(corner.left_top_back.gradient, offset.left_top_back),
37+
.right_top_back = dot(corner.right_top_back.gradient, offset.right_top_back),
38+
.left_bottom_back = dot(corner.left_bottom_back.gradient, offset.left_bottom_back),
39+
.right_bottom_back = dot(corner.right_bottom_back.gradient, offset.right_bottom_back),
40+
};
41+
}
42+
43+
template <std::floating_point Type>
44+
constexpr auto interpolate(Vec3<Type> const point, TCell3<Type> const& dot_products) -> Type {
45+
auto const uvw = point.fract().fade();
46+
47+
auto const below_a = std::lerp(dot_products.left_top_front, dot_products.right_top_front, uvw.x);
48+
auto const below_b = std::lerp(dot_products.left_bottom_front, dot_products.right_bottom_front, uvw.x);
49+
auto const below = std::lerp(below_a, below_b, uvw.y);
50+
51+
auto const above_a = std::lerp(dot_products.left_top_back, dot_products.right_top_back, uvw.x);
52+
auto const above_b = std::lerp(dot_products.left_bottom_back, dot_products.right_bottom_back, uvw.x);
53+
auto const above = std::lerp(above_a, above_b, uvw.y);
54+
55+
//i might need to swap the position of below and above, not really sure
56+
return std::lerp(below, above, uvw.z);
57+
}
58+
} // namespace noiz::detail

noiz/include/noiz/detail/data4.hpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#pragma once
2+
#include "generator.hpp"
3+
#include "grid4.hpp"
4+
5+
namespace noiz::detail {
6+
template <std::floating_point Type>
7+
auto make_populated_grid(Index4 const grid_extent, Seed seed = Generator::make_random_seed()) -> Grid4<Type> {
8+
auto ret = make_grid4<Type>(grid_extent);
9+
auto generator = Generator{seed};
10+
for (auto& corner : ret.corners) { generator.next(corner.gradient); }
11+
return ret;
12+
}
13+
14+
template <std::floating_point Type>
15+
constexpr auto compute_offsets(CornerCell4<Type> const& corner, Vec4<Type> const point) -> Cell4<Type> {
16+
17+
Cell4<Type> ret;
18+
for(uint8_t i = 0; i < 16; i++){
19+
ret.corners[i] = point - corner.corners[i];
20+
}
21+
return ret;
22+
}
23+
24+
template <std::floating_point Type>
25+
constexpr auto compute_dot_products(CornerCell4<Type> const& corner, Cell4<Type> const& offset) -> TCell4<Type> {
26+
27+
TCell4<Type> ret;
28+
for(int i = 0; i < 16; i++){
29+
ret.corners[i] = dot(corner.corners[i].gradient, offset.corners[i]);
30+
}
31+
return ret;
32+
}
33+
34+
template <std::floating_point Type>
35+
constexpr auto interpolate(Vec4<Type> const point, TCell4<Type> const& dot_products) -> Type {
36+
auto const cell_interpolated_position = point.fract().fade();
37+
38+
//1st dimension
39+
auto const below_a = std::lerp(dot_products.corners[0], dot_products.corners[1], cell_interpolated_position.x);
40+
//2nd dimension
41+
auto const below_b = std::lerp(dot_products.corners[2], dot_products.corners[3], cell_interpolated_position.x);
42+
auto const below = std::lerp(below_a, below_b, cell_interpolated_position.y);
43+
44+
//3rd dimension
45+
auto const above_a = std::lerp(dot_products.corners[4], dot_products.corners[5], cell_interpolated_position.x);
46+
auto const above_b = std::lerp(dot_products.corners[6], dot_products.corners[7], cell_interpolated_position.x);
47+
auto const above = std::lerp(above_a, above_b, cell_interpolated_position.y);
48+
49+
auto const third_lerp_a = std::lerp(below, above, cell_interpolated_position.z);
50+
51+
//4th dimension
52+
auto const fourth_below_a = std::lerp(dot_products.corners[8], dot_products.corners[9], cell_interpolated_position.x);
53+
auto const fourth_below_b = std::lerp(dot_products.corners[10], dot_products.corners[11], cell_interpolated_position.x);
54+
auto const fourth_below = std::lerp(fourth_below_a, fourth_below_b, cell_interpolated_position.y);
55+
56+
auto const fourth_above_a = std::lerp(dot_products.corners[12], dot_products.corners[13], cell_interpolated_position.x);
57+
auto const fourth_above_b = std::lerp(dot_products.corners[14], dot_products.corners[15], cell_interpolated_position.x);
58+
auto const fourth_above = std::lerp(fourth_above_a, fourth_above_b, cell_interpolated_position.y);
59+
60+
auto const third_lerp_b = std::lerp(fourth_below, fourth_above, cell_interpolated_position.z);
61+
62+
63+
64+
//i might need to swap the position of below and above, not really sure
65+
return std::lerp(third_lerp_a, third_lerp_b, cell_interpolated_position.w);
66+
}
67+
} // namespace noiz::detail

0 commit comments

Comments
 (0)