forked from LeenkxTeam/LNXSDK
Patch_1
This commit is contained in:
@ -18,10 +18,44 @@ import iron.object.LightObject;
|
||||
import iron.object.MeshObject;
|
||||
import iron.object.Uniforms;
|
||||
import iron.object.Clipmap;
|
||||
#if lnx_vr
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Mat4;
|
||||
import iron.math.Quat;
|
||||
#end
|
||||
|
||||
class RenderPath {
|
||||
|
||||
public static var active: RenderPath;
|
||||
#if lnx_vr
|
||||
static var vrSimulateMode: Bool = false;
|
||||
static var vrCameraOffsetSet:Bool = false;
|
||||
static var vrCameraOffset:Vec4 = new Vec4();
|
||||
static var wasVRPresenting:Bool = false;
|
||||
public static var vrCalibrationPosition:Vec4 = null;
|
||||
public static var vrCalibrationRotation:iron.math.Quat = null;
|
||||
public static var vrCalibrationSaved:Bool = false;
|
||||
|
||||
public static var vrCenterCameraWorld:Mat4 = null;
|
||||
|
||||
static var vrOriginalSuperSample:Float = -1.0;
|
||||
public static inline function isVRPresenting(): Bool {
|
||||
#if (kha_webgl && lnx_vr)
|
||||
return kha.vr.VrInterface.instance != null && kha.vr.VrInterface.instance.IsPresenting();
|
||||
#else
|
||||
return false;
|
||||
#end
|
||||
}
|
||||
|
||||
public static inline function isVRSimulateMode(): Bool {
|
||||
return vrSimulateMode;
|
||||
}
|
||||
|
||||
// TODO: done remove safely
|
||||
public static inline function debugLog(msg: String, once: Bool = true): Void {
|
||||
return;
|
||||
}
|
||||
#end
|
||||
|
||||
public var frameScissor = false;
|
||||
public var frameScissorX = 0;
|
||||
@ -43,9 +77,15 @@ class RenderPath {
|
||||
public var isProbe = false;
|
||||
public var currentG: Graphics = null;
|
||||
public var frameG: Graphics;
|
||||
#if lnx_vr
|
||||
var beginCalled = false;
|
||||
var scissorSet = false;
|
||||
var viewportScaled = false;
|
||||
var renderToXRFramebuffer = false;
|
||||
#end
|
||||
public var drawOrder = DrawOrder.Distance;
|
||||
public var paused = false;
|
||||
public var ready(get, null): Bool;
|
||||
public var ready(get, never): Bool;
|
||||
function get_ready(): Bool { return loading == 0; }
|
||||
public var commands: Void->Void = null;
|
||||
public var setupDepthTexture: Void->Void = null;
|
||||
@ -123,9 +163,93 @@ class RenderPath {
|
||||
public function renderFrame(g: Graphics) {
|
||||
if (!ready || paused || iron.App.w() == 0 || iron.App.h() == 0) return;
|
||||
|
||||
if (lastW > 0 && (lastW != iron.App.w() || lastH != iron.App.h())) resize();
|
||||
lastW = iron.App.w();
|
||||
lastH = iron.App.h();
|
||||
var appW = iron.App.w();
|
||||
var appH = iron.App.h();
|
||||
|
||||
// use native XR framebuffer dimensions
|
||||
#if (kha_webgl && lnx_vr)
|
||||
if (kha.vr.VrInterface.instance != null) {
|
||||
var vr = kha.vr.VrInterface.instance;
|
||||
var isPresenting = vr != null && vr.IsPresenting();
|
||||
|
||||
// save/restore camera position between modes
|
||||
if (!wasVRPresenting && isPresenting) {
|
||||
if (Scene.active != null && Scene.active.camera != null) {
|
||||
if (vrCalibrationPosition == null) vrCalibrationPosition = new Vec4();
|
||||
if (vrCalibrationRotation == null) vrCalibrationRotation = new Quat();
|
||||
|
||||
vrCalibrationPosition.setFrom(Scene.active.camera.transform.loc);
|
||||
vrCalibrationRotation.setFrom(Scene.active.camera.transform.rot);
|
||||
vrCalibrationSaved = true;
|
||||
}
|
||||
|
||||
// save original super sampling for later
|
||||
vrOriginalSuperSample = leenkx.renderpath.Inc.superSample;
|
||||
|
||||
// compositeToXR function handles blitting to VR framebuffer
|
||||
|
||||
var xrVr: kha.js.vr.VrInterface = cast vr;
|
||||
if (xrVr.xrGLLayer != null) {
|
||||
var vrWidth = untyped xrVr.xrGLLayer.framebufferWidth;
|
||||
var vrHeight = untyped xrVr.xrGLLayer.framebufferHeight;
|
||||
}
|
||||
}
|
||||
else if (wasVRPresenting && !isPresenting) {
|
||||
// reset VR frame time before anything else
|
||||
#if (kha_webgl && lnx_vr)
|
||||
iron.system.Time.vrFrameTime = -1.0;
|
||||
#end
|
||||
|
||||
if (vrCalibrationSaved && Scene.active != null && Scene.active.camera != null) {
|
||||
Scene.active.camera.transform.loc.setFrom(vrCalibrationPosition);
|
||||
Scene.active.camera.transform.rot.setFrom(vrCalibrationRotation);
|
||||
Scene.active.camera.buildMatrix();
|
||||
Scene.active.camera.buildProjection();
|
||||
}
|
||||
|
||||
// restore original super sampling from simulate mode
|
||||
if (vrOriginalSuperSample >= 0.0) {
|
||||
leenkx.renderpath.Inc.superSample = vrOriginalSuperSample;
|
||||
|
||||
for (rt in renderTargets) {
|
||||
if (rt.raw.width == 0 && rt.raw.scale != null) {
|
||||
rt.raw.scale = vrOriginalSuperSample;
|
||||
}
|
||||
}
|
||||
resize();
|
||||
vrOriginalSuperSample = -1.0;
|
||||
}
|
||||
|
||||
// reset offset for next session
|
||||
vrCameraOffsetSet = false;
|
||||
vrCameraOffset = null;
|
||||
}
|
||||
wasVRPresenting = isPresenting;
|
||||
|
||||
if (isPresenting) {
|
||||
// TODO: re-investigate using super sampling to avoid pixelation in simulate mode while giving max quality in headset
|
||||
if (vrOriginalSuperSample >= 0.0 && leenkx.renderpath.Inc.superSample != 4.0) {
|
||||
leenkx.renderpath.Inc.superSample = 4.0;
|
||||
for (rt in renderTargets) {
|
||||
if (rt.raw.width == 0 && rt.raw.scale != null) {
|
||||
rt.raw.scale = 4.0;
|
||||
}
|
||||
}
|
||||
resize();
|
||||
}
|
||||
|
||||
var xrVr: kha.js.vr.VrInterface = cast vr;
|
||||
if (xrVr.xrGLLayer != null) {
|
||||
appW = xrVr.xrGLLayer.framebufferWidth;
|
||||
appH = xrVr.xrGLLayer.framebufferHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
if (lastW > 0 && (lastW != appW || lastH != appH)) resize();
|
||||
lastW = appW;
|
||||
lastH = appH;
|
||||
|
||||
frameTime = Time.time() - lastFrameTime;
|
||||
lastFrameTime = Time.time();
|
||||
@ -191,7 +315,9 @@ class RenderPath {
|
||||
}
|
||||
light = Scene.active.lights[0];
|
||||
|
||||
commands();
|
||||
if (commands != null) {
|
||||
commands();
|
||||
}
|
||||
|
||||
if (!isProbe) frame++;
|
||||
}
|
||||
@ -207,13 +333,13 @@ class RenderPath {
|
||||
begin(frameG, Scene.active.camera.currentFace);
|
||||
}
|
||||
else { // Screen, planar probe
|
||||
currentW = iron.App.w();
|
||||
currentH = iron.App.h();
|
||||
currentW = kha.System.windowWidth();
|
||||
currentH = kha.System.windowHeight();
|
||||
if (frameScissor) setFrameScissor();
|
||||
begin(frameG);
|
||||
if (!isProbe) {
|
||||
setCurrentViewport(iron.App.w(), iron.App.h());
|
||||
setCurrentScissor(iron.App.w(), iron.App.h());
|
||||
setCurrentViewport(kha.System.windowWidth(), kha.System.windowHeight());
|
||||
setCurrentScissor(kha.System.windowWidth(), kha.System.windowHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,16 +384,42 @@ class RenderPath {
|
||||
if (currentG != null) end();
|
||||
currentG = g;
|
||||
additionalTargets = additionalRenderTargets;
|
||||
face >= 0 ? g.beginFace(face) : g.begin(additionalRenderTargets);
|
||||
|
||||
// we still bind but skip begin() when explicitly rendering to XR framebuffer (renderToXRFramebuffer flag)
|
||||
#if lnx_vr
|
||||
if (!renderToXRFramebuffer) {
|
||||
face >= 0 ? g.beginFace(face) : g.begin(additionalRenderTargets);
|
||||
beginCalled = true;
|
||||
} else {
|
||||
// XR framebuffer is already bound by VrInterface so we dont rebind
|
||||
beginCalled = false;
|
||||
}
|
||||
#else
|
||||
face >= 0 ? g.beginFace(face) : g.begin(additionalRenderTargets);
|
||||
#end
|
||||
}
|
||||
|
||||
inline function end() {
|
||||
if (currentG == null) return;
|
||||
if (scissorSet) {
|
||||
currentG.disableScissor();
|
||||
scissorSet = false;
|
||||
}
|
||||
|
||||
#if lnx_vr
|
||||
if (beginCalled) {
|
||||
currentG.end();
|
||||
beginCalled = false;
|
||||
}
|
||||
// persist for rendering both eyes
|
||||
if (!isVRPresenting()) {
|
||||
currentG = null;
|
||||
additionalTargets = null;
|
||||
}
|
||||
#else
|
||||
currentG.end();
|
||||
currentG = null;
|
||||
#end
|
||||
bindParams = null;
|
||||
}
|
||||
|
||||
@ -341,8 +493,8 @@ class RenderPath {
|
||||
if (a.data.sortingIndex != b.data.sortingIndex) {
|
||||
return a.data.sortingIndex > b.data.sortingIndex ? 1 : -1;
|
||||
}
|
||||
|
||||
return a.data.name >= b.data.name ? 1 : -1; });
|
||||
return a.data.name >= b.data.name ? 1 : -1;
|
||||
});
|
||||
}
|
||||
|
||||
public function drawMeshes(context: String) {
|
||||
@ -521,44 +673,208 @@ class RenderPath {
|
||||
return Reflect.field(kha.Shaders, handle + "_comp");
|
||||
}
|
||||
|
||||
#if lnx_vr
|
||||
// blits to each eyes viewport in the XR framebuffer.
|
||||
public function compositeToXR(sourceTarget: String) {
|
||||
#if (kha_webgl && lnx_vr)
|
||||
|
||||
var vr: kha.js.vr.VrInterface = cast kha.vr.VrInterface.instance;
|
||||
if (vr == null || vr._glContext == null || vr.xrGLLayer == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var gl: js.html.webgl.WebGL2RenderingContext = cast vr._glContext;
|
||||
var source = renderTargets.get(sourceTarget);
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
var sourceFB: js.html.webgl.Framebuffer = untyped source.image.g4.renderTargetFrameBuffer;
|
||||
if (sourceFB == null) {
|
||||
return;
|
||||
}
|
||||
// trace('Framebuffer OK');
|
||||
|
||||
renderToXRFramebuffer = true;
|
||||
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.DRAW_FRAMEBUFFER, vr.xrGLLayer.framebuffer);
|
||||
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.READ_FRAMEBUFFER, sourceFB);
|
||||
|
||||
var readStatus = gl.checkFramebufferStatus(js.html.webgl.WebGL2RenderingContext.READ_FRAMEBUFFER);
|
||||
var drawStatus = gl.checkFramebufferStatus(js.html.webgl.WebGL2RenderingContext.DRAW_FRAMEBUFFER);
|
||||
if (readStatus != js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER_COMPLETE ||
|
||||
drawStatus != js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER_COMPLETE) {
|
||||
return;
|
||||
}
|
||||
|
||||
var halfWidth = Std.int(source.image.width / 2);
|
||||
var fullHeight = source.image.height;
|
||||
|
||||
if (vr._leftViewport != null) {
|
||||
var vp = vr._leftViewport;
|
||||
gl.blitFramebuffer(
|
||||
0, 0, halfWidth, fullHeight,
|
||||
vp.x, vp.y, vp.x + vp.width, vp.y + vp.height,
|
||||
js.html.webgl.WebGL2RenderingContext.COLOR_BUFFER_BIT,
|
||||
js.html.webgl.WebGL2RenderingContext.LINEAR
|
||||
);
|
||||
}
|
||||
if (vr._rightViewport != null) {
|
||||
var vp = vr._rightViewport;
|
||||
gl.blitFramebuffer(
|
||||
halfWidth, 0, source.image.width, fullHeight,
|
||||
vp.x, vp.y, vp.x + vp.width, vp.y + vp.height,
|
||||
js.html.webgl.WebGL2RenderingContext.COLOR_BUFFER_BIT,
|
||||
js.html.webgl.WebGL2RenderingContext.LINEAR
|
||||
);
|
||||
}
|
||||
|
||||
gl.bindFramebuffer(js.html.webgl.WebGL2RenderingContext.FRAMEBUFFER, null);
|
||||
renderToXRFramebuffer = false;
|
||||
#end
|
||||
}
|
||||
#end
|
||||
#if lnx_vr
|
||||
public function drawStereo(drawMeshes: Void->Void) {
|
||||
var vr = kha.vr.VrInterface.instance;
|
||||
vrSimulateMode = false;
|
||||
|
||||
if (currentG == null && frameG != null) {
|
||||
currentG = frameG;
|
||||
}
|
||||
|
||||
var appw = iron.App.w();
|
||||
var apph = iron.App.h();
|
||||
var halfw = Std.int(appw / 2);
|
||||
var g = currentG;
|
||||
|
||||
// get render target dimensions not App.w/h gbuffer is scaled in simulate mode with supersampling
|
||||
|
||||
if (vr != null && vr.IsPresenting()) {
|
||||
// Left eye
|
||||
Scene.active.camera.V.setFrom(Scene.active.camera.leftV);
|
||||
var gbuffer0 = renderTargets.get("gbuffer0");
|
||||
var actualWidth = (gbuffer0 != null && gbuffer0.image != null) ? gbuffer0.image.width : appw;
|
||||
var actualHeight = (gbuffer0 != null && gbuffer0.image != null) ? gbuffer0.image.height : apph;
|
||||
var actualHalfWidth = Std.int(actualWidth / 2);
|
||||
|
||||
var vrFBWidth = actualWidth;
|
||||
var vrFBHeight = actualHeight;
|
||||
var vrHalfWidth = actualHalfWidth;
|
||||
var isVRPresenting = false;
|
||||
vrSimulateMode = false;
|
||||
|
||||
var vr:Dynamic = null;
|
||||
var vrExists = false;
|
||||
#if (kha_webgl && lnx_vr)
|
||||
if (kha.vr.VrInterface.instance != null) {
|
||||
vr = kha.vr.VrInterface.instance;
|
||||
vrExists = true;
|
||||
}
|
||||
#end
|
||||
|
||||
if (vrExists && vr != null && vr.IsPresenting()) {
|
||||
vrSimulateMode = false;
|
||||
isVRPresenting = true;
|
||||
|
||||
// get framebuffer dimensions from XR layer
|
||||
#if (kha_webgl && lnx_vr)
|
||||
var xrVr: kha.js.vr.VrInterface = cast vr;
|
||||
if (xrVr.xrGLLayer != null) {
|
||||
vrFBWidth = untyped xrVr.xrGLLayer.framebufferWidth;
|
||||
vrFBHeight = untyped xrVr.xrGLLayer.framebufferHeight;
|
||||
vrHalfWidth = Std.int(vrFBWidth / 2);
|
||||
}
|
||||
#end
|
||||
|
||||
if (Scene.active == null || Scene.active.camera == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if (kha_webgl && lnx_vr)
|
||||
if (vrCenterCameraWorld == null) vrCenterCameraWorld = Mat4.identity();
|
||||
vrCenterCameraWorld.setFrom(Scene.active.camera.transform.world);
|
||||
#end
|
||||
|
||||
// LEFT EYE
|
||||
// HMD center for room scale position tracking
|
||||
#if (kha_webgl && lnx_vr)
|
||||
var xrVr: kha.js.vr.VrInterface = cast vr;
|
||||
if (xrVr.currentViewerPose != null) {
|
||||
var viewerTransform = untyped xrVr.currentViewerPose.transform;
|
||||
if (viewerTransform != null && viewerTransform.position != null) {
|
||||
// VR present calibration is used to position objects in world space not the camera
|
||||
var pos = viewerTransform.position;
|
||||
|
||||
// camera follows headset directly in local floor space
|
||||
Scene.active.camera.transform.loc.set(pos.x, pos.y, pos.z);
|
||||
|
||||
if (viewerTransform.orientation != null) {
|
||||
Scene.active.camera.transform.rot.set(
|
||||
viewerTransform.orientation.x,
|
||||
viewerTransform.orientation.y,
|
||||
viewerTransform.orientation.z,
|
||||
viewerTransform.orientation.w
|
||||
);
|
||||
}
|
||||
Scene.active.camera.transform.buildMatrix();
|
||||
}
|
||||
}
|
||||
iron.system.VRController.updatePoses();
|
||||
#end
|
||||
|
||||
Scene.active.camera.V.self = vr.GetViewMatrix(0);
|
||||
Scene.active.camera.P.self = vr.GetProjectionMatrix(0);
|
||||
g.viewport(0, 0, halfw, apph);
|
||||
Scene.active.camera.VP.setFrom(Scene.active.camera.P);
|
||||
Scene.active.camera.VP.multmat(Scene.active.camera.V);
|
||||
Scene.active.camera.buildMatrix(); // update frustum for culling
|
||||
|
||||
var renderWidth = actualWidth;
|
||||
var renderHeight = actualHeight;
|
||||
var renderHalfWidth = actualHalfWidth;
|
||||
|
||||
// left half of render target
|
||||
g.viewport(0, 0, renderHalfWidth, renderHeight);
|
||||
g.scissor(0, 0, renderHalfWidth, renderHeight);
|
||||
drawMeshes();
|
||||
|
||||
// Right eye
|
||||
begin(g, additionalTargets);
|
||||
Scene.active.camera.V.setFrom(Scene.active.camera.rightV);
|
||||
// RIGHT EYE
|
||||
Scene.active.camera.V.self = vr.GetViewMatrix(1);
|
||||
Scene.active.camera.P.self = vr.GetProjectionMatrix(1);
|
||||
g.viewport(halfw, 0, halfw, apph);
|
||||
Scene.active.camera.VP.setFrom(Scene.active.camera.P);
|
||||
Scene.active.camera.VP.multmat(Scene.active.camera.V);
|
||||
Scene.active.camera.buildMatrix();
|
||||
|
||||
// right half of render target
|
||||
g.viewport(renderHalfWidth, 0, renderHalfWidth, renderHeight);
|
||||
g.scissor(renderHalfWidth, 0, renderHalfWidth, renderHeight);
|
||||
drawMeshes();
|
||||
|
||||
// restore for post-processing
|
||||
g.disableScissor();
|
||||
g.viewport(0, 0, renderWidth, renderHeight);
|
||||
}
|
||||
else { // Simulate
|
||||
Scene.active.camera.buildProjection(halfw / apph);
|
||||
vrSimulateMode = true;
|
||||
var ipd_offset = 0.032 * 35.0;
|
||||
|
||||
// Left eye
|
||||
g.viewport(0, 0, halfw, apph);
|
||||
#if (kha_webgl && lnx_vr)
|
||||
if (vrCenterCameraWorld == null) vrCenterCameraWorld = Mat4.identity();
|
||||
vrCenterCameraWorld.setFrom(Scene.active.camera.transform.world);
|
||||
#end
|
||||
|
||||
Scene.active.camera.buildProjection(actualHalfWidth / actualHeight);
|
||||
|
||||
Scene.active.camera.transform.move(Scene.active.camera.right(), -ipd_offset);
|
||||
Scene.active.camera.buildMatrix();
|
||||
g.viewport(0, 0, actualHalfWidth, actualHeight);
|
||||
g.scissor(0, 0, actualHalfWidth, actualHeight);
|
||||
drawMeshes();
|
||||
|
||||
// Right eye
|
||||
begin(g, additionalTargets);
|
||||
Scene.active.camera.transform.move(Scene.active.camera.right(), 0.032);
|
||||
Scene.active.camera.transform.move(Scene.active.camera.right(), ipd_offset * 2.0);
|
||||
Scene.active.camera.buildMatrix();
|
||||
g.viewport(halfw, 0, halfw, apph);
|
||||
g.viewport(actualHalfWidth, 0, actualHalfWidth, actualHeight);
|
||||
g.scissor(actualHalfWidth, 0, actualHalfWidth, actualHeight);
|
||||
drawMeshes();
|
||||
|
||||
Scene.active.camera.transform.move(Scene.active.camera.right(), -0.032);
|
||||
Scene.active.camera.transform.move(Scene.active.camera.right(), -ipd_offset);
|
||||
Scene.active.camera.buildMatrix();
|
||||
g.disableScissor();
|
||||
g.viewport(0, 0, actualWidth, actualHeight);
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
Reference in New Issue
Block a user