i hate metal cpp
This commit is contained in:
Vendored
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
"program": "${workspaceFolder}/build/Debug/RayTracer",
|
"program": "${workspaceFolder}/build/Debug/RayTracer",
|
||||||
"args": [],
|
"args": [],
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}/build",
|
"cwd": "${workspaceFolder}/build/Debug",
|
||||||
"environment": [],
|
"environment": [],
|
||||||
"externalConsole": false,
|
"externalConsole": false,
|
||||||
"MIMode": "lldb"
|
"MIMode": "lldb"
|
||||||
|
|||||||
+6
-7
@@ -19,9 +19,6 @@ find_package(glfw3 CONFIG REQUIRED)
|
|||||||
find_package(glm CONFIG REQUIRED)
|
find_package(glm CONFIG REQUIRED)
|
||||||
find_package(Ktx CONFIG REQUIRED)
|
find_package(Ktx CONFIG REQUIRED)
|
||||||
find_package(imgui CONFIG REQUIRED)
|
find_package(imgui CONFIG REQUIRED)
|
||||||
find_library(APPLE_FWK_FOUNDATION Foundation REQUIRED)
|
|
||||||
find_library(APPLE_FWK_QUARTZ_CORE QuartzCore REQUIRED)
|
|
||||||
find_library(APPLE_FWK_METAL Metal REQUIRED)
|
|
||||||
|
|
||||||
add_executable(RayTracer "")
|
add_executable(RayTracer "")
|
||||||
target_include_directories(RayTracer PUBLIC src/)
|
target_include_directories(RayTracer PUBLIC src/)
|
||||||
@@ -40,12 +37,14 @@ target_link_libraries(RayTracer PUBLIC ${VCPKG_INSTALLED_DIR}/x64-windows/lib/sl
|
|||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
target_include_directories(RayTracer PUBLIC ${VCPKG_INSTALLED_DIR}/arm64-osx/include)
|
target_include_directories(RayTracer PUBLIC ${VCPKG_INSTALLED_DIR}/arm64-osx/include)
|
||||||
target_include_directories(RayTracer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/external/metal-cpp)
|
target_include_directories(RayTracer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/external/metal-cpp)
|
||||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET 15.0)
|
SET(CMAKE_OSX_DEPLOYMENT_TARGET 15.3.1)
|
||||||
|
|
||||||
target_link_libraries(RayTracer PUBLIC
|
target_link_libraries(RayTracer PUBLIC
|
||||||
${APPLE_FWK_FOUNDATION}
|
"-framework Metal"
|
||||||
${APPLE_FWK_QUARTZ_CORE}
|
"-framework MetalKit"
|
||||||
${APPLE_FWK_METAL}
|
"-framework AppKit"
|
||||||
|
"-framework Foundation"
|
||||||
|
"-framework QuartzCore"
|
||||||
)
|
)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -11,5 +11,4 @@ if(APPLE)
|
|||||||
add_subdirectory(metal/)
|
add_subdirectory(metal/)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(scene/)
|
add_subdirectory(scene/)
|
||||||
add_subdirectory(window/)
|
|
||||||
add_subdirectory(util/)
|
add_subdirectory(util/)
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <coroutine>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#define DEFINE_REF(x) typedef ::std::unique_ptr<x> P##x;
|
#define DEFINE_REF(x) typedef ::std::unique_ptr<x> P##x;
|
||||||
|
|
||||||
@@ -8,15 +6,3 @@
|
|||||||
class x; \
|
class x; \
|
||||||
typedef ::std::unique_ptr<x> P##x;
|
typedef ::std::unique_ptr<x> P##x;
|
||||||
|
|
||||||
struct Task
|
|
||||||
{
|
|
||||||
struct promise_type
|
|
||||||
{
|
|
||||||
Task get_return_object() { return {std::coroutine_handle<promise_type>::from_promise(*this)}; }
|
|
||||||
std::suspend_always initial_suspend() noexcept { return {}; }
|
|
||||||
std::suspend_never final_suspend() noexcept { return {}; }
|
|
||||||
void return_void() {}
|
|
||||||
void unhandled_exception() {}
|
|
||||||
};
|
|
||||||
std::coroutine_handle<promise_type> handle;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -4,7 +4,20 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "Minimal.h"
|
#include "Minimal.h"
|
||||||
|
#include <coroutine>
|
||||||
|
|
||||||
|
struct Task
|
||||||
|
{
|
||||||
|
struct promise_type
|
||||||
|
{
|
||||||
|
Task get_return_object() { return {std::coroutine_handle<promise_type>::from_promise(*this)}; }
|
||||||
|
std::suspend_always initial_suspend() noexcept { return {}; }
|
||||||
|
std::suspend_never final_suspend() noexcept { return {}; }
|
||||||
|
void return_void() {}
|
||||||
|
void unhandled_exception() {}
|
||||||
|
};
|
||||||
|
std::coroutine_handle<promise_type> handle;
|
||||||
|
};
|
||||||
struct Batch
|
struct Batch
|
||||||
{
|
{
|
||||||
std::list<Task> jobs;
|
std::list<Task> jobs;
|
||||||
|
|||||||
+115
-3
@@ -1,5 +1,95 @@
|
|||||||
#include "CPURenderer.h"
|
#include "CPURenderer.h"
|
||||||
#include "scene/Renderer.h"
|
#include "scene/Renderer.h"
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_impl_glfw.h>
|
||||||
|
#include <imgui_impl_opengl3.h>
|
||||||
|
|
||||||
|
#define GLSL(...) "#version 400\n" #__VA_ARGS__
|
||||||
|
|
||||||
|
CPURenderer::CPURenderer()
|
||||||
|
{
|
||||||
|
glewExperimental = true;
|
||||||
|
glfwInit();
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We don't want the old OpenGL
|
||||||
|
window = glfwCreateWindow(width, height, "RayTracer", nullptr, nullptr);
|
||||||
|
glfwSwapInterval(1);
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||||
|
|
||||||
|
ImGui_ImplGlfw_InitForOpenGL(window,
|
||||||
|
true); // Second param install_callback=true will install GLFW callbacks and chain to existing ones.
|
||||||
|
ImGui_ImplOpenGL3_Init();
|
||||||
|
|
||||||
|
glewInit();
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
glGenTextures(1, &texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, nullptr);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
|
program = glCreateProgram();
|
||||||
|
vertShader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
fragShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
int logLen = 0;
|
||||||
|
const char* vertCode =
|
||||||
|
GLSL(out vec2 texcoords; // texcoords are in the normalized [0,1] range for the viewport-filling quad part of the triangle
|
||||||
|
void main() {
|
||||||
|
vec2 vertices[3] = vec2[3](vec2(-1, -1), vec2(3, -1), vec2(-1, 3));
|
||||||
|
gl_Position = vec4(vertices[gl_VertexID], 0, 1);
|
||||||
|
texcoords = 0.5 * gl_Position.xy + vec2(0.5);
|
||||||
|
});
|
||||||
|
const char* fragCode = GLSL(in vec2 texcoords; out vec4 color;
|
||||||
|
|
||||||
|
uniform sampler2D tex;
|
||||||
|
|
||||||
|
void main() { color = texture(tex, vec2(texcoords.x, -texcoords.y)); });
|
||||||
|
glShaderSource(vertShader, 1, &vertCode, nullptr);
|
||||||
|
glCompileShader(vertShader);
|
||||||
|
int success;
|
||||||
|
char infoLog[1024];
|
||||||
|
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
glGetShaderInfoLog(vertShader, 1024, NULL, infoLog);
|
||||||
|
std::cout << "ERROR::SHADER_COMPILATION_ERROR\n"
|
||||||
|
<< infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
glShaderSource(fragShader, 1, &fragCode, nullptr);
|
||||||
|
glCompileShader(fragShader);
|
||||||
|
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
glGetShaderInfoLog(fragShader, 1024, NULL, infoLog);
|
||||||
|
std::cout << "ERROR::SHADER_COMPILATION_ERROR\n"
|
||||||
|
<< infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
glAttachShader(program, vertShader);
|
||||||
|
glAttachShader(program, fragShader);
|
||||||
|
|
||||||
|
glLinkProgram(program);
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, &logLen);
|
||||||
|
if (logLen > 0)
|
||||||
|
{
|
||||||
|
std::vector<char> log(logLen);
|
||||||
|
glGetProgramInfoLog(program, logLen, &logLen, log.data());
|
||||||
|
std::cout << log.data() << std::endl;
|
||||||
|
}
|
||||||
|
glDeleteShader(vertShader);
|
||||||
|
glDeleteShader(fragShader);
|
||||||
|
glClearColor(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec3 rand01(glm::uvec3 x)
|
glm::vec3 rand01(glm::uvec3 x)
|
||||||
{ // pseudo-random number generator
|
{ // pseudo-random number generator
|
||||||
@@ -8,10 +98,32 @@ glm::vec3 rand01(glm::uvec3 x)
|
|||||||
return glm::vec3(x) * (1.0f / float(0xffffffffU));
|
return glm::vec3(x) * (1.0f / float(0xffffffffU));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CPURenderer::beginFrame()
|
||||||
|
{
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glfwPollEvents();
|
||||||
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
ImGui_ImplGlfw_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CPURenderer::update()
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_FLOAT, image.data());
|
||||||
|
glUseProgram(program);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
ImGui::Render();
|
||||||
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
glfwSwapBuffers(window);
|
||||||
|
}
|
||||||
|
|
||||||
void CPURenderer::render(Camera camera, RenderParameter params)
|
void CPURenderer::render(Camera camera, RenderParameter params)
|
||||||
{
|
{
|
||||||
accumulator.clear();
|
image.clear();
|
||||||
accumulator.resize(params.width * params.height);
|
image.resize(params.width * params.height);
|
||||||
|
accumulator.clear();
|
||||||
|
accumulator.resize(params.width * params.height);
|
||||||
for (int samp = 0; samp < params.numSamples; ++samp)
|
for (int samp = 0; samp < params.numSamples; ++samp)
|
||||||
{
|
{
|
||||||
if (!running)
|
if (!running)
|
||||||
@@ -64,7 +176,7 @@ void CPURenderer::render(Camera camera, RenderParameter params)
|
|||||||
|
|
||||||
scene->traceRay(r, payload, 1e-4, 1e20);
|
scene->traceRay(r, payload, 1e-4, 1e20);
|
||||||
|
|
||||||
float resolver = float(params.numSamples) / float(samp+1);
|
float resolver = float(params.numSamples) / float(samp + 1);
|
||||||
accumulator[w + h * params.width] += payload.accumulatedRadiance / float(params.numSamples);
|
accumulator[w + h * params.width] += payload.accumulatedRadiance / float(params.numSamples);
|
||||||
image[w + h * params.width] = glm::pow(glm::max(accumulator[w + h * params.width] * resolver, 0.0f), glm::vec3(0.45f));
|
image[w + h * params.width] = glm::pow(glm::max(accumulator[w + h * params.width] * resolver, 0.0f), glm::vec3(0.45f));
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-1
@@ -2,14 +2,38 @@
|
|||||||
#include "cpu/CPUScene.h"
|
#include "cpu/CPUScene.h"
|
||||||
#include "scene/Renderer.h"
|
#include "scene/Renderer.h"
|
||||||
#include "util/Camera.h"
|
#include "util/Camera.h"
|
||||||
|
#include "ThreadPool.h"
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include <glfw/glfw3.h>
|
||||||
|
|
||||||
class CPURenderer : public Renderer
|
class CPURenderer : public Renderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
CPURenderer();
|
||||||
|
virtual ~CPURenderer();
|
||||||
|
|
||||||
|
virtual void addPointLight(PointLight point) override { scene->addPointLight(point); }
|
||||||
|
virtual void addDirectionalLight(DirectionalLight dir) override { scene->addDirectionalLight(dir); }
|
||||||
|
virtual void addModel(PModel model, glm::mat4 transform) override { scene->addModel(std::move(model), transform); }
|
||||||
|
virtual void addModels(std::vector<PModel> models, glm::mat4 transform) override { scene->addModels(std::move(models), transform); }
|
||||||
|
virtual void generate() override { scene->generate(); }
|
||||||
|
|
||||||
|
virtual void beginFrame() override;
|
||||||
|
virtual void update() override;
|
||||||
|
protected:
|
||||||
virtual void render(Camera camera, RenderParameter params) override;
|
virtual void render(Camera camera, RenderParameter params) override;
|
||||||
private:
|
|
||||||
CPUScene* scene;
|
CPUScene* scene;
|
||||||
ThreadPool threadPool;
|
ThreadPool threadPool;
|
||||||
// radiance accumulator
|
// radiance accumulator
|
||||||
std::vector<glm::vec3> accumulator;
|
std::vector<glm::vec3> accumulator;
|
||||||
|
// the thing being displayed
|
||||||
|
std::vector<glm::vec3> image;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
GLuint vao;
|
||||||
|
GLuint texture;
|
||||||
|
GLuint program;
|
||||||
|
GLuint vertShader;
|
||||||
|
GLuint fragShader;
|
||||||
|
GLFWwindow* window;
|
||||||
};
|
};
|
||||||
@@ -19,6 +19,9 @@ public:
|
|||||||
virtual void generate() override { scene->generate(); }
|
virtual void generate() override { scene->generate(); }
|
||||||
virtual void render(Camera cam, RenderParameter param) override;
|
virtual void render(Camera cam, RenderParameter param) override;
|
||||||
|
|
||||||
|
virtual void beginFrame() override;
|
||||||
|
virtual void update() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct GPUCamera
|
struct GPUCamera
|
||||||
{
|
{
|
||||||
|
|||||||
+21
-22
@@ -1,26 +1,24 @@
|
|||||||
#include "scene/Renderer.h"
|
|
||||||
#include "metal/MetalRenderer.h"
|
#include "metal/MetalRenderer.h"
|
||||||
#include "window/Window.h"
|
#include "scene/Renderer.h"
|
||||||
#include "util/ModelLoader.h"
|
#include "util/ModelLoader.h"
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
std::unique_ptr<Renderer> scene = std::make_unique<MetalRenderer>();
|
std::unique_ptr<Renderer> renderer = std::make_unique<MetalRenderer>();
|
||||||
|
|
||||||
scene->addDirectionalLight(DirectionalLight{
|
renderer->addDirectionalLight(DirectionalLight{
|
||||||
.direction = glm::normalize(glm::vec3(-0.4f, -0.3f, -0.2f)),
|
.direction = glm::normalize(glm::vec3(-0.4f, -0.3f, -0.2f)),
|
||||||
.color = glm::vec3(1, 1, 1),
|
.color = glm::vec3(1, 1, 1),
|
||||||
});
|
});
|
||||||
scene->addPointLight(PointLight{});
|
renderer->addPointLight(PointLight{});
|
||||||
scene->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"),
|
renderer->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"),
|
||||||
glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
|
glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
|
||||||
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)));
|
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)));
|
||||||
scene->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"),
|
renderer->addModels(ModelLoader::loadModel("../../res/models/cube.fbx"),
|
||||||
glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
|
glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f), glm::vec4(0.0f, 0.0f, 1.0f, 0.0f),
|
||||||
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)));
|
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)));
|
||||||
scene->generate();
|
renderer->generate();
|
||||||
Window window(1920, 1080);
|
|
||||||
Camera camera = Camera{
|
Camera camera = Camera{
|
||||||
.position = glm::vec3(5, 1, 2),
|
.position = glm::vec3(5, 1, 2),
|
||||||
.target = glm::vec3(0, 0, 0),
|
.target = glm::vec3(0, 0, 0),
|
||||||
@@ -31,11 +29,11 @@ int main()
|
|||||||
.height = 1080,
|
.height = 1080,
|
||||||
.numSamples = 10000,
|
.numSamples = 10000,
|
||||||
};
|
};
|
||||||
scene->startRender(camera, render);
|
renderer->startRender(camera, render);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
window.beginFrame();
|
renderer->beginFrame();
|
||||||
ImGui::Text("Camera Parameters");
|
ImGui::Text("Camera Parameters");
|
||||||
ImGui::InputFloat3("Position", &camera.position.x);
|
ImGui::InputFloat3("Position", &camera.position.x);
|
||||||
ImGui::InputFloat3("Target", &camera.target.x);
|
ImGui::InputFloat3("Target", &camera.target.x);
|
||||||
@@ -47,13 +45,14 @@ int main()
|
|||||||
ImGui::InputInt("Samples", (int*)&render.numSamples);
|
ImGui::InputInt("Samples", (int*)&render.numSamples);
|
||||||
if (ImGui::Button("Render"))
|
if (ImGui::Button("Render"))
|
||||||
{
|
{
|
||||||
scene->startRender(camera, render);
|
renderer->startRender(camera, render);
|
||||||
}
|
}
|
||||||
ImGui::Text("Render Stats");
|
ImGui::Text("Render Stats");
|
||||||
ImGui::Text("Last Sample Time: %.3f ms", scene->getLastSampleTime());
|
ImGui::Text("Last Sample Time: %.3f ms", renderer->getLastSampleTime());
|
||||||
ImGui::Text("Average Sample Time: %.3f ms", scene->getAverageSampleTime());
|
ImGui::Text("Average Sample Time: %.3f ms", renderer->getAverageSampleTime());
|
||||||
ImGui::PlotLines("Sample Times", scene->getSampleTimes().data(), scene->getSampleTimes().size(), 0, 0, FLT_MAX, FLT_MAX, ImVec2(0, 40));
|
ImGui::PlotLines("Sample Times", renderer->getSampleTimes().data(), renderer->getSampleTimes().size(), 0, 0, FLT_MAX, FLT_MAX,
|
||||||
window.update(scene->getImage());
|
ImVec2(0, 40));
|
||||||
|
renderer->update();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
target_sources(RayTracer
|
target_sources(RayTracer
|
||||||
PRIVATE
|
PRIVATE
|
||||||
MetalRenderer.h
|
MetalRenderer.h
|
||||||
MetalRenderer.cpp
|
MetalRenderer.mm
|
||||||
MetalScene.h
|
MetalScene.h
|
||||||
MetalScene.cpp
|
MetalScene.mm
|
||||||
Compute.metal
|
Compute.metal
|
||||||
PrivateImpl.mm)
|
PrivateImpl.mm)
|
||||||
@@ -133,8 +133,8 @@ kernel void computeKernel(
|
|||||||
constant PointLight* pointLights [[buffer(6)]],
|
constant PointLight* pointLights [[buffer(6)]],
|
||||||
constant MTLAccelerationStructureInstanceDescriptor* instances [[buffer(7)]],
|
constant MTLAccelerationStructureInstanceDescriptor* instances [[buffer(7)]],
|
||||||
instance_acceleration_structure accelerationStructure [[buffer(8)]],
|
instance_acceleration_structure accelerationStructure [[buffer(8)]],
|
||||||
device packed_float3* accumulator [[buffer(9)]],
|
texture2d<float, access::read_write> accumulator [[texture(0)]],
|
||||||
device packed_float3* image [[buffer(10)]]
|
texture2d<float, access::read_write> image [[texture(1)]]
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Payload payload;
|
Payload payload;
|
||||||
@@ -267,6 +267,8 @@ kernel void computeKernel(
|
|||||||
payload.depth++;
|
payload.depth++;
|
||||||
}
|
}
|
||||||
float resolver = float(sample.samplesPerPixel) / float(sample.pass+1);
|
float resolver = float(sample.samplesPerPixel) / float(sample.pass+1);
|
||||||
accumulator[threadId.x + threadId.y * camera.width] += payload.accumulatedRadiance / float(sample.samplesPerPixel);
|
float4 previous = accumulator.read(threadId);
|
||||||
image[threadId.x + threadId.y * camera.width] = pow(max(accumulator[threadId.x + threadId.y * camera.width] * resolver, 0), float3(0.45f));
|
float4 result = previous + float4(payload.accumulatedRadiance / float(sample.samplesPerPixel), 0);
|
||||||
|
accumulator.write(result, threadId);
|
||||||
|
image.write(pow(max(result * resolver, 0), float4(0.45f)), threadId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
#include "MetalRenderer.h"
|
|
||||||
#include "metal/MetalScene.h"
|
|
||||||
#include "scene/Renderer.h"
|
|
||||||
#include "util/Camera.h"
|
|
||||||
#include <Foundation/Foundation.hpp>
|
|
||||||
#include <Metal/Metal.hpp>
|
|
||||||
#include <QuartzCore/QuartzCore.hpp>
|
|
||||||
|
|
||||||
MetalRenderer::MetalRenderer()
|
|
||||||
{
|
|
||||||
device = MTL::CreateSystemDefaultDevice();
|
|
||||||
|
|
||||||
library = device->newDefaultLibrary();
|
|
||||||
|
|
||||||
queue = device->newCommandQueue();
|
|
||||||
|
|
||||||
scene = new MetalScene(device, queue);
|
|
||||||
|
|
||||||
function = library->newFunction(NS::String::string("computeKernel", NS::ASCIIStringEncoding));
|
|
||||||
|
|
||||||
NS::Error* error;
|
|
||||||
computePipeline = device->newComputePipelineState(function, &error);
|
|
||||||
}
|
|
||||||
|
|
||||||
MetalRenderer::~MetalRenderer() {}
|
|
||||||
|
|
||||||
void MetalRenderer::render(Camera camera, RenderParameter parameter)
|
|
||||||
{
|
|
||||||
MTL::Buffer* cameraBuffer = device->newBuffer(sizeof(GPUCamera), 0);
|
|
||||||
*(GPUCamera*)cameraBuffer->contents() = GPUCamera {
|
|
||||||
.cameraPosition = camera.position,
|
|
||||||
.A = camera.A,
|
|
||||||
.cameraForward = camera.target - camera.position,
|
|
||||||
.f = camera.f,
|
|
||||||
.S_O = camera.S_O,
|
|
||||||
.sensorSize = camera.sensorSize,
|
|
||||||
.width = parameter.width,
|
|
||||||
.height = parameter.height,
|
|
||||||
};
|
|
||||||
|
|
||||||
SampleParams sample = {
|
|
||||||
.samplesPerPixel = parameter.numSamples,
|
|
||||||
.numDirectionalLights = scene->getNumDirLights(),
|
|
||||||
.numPointLights = scene->getNumPointLights(),
|
|
||||||
};
|
|
||||||
accumulator = device->newBuffer(parameter.width * parameter.height * sizeof(glm::vec3), 0);
|
|
||||||
resultTexture = device->newBuffer(parameter.width * parameter.height * sizeof(glm::vec3), 0);
|
|
||||||
for (uint i = 0; i < parameter.numSamples; ++i)
|
|
||||||
{
|
|
||||||
MTL::CommandBuffer* cmdBuffer = queue->commandBuffer();
|
|
||||||
MTL::ComputeCommandEncoder* encoder = cmdBuffer->computeCommandEncoder();
|
|
||||||
//cmdBuffer->addCompletedHandler([this](MTL::CommandBuffer* cmdBuffer)
|
|
||||||
// { std::memcpy(image.data(), resultTexture->buffer(), image.size() * sizeof(glm::vec3)); });
|
|
||||||
sample.pass = i;
|
|
||||||
MTL::Buffer* sampleBuffer = device->newBuffer(sizeof(SampleParams), 0);
|
|
||||||
*(SampleParams*)sampleBuffer->contents() = sample;
|
|
||||||
encoder->setComputePipelineState(computePipeline);
|
|
||||||
encoder->setBuffer(scene->indicesBuffer, 0, 0);
|
|
||||||
encoder->setBuffer(scene->positionBuffer, 0, 1);
|
|
||||||
encoder->setBuffer(scene->texCoordsBuffer, 0, 2);
|
|
||||||
encoder->setBuffer(scene->normalBuffer, 0, 3);
|
|
||||||
encoder->setBuffer(scene->modelRefsBuffer, 0, 4);
|
|
||||||
encoder->setBuffer(scene->directionalLightBuffer, 0, 5);
|
|
||||||
encoder->setBuffer(scene->pointLightBuffer, 0, 6);
|
|
||||||
encoder->setBuffer(scene->instanceBuffer, 0, 7);
|
|
||||||
encoder->setAccelerationStructure(scene->accelerationStructure, 8);
|
|
||||||
encoder->setBuffer(accumulator, 0, 9);
|
|
||||||
encoder->setBuffer(resultTexture, 0, 10);
|
|
||||||
encoder->setBuffer(cameraBuffer, 0, 11);
|
|
||||||
encoder->setBuffer(sampleBuffer, 0, 12);
|
|
||||||
encoder->useResource(scene->instanceBuffer, MTL::ResourceUsageRead);
|
|
||||||
encoder->useResource(scene->positionBuffer, MTL::ResourceUsageRead);
|
|
||||||
encoder->useResource(scene->texCoordsBuffer, MTL::ResourceUsageRead);
|
|
||||||
encoder->useResource(scene->normalBuffer, MTL::ResourceUsageRead);
|
|
||||||
encoder->useResource(scene->modelRefsBuffer, MTL::ResourceUsageRead);
|
|
||||||
if(scene->getNumDirLights() > 0)
|
|
||||||
{
|
|
||||||
encoder->useResource(scene->directionalLightBuffer, MTL::ResourceUsageRead);}
|
|
||||||
if(scene->getNumPointLights() > 0)
|
|
||||||
{encoder->useResource(scene->pointLightBuffer, MTL::ResourceUsageRead);}
|
|
||||||
encoder->useResource(scene->instanceBuffer, MTL::ResourceUsageRead);
|
|
||||||
encoder->useResource(scene->accelerationStructure, MTL::ResourceUsageRead);
|
|
||||||
encoder->useResource(accumulator, MTL::ResourceUsageWrite);
|
|
||||||
encoder->useResource(resultTexture, MTL::ResourceUsageWrite);
|
|
||||||
NS::UInteger width = (NS::UInteger)parameter.width;
|
|
||||||
NS::UInteger height = (NS::UInteger)parameter.height;
|
|
||||||
MTL::Size threadsPerThreadgroup = MTL::Size(8, 8, 1);
|
|
||||||
MTL::Size threadgroups = MTL::Size((width + threadsPerThreadgroup.width - 1) / threadsPerThreadgroup.width,
|
|
||||||
(height + threadsPerThreadgroup.height - 1) / threadsPerThreadgroup.height, 1);
|
|
||||||
encoder->dispatchThreadgroups(threadgroups, threadsPerThreadgroup);
|
|
||||||
encoder->endEncoding();
|
|
||||||
cmdBuffer->commit();
|
|
||||||
cmdBuffer->waitUntilCompleted();
|
|
||||||
std::memcpy(image.data(), resultTexture->contents(), image.size() * sizeof(glm::vec3));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+45
-23
@@ -2,8 +2,14 @@
|
|||||||
#include "metal/MetalScene.h"
|
#include "metal/MetalScene.h"
|
||||||
#include "scene/Renderer.h"
|
#include "scene/Renderer.h"
|
||||||
#include "util/Camera.h"
|
#include "util/Camera.h"
|
||||||
#include <Foundation/Foundation.hpp>
|
|
||||||
|
#define GLFW_INCLUDE_NONE
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||||
|
#include <GLFW/glfw3native.h>
|
||||||
|
|
||||||
#include <Metal/Metal.hpp>
|
#include <Metal/Metal.hpp>
|
||||||
|
#include <QuartzCore/CAMetalLayer.hpp>
|
||||||
#include <QuartzCore/QuartzCore.hpp>
|
#include <QuartzCore/QuartzCore.hpp>
|
||||||
|
|
||||||
struct GPUCamera
|
struct GPUCamera
|
||||||
@@ -17,38 +23,54 @@ struct GPUCamera
|
|||||||
float A;
|
float A;
|
||||||
float ka;
|
float ka;
|
||||||
glm::vec2 sensorSize;
|
glm::vec2 sensorSize;
|
||||||
uint width;
|
uint width;
|
||||||
uint height;
|
uint height;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SampleParams
|
struct SampleParams
|
||||||
{
|
{
|
||||||
uint pass;
|
uint pass;
|
||||||
uint samplesPerPixel;
|
uint samplesPerPixel;
|
||||||
uint numDirectionalLights;
|
uint numDirectionalLights;
|
||||||
uint numPointLights;
|
uint numPointLights;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MetalRenderer : public Renderer
|
class MetalRenderer : public Renderer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MetalRenderer();
|
MetalRenderer();
|
||||||
virtual ~MetalRenderer();
|
virtual ~MetalRenderer();
|
||||||
virtual void addPointLight(PointLight point) override { scene->addPointLight(point); }
|
virtual void addPointLight(PointLight point) override { scene->addPointLight(point); }
|
||||||
virtual void addDirectionalLight(DirectionalLight dir) override { scene->addDirectionalLight(dir); }
|
virtual void addDirectionalLight(DirectionalLight dir) override { scene->addDirectionalLight(dir); }
|
||||||
virtual void addModel(PModel model, glm::mat4 transform) override { scene->addModel(std::move(model), transform); }
|
virtual void addModel(PModel model, glm::mat4 transform) override { scene->addModel(std::move(model), transform); }
|
||||||
virtual void addModels(std::vector<PModel> models, glm::mat4 transform) override { scene->addModels(std::move(models), transform); }
|
virtual void addModels(std::vector<PModel> models, glm::mat4 transform) override { scene->addModels(std::move(models), transform); }
|
||||||
virtual void generate() override { scene->generate(); }
|
virtual void generate() override { scene->generate(); }
|
||||||
virtual void render(Camera camera, RenderParameter params) override;
|
virtual void render(Camera camera, RenderParameter params) override;
|
||||||
|
|
||||||
|
virtual void beginFrame() override;
|
||||||
|
virtual void update() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MTL::Device* device;
|
uint width;
|
||||||
MTL::Library* library;
|
uint height;
|
||||||
MTL::CommandQueue* queue;
|
uint framebufferWidth;
|
||||||
MTL::Function* function;
|
uint framebufferHeight;
|
||||||
MTL::ComputePipelineState* computePipeline;
|
GLFWwindow* handle;
|
||||||
MTL::Buffer* accumulator;
|
CA::MetalLayer* metalLayer;
|
||||||
MTL::Buffer* resultTexture;
|
CA::MetalDrawable* drawable;
|
||||||
|
|
||||||
MetalScene* scene;
|
MTL::Device* device;
|
||||||
|
MTL::Library* library;
|
||||||
|
MTL::CommandQueue* queue;
|
||||||
|
MTL::Function* function;
|
||||||
|
MTL::ComputePipelineState* computePipeline;
|
||||||
|
MTL::Texture* accumulator;
|
||||||
|
MTL::Texture* resultTexture;
|
||||||
|
|
||||||
|
MTL::RenderPassDescriptor* renderPass;
|
||||||
|
MTL::RenderCommandEncoder* renderEncoder;
|
||||||
|
MTL::CommandBuffer* renderCmd;
|
||||||
|
|
||||||
|
MetalScene* scene;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,172 @@
|
|||||||
|
#include "MetalRenderer.h"
|
||||||
|
#include "Foundation/NSSharedPtr.hpp"
|
||||||
|
#include "Metal/MTLBlitCommandEncoder.hpp"
|
||||||
|
#include "Metal/MTLDrawable.hpp"
|
||||||
|
#include "Metal/MTLRenderPass.hpp"
|
||||||
|
#include "QuartzCore/CAMetalLayer.hpp"
|
||||||
|
#include "metal/MetalScene.h"
|
||||||
|
#include "scene/Renderer.h"
|
||||||
|
#include "util/Camera.h"
|
||||||
|
#include <Foundation/Foundation.hpp>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <Metal/Metal.hpp>
|
||||||
|
#include <QuartzCore/QuartzCore.hpp>
|
||||||
|
#include <QuartzCore/CAMetalLayer.h>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <imgui_impl_glfw.h>
|
||||||
|
#include <imgui_impl_metal.h>
|
||||||
|
|
||||||
|
MetalRenderer::MetalRenderer()
|
||||||
|
{
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||||
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||||
|
|
||||||
|
width = 1920;
|
||||||
|
height = 1080;
|
||||||
|
device = MTL::CreateSystemDefaultDevice();
|
||||||
|
|
||||||
|
library = device->newDefaultLibrary();
|
||||||
|
|
||||||
|
queue = device->newCommandQueue();
|
||||||
|
|
||||||
|
scene = new MetalScene(device, queue);
|
||||||
|
|
||||||
|
function = library->newFunction(NS::String::string("computeKernel", NS::ASCIIStringEncoding));
|
||||||
|
|
||||||
|
NS::Error* error;
|
||||||
|
computePipeline = device->newComputePipelineState(function, &error);
|
||||||
|
|
||||||
|
glfwInit();
|
||||||
|
float xscale = 1, yscale = 1;
|
||||||
|
glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, &yscale);
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
handle = glfwCreateWindow(width / xscale, height / yscale, "RayTracer", nullptr, nullptr);
|
||||||
|
|
||||||
|
int w, h;
|
||||||
|
glfwGetFramebufferSize(handle, &w, &h);
|
||||||
|
framebufferWidth = width;
|
||||||
|
framebufferHeight = height;
|
||||||
|
|
||||||
|
ImGui_ImplGlfw_InitForOpenGL(handle, false);
|
||||||
|
ImGui_ImplMetal_Init((__bridge id)device);
|
||||||
|
|
||||||
|
metalLayer = CA::MetalLayer::layer();
|
||||||
|
metalLayer->setDevice(device);
|
||||||
|
metalLayer->setPixelFormat(MTL::PixelFormatBGRA8Unorm);
|
||||||
|
metalLayer->setDrawableSize(CGSizeMake(w, h));
|
||||||
|
metalLayer->setFramebufferOnly(true);
|
||||||
|
CAMetalLayer* native_layer = (__bridge CAMetalLayer*)metalLayer;
|
||||||
|
NSWindow* cocoaWindow = glfwGetCocoaWindow(handle);
|
||||||
|
[[cocoaWindow contentView] setLayer:native_layer];
|
||||||
|
[[cocoaWindow contentView] setWantsLayer:YES];
|
||||||
|
[[cocoaWindow contentView] setNeedsLayout:YES];
|
||||||
|
|
||||||
|
renderPass= MTL::RenderPassDescriptor::alloc()->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
MetalRenderer::~MetalRenderer() {}
|
||||||
|
|
||||||
|
void MetalRenderer::beginFrame()
|
||||||
|
{
|
||||||
|
drawable = metalLayer->nextDrawable();
|
||||||
|
renderCmd = queue->commandBuffer();
|
||||||
|
MTL::RenderPassColorAttachmentDescriptor* colorAttachment = MTL::RenderPassColorAttachmentDescriptor::alloc()->init();
|
||||||
|
colorAttachment->setClearColor(MTL::ClearColor(0, 0, 0, 0));
|
||||||
|
colorAttachment->setTexture(drawable->texture());
|
||||||
|
colorAttachment->setLoadAction(MTL::LoadActionClear);
|
||||||
|
colorAttachment->setStoreAction(MTL::StoreActionStore);
|
||||||
|
renderPass->colorAttachments()->setObject(colorAttachment, 0);
|
||||||
|
renderEncoder = renderCmd->renderCommandEncoder(renderPass);
|
||||||
|
ImGui_ImplMetal_NewFrame((__bridge id)renderPass);
|
||||||
|
ImGui_ImplGlfw_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetalRenderer::update()
|
||||||
|
{
|
||||||
|
ImGui::Render();
|
||||||
|
ImGui_ImplMetal_RenderDrawData(ImGui::GetDrawData(), (__bridge id)renderCmd, (__bridge id)renderEncoder);
|
||||||
|
renderCmd->presentDrawable((const MTL::Drawable*)drawable);
|
||||||
|
renderCmd->commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetalRenderer::render(Camera camera, RenderParameter parameter)
|
||||||
|
{
|
||||||
|
GPUCamera gpuCam = {
|
||||||
|
.cameraPosition = camera.position,
|
||||||
|
.A = camera.A,
|
||||||
|
.cameraForward = camera.target - camera.position,
|
||||||
|
.f = camera.f,
|
||||||
|
.S_O = camera.S_O,
|
||||||
|
.sensorSize = camera.sensorSize,
|
||||||
|
.width = parameter.width,
|
||||||
|
.height = parameter.height,
|
||||||
|
};
|
||||||
|
|
||||||
|
MTL::TextureDescriptor* texDescriptor = MTL::TextureDescriptor::alloc()->init();
|
||||||
|
texDescriptor->setWidth(parameter.width);
|
||||||
|
texDescriptor->setHeight(parameter.height);
|
||||||
|
texDescriptor->setPixelFormat(MTL::PixelFormatRGBA32Float);
|
||||||
|
texDescriptor->setUsage(MTL::TextureUsageShaderWrite | MTL::TextureUsageShaderRead);
|
||||||
|
accumulator = device->newTexture(texDescriptor);
|
||||||
|
resultTexture = device->newTexture(texDescriptor);
|
||||||
|
for (uint i = 0; i < parameter.numSamples; ++i)
|
||||||
|
{
|
||||||
|
MTL::CommandBuffer* cmdBuffer = queue->commandBuffer();
|
||||||
|
MTL::ComputeCommandEncoder* encoder = cmdBuffer->computeCommandEncoder();
|
||||||
|
// cmdBuffer->addCompletedHandler([this](MTL::CommandBuffer* cmdBuffer)
|
||||||
|
// { std::memcpy(image.data(), resultTexture->buffer(), image.size() * sizeof(glm::vec3)); });
|
||||||
|
|
||||||
|
SampleParams sample = {
|
||||||
|
.pass = i,
|
||||||
|
.samplesPerPixel = parameter.numSamples,
|
||||||
|
.numDirectionalLights = scene->getNumDirLights(),
|
||||||
|
.numPointLights = scene->getNumPointLights(),
|
||||||
|
};
|
||||||
|
encoder->setComputePipelineState(computePipeline);
|
||||||
|
encoder->setBuffer(scene->indicesBuffer, 0, 0);
|
||||||
|
encoder->setBuffer(scene->positionBuffer, 0, 1);
|
||||||
|
encoder->setBuffer(scene->texCoordsBuffer, 0, 2);
|
||||||
|
encoder->setBuffer(scene->normalBuffer, 0, 3);
|
||||||
|
encoder->setBuffer(scene->modelRefsBuffer, 0, 4);
|
||||||
|
encoder->setBuffer(scene->directionalLightBuffer, 0, 5);
|
||||||
|
encoder->setBuffer(scene->pointLightBuffer, 0, 6);
|
||||||
|
encoder->setBuffer(scene->instanceBuffer, 0, 7);
|
||||||
|
encoder->setAccelerationStructure(scene->accelerationStructure, 8);
|
||||||
|
encoder->setTexture(accumulator, 0);
|
||||||
|
encoder->setTexture(resultTexture, 1);
|
||||||
|
encoder->setBytes(&gpuCam, sizeof(GPUCamera), 9);
|
||||||
|
encoder->setBytes(&sample, sizeof(SampleParams), 10);
|
||||||
|
encoder->useResource(scene->instanceBuffer, MTL::ResourceUsageRead);
|
||||||
|
encoder->useResource(scene->positionBuffer, MTL::ResourceUsageRead);
|
||||||
|
encoder->useResource(scene->texCoordsBuffer, MTL::ResourceUsageRead);
|
||||||
|
encoder->useResource(scene->normalBuffer, MTL::ResourceUsageRead);
|
||||||
|
encoder->useResource(scene->modelRefsBuffer, MTL::ResourceUsageRead);
|
||||||
|
if (scene->getNumDirLights() > 0)
|
||||||
|
{
|
||||||
|
encoder->useResource(scene->directionalLightBuffer, MTL::ResourceUsageRead);
|
||||||
|
}
|
||||||
|
if (scene->getNumPointLights() > 0)
|
||||||
|
{
|
||||||
|
encoder->useResource(scene->pointLightBuffer, MTL::ResourceUsageRead);
|
||||||
|
}
|
||||||
|
encoder->useResource(scene->instanceBuffer, MTL::ResourceUsageRead);
|
||||||
|
encoder->useResource(scene->accelerationStructure, MTL::ResourceUsageRead);
|
||||||
|
encoder->useResource(accumulator, MTL::ResourceUsageWrite);
|
||||||
|
encoder->useResource(resultTexture, MTL::ResourceUsageWrite);
|
||||||
|
NS::UInteger width = (NS::UInteger)parameter.width;
|
||||||
|
NS::UInteger height = (NS::UInteger)parameter.height;
|
||||||
|
MTL::Size threadsPerThreadgroup = MTL::Size(8, 8, 1);
|
||||||
|
MTL::Size threadgroups = MTL::Size((width + threadsPerThreadgroup.width - 1) / threadsPerThreadgroup.width,
|
||||||
|
(height + threadsPerThreadgroup.height - 1) / threadsPerThreadgroup.height, 1);
|
||||||
|
encoder->dispatchThreadgroups(threadgroups, threadsPerThreadgroup);
|
||||||
|
encoder->endEncoding();
|
||||||
|
MTL::BlitCommandEncoder* blitCommandEncoder = cmdBuffer->blitCommandEncoder();
|
||||||
|
blitCommandEncoder->copyFromTexture(resultTexture, 0, 0, MTL::Origin(), MTL::Size(parameter.width, parameter.height, 1), drawable->texture(), 0, 0, MTL::Origin());
|
||||||
|
cmdBuffer->commit();
|
||||||
|
cmdBuffer->waitUntilCompleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
#include "MetalScene.h"
|
|
||||||
|
|
||||||
MetalScene::MetalScene(MTL::Device* device, MTL::CommandQueue* queue)
|
|
||||||
: device(device), queue(queue)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
MetalScene::~MetalScene()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void MetalScene::createRayTracingHierarchy()
|
|
||||||
{
|
|
||||||
indicesBuffer = device->newBuffer(indicesPool.size() * sizeof(decltype(indicesPool)::value_type), MTL::ResourceStorageModeShared);
|
|
||||||
positionBuffer = device->newBuffer(positionPool.size() * sizeof(decltype(positionPool)::value_type), MTL::ResourceStorageModeShared);
|
|
||||||
texCoordsBuffer = device->newBuffer(texCoordsPool.size() * sizeof(decltype(texCoordsPool)::value_type), MTL::ResourceStorageModeShared);
|
|
||||||
normalBuffer = device->newBuffer(normalsPool.size() * sizeof(decltype(normalsPool)::value_type), MTL::ResourceStorageModeShared);
|
|
||||||
modelRefsBuffer = device->newBuffer(refs.size() * sizeof(decltype(refs)::value_type), MTL::ResourceStorageModeShared);
|
|
||||||
if(directionalLights.size() > 0)
|
|
||||||
{
|
|
||||||
directionalLightBuffer = device->newBuffer(directionalLights.size() * sizeof(decltype(directionalLights)::value_type), MTL::ResourceStorageModeShared);
|
|
||||||
std::memcpy(directionalLightBuffer->contents(), directionalLights.data(), directionalLights.size() * sizeof(decltype(directionalLights)::value_type));
|
|
||||||
}
|
|
||||||
if(pointLights.size() > 0)
|
|
||||||
{
|
|
||||||
pointLightBuffer = device->newBuffer(pointLights.size() * sizeof(decltype(pointLights)::value_type), MTL::ResourceStorageModeShared);
|
|
||||||
std::memcpy(pointLightBuffer->contents(), pointLights.data(), pointLights.size() * sizeof(decltype(pointLights)::value_type));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(indicesBuffer->contents(), indicesPool.data(), indicesPool.size() * sizeof(decltype(indicesPool)::value_type));
|
|
||||||
std::memcpy(positionBuffer->contents(), positionPool.data(), positionPool.size() * sizeof(decltype(positionPool)::value_type));
|
|
||||||
std::memcpy(texCoordsBuffer->contents(), texCoordsPool.data(), texCoordsPool.size() * sizeof(decltype(texCoordsPool)::value_type));
|
|
||||||
std::memcpy(normalBuffer->contents(), normalsPool.data(), normalsPool.size() * sizeof(decltype(normalsPool)::value_type));
|
|
||||||
std::memcpy(modelRefsBuffer->contents(), refs.data(), refs.size() * sizeof(decltype(refs)::value_type));
|
|
||||||
|
|
||||||
MTL::AccelerationStructure** primitiveAccelerationStructures = new MTL::AccelerationStructure*[refs.size()];
|
|
||||||
for(uint i = 0; i < refs.size(); ++i)
|
|
||||||
{
|
|
||||||
MTL::AccelerationStructureTriangleGeometryDescriptor* descriptor = MTL::AccelerationStructureTriangleGeometryDescriptor::descriptor();
|
|
||||||
descriptor->setTriangleCount(refs[i].numIndices / 3);
|
|
||||||
descriptor->setIndexBuffer(indicesBuffer);
|
|
||||||
descriptor->setIndexBufferOffset(refs[i].indicesOffset * sizeof(glm::uvec3));
|
|
||||||
descriptor->setIndexType(MTL::IndexTypeUInt32);
|
|
||||||
descriptor->setVertexBuffer(positionBuffer);
|
|
||||||
descriptor->setVertexBufferOffset(refs[i].positionOffset * sizeof(glm::vec3));
|
|
||||||
|
|
||||||
MTL::PrimitiveAccelerationStructureDescriptor* primitiveDescriptor = MTL::PrimitiveAccelerationStructureDescriptor::descriptor();
|
|
||||||
primitiveDescriptor->setGeometryDescriptors(NS::Array::array(descriptor));
|
|
||||||
|
|
||||||
primitiveAccelerationStructures[i] = device->newAccelerationStructure(primitiveDescriptor);
|
|
||||||
primitiveAccelerationStructures[i]->setLabel(NS::String::string("Primitive Structure", NS::ASCIIStringEncoding));
|
|
||||||
std::cout << primitiveAccelerationStructures[i]->debugDescription()->cString(NS::ASCIIStringEncoding) << std::endl;
|
|
||||||
}
|
|
||||||
NS::Array* primitiveArray = NS::Array::array((const NS::Object* const*)primitiveAccelerationStructures, refs.size());
|
|
||||||
std::cout << primitiveArray->debugDescription()->cString(NS::ASCIIStringEncoding) << std::endl;
|
|
||||||
instanceBuffer = device->newBuffer(sizeof(MTL::AccelerationStructureInstanceDescriptor) * refs.size(), MTL::ResourceOptionCPUCacheModeDefault);
|
|
||||||
|
|
||||||
MTL::AccelerationStructureInstanceDescriptor* instanceDescriptors = (MTL::AccelerationStructureInstanceDescriptor*)instanceBuffer->contents();
|
|
||||||
for(uint i = 0; i < refs.size(); ++i)
|
|
||||||
{
|
|
||||||
instanceDescriptors[i].transformationMatrix[0][0] = 1.0f;
|
|
||||||
instanceDescriptors[i].transformationMatrix[1][0] = 0.0f;
|
|
||||||
instanceDescriptors[i].transformationMatrix[2][0] = 0.0f;
|
|
||||||
instanceDescriptors[i].transformationMatrix[3][0] = 0.0f;
|
|
||||||
|
|
||||||
instanceDescriptors[i].transformationMatrix[0][1] = 0.0f;
|
|
||||||
instanceDescriptors[i].transformationMatrix[1][1] = 1.0f;
|
|
||||||
instanceDescriptors[i].transformationMatrix[2][1] = 0.0f;
|
|
||||||
instanceDescriptors[i].transformationMatrix[3][1] = 0.0f;
|
|
||||||
|
|
||||||
instanceDescriptors[i].transformationMatrix[0][2] = 0.0f;
|
|
||||||
instanceDescriptors[i].transformationMatrix[1][2] = 0.0f;
|
|
||||||
instanceDescriptors[i].transformationMatrix[2][2] = 1.0f;
|
|
||||||
instanceDescriptors[i].transformationMatrix[3][2] = 0.0f;
|
|
||||||
|
|
||||||
instanceDescriptors[i].accelerationStructureIndex = i;
|
|
||||||
|
|
||||||
instanceDescriptors[i].options = MTL::AccelerationStructureInstanceOptionOpaque;
|
|
||||||
instanceDescriptors[i].mask = 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
MTL::InstanceAccelerationStructureDescriptor* accelDesc = MTL::InstanceAccelerationStructureDescriptor::descriptor();
|
|
||||||
accelDesc->setInstancedAccelerationStructures(primitiveArray);
|
|
||||||
accelDesc->setInstanceDescriptorBuffer(instanceBuffer);
|
|
||||||
accelDesc->setInstanceCount(refs.size());
|
|
||||||
|
|
||||||
MTL::AccelerationStructureSizes accelSizes = device->accelerationStructureSizes(accelDesc);
|
|
||||||
MTL::AccelerationStructure* tempStructure = device->newAccelerationStructure(accelSizes.accelerationStructureSize);
|
|
||||||
tempStructure->setLabel(NS::String::string("Temporary AS", NS::ASCIIStringEncoding));
|
|
||||||
MTL::Buffer* scratchBuffer = device->newBuffer(accelSizes.buildScratchBufferSize, MTL::StorageModeManaged);
|
|
||||||
MTL::CommandBuffer* cmdBuffer = queue->commandBuffer();
|
|
||||||
MTL::AccelerationStructureCommandEncoder* encoder = cmdBuffer->accelerationStructureCommandEncoder();
|
|
||||||
MTL::Buffer* compactedBuffer = device->newBuffer(sizeof(uint), MTL::ResourceOptionCPUCacheModeDefault);
|
|
||||||
encoder->buildAccelerationStructure(tempStructure, accelDesc, scratchBuffer, 0);
|
|
||||||
encoder->writeCompactedAccelerationStructureSize(tempStructure, compactedBuffer, 0);
|
|
||||||
encoder->endEncoding();
|
|
||||||
cmdBuffer->commit();
|
|
||||||
cmdBuffer->waitUntilCompleted();
|
|
||||||
uint compactedSize = *(uint*)compactedBuffer->contents();
|
|
||||||
accelerationStructure = device->newAccelerationStructure(compactedSize);
|
|
||||||
accelerationStructure->setLabel(NS::String::string("Instance AS", NS::ASCIIStringEncoding));
|
|
||||||
cmdBuffer = queue->commandBuffer();
|
|
||||||
encoder = cmdBuffer->accelerationStructureCommandEncoder();
|
|
||||||
encoder->copyAndCompactAccelerationStructure(tempStructure, accelerationStructure);
|
|
||||||
encoder->endEncoding();
|
|
||||||
cmdBuffer->commit();
|
|
||||||
cmdBuffer->waitUntilCompleted();
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
#include "MetalScene.h"
|
||||||
|
|
||||||
|
MetalScene::MetalScene(MTL::Device* device, MTL::CommandQueue* queue) : device(device), queue(queue) {}
|
||||||
|
|
||||||
|
MetalScene::~MetalScene() {}
|
||||||
|
|
||||||
|
void MetalScene::createRayTracingHierarchy()
|
||||||
|
{
|
||||||
|
indicesBuffer = device->newBuffer(indicesPool.size() * sizeof(decltype(indicesPool)::value_type), MTL::ResourceStorageModeShared);
|
||||||
|
positionBuffer = device->newBuffer(positionPool.size() * sizeof(decltype(positionPool)::value_type), MTL::ResourceStorageModeShared);
|
||||||
|
texCoordsBuffer = device->newBuffer(texCoordsPool.size() * sizeof(decltype(texCoordsPool)::value_type), MTL::ResourceStorageModeShared);
|
||||||
|
normalBuffer = device->newBuffer(normalsPool.size() * sizeof(decltype(normalsPool)::value_type), MTL::ResourceStorageModeShared);
|
||||||
|
modelRefsBuffer = device->newBuffer(refs.size() * sizeof(decltype(refs)::value_type), MTL::ResourceStorageModeShared);
|
||||||
|
if (directionalLights.size() > 0)
|
||||||
|
{
|
||||||
|
directionalLightBuffer =
|
||||||
|
device->newBuffer(directionalLights.size() * sizeof(decltype(directionalLights)::value_type), MTL::ResourceStorageModeShared);
|
||||||
|
std::memcpy(directionalLightBuffer->contents(), directionalLights.data(),
|
||||||
|
directionalLights.size() * sizeof(decltype(directionalLights)::value_type));
|
||||||
|
}
|
||||||
|
if (pointLights.size() > 0)
|
||||||
|
{
|
||||||
|
pointLightBuffer = device->newBuffer(pointLights.size() * sizeof(decltype(pointLights)::value_type), MTL::ResourceStorageModeShared);
|
||||||
|
std::memcpy(pointLightBuffer->contents(), pointLights.data(), pointLights.size() * sizeof(decltype(pointLights)::value_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(indicesBuffer->contents(), indicesPool.data(), indicesPool.size() * sizeof(decltype(indicesPool)::value_type));
|
||||||
|
std::memcpy(positionBuffer->contents(), positionPool.data(), positionPool.size() * sizeof(decltype(positionPool)::value_type));
|
||||||
|
std::memcpy(texCoordsBuffer->contents(), texCoordsPool.data(), texCoordsPool.size() * sizeof(decltype(texCoordsPool)::value_type));
|
||||||
|
std::memcpy(normalBuffer->contents(), normalsPool.data(), normalsPool.size() * sizeof(decltype(normalsPool)::value_type));
|
||||||
|
std::memcpy(modelRefsBuffer->contents(), refs.data(), refs.size() * sizeof(decltype(refs)::value_type));
|
||||||
|
|
||||||
|
CFTypeRef* descriptors = new CFTypeRef[refs.size()];
|
||||||
|
MTL::AccelerationStructure** primitiveAccelerationStructures = new MTL::AccelerationStructure*[refs.size()];
|
||||||
|
for (uint i = 0; i < refs.size(); ++i)
|
||||||
|
{
|
||||||
|
MTL::AccelerationStructureTriangleGeometryDescriptor* descriptor = MTL::AccelerationStructureTriangleGeometryDescriptor::descriptor();
|
||||||
|
descriptor->setTriangleCount(refs[i].numIndices / 3);
|
||||||
|
descriptor->setIndexBuffer(indicesBuffer);
|
||||||
|
descriptor->setIndexBufferOffset(refs[i].indicesOffset * sizeof(glm::uvec3));
|
||||||
|
descriptor->setIndexType(MTL::IndexTypeUInt32);
|
||||||
|
descriptor->setVertexBuffer(positionBuffer);
|
||||||
|
descriptor->setVertexBufferOffset(refs[i].positionOffset * sizeof(glm::vec3));
|
||||||
|
|
||||||
|
MTL::PrimitiveAccelerationStructureDescriptor* primitiveDescriptor = MTL::PrimitiveAccelerationStructureDescriptor::descriptor();
|
||||||
|
primitiveDescriptor->setGeometryDescriptors(NS::Array::array(descriptor));
|
||||||
|
|
||||||
|
primitiveAccelerationStructures[i] = device->newAccelerationStructure(primitiveDescriptor);
|
||||||
|
primitiveAccelerationStructures[i]->setLabel(NS::String::string("Primitive Structure", NS::ASCIIStringEncoding));
|
||||||
|
std::cout << primitiveAccelerationStructures[i]->debugDescription()->cString(NS::ASCIIStringEncoding) << std::endl;
|
||||||
|
descriptors[i] = (CFTypeRef)primitiveAccelerationStructures[i];
|
||||||
|
}
|
||||||
|
instanceBuffer =
|
||||||
|
device->newBuffer(sizeof(MTL::AccelerationStructureInstanceDescriptor) * refs.size(), MTL::ResourceOptionCPUCacheModeDefault);
|
||||||
|
|
||||||
|
MTL::AccelerationStructureInstanceDescriptor* instanceDescriptors =
|
||||||
|
(MTL::AccelerationStructureInstanceDescriptor*)instanceBuffer->contents();
|
||||||
|
for (uint i = 0; i < refs.size(); ++i)
|
||||||
|
{
|
||||||
|
instanceDescriptors[i].transformationMatrix[0][0] = 1.0f;
|
||||||
|
instanceDescriptors[i].transformationMatrix[1][0] = 0.0f;
|
||||||
|
instanceDescriptors[i].transformationMatrix[2][0] = 0.0f;
|
||||||
|
instanceDescriptors[i].transformationMatrix[3][0] = 0.0f;
|
||||||
|
|
||||||
|
instanceDescriptors[i].transformationMatrix[0][1] = 0.0f;
|
||||||
|
instanceDescriptors[i].transformationMatrix[1][1] = 1.0f;
|
||||||
|
instanceDescriptors[i].transformationMatrix[2][1] = 0.0f;
|
||||||
|
instanceDescriptors[i].transformationMatrix[3][1] = 0.0f;
|
||||||
|
|
||||||
|
instanceDescriptors[i].transformationMatrix[0][2] = 0.0f;
|
||||||
|
instanceDescriptors[i].transformationMatrix[1][2] = 0.0f;
|
||||||
|
instanceDescriptors[i].transformationMatrix[2][2] = 1.0f;
|
||||||
|
instanceDescriptors[i].transformationMatrix[3][2] = 0.0f;
|
||||||
|
|
||||||
|
instanceDescriptors[i].accelerationStructureIndex = i;
|
||||||
|
|
||||||
|
instanceDescriptors[i].options = MTL::AccelerationStructureInstanceOptionOpaque;
|
||||||
|
instanceDescriptors[i].mask = 0xff;
|
||||||
|
}
|
||||||
|
NS::Array* pGeoDescriptors = ( NS::Array* )( CFArrayCreate( kCFAllocatorDefault, descriptors, refs.size(), &kCFTypeArrayCallBacks ) );
|
||||||
|
MTL::InstanceAccelerationStructureDescriptor* accelDesc = MTL::InstanceAccelerationStructureDescriptor::descriptor();
|
||||||
|
accelDesc->setInstancedAccelerationStructures(pGeoDescriptors);
|
||||||
|
accelDesc->setInstanceDescriptorBuffer(instanceBuffer);
|
||||||
|
accelDesc->setInstanceCount(refs.size());
|
||||||
|
|
||||||
|
MTL::AccelerationStructureSizes accelSizes = device->accelerationStructureSizes(accelDesc);
|
||||||
|
MTL::AccelerationStructure* tempStructure = device->newAccelerationStructure(accelSizes.accelerationStructureSize);
|
||||||
|
tempStructure->setLabel(NS::String::string("Temporary AS", NS::ASCIIStringEncoding));
|
||||||
|
MTL::Buffer* scratchBuffer = device->newBuffer(accelSizes.buildScratchBufferSize, MTL::StorageModeManaged);
|
||||||
|
MTL::CommandBuffer* cmdBuffer = queue->commandBuffer();
|
||||||
|
MTL::AccelerationStructureCommandEncoder* encoder = cmdBuffer->accelerationStructureCommandEncoder();
|
||||||
|
MTL::Buffer* compactedBuffer = device->newBuffer(sizeof(uint), MTL::ResourceOptionCPUCacheModeDefault);
|
||||||
|
encoder->buildAccelerationStructure(tempStructure, accelDesc, scratchBuffer, 0);
|
||||||
|
encoder->writeCompactedAccelerationStructureSize(tempStructure, compactedBuffer, 0);
|
||||||
|
encoder->endEncoding();
|
||||||
|
cmdBuffer->commit();
|
||||||
|
cmdBuffer->waitUntilCompleted();
|
||||||
|
uint compactedSize = *(uint*)compactedBuffer->contents();
|
||||||
|
accelerationStructure = device->newAccelerationStructure(compactedSize);
|
||||||
|
accelerationStructure->setLabel(NS::String::string("Instance AS", NS::ASCIIStringEncoding));
|
||||||
|
cmdBuffer = queue->commandBuffer();
|
||||||
|
encoder = cmdBuffer->accelerationStructureCommandEncoder();
|
||||||
|
encoder->copyAndCompactAccelerationStructure(tempStructure, accelerationStructure);
|
||||||
|
encoder->endEncoding();
|
||||||
|
cmdBuffer->commit();
|
||||||
|
cmdBuffer->waitUntilCompleted();
|
||||||
|
}
|
||||||
@@ -16,8 +16,6 @@ void Renderer::startRender(Camera cam, RenderParameter params)
|
|||||||
worker.join();
|
worker.join();
|
||||||
}
|
}
|
||||||
sampleTimes.clear();
|
sampleTimes.clear();
|
||||||
image.clear();
|
|
||||||
image.resize(params.width * params.height);
|
|
||||||
running = true;
|
running = true;
|
||||||
worker = std::thread(&Renderer::render, this, cam, params);
|
worker = std::thread(&Renderer::render, this, cam, params);
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Scene.h"
|
#include "Scene.h"
|
||||||
#include "ThreadPool.h"
|
|
||||||
#include "util/Camera.h"
|
#include "util/Camera.h"
|
||||||
#include "window/Window.h"
|
#include <thread>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
||||||
struct RenderParameter
|
struct RenderParameter
|
||||||
@@ -23,13 +22,15 @@ public:
|
|||||||
virtual void addModels(std::vector<PModel> models, glm::mat4 transform) = 0;
|
virtual void addModels(std::vector<PModel> models, glm::mat4 transform) = 0;
|
||||||
virtual void generate() = 0;
|
virtual void generate() = 0;
|
||||||
void startRender(Camera cam, RenderParameter params);
|
void startRender(Camera cam, RenderParameter params);
|
||||||
constexpr const std::vector<glm::vec3>& getImage() const { return image; }
|
|
||||||
constexpr const std::vector<float>& getSampleTimes() const { return sampleTimes; }
|
constexpr const std::vector<float>& getSampleTimes() const { return sampleTimes; }
|
||||||
constexpr const float getLastSampleTime() const { return sampleTimes.empty() ? 0 : sampleTimes.back(); }
|
constexpr const float getLastSampleTime() const { return sampleTimes.empty() ? 0 : sampleTimes.back(); }
|
||||||
constexpr const float getAverageSampleTime() const
|
constexpr const float getAverageSampleTime() const
|
||||||
{
|
{
|
||||||
return std::accumulate(sampleTimes.begin(), sampleTimes.end(), 0.0f) / sampleTimes.size();
|
return std::accumulate(sampleTimes.begin(), sampleTimes.end(), 0.0f) / sampleTimes.size();
|
||||||
}
|
}
|
||||||
|
// main thread
|
||||||
|
virtual void beginFrame() = 0;
|
||||||
|
virtual void update() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void render(Camera cam, RenderParameter params) = 0;
|
virtual void render(Camera cam, RenderParameter params) = 0;
|
||||||
@@ -38,6 +39,4 @@ protected:
|
|||||||
std::vector<float> sampleTimes;
|
std::vector<float> sampleTimes;
|
||||||
float lastSampleTime;
|
float lastSampleTime;
|
||||||
float averageSampleTime;
|
float averageSampleTime;
|
||||||
// the thing being displayed
|
|
||||||
std::vector<glm::vec3> image;
|
|
||||||
};
|
};
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
target_sources(RayTracer
|
|
||||||
PRIVATE
|
|
||||||
Window.h
|
|
||||||
Window.cpp)
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
#include "Window.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <imgui_impl_glfw.h>
|
|
||||||
#include <imgui_impl_opengl3.h>
|
|
||||||
|
|
||||||
#define GLSL(...) "#version 400\n" #__VA_ARGS__
|
|
||||||
|
|
||||||
Window::Window(int width, int height) : width(width), height(height)
|
|
||||||
{
|
|
||||||
glewExperimental = true;
|
|
||||||
glfwInit();
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We don't want the old OpenGL
|
|
||||||
window = glfwCreateWindow(width, height, "RayTracer", nullptr, nullptr);
|
|
||||||
glfwSwapInterval(1);
|
|
||||||
glfwMakeContextCurrent(window);
|
|
||||||
|
|
||||||
IMGUI_CHECKVERSION();
|
|
||||||
ImGui::CreateContext();
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
|
||||||
|
|
||||||
ImGui_ImplGlfw_InitForOpenGL(window,
|
|
||||||
true); // Second param install_callback=true will install GLFW callbacks and chain to existing ones.
|
|
||||||
ImGui_ImplOpenGL3_Init();
|
|
||||||
|
|
||||||
glewInit();
|
|
||||||
|
|
||||||
glGenVertexArrays(1, &vao);
|
|
||||||
glBindVertexArray(vao);
|
|
||||||
|
|
||||||
glGenTextures(1, &texture);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_FLOAT, nullptr);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
||||||
|
|
||||||
program = glCreateProgram();
|
|
||||||
vertShader = glCreateShader(GL_VERTEX_SHADER);
|
|
||||||
fragShader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
||||||
int logLen = 0;
|
|
||||||
const char* vertCode =
|
|
||||||
GLSL(out vec2 texcoords; // texcoords are in the normalized [0,1] range for the viewport-filling quad part of the triangle
|
|
||||||
void main() {
|
|
||||||
vec2 vertices[3] = vec2[3](vec2(-1, -1), vec2(3, -1), vec2(-1, 3));
|
|
||||||
gl_Position = vec4(vertices[gl_VertexID], 0, 1);
|
|
||||||
texcoords = 0.5 * gl_Position.xy + vec2(0.5);
|
|
||||||
});
|
|
||||||
const char* fragCode = GLSL(in vec2 texcoords; out vec4 color;
|
|
||||||
|
|
||||||
uniform sampler2D tex;
|
|
||||||
|
|
||||||
void main() { color = texture(tex, vec2(texcoords.x, -texcoords.y)); });
|
|
||||||
glShaderSource(vertShader, 1, &vertCode, nullptr);
|
|
||||||
glCompileShader(vertShader);
|
|
||||||
int success;
|
|
||||||
char infoLog[1024];
|
|
||||||
glGetShaderiv(vertShader, GL_COMPILE_STATUS, &success);
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
glGetShaderInfoLog(vertShader, 1024, NULL, infoLog);
|
|
||||||
std::cout << "ERROR::SHADER_COMPILATION_ERROR\n"
|
|
||||||
<< infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
glShaderSource(fragShader, 1, &fragCode, nullptr);
|
|
||||||
glCompileShader(fragShader);
|
|
||||||
glGetShaderiv(fragShader, GL_COMPILE_STATUS, &success);
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
glGetShaderInfoLog(fragShader, 1024, NULL, infoLog);
|
|
||||||
std::cout << "ERROR::SHADER_COMPILATION_ERROR\n"
|
|
||||||
<< infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
glAttachShader(program, vertShader);
|
|
||||||
glAttachShader(program, fragShader);
|
|
||||||
|
|
||||||
glLinkProgram(program);
|
|
||||||
glGetProgramiv(program, GL_LINK_STATUS, &logLen);
|
|
||||||
if (logLen > 0)
|
|
||||||
{
|
|
||||||
std::vector<char> log(logLen);
|
|
||||||
glGetProgramInfoLog(program, logLen, &logLen, log.data());
|
|
||||||
std::cout << log.data() << std::endl;
|
|
||||||
}
|
|
||||||
glDeleteShader(vertShader);
|
|
||||||
glDeleteShader(fragShader);
|
|
||||||
glClearColor(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Window::~Window() {}
|
|
||||||
|
|
||||||
void Window::beginFrame()
|
|
||||||
{
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
glfwPollEvents();
|
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
|
||||||
ImGui_ImplGlfw_NewFrame();
|
|
||||||
ImGui::NewFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::update(const std::vector<glm::vec3>& textureData)
|
|
||||||
{
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGB, GL_FLOAT, textureData.data());
|
|
||||||
glUseProgram(program);
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
||||||
ImGui::Render();
|
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
||||||
glfwSwapBuffers(window);
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <GL/glew.h>
|
|
||||||
#include <glfw/glfw3.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
class Window
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Window(int width, int height);
|
|
||||||
~Window();
|
|
||||||
void beginFrame();
|
|
||||||
void update(const std::vector<glm::vec3>& textureData);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
GLuint vao;
|
|
||||||
GLuint texture;
|
|
||||||
GLuint program;
|
|
||||||
GLuint vertShader;
|
|
||||||
GLuint fragShader;
|
|
||||||
GLFWwindow* window;
|
|
||||||
};
|
|
||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
"dependencies": [
|
"dependencies": [
|
||||||
{
|
{
|
||||||
"name": "imgui",
|
"name": "imgui",
|
||||||
"features": [ "glfw-binding", "opengl3-binding" ]
|
"features": [ "glfw-binding", "opengl3-binding", "metal-binding" ]
|
||||||
},
|
},
|
||||||
"vulkan",
|
"vulkan",
|
||||||
"vulkan-memory-allocator",
|
"vulkan-memory-allocator",
|
||||||
|
|||||||
Reference in New Issue
Block a user