SDL로 망델브로 집합 그려보기 시리즈
- 1편 – SDL 설치와 망델브로 집합
- 2편 – FPS 제한과 키보드, 마우스 입력
- 3편 – 윈도우 리사이징과 GUI
- 4편 – 스크린샷기능, 비동기 렌더링과 OneTBB 멀티스레드 렌더링
- 5편 – 최적화와 GUI개선
- 6편 – 스레드 선택 기능과 컬러맵 입히기
- 7편 – CUDA 및 멀티 샘플링
6-1. 스레드 개수 선택 기능 추가
tbb::task_arena는 명시적인 사용자 관리 작업 스케줄러 영역을 나타내는 클래스입니다. 간단히 말하면 task_arena를 통해 실행시킨 코드의 스레드 수를 명시적으로 설정할 수 있습니다. 그리고 TBB에선 이 스레드 수를 concurrency라고 부릅니다. std::async() 함수를 사용하지 않고 tbb::task_arena를 사용하기 위해 먼저 mandelbrot_tbb.h를 수정합니다.
#pragma once
#include <oneapi/tbb/task_arena.h>
#include "mandelbrot.h"
class MandelbrotTBB : public Mandelbrot
{
public:
using real_t = Mandelbrot::real_t;
MandelbrotTBB(SDL_Renderer* renderer);
~MandelbrotTBB() override;
uint32_t getMaxConcurrency() const;
void setMaxConcurrency(uint32_t val);
private:
void startAsync() override;
void drawSurface() override;
oneapi::tbb::task_arena arena;
};
4-2. 비동기 렌더링 기능 추가에서 std::async() 함수와 std::future 클래스를 알아봤었습니다. 이번에 소개할 std::promise 클래스는 std::future를 std::async() 없이 사용하도록 해줍니다. std::promise의 인스턴스를 하나 만들고 std::promise::get_future() 메서드를 호출하면 연결된 std::future를 얻을 수 있습니다. 아래 43번 줄과 같이 std::promise::set_value() 메서드를 호출하면 std::future::wait()로 블록된 상태를 풀 수 있습니다. 이 튜토리얼에선 템플릿 인자로 void를 넘겨줬지만, 원하는 데이터 타입을 명시하면 set_value() 메서드를 통해 리턴값의 개념으로 그 데이터를 future로 넘길 수 있습니다.
다만 std::promise를 넘겨줄 때 아래와 같은 상황에선 변수 p가 startAsync() 메서드를 벗어나면서 파괴되기 때문에 이동 문법으로 람다에 넘겨줘야 합니다. 람다를 mutable로 선언해서 43번 줄 같은 번거로운 상황을 막을 수 있지만, task_arena의 enqueue() 메서드가 const한 callable 만을 허용하기 때문에 캡쳐된 변수 p의 const 성질을 없애기 위해 const_cast<>()를 사용해야만 합니다. 람다는 캡쳐된 변수 별 mutable 키워드를 허용하지 않기 때문에 캐스팅으로 해결합니다.
MandelbrotTBB::MandelbrotTBB(SDL_Renderer* renderer)
: Mandelbrot(renderer)
{
arena.initialize();
}
MandelbrotTBB::~MandelbrotTBB()
{
arena.terminate();
}
uint32_t MandelbrotTBB::getMaxConcurrency() const
{
return arena.max_concurrency();
}
void MandelbrotTBB::setMaxConcurrency(uint32_t val)
{
stop();
arena.terminate();
arena.initialize(val);
update(false, false);
}
void MandelbrotTBB::startAsync() {
promise<void> p;
future = p.get_future();
arena.enqueue([this, p = std::move(p)]() {
is_rendering = true;
drawSurface();
is_rendering = false;
const_cast<promise<void>&>(p).set_value();
});
}
GUI 클래스의 update() 메소드에 UI 코드가 많아지면서 점점 덩치가 커지고 있기 때문에 show*() 메서드 들로 쪼갭니다. 쪼개는 김에 ImGui::TreeNode()를 ImGui::CollapsingHeader()로 바꾸겠습니다. ImGui::TreePop()을 전부 없애주셔야 합니다.
private:
void acceleratorChanged(std::unique_ptr<Mandelbrot>& mandelbrot);
void showBasicUI(std::unique_ptr<Mandelbrot>& mandelbrot);
void showMoreSettingsUI(std::unique_ptr<Mandelbrot>& mandelbrot);
void showAcceleratorUI(std::unique_ptr<Mandelbrot>& mandelbrot);
void showScreenshotUI(std::unique_ptr<Mandelbrot>& mandelbrot);
void showErrorMessage();
void GUI::update(std::unique_ptr<Mandelbrot>& mandelbrot)
{
ImGui_ImplSDLRenderer_NewFrame();
ImGui_ImplSDL2_NewFrame(window);
ImGui::NewFrame();
ImGui::Begin("control", nullptr, ImGuiWindowFlags_NoResize);
showBasicUI(mandelbrot);
showAcceleratorUI(mandelbrot);
showMoreSettingsUI(mandelbrot);
showScreenshotUI(mandelbrot);
ImGui::SetWindowSize({ 260, ImGui::GetContentRegionAvail().y });
showErrorMessage();
ImGui::End();
}
...
void GUI::showBasicUI(std::unique_ptr<Mandelbrot>& mandelbrot)
{
stringstream ss;
int px, py, width, height;
SDL_GetMouseState(&px, &py);
SDL_GetWindowSize(window, &width, &height);
ss << "resolution: " << width << "X" << height << "\n";
ss << "mouse : (" << px << ", " << py << ")\n";
ss << "fps : " << round(Time::fps * 10) / 10;
ss << "(" << round(10000. * Time::dt) / 10. << "ms)\n";
ss << "cursor: " << mandelbrot->pixelToComplex(px, py) << "\n";
ss << "pos : " << mandelbrot->getPosition() << "\n";
ss << "scale : " << mandelbrot->getScale() << "\n";
ss << "iter : " << mandelbrot->getIteration() << "\n";
ImGui::Text(ss.str().c_str());
if (mandelbrot->isRendering())
ImGui::TextColored(ImColor(255, 0, 0), "rendering...");
else ImGui::TextColored(ImColor(0, 255, 0), "rendered");
if (ImGui::Button("reset parameters")) {
mandelbrot->setPosition(0., 0.);
mandelbrot->setScale(1.);
mandelbrot->setIteration(32);
}
}
void GUI::showMoreSettingsUI(std::unique_ptr<Mandelbrot>& mandelbrot)
{
if (ImGui::CollapsingHeader("more settings...")) {
ImGui::Text("move speed (pixel/s) :");
ImGui::SliderFloat(IMGUI_NO_LABEL, &settings.move_speed, 200.f, 600.f);
ImGui::Text("scroll scale :");
ImGui::SliderFloat(IMGUI_NO_LABEL, &settings.scroll_scale, 1.1f, 10.f, "%f", 32);
ImGui::Checkbox("render async", &settings.render_async);
ImGui::Checkbox("scale to cursor", &settings.scaleToCursor);
ImGui::Checkbox("auto iter", &settings.auto_iter);
if (settings.auto_iter) {
ImGui::Text("initial iteration:");
ImGui::InputInt(IMGUI_NO_LABEL, &settings.initial_iter);
}
}
if (settings.auto_iter) {
auto iter = mandelbrot->getIteration();
auto mag = 1. / mandelbrot->getScale();
int new_iter = settings.initial_iter * (log(mag + 1) - log(2) + 1.);
if (iter != new_iter) mandelbrot->setIteration(new_iter);
}
}
void GUI::showAcceleratorUI(std::unique_ptr<Mandelbrot>& mandelbrot)
{
if (ImGui::CollapsingHeader("accelerator")) {
static const char* items[] = { "CPU", "CPU - TBB" };
ImGui::Text("accelerator :");
if (ImGui::Combo(IMGUI_NO_LABEL, (int*)&settings.accelerator, items, 2))
acceleratorChanged(mandelbrot);
if (settings.accelerator == Acc::CPU_TBB) {
auto* man_tbb = dynamic_cast<MandelbrotTBB*>(mandelbrot.get()); // will not fail
auto value = (int)man_tbb->getMaxConcurrency();
ImGui::Text("max concurrency:");
if (ImGui::InputInt(IMGUI_NO_LABEL, &value, 1)) {
value = SDL_clamp(value, 1, thread::hardware_concurrency());
man_tbb->setMaxConcurrency(value);
}
}
}
}
void GUI::showScreenshotUI(std::unique_ptr<Mandelbrot>& mandelbrot)
{
int width, height;
SDL_GetWindowSize(window, &width, &height);
if (ImGui::CollapsingHeader("screenshot")) {
ImGui::Text("directory :");
ImGui::InputText(IMGUI_NO_LABEL, settings.capture_dir, 255);
ImGui::Checkbox("no UI", &settings.capture_no_ui);
if (ImGui::Button("capture")) {
if (settings.capture_no_ui) {
saveCapture(mandelbrot->getSurface());
} else {
SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);
auto* format = (uint32_t*)(surface->format);
SDL_RenderReadPixels(renderer, 0, *format, surface->pixels, width * 4);
saveCapture(surface);
SDL_FreeSurface(surface);
}
}
}
}
void GUI::showErrorMessage()
{
if (clock() - msg_timepoint < 3000) {
auto* drawlist = ImGui::GetForegroundDrawList();
auto position = ImGui::GetWindowPos();
ImColor color = { 255, 0, 0 };
position.y += ImGui::GetWindowHeight();
drawlist->AddText(position, color, message.c_str());
}
}
이제 렌더링 시 사용할 스레드 수를 선택할 수 있습니다. 스레드가 너무 많으면 오히려 이미지를 움직이거나 할 때 반응성이 낮아져서 버벅거리는 현상이 있습니다. 8코어 16스레드 기준으로 4스레드를 사용하는것이 가장 반응성이 좋았습니다.

6-2. 다양한 색상 입히기
지금껏 만들어온 이미지는 밋밋한 그레이 스케일이었습니다. 이제 컬러맵을 입혀보고 반복횟수에 따라 생긴 불연속적인 선들을 없애보겠습니다. 물론 색상을 입히는 알고리즘은 정해진 것이 없습니다. 이번 절을 따라해보고 추후에 본인만의 알고리즘으로 색을 입혀보는 것도 좋을 것 같습니다.
6-2-1. 컬러맵 입히기
mandelbrot.h에 있는 make_color() 함수를 새로 color.h 파일을 만들고 옮겨줍니다. 파일에 미리 제가 몇몇 컬러맵의 데이터를 생성해서 argb포맷으로 만들어 놓았습니다. 두 색상을 섞기 위해서 lerp_color() 함수도 미리 만들어 줍니다. 파일에 있는 컬러맵은 아래와 같이 6개 입니다. 색상이 끊겨 보이지 않도록 하기 위해 앞 뒤로 이어붙였을 때 자연스럽게 연결되도록 만들어야 합니다(ultra 빼고 모두 좌우대칭).






#pragma once
#include <stdint.h>
inline uint32_t make_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 0xff) {
return (a << 24) + (r << 16) + (g << 8) + b;
}
inline uint32_t lerp_color(uint32_t a, uint32_t b, double t) {
struct Color { uint8_t b, g, r, a; } result;
result.a = t * ((Color*)&a)->a + (1. - t) * ((Color*)&a)->a;
result.r = t * ((Color*)&a)->r + (1. - t) * ((Color*)&a)->r;
result.g = t * ((Color*)&a)->g + (1. - t) * ((Color*)&a)->g;
result.b = t * ((Color*)&a)->b + (1. - t) * ((Color*)&a)->b;
return *(uint32_t*)&result;
}
static uint32_t colormap[][256] = {
{ // gray
0xff000000, 0xff030303, 0xff070707, 0xff0b0b0b, 0xff0f0f0f, 0xff131313, 0xff171717, 0xff1b1b1b,
0xff1f1f1f, 0xff222222, 0xff262626, 0xff2a2a2a, 0xff2d2d2d, 0xff313131, 0xff353535, 0xff383838,
0xff3c3c3c, 0xff3f3f3f, 0xff434343, 0xff464646, 0xff4a4a4a, 0xff4d4d4d, 0xff505050, 0xff545454,
0xff575757, 0xff5a5a5a, 0xff5d5d5d, 0xff606060, 0xff646464, 0xff676767, 0xff6a6a6a, 0xff6d6d6d,
0xff707070, 0xff737373, 0xff767676, 0xff797979, 0xff7c7c7c, 0xff7f7f7f, 0xff818181, 0xff848484,
0xff878787, 0xff8a8a8a, 0xff8c8c8c, 0xff8f8f8f, 0xff929292, 0xff949494, 0xff979797, 0xff999999,
0xff9c9c9c, 0xff9e9e9e, 0xffa1a1a1, 0xffa3a3a3, 0xffa6a6a6, 0xffa8a8a8, 0xffaaaaaa, 0xffadadad,
0xffafafaf, 0xffb1b1b1, 0xffb3b3b3, 0xffb6b6b6, 0xffb8b8b8, 0xffbababa, 0xffbcbcbc, 0xffbebebe,
0xffc0c0c0, 0xffc2c2c2, 0xffc4c4c4, 0xffc6c6c6, 0xffc8c8c8, 0xffcacaca, 0xffcbcbcb, 0xffcdcdcd,
0xffcfcfcf, 0xffd1d1d1, 0xffd2d2d2, 0xffd4d4d4, 0xffd6d6d6, 0xffd7d7d7, 0xffd9d9d9, 0xffdadada,
0xffdcdcdc, 0xffdddddd, 0xffdfdfdf, 0xffe0e0e0, 0xffe2e2e2, 0xffe3e3e3, 0xffe4e4e4, 0xffe6e6e6,
0xffe7e7e7, 0xffe8e8e8, 0xffe9e9e9, 0xffebebeb, 0xffececec, 0xffededed, 0xffeeeeee, 0xffefefef,
0xfff0f0f0, 0xfff1f1f1, 0xfff2f2f2, 0xfff3f3f3, 0xfff4f4f4, 0xfff4f4f4, 0xfff5f5f5, 0xfff6f6f6,
0xfff7f7f7, 0xfff8f8f8, 0xfff8f8f8, 0xfff9f9f9, 0xfffafafa, 0xfffafafa, 0xfffbfbfb, 0xfffbfbfb,
0xfffcfcfc, 0xfffcfcfc, 0xfffdfdfd, 0xfffdfdfd, 0xfffdfdfd, 0xfffefefe, 0xfffefefe, 0xfffefefe,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xfffefefe, 0xfffefefe, 0xfffefefe, 0xfffdfdfd, 0xfffdfdfd, 0xfffdfdfd, 0xfffcfcfc, 0xfffcfcfc,
0xfffbfbfb, 0xfffbfbfb, 0xfffafafa, 0xfffafafa, 0xfff9f9f9, 0xfff8f8f8, 0xfff8f8f8, 0xfff7f7f7,
0xfff6f6f6, 0xfff5f5f5, 0xfff4f4f4, 0xfff4f4f4, 0xfff3f3f3, 0xfff2f2f2, 0xfff1f1f1, 0xfff0f0f0,
0xffefefef, 0xffeeeeee, 0xffededed, 0xffececec, 0xffebebeb, 0xffe9e9e9, 0xffe8e8e8, 0xffe7e7e7,
0xffe6e6e6, 0xffe4e4e4, 0xffe3e3e3, 0xffe2e2e2, 0xffe0e0e0, 0xffdfdfdf, 0xffdddddd, 0xffdcdcdc,
0xffdadada, 0xffd9d9d9, 0xffd7d7d7, 0xffd6d6d6, 0xffd4d4d4, 0xffd2d2d2, 0xffd1d1d1, 0xffcfcfcf,
0xffcdcdcd, 0xffcbcbcb, 0xffcacaca, 0xffc8c8c8, 0xffc6c6c6, 0xffc4c4c4, 0xffc2c2c2, 0xffc0c0c0,
0xffbebebe, 0xffbcbcbc, 0xffbababa, 0xffb8b8b8, 0xffb6b6b6, 0xffb3b3b3, 0xffb1b1b1, 0xffafafaf,
0xffadadad, 0xffaaaaaa, 0xffa8a8a8, 0xffa6a6a6, 0xffa3a3a3, 0xffa1a1a1, 0xff9e9e9e, 0xff9c9c9c,
0xff999999, 0xff979797, 0xff949494, 0xff929292, 0xff8f8f8f, 0xff8c8c8c, 0xff8a8a8a, 0xff878787,
0xff848484, 0xff818181, 0xff7f7f7f, 0xff7c7c7c, 0xff797979, 0xff767676, 0xff737373, 0xff707070,
0xff6d6d6d, 0xff6a6a6a, 0xff676767, 0xff646464, 0xff606060, 0xff5d5d5d, 0xff5a5a5a, 0xff575757,
0xff545454, 0xff505050, 0xff4d4d4d, 0xff4a4a4a, 0xff464646, 0xff434343, 0xff3f3f3f, 0xff3c3c3c,
0xff383838, 0xff353535, 0xff313131, 0xff2d2d2d, 0xff2a2a2a, 0xff262626, 0xff222222, 0xff1f1f1f,
0xff1b1b1b, 0xff171717, 0xff131313, 0xff0f0f0f, 0xff0b0b0b, 0xff070707, 0xff030303, 0xff000000,
},
{ // ultra
0xff000764, 0xff000966, 0xff010b69, 0xff020e6b, 0xff02106e, 0xff031371, 0xff031573, 0xff041876,
0xff041a79, 0xff051d7c, 0xff051f7e, 0xff062281, 0xff062484, 0xff062787, 0xff07298a, 0xff072c8c,
0xff082e8f, 0xff083192, 0xff083395, 0xff093698, 0xff09389a, 0xff0a3b9d, 0xff0a3da0, 0xff0b3fa2,
0xff0c42a5, 0xff0c44a8, 0xff0d47aa, 0xff0e49ad, 0xff0f4caf, 0xff0f4eb2, 0xff1051b4, 0xff1153b7,
0xff1256b9, 0xff1358bb, 0xff155abd, 0xff165dc0, 0xff175fc2, 0xff1962c4, 0xff1b64c6, 0xff1c66c7,
0xff1e69c9, 0xff206bcb, 0xff226dcd, 0xff2470ce, 0xff2672d0, 0xff2975d2, 0xff2b77d3, 0xff2e7ad5,
0xff307cd7, 0xff337fd9, 0xff3682db, 0xff3885dc, 0xff3b87de, 0xff3e8ae0, 0xff418de2, 0xff4590e4,
0xff4892e5, 0xff4b95e7, 0xff4e98e9, 0xff529beb, 0xff559eec, 0xff59a1ee, 0xff5ca3f0, 0xff60a6f2,
0xff63a9f3, 0xff67acf5, 0xff6aaff6, 0xff6eb2f8, 0xff72b5f9, 0xff76b7fb, 0xff79bafc, 0xff7dbdfe,
0xff81c0ff, 0xff84c2ff, 0xff88c5ff, 0xff8cc8ff, 0xff90caff, 0xff93cdff, 0xff97cfff, 0xff9bd2ff,
0xff9ed4ff, 0xffa2d7ff, 0xffa6d9ff, 0xffa9dcff, 0xffaddeff, 0xffb0e0ff, 0xffb4e2ff, 0xffb7e4ff,
0xffbae6ff, 0xffbee8ff, 0xffc1eaff, 0xffc4ecff, 0xffc7eeff, 0xffcaf0ff, 0xffcdf1ff, 0xffd0f3ff,
0xffd3f4ff, 0xffd6f6ff, 0xffd9f7ff, 0xffdbf8ff, 0xffdef9ff, 0xffe0faff, 0xffe2fbff, 0xffe5fcff,
0xffe7fdff, 0xffe9fdff, 0xffebfeff, 0xffecfeff, 0xffeefffd, 0xfff0fffb, 0xfff1fff8, 0xfff3fff5,
0xfff5fff2, 0xfff6ffef, 0xfff8ffec, 0xfff9fee8, 0xfffbfee5, 0xfffdfde1, 0xfffefddc, 0xfffffcd8,
0xfffffbd4, 0xfffffacf, 0xfffffaca, 0xfffff9c6, 0xfffff7c1, 0xfffff6bc, 0xfffff5b6, 0xfffff4b1,
0xfffff3ac, 0xfffff1a6, 0xfffff0a1, 0xffffee9b, 0xffffed96, 0xffffeb90, 0xffffe98a, 0xffffe884,
0xffffe67f, 0xffffe479, 0xffffe273, 0xffffe06e, 0xffffde68, 0xffffdc62, 0xffffda5d, 0xffffd857,
0xffffd652, 0xffffd44c, 0xffffd247, 0xffffd042, 0xffffce3d, 0xffffcb38, 0xffffc933, 0xffffc72e,
0xffffc529, 0xffffc225, 0xffffc020, 0xffffbe1c, 0xffffbc18, 0xffffb914, 0xffffb711, 0xffffb50d,
0xffffb20a, 0xffffb007, 0xffffae04, 0xffffab01, 0xfffea900, 0xfffca700, 0xfff9a400, 0xfff6a200,
0xfff39f00, 0xfff09c00, 0xffec9900, 0xffe99600, 0xffe59300, 0xffe19000, 0xffdc8d00, 0xffd88a00,
0xffd38700, 0xffcf8300, 0xffca8000, 0xffc57c00, 0xffbf7900, 0xffba7500, 0xffb57200, 0xffaf6e00,
0xffaa6b00, 0xffa46700, 0xff9f6300, 0xff996000, 0xff935c00, 0xff8d5800, 0xff875400, 0xff825100,
0xff7c4d00, 0xff764a00, 0xff704600, 0xff6a4200, 0xff643f00, 0xff5f3b00, 0xff593800, 0xff533400,
0xff4e3100, 0xff482e00, 0xff432a00, 0xff3e2700, 0xff392400, 0xff332100, 0xff2f1e00, 0xff2a1b00,
0xff251800, 0xff211600, 0xff1c1300, 0xff181100, 0xff140e00, 0xff110c00, 0xff0d0a00, 0xff0a0800,
0xff070600, 0xff040400, 0xff010300, 0xff000100, 0xff000001, 0xff000003, 0xff000005, 0xff000007,
0xff000009, 0xff00000b, 0xff00000d, 0xff000010, 0xff000012, 0xff000015, 0xff000017, 0xff00001a,
0xff00001d, 0xff000020, 0xff000023, 0xff000026, 0xff000029, 0xff00002c, 0xff00002f, 0xff000032,
0xff000035, 0xff000038, 0xff00003c, 0xff00013f, 0xff000142, 0xff000245, 0xff000348, 0xff00034c,
0xff00044f, 0xff000452, 0xff000555, 0xff000558, 0xff00065b, 0xff00065e, 0xff000661, 0xff000764,
},
{ // viridis
0xff47004d, 0xff470252, 0xff470556, 0xff47085b, 0xff470b5f, 0xff460e62, 0xff461166, 0xff461469,
0xff46176c, 0xff461a6f, 0xff461d71, 0xff461f74, 0xff462276, 0xff462578, 0xff46277a, 0xff462a7b,
0xff462c7d, 0xff452f7e, 0xff45317f, 0xff453480, 0xff443682, 0xff443982, 0xff443b83, 0xff433d84,
0xff434085, 0xff424286, 0xff414486, 0xff414687, 0xff404987, 0xff3f4b88, 0xff3e4d88, 0xff3d4f89,
0xff3d5189, 0xff3c538a, 0xff3b568a, 0xff3a588a, 0xff395a8b, 0xff375c8b, 0xff365e8b, 0xff35608c,
0xff34628c, 0xff33648c, 0xff32668d, 0xff31688d, 0xff2f6a8d, 0xff2e6c8d, 0xff2d6e8e, 0xff2c708e,
0xff2b728e, 0xff2a748e, 0xff28768e, 0xff27788f, 0xff267a8f, 0xff257c8f, 0xff247e8f, 0xff23808f,
0xff23828f, 0xff22848f, 0xff21868f, 0xff20888f, 0xff20898f, 0xff1f8b8f, 0xff1f8d8f, 0xff1f8f8e,
0xff1e918e, 0xff1e938e, 0xff1e958d, 0xff1e978d, 0xff1f998c, 0xff1f9b8c, 0xff1f9c8b, 0xff209e8a,
0xff21a08a, 0xff21a289, 0xff22a488, 0xff23a687, 0xff25a786, 0xff26a985, 0xff27ab83, 0xff29ad82,
0xff2baf81, 0xff2db07f, 0xff2fb27d, 0xff31b47c, 0xff34b67a, 0xff36b778, 0xff39b976, 0xff3cbb74,
0xff3fbc72, 0xff42be70, 0xff46c06e, 0xff49c16c, 0xff4dc369, 0xff51c567, 0xff55c664, 0xff59c861,
0xff5dc95f, 0xff61cb5c, 0xff66cc59, 0xff6ace56, 0xff6fcf54, 0xff74d051, 0xff79d24e, 0xff7ed34b,
0xff83d448, 0xff88d545, 0xff8ed742, 0xff93d83f, 0xff99d93c, 0xff9eda39, 0xffa4db36, 0xffa9dc33,
0xffafdd31, 0xffb4de2e, 0xffbadf2b, 0xffbfe029, 0xffc5e126, 0xffcae124, 0xffd0e222, 0xffd5e320,
0xffdae31e, 0xffdfe41d, 0xffe4e41c, 0xffe9e51b, 0xffeee51a, 0xfff2e519, 0xfff6e619, 0xfffae619,
0xfffae619, 0xfff6e619, 0xfff2e519, 0xffeee51a, 0xffe9e51b, 0xffe4e41c, 0xffdfe41d, 0xffdae31e,
0xffd5e320, 0xffd0e222, 0xffcae124, 0xffc5e126, 0xffbfe029, 0xffbadf2b, 0xffb4de2e, 0xffafdd31,
0xffa9dc33, 0xffa4db36, 0xff9eda39, 0xff99d93c, 0xff93d83f, 0xff8ed742, 0xff88d545, 0xff83d448,
0xff7ed34b, 0xff79d24e, 0xff74d051, 0xff6fcf54, 0xff6ace56, 0xff66cc59, 0xff61cb5c, 0xff5dc95f,
0xff59c861, 0xff55c664, 0xff51c567, 0xff4dc369, 0xff49c16c, 0xff46c06e, 0xff42be70, 0xff3fbc72,
0xff3cbb74, 0xff39b976, 0xff36b778, 0xff34b67a, 0xff31b47c, 0xff2fb27d, 0xff2db07f, 0xff2baf81,
0xff29ad82, 0xff27ab83, 0xff26a985, 0xff25a786, 0xff23a687, 0xff22a488, 0xff21a289, 0xff21a08a,
0xff209e8a, 0xff1f9c8b, 0xff1f9b8c, 0xff1f998c, 0xff1e978d, 0xff1e958d, 0xff1e938e, 0xff1e918e,
0xff1f8f8e, 0xff1f8d8f, 0xff1f8b8f, 0xff20898f, 0xff20888f, 0xff21868f, 0xff22848f, 0xff23828f,
0xff23808f, 0xff247e8f, 0xff257c8f, 0xff267a8f, 0xff27788f, 0xff28768e, 0xff2a748e, 0xff2b728e,
0xff2c708e, 0xff2d6e8e, 0xff2e6c8d, 0xff2f6a8d, 0xff31688d, 0xff32668d, 0xff33648c, 0xff34628c,
0xff35608c, 0xff365e8b, 0xff375c8b, 0xff395a8b, 0xff3a588a, 0xff3b568a, 0xff3c538a, 0xff3d5189,
0xff3d4f89, 0xff3e4d88, 0xff3f4b88, 0xff404987, 0xff414687, 0xff414486, 0xff424286, 0xff434085,
0xff433d84, 0xff443b83, 0xff443982, 0xff443682, 0xff453480, 0xff45317f, 0xff452f7e, 0xff462c7d,
0xff462a7b, 0xff46277a, 0xff462578, 0xff462276, 0xff461f74, 0xff461d71, 0xff461a6f, 0xff46176c,
0xff461469, 0xff461166, 0xff460e62, 0xff470b5f, 0xff47085b, 0xff470556, 0xff470252, 0xff47004d,
},
{ // magma
0xff000200, 0xff000302, 0xff000307, 0xff00040b, 0xff020410, 0xff050515, 0xff07051a, 0xff09061e,
0xff0b0623, 0xff0e0728, 0xff10082c, 0xff120831, 0xff150936, 0xff170a3a, 0xff1a0a3f, 0xff1c0b43,
0xff1f0c47, 0xff210c4b, 0xff240d4f, 0xff260e53, 0xff290f57, 0xff2c0f5b, 0xff2f105e, 0xff311162,
0xff341165, 0xff371268, 0xff3a136b, 0xff3d146e, 0xff401471, 0xff431573, 0xff461675, 0xff4a1678,
0xff4d177a, 0xff50187b, 0xff53187d, 0xff57197f, 0xff5a1a80, 0xff5d1a81, 0xff611b82, 0xff641c83,
0xff671c84, 0xff6b1d85, 0xff6e1e85, 0xff721f86, 0xff751f86, 0xff792086, 0xff7c2186, 0xff802286,
0xff832386, 0xff872485, 0xff8a2485, 0xff8e2584, 0xff912683, 0xff952783, 0xff982882, 0xff9c2981,
0xff9f2a80, 0xffa32c7f, 0xffa62d7e, 0xffa92e7c, 0xffad2f7b, 0xffb0317a, 0xffb33279, 0xffb63377,
0xffba3576, 0xffbd3675, 0xffc03873, 0xffc33a72, 0xffc63b70, 0xffc93d6f, 0xffcc3f6e, 0xffce416c,
0xffd1436b, 0xffd4456a, 0xffd64769, 0xffd94967, 0xffdb4b66, 0xffde4e65, 0xffe05064, 0xffe25363,
0xffe55562, 0xffe75862, 0xffe95a61, 0xffeb5d60, 0xffed6060, 0xffee6360, 0xfff0665f, 0xfff2695f,
0xfff36c5f, 0xfff56f5f, 0xfff67260, 0xfff77660, 0xfff87960, 0xfff97c61, 0xfffa8062, 0xfffb8363,
0xfffc8764, 0xfffd8b65, 0xfffe8e66, 0xfffe9268, 0xffff9669, 0xffff9a6b, 0xffff9e6d, 0xffffa26f,
0xffffa671, 0xffffaa73, 0xffffae76, 0xffffb278, 0xffffb67b, 0xffffba7e, 0xffffbe81, 0xffffc284,
0xffffc687, 0xffffca8b, 0xffffcd8e, 0xffffd191, 0xffffd595, 0xfffed999, 0xfffedd9c, 0xfffee0a0,
0xfffde4a4, 0xfffde8a8, 0xfffdebac, 0xfffceeb0, 0xfffcf2b4, 0xfffcf5b8, 0xfffcf8bc, 0xfffcfac0,
0xfffcfac0, 0xfffcf8bc, 0xfffcf5b8, 0xfffcf2b4, 0xfffceeb0, 0xfffdebac, 0xfffde8a8, 0xfffde4a4,
0xfffee0a0, 0xfffedd9c, 0xfffed999, 0xffffd595, 0xffffd191, 0xffffcd8e, 0xffffca8b, 0xffffc687,
0xffffc284, 0xffffbe81, 0xffffba7e, 0xffffb67b, 0xffffb278, 0xffffae76, 0xffffaa73, 0xffffa671,
0xffffa26f, 0xffff9e6d, 0xffff9a6b, 0xffff9669, 0xfffe9268, 0xfffe8e66, 0xfffd8b65, 0xfffc8764,
0xfffb8363, 0xfffa8062, 0xfff97c61, 0xfff87960, 0xfff77660, 0xfff67260, 0xfff56f5f, 0xfff36c5f,
0xfff2695f, 0xfff0665f, 0xffee6360, 0xffed6060, 0xffeb5d60, 0xffe95a61, 0xffe75862, 0xffe55562,
0xffe25363, 0xffe05064, 0xffde4e65, 0xffdb4b66, 0xffd94967, 0xffd64769, 0xffd4456a, 0xffd1436b,
0xffce416c, 0xffcc3f6e, 0xffc93d6f, 0xffc63b70, 0xffc33a72, 0xffc03873, 0xffbd3675, 0xffba3576,
0xffb63377, 0xffb33279, 0xffb0317a, 0xffad2f7b, 0xffa92e7c, 0xffa62d7e, 0xffa32c7f, 0xff9f2a80,
0xff9c2981, 0xff982882, 0xff952783, 0xff912683, 0xff8e2584, 0xff8a2485, 0xff872485, 0xff832386,
0xff802286, 0xff7c2186, 0xff792086, 0xff751f86, 0xff721f86, 0xff6e1e85, 0xff6b1d85, 0xff671c84,
0xff641c83, 0xff611b82, 0xff5d1a81, 0xff5a1a80, 0xff57197f, 0xff53187d, 0xff50187b, 0xff4d177a,
0xff4a1678, 0xff461675, 0xff431573, 0xff401471, 0xff3d146e, 0xff3a136b, 0xff371268, 0xff341165,
0xff311162, 0xff2f105e, 0xff2c0f5b, 0xff290f57, 0xff260e53, 0xff240d4f, 0xff210c4b, 0xff1f0c47,
0xff1c0b43, 0xff1a0a3f, 0xff170a3a, 0xff150936, 0xff120831, 0xff10082c, 0xff0e0728, 0xff0b0623,
0xff09061e, 0xff07051a, 0xff050515, 0xff020410, 0xff00040b, 0xff000307, 0xff000302, 0xff000200,
},
{ // inferno
0xff000300, 0xff000301, 0xff000307, 0xff00030c, 0xff020412, 0xff050418, 0xff07041d, 0xff0a0422,
0xff0d0527, 0xff0f052c, 0xff120530, 0xff150635, 0xff170639, 0xff1a073d, 0xff1d0741, 0xff200845,
0xff220848, 0xff25094c, 0xff28094f, 0xff2b0a52, 0xff2e0a55, 0xff310b58, 0xff340b5b, 0xff370c5d,
0xff3a0d5f, 0xff3d0d62, 0xff410e64, 0xff440f66, 0xff470f67, 0xff4a1069, 0xff4d116a, 0xff51116c,
0xff54126d, 0xff57136e, 0xff5b136f, 0xff5e1470, 0xff611570, 0xff651671, 0xff681771, 0xff6c1771,
0xff6f1871, 0xff721971, 0xff761a71, 0xff791b71, 0xff7d1c70, 0xff801d70, 0xff831e6f, 0xff871f6e,
0xff8a206e, 0xff8e216d, 0xff91226c, 0xff94236a, 0xff982569, 0xff9b2668, 0xff9e2766, 0xffa22965,
0xffa52a63, 0xffa82b61, 0xffab2d5f, 0xffae2e5d, 0xffb1305b, 0xffb53259, 0xffb83357, 0xffbb3555,
0xffbd3753, 0xffc03851, 0xffc33a4e, 0xffc63c4c, 0xffc93e49, 0xffcb4047, 0xffce4244, 0xffd04542,
0xffd3473f, 0xffd5493d, 0xffd84c3a, 0xffda4e38, 0xffdc5035, 0xffde5333, 0xffe05630, 0xffe2582e,
0xffe45b2c, 0xffe65e29, 0xffe86127, 0xffea6425, 0xffeb6623, 0xffed6a20, 0xffee6d1e, 0xfff0701d,
0xfff1731b, 0xfff27619, 0xfff37a18, 0xfff47d16, 0xfff58015, 0xfff68414, 0xfff78713, 0xfff88b12,
0xfff88f12, 0xfff99212, 0xfffa9611, 0xfffa9a12, 0xfffa9e12, 0xfffba113, 0xfffba514, 0xfffba915,
0xfffbad16, 0xfffbb118, 0xfffbb51a, 0xfffbb91d, 0xfffbbd20, 0xfffbc123, 0xfffac527, 0xfffac82b,
0xfffacc2f, 0xfff9d034, 0xfff9d439, 0xfff9d83f, 0xfff8dc46, 0xfff8df4d, 0xfff7e354, 0xfff7e75c,
0xfff6ea64, 0xfff6ee6e, 0xfff5f177, 0xfff5f482, 0xfff4f88d, 0xfff4fb98, 0xfff3fea5, 0xfff3ffb2,
0xfff3ffb2, 0xfff3fea5, 0xfff4fb98, 0xfff4f88d, 0xfff5f482, 0xfff5f177, 0xfff6ee6e, 0xfff6ea64,
0xfff7e75c, 0xfff7e354, 0xfff8df4d, 0xfff8dc46, 0xfff9d83f, 0xfff9d439, 0xfff9d034, 0xfffacc2f,
0xfffac82b, 0xfffac527, 0xfffbc123, 0xfffbbd20, 0xfffbb91d, 0xfffbb51a, 0xfffbb118, 0xfffbad16,
0xfffba915, 0xfffba514, 0xfffba113, 0xfffa9e12, 0xfffa9a12, 0xfffa9611, 0xfff99212, 0xfff88f12,
0xfff88b12, 0xfff78713, 0xfff68414, 0xfff58015, 0xfff47d16, 0xfff37a18, 0xfff27619, 0xfff1731b,
0xfff0701d, 0xffee6d1e, 0xffed6a20, 0xffeb6623, 0xffea6425, 0xffe86127, 0xffe65e29, 0xffe45b2c,
0xffe2582e, 0xffe05630, 0xffde5333, 0xffdc5035, 0xffda4e38, 0xffd84c3a, 0xffd5493d, 0xffd3473f,
0xffd04542, 0xffce4244, 0xffcb4047, 0xffc93e49, 0xffc63c4c, 0xffc33a4e, 0xffc03851, 0xffbd3753,
0xffbb3555, 0xffb83357, 0xffb53259, 0xffb1305b, 0xffae2e5d, 0xffab2d5f, 0xffa82b61, 0xffa52a63,
0xffa22965, 0xff9e2766, 0xff9b2668, 0xff982569, 0xff94236a, 0xff91226c, 0xff8e216d, 0xff8a206e,
0xff871f6e, 0xff831e6f, 0xff801d70, 0xff7d1c70, 0xff791b71, 0xff761a71, 0xff721971, 0xff6f1871,
0xff6c1771, 0xff681771, 0xff651671, 0xff611570, 0xff5e1470, 0xff5b136f, 0xff57136e, 0xff54126d,
0xff51116c, 0xff4d116a, 0xff4a1069, 0xff470f67, 0xff440f66, 0xff410e64, 0xff3d0d62, 0xff3a0d5f,
0xff370c5d, 0xff340b5b, 0xff310b58, 0xff2e0a55, 0xff2b0a52, 0xff28094f, 0xff25094c, 0xff220848,
0xff200845, 0xff1d0741, 0xff1a073d, 0xff170639, 0xff150635, 0xff120530, 0xff0f052c, 0xff0d0527,
0xff0a0422, 0xff07041d, 0xff050418, 0xff020412, 0xff00030c, 0xff000307, 0xff000301, 0xff000300,
},
{ // turbo
0xff22171b, 0xff2b1b33, 0xff32204a, 0xff38255f, 0xff3e2a72, 0xff422f84, 0xff453494, 0xff4739a2,
0xff493eaf, 0xff4a43bb, 0xff4b49c6, 0xff4b4ecf, 0xff4a54d8, 0xff4959df, 0xff485fe5, 0xff4664eb,
0xff446aef, 0xff4270f3, 0xff4075f5, 0xff3e7bf7, 0xff3b80f9, 0xff3986f9, 0xff368bf9, 0xff3491f9,
0xff3296f8, 0xff309bf6, 0xff2ea0f4, 0xff2ca5f2, 0xff2aaaef, 0xff28afec, 0xff27b4e8, 0xff26b9e4,
0xff25bee0, 0xff25c2dc, 0xff25c6d8, 0xff25cbd3, 0xff25cfce, 0xff26d3ca, 0xff27d7c5, 0xff28dac0,
0xff29deba, 0xff2be1b5, 0xff2de4b0, 0xff30e7ab, 0xff33eaa6, 0xff36eda0, 0xff39ef9b, 0xff3cf296,
0xff40f491, 0xff44f68c, 0xff49f787, 0xff4df983, 0xff52fa7e, 0xff57fb79, 0xff5cfc75, 0xff62fd70,
0xff67fe6c, 0xff6dfe68, 0xff73fe64, 0xff79fe60, 0xff7ffe5c, 0xff85fd59, 0xff8bfd55, 0xff91fc52,
0xff98fb4f, 0xff9ef94c, 0xffa4f849, 0xffaaf646, 0xffb1f443, 0xffb7f241, 0xffbdf03f, 0xffc2ed3c,
0xffc8ea3a, 0xffcee838, 0xffd3e536, 0xffd8e134, 0xffddde32, 0xffe2da31, 0xffe7d72f, 0xffebd32e,
0xffefcf2c, 0xfff3ca2b, 0xfff7c62a, 0xfffac129, 0xfffdbd28, 0xffffb826, 0xffffb325, 0xffffae24,
0xffffa923, 0xffffa423, 0xffff9f22, 0xffff9921, 0xffff9420, 0xffff8f1f, 0xffff891e, 0xffff831d,
0xffff7e1c, 0xffff781b, 0xffff731b, 0xfffe6d1a, 0xfffb6719, 0xfff86218, 0xfff55c17, 0xfff15716,
0xffed5115, 0xffe94c14, 0xffe54712, 0xffe04211, 0xffdb3d10, 0xffd6380f, 0xffd1330e, 0xffcc2f0c,
0xffc62a0b, 0xffc1260a, 0xffbc2208, 0xffb71f07, 0xffb21b06, 0xffad1804, 0xffa81503, 0xffa31302,
0xff9f1000, 0xff9b0f00, 0xff980d00, 0xff950c00, 0xff930b00, 0xff910b00, 0xff900b00, 0xff900c00,
0xff900c00, 0xff900b00, 0xff910b00, 0xff930b00, 0xff950c00, 0xff980d00, 0xff9b0f00, 0xff9f1000,
0xffa31302, 0xffa81503, 0xffad1804, 0xffb21b06, 0xffb71f07, 0xffbc2208, 0xffc1260a, 0xffc62a0b,
0xffcc2f0c, 0xffd1330e, 0xffd6380f, 0xffdb3d10, 0xffe04211, 0xffe54712, 0xffe94c14, 0xffed5115,
0xfff15716, 0xfff55c17, 0xfff86218, 0xfffb6719, 0xfffe6d1a, 0xffff731b, 0xffff781b, 0xffff7e1c,
0xffff831d, 0xffff891e, 0xffff8f1f, 0xffff9420, 0xffff9921, 0xffff9f22, 0xffffa423, 0xffffa923,
0xffffae24, 0xffffb325, 0xffffb826, 0xfffdbd28, 0xfffac129, 0xfff7c62a, 0xfff3ca2b, 0xffefcf2c,
0xffebd32e, 0xffe7d72f, 0xffe2da31, 0xffddde32, 0xffd8e134, 0xffd3e536, 0xffcee838, 0xffc8ea3a,
0xffc2ed3c, 0xffbdf03f, 0xffb7f241, 0xffb1f443, 0xffaaf646, 0xffa4f849, 0xff9ef94c, 0xff98fb4f,
0xff91fc52, 0xff8bfd55, 0xff85fd59, 0xff7ffe5c, 0xff79fe60, 0xff73fe64, 0xff6dfe68, 0xff67fe6c,
0xff62fd70, 0xff5cfc75, 0xff57fb79, 0xff52fa7e, 0xff4df983, 0xff49f787, 0xff44f68c, 0xff40f491,
0xff3cf296, 0xff39ef9b, 0xff36eda0, 0xff33eaa6, 0xff30e7ab, 0xff2de4b0, 0xff2be1b5, 0xff29deba,
0xff28dac0, 0xff27d7c5, 0xff26d3ca, 0xff25cfce, 0xff25cbd3, 0xff25c6d8, 0xff25c2dc, 0xff25bee0,
0xff26b9e4, 0xff27b4e8, 0xff28afec, 0xff2aaaef, 0xff2ca5f2, 0xff2ea0f4, 0xff309bf6, 0xff3296f8,
0xff3491f9, 0xff368bf9, 0xff3986f9, 0xff3b80f9, 0xff3e7bf7, 0xff4075f5, 0xff4270f3, 0xff446aef,
0xff4664eb, 0xff485fe5, 0xff4959df, 0xff4a54d8, 0xff4b4ecf, 0xff4b49c6, 0xff4a43bb, 0xff493eaf,
0xff4739a2, 0xff453494, 0xff422f84, 0xff3e2a72, 0xff38255f, 0xff32204a, 0xff2b1b33, 0xff22171b,
}
};
C++컬러 렌더링 기능을 추가하기 위해 mandelbrot.h의 다음 부분을 수정해 줍니다. 6-2-2. 색상입히기2에서 사용되는 potential function에 처음 발산한 때의 수열 값을 요구하므로 9번에서 cx, cy를 참조로 선언해서 계산이 끝나고 그 값을 받아오도록 합니다.
template <class T>
inline uint32_t mandelbrot(T& cx, T& cy, uint32_t max_iter) {
T cx_ = cx, cy_ = cy, zx = 0., zy = 0.;
int i = 0;
do {
T temp = zx * zx - zy * zy + cx_;
zy = 2. * zx * zy + cy_;
zx = temp;
} while (zx * zx + zy * zy < 65536. && ++i < max_iter);
cx = zx;
cy = zy;
return i;
}
...
inline uint32_t getIteration() const { return iter; }
void setIteration(uint32_t iter);
inline uint32_t getColormap() const { return color_idx; }
void setColormap(uint32_t idx);
inline real_t getColorScale() const { return color_scale; }
void setColorScale(real_t scale);
inline bool getColorSmooth() const { return smooth; }
void setColorSmooth(bool val);
...
real_t pos_x;
real_t pos_y;
real_t scale;
uint32_t iter;
uint32_t color_idx;
real_t color_scale;
bool smooth;
mandelbrot.cpp도 수정해 줍니다.
#include "mandelbrot.h"
#include "color.h"
...
pos_x = 0.;
pos_y = 0.;
scale = 1.;
iter = 32;
color_idx = 1;
color_scale = 4;
smooth = false;
...
void Mandelbrot::setIteration(uint32_t iter)
{
stop();
this->iter = iter;
update(true, false);
}
void Mandelbrot::setColormap(uint32_t idx)
{
color_idx = idx;
update(true, false);
}
void Mandelbrot::setColorScale(real_t scale)
{
color_scale = scale;
update(true, false);
}
void Mandelbrot::setColorSmooth(bool val)
{
smooth = val;
update(true, false);
}
멀티스레드 렌더러인 mandelbrot_tbb.cpp에 먼저 변경사항을 적용하도록 하겠습니다. MandelbrotTBB::drawSurface()를 수정합니다.
#include "mandelbrot_tbb.h"
#include <oneapi/tbb/parallel_for.h>
#include <oneapi/tbb/blocked_range2d.h>
#include <oneapi/tbb/task.h>
#include "color.h"
...
tbb::parallel_for(range_t(0, height, 0, width), [=](range_t r) {
for (int h = r.rows().begin(); h < r.rows().end(); ++h) {
if (stop_all) {
tbb::task::current_context()->cancel_group_execution();
return;
}
for (int w = r.cols().begin(); w < r.cols().end(); ++w) {
auto& info = render_info.at(w, h);
if (info.rendered) continue;
uint32_t& pixel = *((uint32_t*)surface->pixels + h * surface->w + w);
real_t cx = min_x + dx * (w + 0.5f);
real_t cy = max_y - dy * (h + 0.5f);
auto iterated = mandelbrot<real_t>(cx, cy, iter);
if (iterated == iter) {
pixel = 0xff000000;
} if (!smooth) {
pixel = colormap[color_idx][(int)(color_scale * 256 * iterated / iter) % 256];
}
info.rendered = true;
}
}
});
이제 실행해보면 밋밋한 회색에서 벗어난 화려한 모습을 볼 수 있습니다.





6-2-2. 연속적인 색 입히
위의 사진을 보시면 등고선 처럼 선이 있는 모습을 볼 수 있습니다. 이걸 부드럽게 이어주기 위해서 추가적인 계산이 필요합니다. iteration을 자연수가 아닌 실수범위에서 얻을 수 있도록 potential function을 이용할 겁니다. 자세한 부분은 위키피디아의 Plotting algorithms for the Mandelbrot set을 참조하시기 바랍니다.
색상 입히기1에서 필요한 부분을 미리 수정했으므로 mandelbrot_tbb.cpp만 수정하면 됩니다.
if (iterated == iter) {
pixel = 0xff000000;
} else if (!smooth) {
pixel = colormap[color_idx][(int)(color_scale * 256 * iterated / iter) % 256];
} else {
double log_zn = log(cx * cx + cy * cy) / 2.;
double nu = log(log_zn / log(2)) / log(2);
auto real_iter = iterated + 3.5 - nu;
auto col1 = colormap[color_idx][(int)(color_scale * 256 * real_iter / iter) % 256];
auto col2 = colormap[color_idx][(int)(color_scale * 256 * (real_iter + 1) / iter) % 256];
pixel = lerp_color(col1, col2, fmod(iter, 1));
}
실행하기 전에 mandelbrot.cpp의 29번 줄에서 smooth = true로 잠시 변경합니다. 실행해보면 등고선 같은 무늬 없이 연속적으로 색이 연결된 모습을 볼 수 있습니다.

이제 단일 스레드 렌더러 구현인 mandelbrot.cpp도 수정해 주고 UI도 추가해 주도록 하겠습니다. 먼저 mandelbrot.cpp의 Mandelbrot::drawSurface()를 수정합니다.
auto iterated = mandelbrot<real_t>(cx, cy, iter);
if (iterated == iter) {
pixel = 0xff000000;
} else if (!smooth) {
pixel = colormap[color_idx][(int)(color_scale * 256 * iterated / iter) % 256];
} else {
double log_zn = log(cx * cx + cy * cy) / 2.;
double nu = log(log_zn / log(2)) / log(2);
auto real_iter = iterated + 3.5 - nu;
auto col1 = colormap[color_idx][(int)(color_scale * 256 * real_iter / iter) % 256];
auto col2 = colormap[color_idx][(int)(color_scale * 256 * (real_iter + 1) / iter) % 256];
pixel = lerp_color(col1, col2, fmod(iter, 1));
}
info.rendered = true;
다음 gui.h와 gui.cpp도 수정합니다.
private:
void acceleratorChanged(std::unique_ptr<Mandelbrot>& mandelbrot);
void showBasicUI(std::unique_ptr<Mandelbrot>& mandelbrot);
void showMoreSettingsUI(std::unique_ptr<Mandelbrot>& mandelbrot);
void showAcceleratorUI(std::unique_ptr<Mandelbrot>& mandelbrot);
void showAppearanceUI(std::unique_ptr<Mandelbrot>& mandelbrot);
void showScreenshotUI(std::unique_ptr<Mandelbrot>& mandelbrot);
void showErrorMessage();
GUI::acceleratorChanged() 메서드 내부가 변수가 많아지며 상당히 지저분해 졌는데, 여기선 하지 않았지만, Mandelbrot클래스에 복사생성자를 만들고 MandelbrotTBB에서 이 생성자를 상속받는 방법으로 아주 깔끔하게 만들 수 있습니다.
void GUI::update(std::unique_ptr<Mandelbrot>& mandelbrot)
{
ImGui_ImplSDLRenderer_NewFrame();
ImGui_ImplSDL2_NewFrame(window);
ImGui::NewFrame();
ImGui::Begin("control", nullptr, ImGuiWindowFlags_NoResize);
showBasicUI(mandelbrot);
showAcceleratorUI(mandelbrot);
showAppearanceUI(mandelbrot);
showMoreSettingsUI(mandelbrot);
showScreenshotUI(mandelbrot);
ImGui::SetWindowSize({ 260, ImGui::GetContentRegionAvail().y });
showErrorMessage();
ImGui::End();
}
void GUI::acceleratorChanged(std::unique_ptr<Mandelbrot>& mandelbrot)
{
auto pos = mandelbrot->getPosition();
auto scale = mandelbrot->getScale();
auto iter = mandelbrot->getIteration();
auto color_map = mandelbrot->getColormap();
auto color_scale = mandelbrot->getColorScale();
auto smooth = mandelbrot->getSmoothColor();
mandelbrot->stop();
switch (settings.accelerator) {
case Acc::CPU:
mandelbrot = make_unique<Mandelbrot>(renderer);
break;
case Acc::CPU_TBB:
mandelbrot = make_unique<MandelbrotTBB>(renderer);
break;
}
mandelbrot->setPosition(pos.real(), pos.imag());
mandelbrot->setScale(scale);
mandelbrot->setIteration(iter);
mandelbrot->setColormap(color_map);
mandelbrot->setColorScale(color_scale);
mandelbrot->setSmoothColor(smooth);
}
...
void GUI::showAppearanceUI(std::unique_ptr<Mandelbrot>& mandelbrot)
{
if (ImGui::CollapsingHeader("appearance")) {
static const char* items[] = { "gray", "ultra", "viridis", "magma", "inferno", "turbo" };
auto color_map = mandelbrot->getColormap();
float color_scale = mandelbrot->getColorScale();
auto smooth = mandelbrot->getColorSmooth();
ImGui::Text("colormap :");
if (ImGui::Combo(IMGUI_NO_LABEL, (int*)&color_map, items, 6))
mandelbrot->setColormap(color_map);
ImGui::Text("color scale :");
if (ImGui::DragFloat(IMGUI_NO_LABEL, &color_scale, 1.f, 1.f, 128, "%f", ImGuiSliderFlags_Logarithmic))
mandelbrot->setColorScale(color_scale);
ImGui::Text("smooth color :");
if (ImGui::Checkbox(IMGUI_NO_LABEL, &smooth))
mandelbrot->setColorSmooth(smooth);
}
}
아래는 결과물 입니다.




같은 부분에 서로 다른 컬러맵을 적용시켜 봤습니다.












원래 계획대로라면 여기서 끝내려고 했으나… 뭔가 아쉬운 부분이 있어서 다음 편에선 멀티 샘플링과 CUDA로 GPU를 이용해 렌더링 하는 기능을 추가해 보도록 하겠습니다.
최신 댓글