webgpu triangle
This commit is contained in:
parent
64116cd980
commit
5553ded476
22 changed files with 2107 additions and 42 deletions
12
examples/VulkanTriangle/closesthit.wgsl
Normal file
12
examples/VulkanTriangle/closesthit.wgsl
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// WebGPU port of closesthit.glsl. Library concatenates this BEFORE the
|
||||
// library helpers, so `Payload` declared here is visible to traceRay,
|
||||
// runClosestHit, the mega-switch, and the user's raygen source.
|
||||
|
||||
struct Payload {
|
||||
color: vec3<f32>,
|
||||
};
|
||||
|
||||
fn closesthit_main(ray: RayDesc, hit: HitInfo, payload: ptr<function, Payload>) {
|
||||
let bary = vec3<f32>(1.0 - hit.attribs.x - hit.attribs.y, hit.attribs.x, hit.attribs.y);
|
||||
(*payload).color = bary;
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
#include "vulkan/vulkan.h"
|
||||
#endif
|
||||
#include <cassert>
|
||||
|
||||
import Crafter.Graphics;
|
||||
|
|
@ -7,7 +9,7 @@ import std;
|
|||
import Crafter.Event;
|
||||
import Crafter.Math;
|
||||
|
||||
|
||||
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
|
||||
int main() {
|
||||
Device::Initialize();
|
||||
Window window(1280, 720, "HelloVulkan");
|
||||
|
|
@ -89,7 +91,7 @@ int main() {
|
|||
RenderingElement3D::elements.emplace_back(&renderer);
|
||||
|
||||
MatrixRowMajor<float, 4, 3, 1> transform = MatrixRowMajor<float, 4, 3, 1>::Identity();
|
||||
std::memcpy(renderer.instance.transform.matrix, transform.m, sizeof(transform.m));
|
||||
transform.Store(reinterpret_cast<float*>(renderer.instance.transform.matrix));
|
||||
RenderingElement3D::BuildTLAS(cmd, 0);
|
||||
RenderingElement3D::BuildTLAS(cmd, 1);
|
||||
RenderingElement3D::BuildTLAS(cmd, 2);
|
||||
|
|
@ -202,3 +204,65 @@ int main() {
|
|||
window.Render();
|
||||
window.StartSync();
|
||||
}
|
||||
#else
|
||||
// DOM-mode port. Same scene (one triangle), software-emulated raytracing
|
||||
// via compute. Shaders are read from .wgsl files shipped as static
|
||||
// assets (see project.cpp). Renders barycentric colors via the
|
||||
// hit/miss/raygen mega-switch in PipelineRTWebGPU.
|
||||
int main() {
|
||||
Device::Initialize();
|
||||
static Window window(1280, 720, "HelloVulkan");
|
||||
auto cmd = window.StartInit();
|
||||
|
||||
DescriptorHeapWebGPU heap;
|
||||
heap.Initialize(/*images*/ 4, /*buffers*/ 4, /*samplers*/ 2);
|
||||
|
||||
std::array<WebGPUShader, 3> shaders {{
|
||||
WebGPUShader(std::filesystem::path("raygen.wgsl"), "raygen_main", WebGPURTStage::Raygen),
|
||||
WebGPUShader(std::filesystem::path("miss.wgsl"), "miss_main", WebGPURTStage::Miss),
|
||||
WebGPUShader(std::filesystem::path("closesthit.wgsl"), "closesthit_main", WebGPURTStage::ClosestHit),
|
||||
}};
|
||||
ShaderBindingTableWebGPU sbt;
|
||||
sbt.Init(shaders);
|
||||
|
||||
std::array<RTShaderGroup, 1> raygenGroups {{
|
||||
{ .type = RTShaderGroupType::General, .generalShader = 0 },
|
||||
}};
|
||||
std::array<RTShaderGroup, 1> missGroups {{
|
||||
{ .type = RTShaderGroupType::General, .generalShader = 1 },
|
||||
}};
|
||||
std::array<RTShaderGroup, 1> hitGroups {{
|
||||
{ .type = RTShaderGroupType::TrianglesHitGroup, .closestHitShader = 2 },
|
||||
}};
|
||||
|
||||
PipelineRTWebGPU pipeline;
|
||||
pipeline.Init(cmd, raygenGroups, missGroups, hitGroups, sbt);
|
||||
|
||||
Mesh triangleMesh;
|
||||
std::array<Vector<float, 3, 3>, 3> verts {{{-150, -150, 100}, {0, 150, 100}, {150, -150, 100}}};
|
||||
std::array<std::uint32_t, 3> index {{2, 1, 0}};
|
||||
triangleMesh.Build(verts, index, cmd);
|
||||
|
||||
static RenderingElement3D renderer;
|
||||
renderer.instance.transform.matrix[0][0] = 1; renderer.instance.transform.matrix[0][1] = 0; renderer.instance.transform.matrix[0][2] = 0; renderer.instance.transform.matrix[0][3] = 0;
|
||||
renderer.instance.transform.matrix[1][0] = 0; renderer.instance.transform.matrix[1][1] = 1; renderer.instance.transform.matrix[1][2] = 0; renderer.instance.transform.matrix[1][3] = 0;
|
||||
renderer.instance.transform.matrix[2][0] = 0; renderer.instance.transform.matrix[2][1] = 0; renderer.instance.transform.matrix[2][2] = 1; renderer.instance.transform.matrix[2][3] = 0;
|
||||
renderer.instance.instanceCustomIndex = 0;
|
||||
renderer.instance.mask = 0xFF;
|
||||
renderer.instance.instanceShaderBindingTableRecordOffset = 0;
|
||||
renderer.instance.flags = kRTGeometryInstanceForceOpaque;
|
||||
renderer.instance.accelerationStructureReference = triangleMesh.blasAddr;
|
||||
RenderingElement3D::Add(&renderer);
|
||||
RenderingElement3D::BuildTLAS(cmd, 0);
|
||||
|
||||
window.descriptorHeap = &heap;
|
||||
window.FinishInit();
|
||||
|
||||
RTPass rtPass(&pipeline);
|
||||
window.passes.push_back(&rtPass);
|
||||
|
||||
window.Render();
|
||||
window.StartUpdate();
|
||||
window.StartSync();
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
5
examples/VulkanTriangle/miss.wgsl
Normal file
5
examples/VulkanTriangle/miss.wgsl
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// WebGPU port of miss.glsl.
|
||||
|
||||
fn miss_main(ray: RayDesc, payload: ptr<function, Payload>) {
|
||||
(*payload).color = vec3<f32>(1.0, 1.0, 1.0);
|
||||
}
|
||||
|
|
@ -4,6 +4,14 @@ namespace fs = std::filesystem;
|
|||
using namespace Crafter;
|
||||
|
||||
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
|
||||
bool isWasm = false;
|
||||
for (std::string_view a : args) {
|
||||
if (a.starts_with("--target=") && a.find("wasm") != std::string_view::npos) {
|
||||
isWasm = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> graphicsArgs(args.begin(), args.end());
|
||||
Configuration* graphics = LocalProject({
|
||||
.projectFile = "../../project.cpp",
|
||||
|
|
@ -14,6 +22,12 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
|||
cfg.path = "./";
|
||||
cfg.name = "VulkanTriangle";
|
||||
cfg.outputName = "VulkanTriangle";
|
||||
cfg.type = ConfigurationType::Executable;
|
||||
if (isWasm) {
|
||||
cfg.target = "wasm32-wasip1";
|
||||
cfg.defines.push_back({"CRAFTER_GRAPHICS_WINDOW_DOM", ""});
|
||||
cfg.compileFlags.push_back("-msimd128");
|
||||
}
|
||||
ApplyStandardArgs(cfg, args);
|
||||
cfg.dependencies = { graphics };
|
||||
|
||||
|
|
@ -21,8 +35,15 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
|||
std::array<fs::path, 1> impls = { "main" };
|
||||
cfg.GetInterfacesAndImplementations(ifaces, impls);
|
||||
|
||||
cfg.shaders.emplace_back(fs::path("raygen.glsl"), std::string("main"), ShaderType::RayGen);
|
||||
cfg.shaders.emplace_back(fs::path("closesthit.glsl"), std::string("main"), ShaderType::ClosestHit);
|
||||
cfg.shaders.emplace_back(fs::path("miss.glsl"), std::string("main"), ShaderType::Miss);
|
||||
if (isWasm) {
|
||||
cfg.files.emplace_back(fs::path("raygen.wgsl"));
|
||||
cfg.files.emplace_back(fs::path("closesthit.wgsl"));
|
||||
cfg.files.emplace_back(fs::path("miss.wgsl"));
|
||||
EnableWasiBrowserRuntime(cfg);
|
||||
} else {
|
||||
cfg.shaders.emplace_back(fs::path("raygen.glsl"), std::string("main"), ShaderType::RayGen);
|
||||
cfg.shaders.emplace_back(fs::path("closesthit.glsl"), std::string("main"), ShaderType::ClosestHit);
|
||||
cfg.shaders.emplace_back(fs::path("miss.glsl"), std::string("main"), ShaderType::Miss);
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,17 +34,17 @@ void main() {
|
|||
1.0
|
||||
));
|
||||
|
||||
// traceRayEXT(
|
||||
// topLevelAS[bufferStart],
|
||||
// gl_RayFlagsNoneEXT,
|
||||
// 0xff,
|
||||
// 0, 0, 0,
|
||||
// origin,
|
||||
// 0.001,
|
||||
// direction,
|
||||
// 10000.0,
|
||||
// 0
|
||||
// );
|
||||
traceRayEXT(
|
||||
topLevelAS[bufferStart],
|
||||
gl_RayFlagsNoneEXT,
|
||||
0xff,
|
||||
0, 0, 0,
|
||||
origin,
|
||||
0.001,
|
||||
direction,
|
||||
10000.0,
|
||||
0
|
||||
);
|
||||
|
||||
imageStore(image[0], ivec2(pixel), vec4(hitValue, 1));
|
||||
}
|
||||
|
|
|
|||
39
examples/VulkanTriangle/raygen.wgsl
Normal file
39
examples/VulkanTriangle/raygen.wgsl
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// WebGPU port of raygen.glsl. Mirrors the pinhole camera setup — the
|
||||
// Payload type is declared in closesthit.wgsl (concatenated earlier).
|
||||
|
||||
fn raygen_main(gid: vec3<u32>) {
|
||||
if (gid.x >= hdr.surfaceW || gid.y >= hdr.surfaceH) { return; }
|
||||
|
||||
let pixel = vec2<f32>(f32(gid.x), f32(gid.y));
|
||||
let resolution = vec2<f32>(f32(hdr.surfaceW), f32(hdr.surfaceH));
|
||||
let uv = (pixel + vec2<f32>(0.5)) / resolution;
|
||||
let ndc = uv * 2.0 - vec2<f32>(1.0);
|
||||
|
||||
let origin = vec3<f32>(0.0, 0.0, -300.0);
|
||||
let aspect = resolution.x / resolution.y;
|
||||
let fov = 60.0 * 3.14159265 / 180.0;
|
||||
let tanHalfFov = tan(fov * 0.5);
|
||||
|
||||
let direction = normalize(vec3<f32>(
|
||||
ndc.x * aspect * tanHalfFov,
|
||||
-ndc.y * tanHalfFov,
|
||||
1.0,
|
||||
));
|
||||
|
||||
var payload: Payload;
|
||||
payload.color = vec3<f32>(0.0);
|
||||
|
||||
traceRay(
|
||||
0u, // tlasIdx (unused)
|
||||
0u, // ray flags
|
||||
0xFFu, // cull mask
|
||||
0u, 0u, 0u, // sbtRecordOffset, sbtRecordStride, missIndex
|
||||
origin, 0.001,
|
||||
direction, 10000.0,
|
||||
&payload,
|
||||
);
|
||||
|
||||
textureStore(outImage,
|
||||
vec2<i32>(i32(gid.x), i32(gid.y)),
|
||||
vec4<f32>(payload.color, 1.0));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue