Adding preliminary metal support (it sucks)
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
target_sources(RayTracer
|
||||
PRIVATE
|
||||
MetalRenderer.h
|
||||
MetalRenderer.cpp
|
||||
MetalScene.h
|
||||
MetalScene.cpp
|
||||
Compute.metal
|
||||
PrivateImpl.mm)
|
||||
@@ -0,0 +1,272 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
#include <metal_numeric>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
using namespace raytracing;
|
||||
|
||||
|
||||
enum class MaterialType
|
||||
{
|
||||
BlinnPhong
|
||||
};
|
||||
|
||||
struct GPUCamera
|
||||
{
|
||||
packed_float3 position;
|
||||
float f;
|
||||
packed_float3 forward;
|
||||
float S_O;
|
||||
packed_float3 fogEmm;
|
||||
float ks;
|
||||
float A;
|
||||
float ka;
|
||||
float2 sensorSize;
|
||||
uint width;
|
||||
uint height;
|
||||
};
|
||||
|
||||
struct SampleParams
|
||||
{
|
||||
uint pass;
|
||||
uint samplesPerPixel;
|
||||
uint numDirectionalLights;
|
||||
uint numPointLights;
|
||||
};
|
||||
|
||||
struct Payload
|
||||
{
|
||||
float3 rnd01;
|
||||
float3 accumulatedRadiance = float3(0);
|
||||
float3 accumulatedMaterial = float3(1);
|
||||
uint depth = 0;
|
||||
float emissive = 1;
|
||||
};
|
||||
|
||||
struct ModelReference
|
||||
{
|
||||
uint positionOffset = 0;
|
||||
uint numPositions = 0;
|
||||
uint indicesOffset = 0;
|
||||
uint numIndices = 0;
|
||||
};
|
||||
|
||||
struct HitInfo
|
||||
{
|
||||
float t = numeric_limits<float>::max();
|
||||
float3 position;
|
||||
float3 normal;
|
||||
// not entirely sure what that does
|
||||
// its the normal being flipped based on some dot product
|
||||
float3 normalLight;
|
||||
float2 texCoords;
|
||||
};
|
||||
|
||||
struct BRDF
|
||||
{
|
||||
float3 albedo = float3(1, 1, 1);
|
||||
float alpha = 1;
|
||||
float3 specularColor = float3(1, 1, 1);
|
||||
float shininess = 0.04;
|
||||
float3 emissive = float3(0, 0, 0);
|
||||
MaterialType materialType;
|
||||
float3 evaluate(HitInfo hit, float3 viewDir, float3 lightDir, float3 lightColor)
|
||||
{
|
||||
float3 normal = hit.normal;
|
||||
float diffuse = max(dot(normal, lightDir), 0.0f);
|
||||
float3 h = normalize(lightDir + viewDir);
|
||||
float specular = pow(min(max(dot(normal, h), 0.0f), 1.0f), shininess);
|
||||
|
||||
return (albedo * diffuse * lightColor) + float3(0.03, 0.03, 0.03);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct PointLight
|
||||
{
|
||||
float3 position = float3(0, 0, 0);
|
||||
packed_float3 color = float3(1, 1, 1);
|
||||
float attenuation = 1;
|
||||
};
|
||||
|
||||
struct DirectionalLight
|
||||
{
|
||||
float3 direction = float3(0, 1, 0);
|
||||
float3 color = float3(1, 1, 1);
|
||||
};
|
||||
|
||||
float3 rand01(uint3 x)
|
||||
{ // pseudo-random number generator
|
||||
for (int i = 3; i-- > 0;)
|
||||
x = ((x >> 8U) ^ uint3(x.y, x.z, x.x)) * 1103515245U;
|
||||
return float3(x) * (1.0f / float(0xffffffffU));
|
||||
}
|
||||
|
||||
template<typename T, typename IndexType>
|
||||
inline T interpolateVertexAttribute(constant T *attributes,
|
||||
uint offset,
|
||||
IndexType i0,
|
||||
IndexType i1,
|
||||
IndexType i2,
|
||||
float2 uv) {
|
||||
// Look up value for each vertex.
|
||||
const T T0 = attributes[offset + i0];
|
||||
const T T1 = attributes[offset + i1];
|
||||
const T T2 = attributes[offset + i2];
|
||||
|
||||
// Compute the sum of the vertex attributes weighted by the barycentric coordinates.
|
||||
// The barycentric coordinates sum to one.
|
||||
return (1.0f - uv.x - uv.y) * T0 + uv.x * T1 + uv.y * T2;
|
||||
}
|
||||
|
||||
kernel void computeKernel(
|
||||
uint2 threadId [[thread_position_in_grid]],
|
||||
constant GPUCamera& camera,
|
||||
constant SampleParams& sample,
|
||||
constant packed_uint3* indexBuffer [[buffer(0)]],
|
||||
constant packed_float3* positions [[buffer(1)]],
|
||||
constant packed_float2* texCoords [[buffer(2)]],
|
||||
constant packed_float3* normals [[buffer(3)]],
|
||||
constant ModelReference* modelRefs [[buffer(4)]],
|
||||
constant DirectionalLight* directionalLights [[buffer(5)]],
|
||||
constant PointLight* pointLights [[buffer(6)]],
|
||||
constant MTLAccelerationStructureInstanceDescriptor* instances [[buffer(7)]],
|
||||
instance_acceleration_structure accelerationStructure [[buffer(8)]],
|
||||
device packed_float3* accumulator [[buffer(9)]],
|
||||
device packed_float3* image [[buffer(10)]]
|
||||
)
|
||||
{
|
||||
Payload payload;
|
||||
ray cam;
|
||||
cam.origin = camera.position;
|
||||
cam.direction = normalize(camera.forward);
|
||||
cam.max_distance = INFINITY;
|
||||
float3 cx =
|
||||
normalize(cross(cam.direction, abs(cam.direction.y) < 0.9 ? float3(0, 1, 0) : float3(0, 0, 1))),
|
||||
cy = cross(cx, cam.direction);
|
||||
const float2 sdim = camera.sensorSize; // sensor size (36 x 24 mm)
|
||||
|
||||
float S_I = (camera.S_O * camera.f) / (camera.S_O - camera.f);
|
||||
|
||||
//-- sample sensor
|
||||
uint2 pix = threadId;
|
||||
if(pix.x >= camera.width || pix.y >= camera.height)
|
||||
return;
|
||||
|
||||
payload.rnd01 = rand01(uint3(pix, sample.pass));
|
||||
float2 rnd2 = 2.0f * float2(payload.rnd01.xy); // vvv tent filter sample
|
||||
float2 tent =
|
||||
float2(rnd2.x < 1 ? sqrt(rnd2.x) - 1 : 1 - sqrt(2 - rnd2.x), rnd2.y < 1 ? sqrt(rnd2.y) - 1 : 1 - sqrt(2 - rnd2.y));
|
||||
float2 s =
|
||||
((float2(pix) + 0.5f * (0.5f + float2((sample.pass / 2) % 2, sample.pass % 2) + tent)) / float2(camera.width, camera.height) -
|
||||
0.5f) *
|
||||
sdim;
|
||||
float3 spos = cam.origin + cx * s.x + cy * s.y, lc = cam.origin + cam.direction * 0.035f; // sample on 3d sensor plane
|
||||
cam.origin = lc;
|
||||
cam.direction = normalize(lc - spos); // construct ray
|
||||
|
||||
//-- setup lens
|
||||
float3 lensP = lc;
|
||||
float3 lensN = -cam.direction;
|
||||
float3 lensX = cross(lensN, float3(0, 1, 0)); // the exact vector doesnt matter
|
||||
float3 lensY = cross(lensN, lensX);
|
||||
|
||||
float3 lensSample = lensP + payload.rnd01.x * camera.A * lensX + payload.rnd01.y * camera.A * lensY;
|
||||
|
||||
float3 focalPoint = cam.origin + (camera.S_O + S_I) * cam.direction;
|
||||
float t = dot(focalPoint - cam.origin, lensN) / dot(cam.direction, lensN);
|
||||
float3 focus = cam.origin + t * cam.direction;
|
||||
cam.origin = lensSample;
|
||||
cam.direction = normalize(focus - lensSample); // TODO: Fix lens
|
||||
|
||||
intersector<triangle_data, instancing> i;
|
||||
i.assume_geometry_type(geometry_type::triangle);
|
||||
i.force_opacity(forced_opacity::opaque);
|
||||
|
||||
typename intersector<triangle_data, instancing>::result_type intersection;
|
||||
while(payload.depth < 12) {
|
||||
i.accept_any_intersection(false);
|
||||
|
||||
intersection = i.intersect(cam, accelerationStructure, 0xff);
|
||||
|
||||
if(intersection.type == intersection_type::none)
|
||||
break;
|
||||
|
||||
uint instanceId = intersection.instance_id;
|
||||
constant ModelReference& ref = modelRefs[instanceId];
|
||||
|
||||
HitInfo info;
|
||||
info.t = intersection.distance;
|
||||
const auto indices = indexBuffer[ref.indicesOffset + intersection.primitive_id];
|
||||
info.position = interpolateVertexAttribute(positions, ref.positionOffset, indices.x, indices.y, indices.z, intersection.triangle_barycentric_coord);
|
||||
info.texCoords = interpolateVertexAttribute(texCoords, ref.positionOffset, indices.x, indices.y, indices.z, intersection.triangle_barycentric_coord);
|
||||
info.normal = interpolateVertexAttribute(normals, ref.positionOffset, indices.x, indices.y, indices.z, intersection.triangle_barycentric_coord);
|
||||
info.normalLight = dot(info.normal, cam.direction) < 0 ? info.normal : -info.normal;
|
||||
|
||||
BRDF brdf;
|
||||
brdf.albedo = float3(0, 1, 0);
|
||||
|
||||
float p = max(max(brdf.albedo.x, brdf.albedo.y), brdf.albedo.z);
|
||||
if (payload.depth > 5)
|
||||
{
|
||||
if (payload.rnd01.z >= p)
|
||||
return;
|
||||
else
|
||||
payload.accumulatedMaterial /= p;
|
||||
}
|
||||
// emissive
|
||||
payload.accumulatedRadiance += payload.accumulatedMaterial * brdf.emissive * payload.emissive;
|
||||
payload.accumulatedMaterial *= brdf.albedo;
|
||||
|
||||
// direct lighting
|
||||
for (uint l = 0; l < sample.numDirectionalLights; ++l)
|
||||
{
|
||||
// if there is an intersection, the light is occluded so no lighting
|
||||
ray shadowRay;
|
||||
shadowRay.origin = info.position + info.normal * 1e-3f;
|
||||
shadowRay.direction = -directionalLights[l].direction;
|
||||
shadowRay.max_distance = INFINITY;
|
||||
i.accept_any_intersection(true);
|
||||
intersection = i.intersect(shadowRay, accelerationStructure, 0xff);
|
||||
if(intersection.type != intersection_type::none)
|
||||
{
|
||||
payload.accumulatedRadiance += brdf.evaluate(info, -cam.direction, shadowRay.direction, directionalLights[l].color);
|
||||
}
|
||||
}
|
||||
for (uint l = 0; l < sample.numPointLights; ++l)
|
||||
{
|
||||
float3 lightDir = pointLights[l].position - info.position;
|
||||
ray shadowRay;
|
||||
shadowRay.origin = info.position + info.normal * 1e-3f;
|
||||
shadowRay.direction = lightDir;
|
||||
shadowRay.max_distance = 1;
|
||||
i.accept_any_intersection(true);
|
||||
intersection = i.intersect(shadowRay, accelerationStructure, 0xff);
|
||||
if (intersection.type != intersection_type::none)
|
||||
{
|
||||
float d = length(lightDir);
|
||||
float illuminance = max(1 - d / pointLights[l].attenuation, 0.0f);
|
||||
|
||||
payload.accumulatedRadiance += illuminance * brdf.evaluate(info, -cam.direction, normalize(lightDir), pointLights[l].color);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Next Event Estimation for mesh lights
|
||||
|
||||
// indirect lighting
|
||||
float r1 = 2 * M_PI_F * payload.rnd01.x;
|
||||
float r2 = payload.rnd01.y;
|
||||
float r2s = sqrt(r2);
|
||||
float3 w = info.normalLight;
|
||||
float3 u = normalize(cross(abs(w.x) > 0.1 ? float3(0, 1, 0) : float3(1, 0, 0), w));
|
||||
float3 v = cross(w, u);
|
||||
cam.origin = info.position;
|
||||
cam.direction = normalize(u * cos(r1) * r2s + v * sin(r1) * r2s + w * sqrt(1 - r2));
|
||||
payload.emissive = 0;
|
||||
payload.depth++;
|
||||
}
|
||||
float resolver = float(sample.samplesPerPixel) / float(sample.pass+1);
|
||||
accumulator[threadId.x + threadId.y * camera.width] += payload.accumulatedRadiance / float(sample.samplesPerPixel);
|
||||
image[threadId.x + threadId.y * camera.width] = pow(max(accumulator[threadId.x + threadId.y * camera.width] * resolver, 0), float3(0.45f));
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
#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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include "metal/MetalScene.h"
|
||||
#include "scene/Renderer.h"
|
||||
#include "util/Camera.h"
|
||||
#include <Foundation/Foundation.hpp>
|
||||
#include <Metal/Metal.hpp>
|
||||
#include <QuartzCore/QuartzCore.hpp>
|
||||
|
||||
struct GPUCamera
|
||||
{
|
||||
glm::vec3 cameraPosition;
|
||||
float f;
|
||||
glm::vec3 cameraForward;
|
||||
float S_O;
|
||||
glm::vec3 fogEmm;
|
||||
float ks;
|
||||
float A;
|
||||
float ka;
|
||||
glm::vec2 sensorSize;
|
||||
uint width;
|
||||
uint height;
|
||||
};
|
||||
|
||||
struct SampleParams
|
||||
{
|
||||
uint pass;
|
||||
uint samplesPerPixel;
|
||||
uint numDirectionalLights;
|
||||
uint numPointLights;
|
||||
};
|
||||
|
||||
class MetalRenderer : public Renderer
|
||||
{
|
||||
public:
|
||||
MetalRenderer();
|
||||
virtual ~MetalRenderer();
|
||||
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 render(Camera camera, RenderParameter params) override;
|
||||
|
||||
private:
|
||||
MTL::Device* device;
|
||||
MTL::Library* library;
|
||||
MTL::CommandQueue* queue;
|
||||
MTL::Function* function;
|
||||
MTL::ComputePipelineState* computePipeline;
|
||||
MTL::Buffer* accumulator;
|
||||
MTL::Buffer* resultTexture;
|
||||
|
||||
MetalScene* scene;
|
||||
};
|
||||
@@ -0,0 +1,110 @@
|
||||
#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);
|
||||
descriptor->setVertexBufferOffset(refs[i].positionOffset);
|
||||
descriptor->setVertexBuffer(positionBuffer);
|
||||
descriptor->setIndexType(MTL::IndexTypeUInt32);
|
||||
|
||||
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());
|
||||
|
||||
accelerationStructure = device->newAccelerationStructure(accelDesc);
|
||||
accelerationStructure->setLabel(NS::String::string("InstanceAccelerationStructure", NS::ASCIIStringEncoding));
|
||||
std::cout << accelerationStructure->debugDescription()->cString(NS::ASCIIStringEncoding) << std::endl;
|
||||
/*MTL::AccelerationStructureSizes accelSizes = device->accelerationStructureSizes(accelDesc);
|
||||
MTL::AccelerationStructure* tempStructure = device->newAccelerationStructure(accelSizes.accelerationStructureSize);
|
||||
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);
|
||||
cmdBuffer = queue->commandBuffer();
|
||||
encoder = cmdBuffer->accelerationStructureCommandEncoder();
|
||||
encoder->copyAndCompactAccelerationStructure(tempStructure, accelerationStructure);
|
||||
encoder->endEncoding();
|
||||
cmdBuffer->commit();
|
||||
cmdBuffer->waitUntilCompleted();*/
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#include "scene/Scene.h"
|
||||
#include <Foundation/Foundation.hpp>
|
||||
#include <Metal/Metal.hpp>
|
||||
#include <QuartzCore/QuartzCore.hpp>
|
||||
|
||||
class MetalScene : public Scene
|
||||
{
|
||||
public:
|
||||
MetalScene(MTL::Device* device, MTL::CommandQueue* queue);
|
||||
virtual ~MetalScene();
|
||||
|
||||
virtual void createRayTracingHierarchy() override;
|
||||
|
||||
MTL::Device* device;
|
||||
MTL::CommandQueue* queue;
|
||||
|
||||
MTL::Buffer* indicesBuffer;
|
||||
MTL::Buffer* positionBuffer;
|
||||
MTL::Buffer* texCoordsBuffer;
|
||||
MTL::Buffer* normalBuffer;
|
||||
MTL::Buffer* modelRefsBuffer;
|
||||
MTL::Buffer* directionalLightBuffer;
|
||||
MTL::Buffer* pointLightBuffer;
|
||||
MTL::Buffer* instanceBuffer;
|
||||
|
||||
MTL::AccelerationStructure* accelerationStructure;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
#define NS_PRIVATE_IMPLEMENTATION
|
||||
#define CA_PRIVATE_IMPLEMENTATION
|
||||
#define MTL_PRIVATE_IMPLEMENTATION
|
||||
#include <Foundation/Foundation.hpp>
|
||||
#include <Metal/Metal.hpp>
|
||||
#include <QuartzCore/QuartzCore.hpp>
|
||||
Reference in New Issue
Block a user