diff --git a/README.md b/README.md index 7a2434c3..773a7921 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,17 @@ strip Krom ./Krom ../../build/krom ``` ```bash +# Windows VR - wip +node Kromx/make -g direct3d11 --vr oculus +cd Kromx +# Unpack `v8\libraries\win32\release\v8_monolith.7z` using 7-Zip - Extract Here (exceeds 100MB) +git apply patch/window_handling.diff --directory=Kinc +node Kinc/make -g direct3d11 --vr oculus +# Open generated Visual Studio project +# Set `Project - Properties - Debugging - Command Arguments` to `..\..\build\krom` +# Build for x64 & release +``` +```bash # Updating cloned repository git pull origin master git submodule update --init --recursive diff --git a/Sources/Main.hx b/Sources/Main.hx index aff58a93..c34173a7 100644 --- a/Sources/Main.hx +++ b/Sources/Main.hx @@ -17,6 +17,9 @@ import arm.Context; #if arm_player import arm.sys.Path; #end +#if arm_vr +import arm.render.RenderPathForwardVR; +#end class Main { @@ -84,6 +87,12 @@ class Main { var path = new RenderPath(); Inc.init(path); + #if arm_vr + RenderPathDeferred.init(path); // Allocate gbuffer + RenderPathForward.init(path); + RenderPathForwardVR.init(path); + path.commands = RenderPathForwardVR.commands; + #else if (Context.renderMode == RenderForward) { RenderPathDeferred.init(path); // Allocate gbuffer RenderPathForward.init(path); @@ -93,6 +102,7 @@ class Main { RenderPathDeferred.init(path); path.commands = RenderPathDeferred.commands; } + #end RenderPath.setActive(path); #if arm_player diff --git a/Sources/arm/Context.hx b/Sources/arm/Context.hx index 53aaad8f..aa822fc2 100644 --- a/Sources/arm/Context.hx +++ b/Sources/arm/Context.hx @@ -97,7 +97,7 @@ class Context { public static var decalImage: Image = null; public static var decalPreview = false; public static var viewportMode = ViewLit; - #if (krom_android || krom_ios) + #if (krom_android || krom_ios || arm_vr) public static var renderMode = RenderForward; #else public static var renderMode = RenderDeferred; diff --git a/Sources/arm/render/RenderPathForward.hx b/Sources/arm/render/RenderPathForward.hx index 152c3be4..a96dc687 100644 --- a/Sources/arm/render/RenderPathForward.hx +++ b/Sources/arm/render/RenderPathForward.hx @@ -59,16 +59,16 @@ class RenderPathForward { RenderPathDeferred.taaFrame++; } - static function drawGbuffer() { - path.setTarget("gbuffer0"); + public static function drawGbuffer(gbuffer0 = "gbuffer0", gbuffer1 = "gbuffer1", gbuffer2 = "gbuffer2") { + path.setTarget(gbuffer0); #if kha_metal path.clearTarget(0x00000000, 1.0); #else path.clearTarget(null, 1.0); #end - path.setTarget("gbuffer2"); + path.setTarget(gbuffer2); path.clearTarget(0xff000000); - path.setTarget("gbuffer0", ["gbuffer1", "gbuffer2"]); + path.setTarget(gbuffer0, [gbuffer1, gbuffer2]); var currentG = path.currentG; #if arm_painter RenderPathPaint.bindLayers(); @@ -80,71 +80,73 @@ class RenderPathForward { LineDraw.render(path.currentG); } - static function drawForward() { - path.setDepthFrom("gbuffer1", "gbuffer0"); - path.setTarget("gbuffer1"); + public static function drawForward(eye = false, output = "", gbuffer0 = "gbuffer0", gbuffer1 = "gbuffer1", gbuffer2 = "gbuffer2", buf = "buf", bufa = "bufa", taa = "taa", taa2 = "taa2") { + path.setDepthFrom(gbuffer1, gbuffer0); + path.setTarget(gbuffer1); path.drawSkydome("world_pass/world_pass/world_pass"); - path.setDepthFrom("gbuffer1", "gbuffer2"); + path.setDepthFrom(gbuffer1, gbuffer2); - path.setTarget("buf"); - path.bindTarget("gbuffer1", "tex"); + path.setTarget(buf); + path.bindTarget(gbuffer1, "tex"); path.drawShader("shader_datas/compositor_pass/compositor_pass"); - path.setTarget("buf"); - var currentG = path.currentG; - path.drawMeshes("overlay"); - #if arm_painter - Inc.drawCompass(currentG); - #end + if (output == "") { + path.setTarget(buf); + var currentG = path.currentG; + path.drawMeshes("overlay"); + #if arm_painter + Inc.drawCompass(currentG); + #end + } var taaFrame = RenderPathDeferred.taaFrame; - var current = taaFrame % 2 == 0 ? "bufa" : "taa2"; - var last = taaFrame % 2 == 0 ? "taa2" : "bufa"; + var current = taaFrame % 2 == 0 ? bufa : taa2; + var last = taaFrame % 2 == 0 ? taa2 : bufa; path.setTarget(current); path.clearTarget(0x00000000); - path.bindTarget("buf", "colorTex"); + path.bindTarget(buf, "colorTex"); path.drawShader("shader_datas/smaa_edge_detect/smaa_edge_detect"); - path.setTarget("taa"); + path.setTarget(taa); path.clearTarget(0x00000000); path.bindTarget(current, "edgesTex"); path.drawShader("shader_datas/smaa_blend_weight/smaa_blend_weight"); path.setTarget(current); - path.bindTarget("buf", "colorTex"); - path.bindTarget("taa", "blendTex"); - path.bindTarget("gbuffer2", "sveloc"); + path.bindTarget(buf, "colorTex"); + path.bindTarget(taa, "blendTex"); + path.bindTarget(gbuffer2, "sveloc"); path.drawShader("shader_datas/smaa_neighborhood_blend/smaa_neighborhood_blend"); #if arm_painter - var skipTaa = Context.splitView; + var skipTaa = Context.splitView || eye; #else var skipTaa = false; #end if (skipTaa) { - path.setTarget("taa"); + path.setTarget(taa); path.bindTarget(current, "tex"); path.drawShader("shader_datas/copy_pass/copy_pass"); } else { - path.setTarget("taa"); + path.setTarget(taa); path.bindTarget(current, "tex"); path.bindTarget(last, "tex2"); - path.bindTarget("gbuffer2", "sveloc"); + path.bindTarget(gbuffer2, "sveloc"); path.drawShader("shader_datas/taa_pass/taa_pass"); } if (!Inc.ssaa4()) { - path.setTarget(""); - path.bindTarget(taaFrame == 0 ? current : "taa", "tex"); + path.setTarget(output); + path.bindTarget(taaFrame % 2 == 0 ? current : taa, "tex"); path.drawShader("shader_datas/copy_pass/copy_pass"); } if (Inc.ssaa4()) { - path.setTarget(""); - path.bindTarget(taaFrame % 2 == 0 ? "taa2" : "taa", "tex"); + path.setTarget(output); + path.bindTarget(taaFrame % 2 == 0 ? taa2 : taa, "tex"); path.drawShader("shader_datas/supersample_resolve/supersample_resolve"); } } diff --git a/Sources/arm/render/RenderPathForwardVR.hx b/Sources/arm/render/RenderPathForwardVR.hx new file mode 100644 index 00000000..1b15ae56 --- /dev/null +++ b/Sources/arm/render/RenderPathForwardVR.hx @@ -0,0 +1,200 @@ +package arm.render; + +#if arm_vr + +import kha.System; +import iron.RenderPath; +import iron.Scene; +import arm.ui.UISidebar; + +class RenderPathForwardVR { + + public static var path: RenderPath; + static var m = iron.math.Mat4.identity(); + + public static function init(_path: RenderPath) { + path = _path; + + { + var t = new RenderTargetRaw(); + t.name = "eye0"; + t.width = 1440; + t.height = 1600; + t.format = "RGBA32"; + t.scale = Inc.getSuperSampling(); + path.createRenderTarget(t); + } + { + var t = new RenderTargetRaw(); + t.name = "eye1"; + t.width = 1440; + t.height = 1600; + t.format = "RGBA32"; + t.scale = Inc.getSuperSampling(); + path.createRenderTarget(t); + } + + path.createDepthBuffer("main_eye", "DEPTH24"); + + { + var t = new RenderTargetRaw(); + t.name = "gbuffer0_eye"; + t.width = 1440; + t.height = 1600; + t.format = "RGBA64"; + t.scale = Inc.getSuperSampling(); + t.depth_buffer = "main_eye"; + path.createRenderTarget(t); + } + { + var t = new RenderTargetRaw(); + t.name = "gbuffer1_eye"; + t.width = 1440; + t.height = 1600; + t.format = "RGBA64"; + t.scale = Inc.getSuperSampling(); + path.createRenderTarget(t); + } + { + var t = new RenderTargetRaw(); + t.name = "gbuffer2_eye"; + t.width = 1440; + t.height = 1600; + t.format = "RGBA64"; + t.scale = Inc.getSuperSampling(); + path.createRenderTarget(t); + } + { + var t = new RenderTargetRaw(); + t.name = "buf_eye"; + t.width = 1440; + t.height = 1600; + #if (kha_direct3d12 || kha_vulkan) + t.format = "RGBA64"; // Match raytrace_target format + #else + t.format = "RGBA32"; + #end + t.scale = Inc.getSuperSampling(); + path.createRenderTarget(t); + } + { + var t = new RenderTargetRaw(); + t.name = "bufa_eye"; + t.width = 1440; + t.height = 1600; + t.format = "RGBA32"; + t.scale = Inc.getSuperSampling(); + path.createRenderTarget(t); + } + { + var t = new RenderTargetRaw(); + t.name = "taa_eye"; + t.width = 1440; + t.height = 1600; + t.format = "RGBA32"; + t.scale = Inc.getSuperSampling(); + path.createRenderTarget(t); + } + { + var t = new RenderTargetRaw(); + t.name = "taa2_eye"; + t.width = 1440; + t.height = 1600; + t.format = "RGBA32"; + t.scale = Inc.getSuperSampling(); + path.createRenderTarget(t); + } + } + + @:access(iron.RenderPath) + public static function commands() { + + if (System.windowWidth() == 0 || System.windowHeight() == 0) return; + + { + var current = RenderPathDeferred.taaFrame % 2 == 0 ? "bufa" : "taa2"; + var output = RenderPathDeferred.taaFrame % 2 == 0 ? current : "taa"; + + m.setFrom(Scene.active.camera.transform.world); + var t = Context.object.transform; + t.translate(0, 1, -1); + t.buildMatrix(); + + for (eye in 0...2) { + var view = Krom.vrGetSensorStateView(eye); + var proj = Krom.vrGetSensorStateProjection(eye); + Scene.active.camera.V._00 = view._00; + Scene.active.camera.V._01 = view._01; + Scene.active.camera.V._02 = view._02; + Scene.active.camera.V._03 = view._03; + Scene.active.camera.V._10 = view._10; + Scene.active.camera.V._11 = view._11; + Scene.active.camera.V._12 = view._12; + Scene.active.camera.V._13 = view._13; + Scene.active.camera.V._20 = view._20; + Scene.active.camera.V._21 = view._21; + Scene.active.camera.V._22 = view._22; + Scene.active.camera.V._23 = view._23; + Scene.active.camera.V._30 = view._30; + Scene.active.camera.V._31 = view._31; + Scene.active.camera.V._32 = view._32; + Scene.active.camera.V._33 = view._33; + Scene.active.camera.P._00 = proj._00; + Scene.active.camera.P._01 = proj._01; + Scene.active.camera.P._02 = proj._02; + Scene.active.camera.P._03 = proj._03; + Scene.active.camera.P._10 = proj._10; + Scene.active.camera.P._11 = proj._11; + Scene.active.camera.P._12 = proj._12; + Scene.active.camera.P._13 = proj._13; + Scene.active.camera.P._20 = proj._20; + Scene.active.camera.P._21 = proj._21; + Scene.active.camera.P._22 = proj._22; + Scene.active.camera.P._23 = proj._23; + Scene.active.camera.P._30 = proj._30; + Scene.active.camera.P._31 = proj._31; + Scene.active.camera.P._32 = proj._32; + Scene.active.camera.P._33 = proj._33; + Scene.active.camera.VP.multmats(Scene.active.camera.P, Scene.active.camera.V); + Scene.active.camera.transform.world.getInverse(Scene.active.camera.V); + RenderPathForward.drawGbuffer("gbuffer0_eye", "gbuffer1_eye", "gbuffer2_eye"); + RenderPathForward.drawForward(true, "eye" + eye, "gbuffer0_eye", "gbuffer1_eye", "gbuffer2_eye", "buf_eye", "bufa_eye", "taa_eye", "taa2_eye"); + } + + Scene.active.camera.transform.world.setFrom(m); + t.translate(0, -1, 1); + t.buildMatrix(); + + Krom.vrBegin(); + + path.drawStereo(function(eye: Int) { + path.currentG = path.frameG; + path.bindTarget("eye" + eye, "tex"); + path.drawShader("shader_datas/copy_pass/copy_pass"); + }); + + Krom.vrWarpSwap(); + } + + iron.Scene.active.camera.buildMatrix(); + + #if arm_painter + RenderPathPaint.begin(); + #end // arm_painter + + RenderPathForward.drawGbuffer(); + RenderPathForward.drawForward(); + + #if arm_painter + RenderPathPaint.draw(); + #end + + #if arm_painter + RenderPathPaint.end(); + #end + + RenderPathDeferred.taaFrame++; + } +} + +#end diff --git a/Sources/arm/ui/BoxPreferences.hx b/Sources/arm/ui/BoxPreferences.hx index d3af2ccf..22957368 100644 --- a/Sources/arm/ui/BoxPreferences.hx +++ b/Sources/arm/ui/BoxPreferences.hx @@ -302,6 +302,7 @@ class BoxPreferences { Context.hsupersample = Id.handle({position: Config.getSuperSampleQuality(Config.raw.rp_supersample)}); Context.hvxao = Id.handle({selected: Config.raw.rp_gi}); if (ui.tab(htab, tr("Viewport"), true)) { + #if (!arm_vr) var hrendermode = Id.handle({position: Context.renderMode}); Context.renderMode = ui.combo(hrendermode, [tr("Full"), tr("Mobile")], tr("Renderer"), true); if (hrendermode.changed) { @@ -316,6 +317,7 @@ class BoxPreferences { } MaterialParser.parseMeshMaterial(); } + #end ui.combo(Context.hsupersample, ["0.25x", "0.5x", "1.0x", "1.5x", "2.0x", "4.0x"], tr("Super Sample"), true); if (Context.hsupersample.changed) Config.applyConfig(); diff --git a/khafile.js b/khafile.js index ed6dda62..86a08593 100644 --- a/khafile.js +++ b/khafile.js @@ -8,6 +8,7 @@ let vulkan = process.argv.indexOf("vulkan") >= 0; let raytrace = d3d12 || vulkan; let metal = process.argv.indexOf("metal") >= 0; let build = "painter"; // painter || creator || player +let vr = process.argv.indexOf("--vr") >= 0; let project = new Project("ArmorPaint"); project.addSources("Sources"); @@ -67,6 +68,10 @@ else { project.addDefine("analyzer-optimize"); } +if (vr) { + project.addDefine("arm_vr"); +} + project.addAssets("Assets/readme/readme.txt", { notinlist: true, destination: "{name}" }); if (raytrace) {