206 lines
5.6 KiB
Haxe
206 lines
5.6 KiB
Haxe
|
package iron.object;
|
||
|
|
||
|
import kha.graphics4.Graphics;
|
||
|
import kha.graphics4.TextureFormat;
|
||
|
import kha.graphics4.DepthStencilFormat;
|
||
|
import kha.graphics4.CubeMap;
|
||
|
import iron.data.ProbeData;
|
||
|
import iron.data.CameraData;
|
||
|
import iron.data.SceneFormat;
|
||
|
import iron.math.Vec4;
|
||
|
import iron.math.Mat4;
|
||
|
|
||
|
class ProbeObject extends Object {
|
||
|
|
||
|
#if rp_probes
|
||
|
|
||
|
public var data: ProbeData;
|
||
|
public var renderTarget: kha.Image = null;
|
||
|
public var camera: CameraObject = null;
|
||
|
public var ready = false;
|
||
|
|
||
|
// Cubemap update
|
||
|
public var perFrame = false; // Update probe every frame
|
||
|
public var redraw = true; // Update probe next frame
|
||
|
|
||
|
var m1: Mat4;
|
||
|
var m2: Mat4;
|
||
|
var proben: Vec4;
|
||
|
var probep: Vec4;
|
||
|
// static var v = new Vec4();
|
||
|
static var p = new Vec4();
|
||
|
static var q = new Vec4();
|
||
|
|
||
|
public function new(data: ProbeData) {
|
||
|
super();
|
||
|
this.data = data;
|
||
|
Scene.active.probes.push(this);
|
||
|
iron.App.notifyOnInit(init);
|
||
|
}
|
||
|
|
||
|
public override function remove() {
|
||
|
if (Scene.active != null) Scene.active.probes.remove(this);
|
||
|
// if (camera != null) camera.remove();
|
||
|
super.remove();
|
||
|
}
|
||
|
|
||
|
function init() {
|
||
|
probep = transform.world.getLoc();
|
||
|
proben = transform.up().normalize();
|
||
|
proben.w = -probep.dot(proben);
|
||
|
|
||
|
if (data.raw.type == "planar") {
|
||
|
m1 = Mat4.identity();
|
||
|
m2 = Mat4.identity();
|
||
|
reflect(m1, proben, probep);
|
||
|
reflect(m2, new Vec4(0, 1, 0), probep);
|
||
|
|
||
|
transform.scale.z = 1.0; // Only take dim.z into account
|
||
|
transform.buildMatrix();
|
||
|
|
||
|
// var aspect = transform.scale.x / transform.scale.y;
|
||
|
var aspect = iron.App.w() / iron.App.h(); // TODO
|
||
|
var craw: TCameraData = {
|
||
|
name: raw.name + "_Camera",
|
||
|
near_plane: Scene.active.camera.data.raw.near_plane,
|
||
|
far_plane: Scene.active.camera.data.raw.far_plane,
|
||
|
fov: Scene.active.camera.data.raw.fov,
|
||
|
aspect: aspect
|
||
|
};
|
||
|
new CameraData(craw, function(cdata: CameraData) {
|
||
|
camera = new CameraObject(cdata);
|
||
|
camera.renderTarget = kha.Image.createRenderTarget(
|
||
|
iron.App.w(), // TODO
|
||
|
iron.App.h(),
|
||
|
TextureFormat.RGBA32,
|
||
|
DepthStencilFormat.NoDepthAndStencil
|
||
|
);
|
||
|
camera.name = craw.name;
|
||
|
camera.setParent(iron.Scene.active.root);
|
||
|
// Make target bindable from render path
|
||
|
var rt = new RenderPath.RenderTarget(new RenderPath.RenderTargetRaw());
|
||
|
rt.raw.name = raw.name;
|
||
|
rt.image = camera.renderTarget;
|
||
|
RenderPath.active.renderTargets.set(rt.raw.name, rt);
|
||
|
ready = true;
|
||
|
});
|
||
|
}
|
||
|
else if (data.raw.type == "cubemap") {
|
||
|
transform.scale.x *= transform.dim.x;
|
||
|
transform.scale.y *= transform.dim.y;
|
||
|
transform.scale.z *= transform.dim.z;
|
||
|
transform.buildMatrix();
|
||
|
|
||
|
var craw: TCameraData = {
|
||
|
name: data.raw.name + "_Camera",
|
||
|
near_plane: Scene.active.camera.data.raw.near_plane,
|
||
|
far_plane: Scene.active.camera.data.raw.far_plane,
|
||
|
fov: 1.5708, // pi/2
|
||
|
aspect: 1.0
|
||
|
};
|
||
|
new CameraData(craw, function(cdata: CameraData) {
|
||
|
camera = new CameraObject(cdata);
|
||
|
camera.renderTargetCube = CubeMap.createRenderTarget(
|
||
|
1024, // TODO
|
||
|
TextureFormat.RGBA32,
|
||
|
DepthStencilFormat.NoDepthAndStencil
|
||
|
);
|
||
|
camera.name = craw.name;
|
||
|
camera.setParent(iron.Scene.active.root);
|
||
|
// Make target bindable from render path
|
||
|
var rt = new RenderPath.RenderTarget(new RenderPath.RenderTargetRaw());
|
||
|
rt.raw.name = raw.name;
|
||
|
rt.raw.is_cubemap = true;
|
||
|
rt.isCubeMap = true;
|
||
|
rt.cubeMap = camera.renderTargetCube;
|
||
|
RenderPath.active.renderTargets.set(rt.raw.name, rt);
|
||
|
ready = true;
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static function reflect(m: Mat4, n: Vec4, p: Vec4) {
|
||
|
var c = -p.dot(n);
|
||
|
m._00 = 1 - 2 * n.x * n.x;
|
||
|
m._10 = - 2 * n.x * n.y;
|
||
|
m._20 = - 2 * n.x * n.z;
|
||
|
m._30 = - 2 * n.x * c;
|
||
|
m._01 = - 2 * n.x * n.y;
|
||
|
m._11 = 1 - 2 * n.y * n.y;
|
||
|
m._21 = - 2 * n.y * n.z;
|
||
|
m._31 = - 2 * n.y * c;
|
||
|
m._02 = - 2 * n.x * n.z;
|
||
|
m._12 = - 2 * n.y * n.z;
|
||
|
m._22 = 1 - 2 * n.z * n.z;
|
||
|
m._32 = - 2 * n.z * c;
|
||
|
m._03 = 0;
|
||
|
m._13 = 0;
|
||
|
m._23 = 0;
|
||
|
m._33 = 1;
|
||
|
}
|
||
|
|
||
|
static inline function sign(f: Float): Float {
|
||
|
return f > 0.0 ? 1.0 : f < 0.0 ? -1.0 : 0.0;
|
||
|
}
|
||
|
|
||
|
static function obliqueProjection(m: Mat4, plane: Vec4) {
|
||
|
// http://www.terathon.com/code/oblique.html
|
||
|
p.x = (sign(plane.x) + m._20) / m._00;
|
||
|
p.y = (sign(plane.y) + m._21) / m._11;
|
||
|
p.z = -1.0;
|
||
|
p.w = (1.0 + m._22) / m._32;
|
||
|
q.setFrom(plane).mult(2.0 / plane.dot(p));
|
||
|
m._02 = q.x;
|
||
|
m._12 = q.y;
|
||
|
m._22 = q.z + 1.0;
|
||
|
m._32 = q.w;
|
||
|
}
|
||
|
|
||
|
function cullProbe(camera: CameraObject): Bool {
|
||
|
if (camera.data.raw.frustum_culling) {
|
||
|
if (!CameraObject.sphereInFrustum(camera.frustumPlanes, transform, 1.0)) {
|
||
|
culled = true;
|
||
|
return culled;
|
||
|
}
|
||
|
}
|
||
|
culled = false;
|
||
|
return culled;
|
||
|
}
|
||
|
|
||
|
public function render(g: Graphics, activeCamera: CameraObject) {
|
||
|
if (camera == null || !ready || !RenderPath.active.ready || !visible || cullProbe(activeCamera)) return;
|
||
|
|
||
|
if (data.raw.type == "planar") {
|
||
|
camera.V.setFrom(m1);
|
||
|
camera.V.multmat(activeCamera.V);
|
||
|
camera.V.multmat(m2);
|
||
|
camera.transform.local.getInverse(camera.V);
|
||
|
camera.transform.decompose();
|
||
|
// Skip objects below the reflection plane
|
||
|
// v.setFrom(proben).applyproj(camera.V);
|
||
|
// obliqueProjection(#if (lnx_taa) camera.noJitterP #else camera.P #end, v);
|
||
|
camera.renderFrame(g);
|
||
|
}
|
||
|
else if (data.raw.type == "cubemap") {
|
||
|
if (perFrame || redraw) {
|
||
|
for (i in 0...6) {
|
||
|
camera.currentFace = i;
|
||
|
#if (!kha_opengl && !kha_webgl)
|
||
|
var flip = (i == 2 || i == 3) ? true : false; // Flip +Y, -Y
|
||
|
#else
|
||
|
var flip = false;
|
||
|
#end
|
||
|
CameraObject.setCubeFace(camera.V, probep, i, flip);
|
||
|
camera.transform.local.getInverse(camera.V);
|
||
|
camera.transform.decompose();
|
||
|
camera.renderFrame(g);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
redraw = false;
|
||
|
}
|
||
|
|
||
|
#end
|
||
|
}
|