forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
104
leenkx/Sources/leenkx/renderpath/Downsampler.hx
Normal file
104
leenkx/Sources/leenkx/renderpath/Downsampler.hx
Normal file
@ -0,0 +1,104 @@
|
||||
package leenkx.renderpath;
|
||||
|
||||
import haxe.ds.ReadOnlyArray;
|
||||
|
||||
import iron.RenderPath;
|
||||
import iron.data.MaterialData;
|
||||
import iron.object.Object;
|
||||
|
||||
import leenkx.math.Helper;
|
||||
|
||||
abstract class Downsampler {
|
||||
|
||||
public static var currentMipLevel(default, null) = 0;
|
||||
public static var numMipLevels(default, null) = 0;
|
||||
|
||||
static var isRegistered = false;
|
||||
|
||||
final path: RenderPath;
|
||||
final shaderPassHandle: String;
|
||||
final maxNumMips: Int;
|
||||
final mipmaps: Array<RenderTarget>;
|
||||
|
||||
function new(path: RenderPath, shaderPassHandle: String, maxNumMips: Int) {
|
||||
this.path = path;
|
||||
this.shaderPassHandle = shaderPassHandle;
|
||||
this.maxNumMips = maxNumMips;
|
||||
|
||||
this.mipmaps = new Array();
|
||||
mipmaps.resize(maxNumMips);
|
||||
}
|
||||
|
||||
public static function create(path: RenderPath, shaderPassHandle: String, rtName: String, maxNumMips: Int = 10): Downsampler {
|
||||
if (!isRegistered) {
|
||||
isRegistered = true;
|
||||
iron.object.Uniforms.externalIntLinks.push(intLink);
|
||||
}
|
||||
|
||||
// TODO, implement when Kha supports render targets in compute shaders
|
||||
// and allows to query whether compute shaders are available
|
||||
// if (RenderPath.hasComputeSupport()) {
|
||||
// return new DownsamplerCompute(path, shaderPassHandle, rtName, maxNumMips);
|
||||
// }
|
||||
// else {
|
||||
return new DownsamplerFragment(path, shaderPassHandle, rtName, maxNumMips);
|
||||
// }
|
||||
}
|
||||
|
||||
static function intLink(object: Object, mat: MaterialData, link: String): Null<Int> {
|
||||
return switch (link) {
|
||||
case "_downsampleCurrentMip": Downsampler.currentMipLevel;
|
||||
case "_downsampleNumMips": Downsampler.numMipLevels;
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
|
||||
public inline function getMipmaps(): ReadOnlyArray<RenderTarget> {
|
||||
return mipmaps;
|
||||
}
|
||||
|
||||
abstract public function dispatch(srcImageName: String, numMips: Int = 0): Void;
|
||||
}
|
||||
|
||||
private class DownsamplerFragment extends Downsampler {
|
||||
|
||||
public function new(path: RenderPath, shaderPassHandle: String, rtName: String, maxNumMips: Int) {
|
||||
super(path, shaderPassHandle, maxNumMips);
|
||||
|
||||
var prevScale = 1.0;
|
||||
for (i in 0...maxNumMips) {
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = rtName + "_mip_" + i;
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.scale = (prevScale *= 0.5);
|
||||
t.format = Inc.getHdrFormat();
|
||||
|
||||
mipmaps[i] = path.createRenderTarget(t);
|
||||
}
|
||||
|
||||
path.loadShader(shaderPassHandle);
|
||||
}
|
||||
|
||||
public function dispatch(srcImageName: String, numMips: Int = 0) {
|
||||
Helper.clampInt(numMips, 0, maxNumMips);
|
||||
if (numMips == 0) {
|
||||
numMips = maxNumMips;
|
||||
}
|
||||
|
||||
final srcImageRT = path.renderTargets.get(srcImageName);
|
||||
assert(Error, srcImageRT != null, 'Could not find render target with name $srcImageName');
|
||||
|
||||
final srcImage = srcImageRT.image;
|
||||
assert(Error, srcImage != null);
|
||||
|
||||
Downsampler.numMipLevels = numMips;
|
||||
for (i in 0...numMips) {
|
||||
Downsampler.currentMipLevel = i;
|
||||
path.setTarget(mipmaps[i].raw.name);
|
||||
path.clearTarget();
|
||||
path.bindTarget(i == 0 ? srcImageName : mipmaps[i - 1].raw.name, "tex");
|
||||
path.drawShader(shaderPassHandle);
|
||||
}
|
||||
}
|
||||
}
|
51
leenkx/Sources/leenkx/renderpath/DynamicResolutionScale.hx
Normal file
51
leenkx/Sources/leenkx/renderpath/DynamicResolutionScale.hx
Normal file
@ -0,0 +1,51 @@
|
||||
package leenkx.renderpath;
|
||||
|
||||
import iron.RenderPath;
|
||||
|
||||
class DynamicResolutionScale {
|
||||
|
||||
public static var dynamicScale = 1.0;
|
||||
|
||||
static var firstFrame = true;
|
||||
static inline var startScaleMs = 30;
|
||||
static inline var scaleRangeMs = 10;
|
||||
static inline var maxScale = 0.6;
|
||||
|
||||
public static function run(path: RenderPath) {
|
||||
if (firstFrame) {
|
||||
iron.App.notifyOnRender(render);
|
||||
firstFrame = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: execute once per frame max
|
||||
if (frameTimeAvg > startScaleMs && frameTimeAvg < 100) {
|
||||
var overTime = Math.min(scaleRangeMs, frameTimeAvg - startScaleMs);
|
||||
var scale = 1.0 - (overTime / scaleRangeMs) * (1.0 - maxScale);
|
||||
var w = Std.int(iron.App.w() * scale);
|
||||
var h = Std.int(iron.App.h() * scale);
|
||||
path.setCurrentViewport(w, h);
|
||||
path.setCurrentScissor(w, h);
|
||||
dynamicScale = scale;
|
||||
}
|
||||
else dynamicScale = 1.0;
|
||||
}
|
||||
|
||||
static var frameTime: Float;
|
||||
static var lastTime: Float = 0;
|
||||
static var totalTime: Float = 0;
|
||||
static var frames = 0;
|
||||
static var frameTimeAvg = 0.0;
|
||||
|
||||
public static function render(g: kha.graphics4.Graphics) {
|
||||
frameTime = kha.Scheduler.realTime() - lastTime;
|
||||
lastTime = kha.Scheduler.realTime();
|
||||
totalTime += frameTime;
|
||||
frames++;
|
||||
if (totalTime >= 1) {
|
||||
frameTimeAvg = Std.int(totalTime / frames * 10000) / 10;
|
||||
totalTime = 0;
|
||||
frames = 0;
|
||||
}
|
||||
}
|
||||
}
|
123
leenkx/Sources/leenkx/renderpath/HosekWilkie.hx
Normal file
123
leenkx/Sources/leenkx/renderpath/HosekWilkie.hx
Normal file
@ -0,0 +1,123 @@
|
||||
// An Analytic Model for Full Spectral Sky-Dome Radiance
|
||||
// Lukas Hosek and Alexander Wilkie
|
||||
// Based on https://github.com/ddiakopoulos/sandbox
|
||||
package leenkx.renderpath;
|
||||
|
||||
import kha.math.FastVector3;
|
||||
import iron.data.WorldData;
|
||||
|
||||
class HosekWilkieRadianceData {
|
||||
|
||||
public var A = new FastVector3();
|
||||
public var B = new FastVector3();
|
||||
public var C = new FastVector3();
|
||||
public var D = new FastVector3();
|
||||
public var E = new FastVector3();
|
||||
public var F = new FastVector3();
|
||||
public var G = new FastVector3();
|
||||
public var H = new FastVector3();
|
||||
public var I = new FastVector3();
|
||||
public var Z = new FastVector3();
|
||||
|
||||
function evaluateSpline(spline: Array<Float>, index: Int, stride: Int, value: Float): Float {
|
||||
return
|
||||
1 * Math.pow(1 - value, 5) * spline[index ] +
|
||||
5 * Math.pow(1 - value, 4) * Math.pow(value, 1) * spline[index + 1 * stride] +
|
||||
10 * Math.pow(1 - value, 3) * Math.pow(value, 2) * spline[index + 2 * stride] +
|
||||
10 * Math.pow(1 - value, 2) * Math.pow(value, 3) * spline[index + 3 * stride] +
|
||||
5 * Math.pow(1 - value, 1) * Math.pow(value, 4) * spline[index + 4 * stride] +
|
||||
1 * Math.pow(value, 5) * spline[index + 5 * stride];
|
||||
}
|
||||
|
||||
function clamp(n: Int, lower: Int, upper: Int): Int {
|
||||
return n <= lower ? lower : n >= upper ? upper : n;
|
||||
}
|
||||
|
||||
function clampF(n: Float, lower: Float, upper: Float): Float {
|
||||
return n <= lower ? lower : n >= upper ? upper : n;
|
||||
}
|
||||
|
||||
function evaluate(dataset: Array<Float>, index: Int, stride: Int, turbidity: Float, albedo: Float, sunTheta: Float): Float {
|
||||
// Splines are functions of elevation^1/3
|
||||
var elevationK: Float = Math.pow(Math.max(0.0, 1.0 - sunTheta / (Math.PI / 2.0)), 1.0 / 3.0);
|
||||
|
||||
// Table has values for turbidity 1..10
|
||||
var turbidity0: Int = clamp(Std.int(turbidity), 1, 10);
|
||||
var turbidity1: Int = Std.int(Math.min(turbidity0 + 1, 10));
|
||||
var turbidityK: Float = clampF(turbidity - turbidity0, 0.0, 1.0);
|
||||
|
||||
var datasetA0Index = index;
|
||||
var datasetA1Index = index + stride * 6 * 10;
|
||||
|
||||
var a0t0: Float = evaluateSpline(dataset, datasetA0Index + stride * 6 * (turbidity0 - 1), stride, elevationK);
|
||||
var a1t0: Float = evaluateSpline(dataset, datasetA1Index + stride * 6 * (turbidity0 - 1), stride, elevationK);
|
||||
var a0t1: Float = evaluateSpline(dataset, datasetA0Index + stride * 6 * (turbidity1 - 1), stride, elevationK);
|
||||
var a1t1: Float = evaluateSpline(dataset, datasetA1Index + stride * 6 * (turbidity1 - 1), stride, elevationK);
|
||||
|
||||
return a0t0 * (1 - albedo) * (1 - turbidityK) + a1t0 * albedo * (1 - turbidityK) + a0t1 * (1 - albedo) * turbidityK + a1t1 * albedo * turbidityK;
|
||||
}
|
||||
|
||||
function hosek_wilkie(cos_theta: Float, gamma: Float, cos_gamma: Float, A: FastVector3, B: FastVector3, C: FastVector3, D: FastVector3, E: FastVector3, F: FastVector3, G: FastVector3, H: FastVector3, I: FastVector3): FastVector3 {
|
||||
var val = (1.0 + cos_gamma * cos_gamma);
|
||||
var chix = val / Math.pow(1.0 + H.x * H.x - 2.0 * cos_gamma * H.x, 1.5);
|
||||
var chiy = val / Math.pow(1.0 + H.y * H.y - 2.0 * cos_gamma * H.y, 1.5);
|
||||
var chiz = val / Math.pow(1.0 + H.z * H.z - 2.0 * cos_gamma * H.z, 1.5);
|
||||
var chi = new FastVector3(chix, chiy, chiz);
|
||||
|
||||
var vx = (1.0 + A.x * Math.exp(B.x / (cos_theta + 0.01))) * (C.x + D.x * Math.exp(E.x * gamma) + F.x * (cos_gamma * cos_gamma) + G.x * chi.x + I.x * Math.sqrt(Math.max(0.0, cos_theta)));
|
||||
var vy = (1.0 + A.y * Math.exp(B.y / (cos_theta + 0.01))) * (C.y + D.y * Math.exp(E.y * gamma) + F.y * (cos_gamma * cos_gamma) + G.y * chi.y + I.y * Math.sqrt(Math.max(0.0, cos_theta)));
|
||||
var vz = (1.0 + A.z * Math.exp(B.z / (cos_theta + 0.01))) * (C.z + D.z * Math.exp(E.z * gamma) + F.z * (cos_gamma * cos_gamma) + G.z * chi.z + I.z * Math.sqrt(Math.max(0.0, cos_theta)));
|
||||
return new FastVector3(vx, vy, vz);
|
||||
}
|
||||
|
||||
function setVector(v: FastVector3, index: Int, f: Float) {
|
||||
index == 0 ? v.x = f : index == 1 ? v.y = f : v.z = f;
|
||||
}
|
||||
|
||||
public function new() {}
|
||||
|
||||
public function recompute(sunTheta: Float, turbidity: kha.FastFloat, albedo: kha.FastFloat, normalizedSunY: Float) {
|
||||
for (i in 0...3) {
|
||||
setVector(A, i, evaluate(HosekWilkieData.datasetsRGB[i], 0, 9, turbidity, albedo, sunTheta));
|
||||
setVector(B, i, evaluate(HosekWilkieData.datasetsRGB[i], 1, 9, turbidity, albedo, sunTheta));
|
||||
setVector(C, i, evaluate(HosekWilkieData.datasetsRGB[i], 2, 9, turbidity, albedo, sunTheta));
|
||||
setVector(D, i, evaluate(HosekWilkieData.datasetsRGB[i], 3, 9, turbidity, albedo, sunTheta));
|
||||
setVector(E, i, evaluate(HosekWilkieData.datasetsRGB[i], 4, 9, turbidity, albedo, sunTheta));
|
||||
setVector(F, i, evaluate(HosekWilkieData.datasetsRGB[i], 5, 9, turbidity, albedo, sunTheta));
|
||||
setVector(G, i, evaluate(HosekWilkieData.datasetsRGB[i], 6, 9, turbidity, albedo, sunTheta));
|
||||
|
||||
// Swapped in the dataset
|
||||
setVector(H, i, evaluate(HosekWilkieData.datasetsRGB[i], 8, 9, turbidity, albedo, sunTheta));
|
||||
setVector(I, i, evaluate(HosekWilkieData.datasetsRGB[i], 7, 9, turbidity, albedo, sunTheta));
|
||||
|
||||
setVector(Z, i, evaluate(HosekWilkieData.datasetsRGBRad[i], 0, 1, turbidity, albedo, sunTheta));
|
||||
}
|
||||
|
||||
if (normalizedSunY != 0.0) {
|
||||
var S: FastVector3 = hosek_wilkie(Math.cos(sunTheta), 0, 1.0, A, B, C, D, E, F, G, H, I);
|
||||
S.x *= Z.x;
|
||||
S.y *= Z.y;
|
||||
S.z *= Z.z;
|
||||
var dotS = S.dot(new FastVector3(0.2126, 0.7152, 0.0722));
|
||||
Z.x /= dotS;
|
||||
Z.y /= dotS;
|
||||
Z.z /= dotS;
|
||||
Z = Z.mult(normalizedSunY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class HosekWilkie {
|
||||
|
||||
public static var data: HosekWilkieRadianceData = null;
|
||||
|
||||
public static function recompute(world: WorldData) {
|
||||
if (world == null || world.raw.sun_direction == null) return;
|
||||
if (data == null) data = new HosekWilkieRadianceData();
|
||||
// Clamp Z for night cycle
|
||||
var sunZ = world.raw.sun_direction[2] > 0 ? world.raw.sun_direction[2] : 0;
|
||||
var sunPositionX = Math.acos(sunZ);
|
||||
var normalizedSunY: kha.FastFloat = 1.15;
|
||||
data.recompute(sunPositionX, world.raw.turbidity, world.raw.ground_albedo, normalizedSunY);
|
||||
}
|
||||
}
|
3855
leenkx/Sources/leenkx/renderpath/HosekWilkieData.hx
Normal file
3855
leenkx/Sources/leenkx/renderpath/HosekWilkieData.hx
Normal file
File diff suppressed because it is too large
Load Diff
1955
leenkx/Sources/leenkx/renderpath/Inc.hx
Normal file
1955
leenkx/Sources/leenkx/renderpath/Inc.hx
Normal file
File diff suppressed because it is too large
Load Diff
231
leenkx/Sources/leenkx/renderpath/Nishita.hx
Normal file
231
leenkx/Sources/leenkx/renderpath/Nishita.hx
Normal file
@ -0,0 +1,231 @@
|
||||
package leenkx.renderpath;
|
||||
|
||||
import kha.FastFloat;
|
||||
import kha.arrays.Float32Array;
|
||||
import kha.graphics4.TextureFormat;
|
||||
import kha.graphics4.Usage;
|
||||
|
||||
import iron.data.WorldData;
|
||||
import iron.math.Vec2;
|
||||
import iron.math.Vec3;
|
||||
|
||||
import leenkx.math.Helper;
|
||||
|
||||
/**
|
||||
Utility class to control the Nishita sky model.
|
||||
**/
|
||||
class Nishita {
|
||||
|
||||
public static var data: NishitaData = null;
|
||||
|
||||
/**
|
||||
Recomputes the nishita lookup table after the density settings changed.
|
||||
Do not call this method on every frame (it's slow)!
|
||||
**/
|
||||
public static function recompute(world: WorldData) {
|
||||
if (world == null || world.raw.nishita_density == null) return;
|
||||
if (data == null) data = new NishitaData();
|
||||
|
||||
var density = world.raw.nishita_density;
|
||||
data.computeLUT(new Vec3(density[0], density[1], density[2]));
|
||||
}
|
||||
|
||||
/** Sets the sky's density parameters and calls `recompute()` afterwards. **/
|
||||
public static function setDensity(world: WorldData, densityAir: FastFloat, densityDust: FastFloat, densityOzone: FastFloat) {
|
||||
if (world == null) return;
|
||||
|
||||
if (world.raw.nishita_density == null) world.raw.nishita_density = new Float32Array(3);
|
||||
var density = world.raw.nishita_density;
|
||||
density[0] = Helper.clamp(densityAir, 0, 10);
|
||||
density[1] = Helper.clamp(densityDust, 0, 10);
|
||||
density[2] = Helper.clamp(densityOzone, 0, 10);
|
||||
|
||||
recompute(world);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This class holds the precalculated result of the inner scattering integral
|
||||
of the Nishita sky model. The outer integral is calculated in
|
||||
[`leenkx/Shaders/std/sky.glsl`](https://github.com/leenkx3d/leenkx/blob/master/Shaders/std/sky.glsl).
|
||||
|
||||
@see `leenkx.renderpath.Nishita`
|
||||
**/
|
||||
class NishitaData {
|
||||
|
||||
public var lut: kha.Image;
|
||||
|
||||
/**
|
||||
The amount of individual sample heights stored in the LUT (and the width
|
||||
of the LUT image).
|
||||
**/
|
||||
public static var lutHeightSteps = 128;
|
||||
/**
|
||||
The amount of individual sun angle steps stored in the LUT (and the
|
||||
height of the LUT image).
|
||||
**/
|
||||
public static var lutAngleSteps = 128;
|
||||
|
||||
/**
|
||||
Amount of steps for calculating the inner scattering integral. Heigher
|
||||
values are more precise but take longer to compute.
|
||||
**/
|
||||
public static var jSteps = 8;
|
||||
|
||||
/** Radius of the atmosphere in kilometers. **/
|
||||
public static var radiusAtmo = 6420.0;
|
||||
/**
|
||||
Radius of the planet in kilometers. The default value is the earth radius as
|
||||
defined in Cycles.
|
||||
**/
|
||||
public static var radiusPlanet = 6360.0;
|
||||
|
||||
/** Rayleigh scattering coefficient. **/
|
||||
public static var rayleighCoeff = new Vec3(5.5e-6, 13.0e-6, 22.4e-6);
|
||||
/** Rayleigh scattering scale parameter. **/
|
||||
public static var rayleighScale = 8e3;
|
||||
|
||||
/** Mie scattering coefficient. **/
|
||||
public static var mieCoeff = 2e-5;
|
||||
/** Mie scattering scale parameter. **/
|
||||
public static var mieScale = 1.2e3;
|
||||
|
||||
/** Ozone scattering coefficient. **/
|
||||
// The ozone absorption coefficients are taken from Cycles code.
|
||||
// Because Cycles calculates 21 wavelengths, we use the coefficients
|
||||
// which are closest to the RGB wavelengths (645nm, 510nm, 440nm).
|
||||
// Precalculating values by simulating Blender's spec_to_xyz() function
|
||||
// to include all 21 wavelengths gave unrealistic results.
|
||||
public static var ozoneCoeff = new Vec3(1.59051840791988e-6, 0.00000096707041180970, 0.00000007309568762914);
|
||||
|
||||
public function new() {}
|
||||
|
||||
/** Approximates the density of ozone for a given sample height. **/
|
||||
function getOzoneDensity(height: FastFloat): FastFloat {
|
||||
// Values are taken from Cycles code
|
||||
if (height < 10000.0 || height >= 40000.0) {
|
||||
return 0.0;
|
||||
}
|
||||
if (height < 25000.0) {
|
||||
return (height - 10000.0) / 15000.0;
|
||||
}
|
||||
return -((height - 40000.0) / 15000.0);
|
||||
}
|
||||
|
||||
/**
|
||||
Ray-sphere intersection test that assumes the sphere is centered at the
|
||||
origin. There is no intersection when result.x > result.y. Otherwise
|
||||
this function returns the distances to the two intersection points,
|
||||
which might be equal.
|
||||
**/
|
||||
function raySphereIntersection(rayOrigin: Vec3, rayDirection: Vec3, sphereRadius: Float): Vec2 {
|
||||
// Algorithm is described here: https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection
|
||||
var a = rayDirection.dot(rayDirection);
|
||||
var b = 2.0 * rayDirection.dot(rayOrigin);
|
||||
var c = rayOrigin.dot(rayOrigin) - (sphereRadius * sphereRadius);
|
||||
var d = (b * b) - 4.0 * a * c;
|
||||
|
||||
// Ray does not intersect the sphere
|
||||
if (d < 0.0) return new Vec2(1e5, -1e5);
|
||||
|
||||
return new Vec2(
|
||||
(-b - Math.sqrt(d)) / (2.0 * a),
|
||||
(-b + Math.sqrt(d)) / (2.0 * a)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Computes the LUT texture for the given density values.
|
||||
@param density 3D vector of air density, dust density, ozone density
|
||||
**/
|
||||
public function computeLUT(density: Vec3) {
|
||||
var imageData = new haxe.io.Float32Array(lutHeightSteps * lutAngleSteps * 4);
|
||||
|
||||
for (x in 0...lutHeightSteps) {
|
||||
var height = (x / (lutHeightSteps - 1));
|
||||
|
||||
// Use quadratic height for better horizon precision
|
||||
height *= height;
|
||||
height *= radiusAtmo * 1000; // Denormalize height
|
||||
|
||||
for (y in 0...lutAngleSteps) {
|
||||
var sunTheta = y / (lutAngleSteps - 1) * 2 - 1;
|
||||
|
||||
// Improve horizon precision
|
||||
// See https://sebh.github.io/publications/egsr2020.pdf (5.3)
|
||||
sunTheta = Helper.sign(sunTheta) * sunTheta * sunTheta;
|
||||
sunTheta = sunTheta * Math.PI / 2 + Math.PI / 2; // Denormalize
|
||||
|
||||
var jODepth = sampleSecondaryRay(height, sunTheta, density);
|
||||
|
||||
var pixelIndex = (x + y * lutHeightSteps) * 4;
|
||||
imageData[pixelIndex + 0] = jODepth.x;
|
||||
imageData[pixelIndex + 1] = jODepth.y;
|
||||
imageData[pixelIndex + 2] = jODepth.z;
|
||||
imageData[pixelIndex + 3] = 1.0; // Unused
|
||||
}
|
||||
}
|
||||
|
||||
lut = kha.Image.fromBytes(imageData.view.buffer, lutHeightSteps, lutAngleSteps, TextureFormat.RGBA128, Usage.StaticUsage);
|
||||
}
|
||||
|
||||
/**
|
||||
Calculates the integral for the secondary ray.
|
||||
**/
|
||||
public function sampleSecondaryRay(height: FastFloat, sunTheta: FastFloat, density: Vec3): Vec3 {
|
||||
var radiusPlanetMeters = radiusPlanet * 1000;
|
||||
|
||||
// Reconstruct values from the shader
|
||||
var iPos = new Vec3(0, 0, height + radiusPlanetMeters);
|
||||
var pSun = new Vec3(0.0, Math.sin(sunTheta), Math.cos(sunTheta)).normalize();
|
||||
|
||||
var jTime: FastFloat = 0.0;
|
||||
// We compute the ray-sphere intersection in km to allow larger
|
||||
// atmosphere radii (radius is squared inside raySphereIntersection())
|
||||
var jStepSize: FastFloat = raySphereIntersection(iPos.clone().mult(0.001), pSun, radiusAtmo).y / jSteps;
|
||||
jStepSize *= 1000; // convert back to m
|
||||
|
||||
// Optical depth accumulators for the secondary ray (Rayleigh, Mie, ozone)
|
||||
var jODepth = new Vec3();
|
||||
|
||||
for (i in 0...jSteps) {
|
||||
|
||||
// Calculate the secondary ray sample position and height
|
||||
var jPos = iPos.clone().add(pSun.clone().mult(jTime + jStepSize * 0.5));
|
||||
var jHeight = jPos.length() - radiusPlanetMeters;
|
||||
|
||||
// Accumulate optical depth
|
||||
var optDepthRayleigh = Math.exp(-jHeight / rayleighScale) * density.x;
|
||||
var optDepthMie = Math.exp(-jHeight / mieScale) * density.y;
|
||||
var optDepthOzone = getOzoneDensity(jHeight) * density.z;
|
||||
jODepth.addf(optDepthRayleigh, optDepthMie, optDepthOzone);
|
||||
|
||||
jTime += jStepSize;
|
||||
}
|
||||
|
||||
jODepth.mult(jStepSize);
|
||||
|
||||
// Precalculate a part of the secondary attenuation.
|
||||
// For one variable (e.g. x) in the vector, the formula is as follows:
|
||||
//
|
||||
// attn.x = exp(-(coeffX * (firstOpticalDepth.x + secondOpticalDepth.x)))
|
||||
//
|
||||
// We can split that up via:
|
||||
//
|
||||
// attn.x = exp(-(coeffX * firstOpticalDepth.x + coeffX * secondOpticalDepth.x))
|
||||
// = exp(-(coeffX * firstOpticalDepth.x)) * exp(-(coeffX * secondOpticalDepth.x))
|
||||
//
|
||||
// The first factor of the resulting multiplication is calculated in the
|
||||
// shader, but we can already precalculate the second one. As a side
|
||||
// effect this keeps the range of the LUT values small because we don't
|
||||
// store the optical depth but the attenuation.
|
||||
var jAttenuation = new Vec3();
|
||||
var mie = mieCoeff * jODepth.y;
|
||||
jAttenuation.addf(mie, mie, mie);
|
||||
jAttenuation.add(rayleighCoeff.clone().mult(jODepth.x));
|
||||
jAttenuation.add(ozoneCoeff.clone().mult(jODepth.z));
|
||||
jAttenuation.exp(jAttenuation.mult(-1));
|
||||
|
||||
return jAttenuation;
|
||||
}
|
||||
}
|
351
leenkx/Sources/leenkx/renderpath/Postprocess.hx
Normal file
351
leenkx/Sources/leenkx/renderpath/Postprocess.hx
Normal file
@ -0,0 +1,351 @@
|
||||
package leenkx.renderpath;
|
||||
|
||||
import iron.data.MaterialData;
|
||||
import iron.math.Vec4;
|
||||
import iron.object.Object;
|
||||
|
||||
class Postprocess {
|
||||
|
||||
public static var colorgrading_global_uniforms = [
|
||||
[6500.0, 1.0, 0.0], //0: Whitebalance, Shadow Max, Highlight Min
|
||||
[1.0, 1.0, 1.0], //1: Tint
|
||||
[1.0, 1.0, 1.0], //2: Saturation
|
||||
[1.0, 1.0, 1.0], //3: Contrast
|
||||
[1.0, 1.0, 1.0], //4: Gamma
|
||||
[1.0, 1.0, 1.0], //5: Gain
|
||||
[1.0, 1.0, 1.0], //6: Offset
|
||||
[1.0, 1.0, 1.0] //7: LUT Strength
|
||||
];
|
||||
|
||||
public static var colorgrading_shadow_uniforms = [
|
||||
[1.0, 1.0, 1.0], //0: Saturation
|
||||
[1.0, 1.0, 1.0], //1: Contrast
|
||||
[1.0, 1.0, 1.0], //2: Gamma
|
||||
[1.0, 1.0, 1.0], //3: Gain
|
||||
[1.0, 1.0, 1.0] //4: Offset
|
||||
];
|
||||
|
||||
public static var colorgrading_midtone_uniforms = [
|
||||
[1.0, 1.0, 1.0], //0: Saturation
|
||||
[1.0, 1.0, 1.0], //1: Contrast
|
||||
[1.0, 1.0, 1.0], //2: Gamma
|
||||
[1.0, 1.0, 1.0], //3: Gain
|
||||
[1.0, 1.0, 1.0] //4: Offset
|
||||
];
|
||||
|
||||
public static var colorgrading_highlight_uniforms = [
|
||||
[1.0, 1.0, 1.0], //0: Saturation
|
||||
[1.0, 1.0, 1.0], //1: Contrast
|
||||
[1.0, 1.0, 1.0], //2: Gamma
|
||||
[1.0, 1.0, 1.0], //3: Gain
|
||||
[1.0, 1.0, 1.0] //4: Offset
|
||||
];
|
||||
|
||||
public static var camera_uniforms = [
|
||||
1.0, //0: Camera: F-Number
|
||||
2.8333, //1: Camera: Shutter time
|
||||
100.0, //2: Camera: ISO
|
||||
0.0, //3: Camera: Exposure Compensation
|
||||
0.01, //4: Fisheye Distortion
|
||||
1, //5: DoF AutoFocus §§ If true, it ignores the DoF Distance setting
|
||||
10.0, //6: DoF Distance
|
||||
160.0, //7: DoF Focal Length mm
|
||||
128, //8: DoF F-Stop
|
||||
0, //9: Tonemapping Method
|
||||
2.0, //10: Distort
|
||||
2.0, //11: Film Grain
|
||||
0.25, //12: Sharpen
|
||||
0.7 //13: Vignette
|
||||
];
|
||||
|
||||
public static var tonemapper_uniforms = [
|
||||
1.0, //0: Slope
|
||||
1.0, //1: Toe
|
||||
1.0, //2: Shoulder
|
||||
1.0, //3: Black Clip
|
||||
1.0 //4: White Clip
|
||||
];
|
||||
|
||||
public static var letterbox_uniforms = [
|
||||
[0.0, 0.0, 0.0], //0: Colors
|
||||
[0.1] //1: Size
|
||||
];
|
||||
|
||||
public static var ssr_uniforms = [
|
||||
0.04, //0: Step
|
||||
0.05, //1: StepMin
|
||||
5.0, //2: Search
|
||||
5.0, //3: Falloff
|
||||
0.6 //4: Jitter
|
||||
];
|
||||
|
||||
public static var bloom_uniforms = [
|
||||
0.8, // 0: Threshold
|
||||
0.5, // 1: Knee
|
||||
0.05, // 2: Strength
|
||||
0.0, // 3: Sample scale (value set by renderpath, not used for realtime postprocess)
|
||||
];
|
||||
|
||||
public static var ssao_uniforms = [
|
||||
1.0,
|
||||
1.0,
|
||||
8
|
||||
];
|
||||
|
||||
public static var lenstexture_uniforms = [
|
||||
0.1, //0: Center Min Clip
|
||||
0.5, //1: Center Max Clip
|
||||
0.1, //2: Luminance Min
|
||||
2.5, //3: Luminance Max
|
||||
2.0 //4: Brightness Exponent
|
||||
];
|
||||
|
||||
public static var chromatic_aberration_uniforms = [
|
||||
2.0, //0: Strength
|
||||
32 //1: Samples
|
||||
];
|
||||
|
||||
public static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
var v:Vec4 = null;
|
||||
|
||||
switch link {
|
||||
case "_globalWeight":
|
||||
var ppm_index = 0;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_global_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_global_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_global_uniforms[ppm_index][2];
|
||||
case "_globalTint":
|
||||
var ppm_index = 1;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_global_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_global_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_global_uniforms[ppm_index][2];
|
||||
case "_globalSaturation":
|
||||
var ppm_index = 2;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_global_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_global_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_global_uniforms[ppm_index][2];
|
||||
case "_globalContrast":
|
||||
var ppm_index = 3;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_global_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_global_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_global_uniforms[ppm_index][2];
|
||||
case "_globalGamma":
|
||||
var ppm_index = 4;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_global_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_global_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_global_uniforms[ppm_index][2];
|
||||
case "_globalGain":
|
||||
var ppm_index = 5;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_global_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_global_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_global_uniforms[ppm_index][2];
|
||||
case "_globalOffset":
|
||||
var ppm_index = 6;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_global_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_global_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_global_uniforms[ppm_index][2];
|
||||
|
||||
//Shadow ppm
|
||||
case "_shadowSaturation":
|
||||
var ppm_index = 0;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_shadow_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_shadow_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_shadow_uniforms[ppm_index][2];
|
||||
case "_shadowContrast":
|
||||
var ppm_index = 1;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_shadow_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_shadow_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_shadow_uniforms[ppm_index][2];
|
||||
case "_shadowGamma":
|
||||
var ppm_index = 2;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_shadow_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_shadow_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_shadow_uniforms[ppm_index][2];
|
||||
case "_shadowGain":
|
||||
var ppm_index = 3;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_shadow_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_shadow_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_shadow_uniforms[ppm_index][2];
|
||||
case "_shadowOffset":
|
||||
var ppm_index = 4;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_shadow_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_shadow_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_shadow_uniforms[ppm_index][2];
|
||||
|
||||
//Midtone ppm
|
||||
case "_midtoneSaturation":
|
||||
var ppm_index = 0;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_midtone_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_midtone_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_midtone_uniforms[ppm_index][2];
|
||||
case "_midtoneContrast":
|
||||
var ppm_index = 1;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_midtone_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_midtone_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_midtone_uniforms[ppm_index][2];
|
||||
case "_midtoneGamma":
|
||||
var ppm_index = 2;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_midtone_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_midtone_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_midtone_uniforms[ppm_index][2];
|
||||
case "_midtoneGain":
|
||||
var ppm_index = 3;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_midtone_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_midtone_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_midtone_uniforms[ppm_index][2];
|
||||
case "_midtoneOffset":
|
||||
var ppm_index = 4;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_midtone_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_midtone_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_midtone_uniforms[ppm_index][2];
|
||||
|
||||
//Highlight ppm
|
||||
case "_highlightSaturation":
|
||||
var ppm_index = 0;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_highlight_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_highlight_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_highlight_uniforms[ppm_index][2];
|
||||
case "_highlightContrast":
|
||||
var ppm_index = 1;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_highlight_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_highlight_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_highlight_uniforms[ppm_index][2];
|
||||
case "_highlightGamma":
|
||||
var ppm_index = 2;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_highlight_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_highlight_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_highlight_uniforms[ppm_index][2];
|
||||
case "_highlightGain":
|
||||
var ppm_index = 3;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_highlight_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_highlight_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_highlight_uniforms[ppm_index][2];
|
||||
case "_highlightOffset":
|
||||
var ppm_index = 4;
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = colorgrading_highlight_uniforms[ppm_index][0];
|
||||
v.y = colorgrading_highlight_uniforms[ppm_index][1];
|
||||
v.z = colorgrading_highlight_uniforms[ppm_index][2];
|
||||
|
||||
//Postprocess Components
|
||||
case "_PPComp1":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = camera_uniforms[0]; //F-Number
|
||||
v.y = camera_uniforms[1]; //Shutter
|
||||
v.z = camera_uniforms[2]; //ISO
|
||||
case "_PPComp2":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = camera_uniforms[3]; //EC
|
||||
v.y = camera_uniforms[4]; //Lens Distortion
|
||||
v.z = camera_uniforms[5]; //DOF Autofocus
|
||||
case "_PPComp3":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = camera_uniforms[6]; //Distance
|
||||
v.y = camera_uniforms[7]; //Focal Length
|
||||
v.z = camera_uniforms[8]; //F-Stop
|
||||
case "_PPComp4":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = Std.int(camera_uniforms[9]); //Tonemapping
|
||||
v.y = camera_uniforms[11]; //Film Grain
|
||||
v.z = tonemapper_uniforms[0]; //Slope
|
||||
case "_PPComp5":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = tonemapper_uniforms[1]; //Toe
|
||||
v.y = tonemapper_uniforms[2]; //Shoulder
|
||||
v.z = tonemapper_uniforms[3]; //Black Clip
|
||||
case "_PPComp6":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = tonemapper_uniforms[4]; //White Clip
|
||||
v.y = lenstexture_uniforms[0]; //Center Min
|
||||
v.z = lenstexture_uniforms[1]; //Center Max
|
||||
case "_PPComp7":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = lenstexture_uniforms[2]; //Lum min
|
||||
v.y = lenstexture_uniforms[3]; //Lum max
|
||||
v.z = lenstexture_uniforms[4]; //Expo
|
||||
case "_PPComp9":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = ssr_uniforms[0]; //Step
|
||||
v.y = ssr_uniforms[1]; //StepMin
|
||||
v.z = ssr_uniforms[2]; //Search
|
||||
case "_PPComp10":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = ssr_uniforms[3]; //Falloff
|
||||
v.y = ssr_uniforms[4]; //Jitter
|
||||
v.z = 0;
|
||||
case "_PPComp11":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = bloom_uniforms[2]; // Bloom Strength
|
||||
v.y = 0; // Unused
|
||||
v.z = 0; // Unused
|
||||
case "_PPComp12":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = ssao_uniforms[0]; //SSAO Strength
|
||||
v.y = ssao_uniforms[1]; //SSAO Radius
|
||||
v.z = ssao_uniforms[2]; //SSAO Max Steps
|
||||
case "_PPComp13":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = chromatic_aberration_uniforms[0]; //CA Strength
|
||||
v.y = chromatic_aberration_uniforms[1]; //CA Samples
|
||||
v.z = 0;
|
||||
case "_PPComp14":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = camera_uniforms[10]; //Distort
|
||||
v.y = camera_uniforms[12]; //Sharpen
|
||||
v.z = camera_uniforms[13]; //Vignette
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static function vec4Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
var v: Vec4 = null;
|
||||
|
||||
switch link {
|
||||
case "_BloomThresholdData":
|
||||
if (Downsampler.currentMipLevel == 0) {
|
||||
// See https://catlikecoding.com/unity/tutorials/advanced-rendering/bloom/#3.4
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = bloom_uniforms[0];
|
||||
v.y = v.x - bloom_uniforms[1];
|
||||
v.z = 2 * bloom_uniforms[1];
|
||||
v.w = 0.25 / (bloom_uniforms[1] + 6.2e-5);
|
||||
}
|
||||
case "_PPComp15":
|
||||
v = iron.object.Uniforms.helpVec;
|
||||
v.x = letterbox_uniforms[0][0]; //Color
|
||||
v.y = letterbox_uniforms[0][1];
|
||||
v.z = letterbox_uniforms[0][2];
|
||||
v.w = letterbox_uniforms[1][0]; //Size
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
public static function init() {
|
||||
iron.object.Uniforms.externalVec3Links.push(vec3Link);
|
||||
iron.object.Uniforms.externalVec4Links.push(vec4Link);
|
||||
}
|
||||
|
||||
}
|
62
leenkx/Sources/leenkx/renderpath/RenderPathCreator.hx
Normal file
62
leenkx/Sources/leenkx/renderpath/RenderPathCreator.hx
Normal file
@ -0,0 +1,62 @@
|
||||
// Reference: https://github.com/leenkx3d/leenkx_docs/blob/master/dev/renderpath.md
|
||||
package leenkx.renderpath;
|
||||
|
||||
import iron.RenderPath;
|
||||
|
||||
class RenderPathCreator {
|
||||
|
||||
public static var path: RenderPath;
|
||||
|
||||
public static var commands: Void->Void = function() {};
|
||||
|
||||
#if (rp_renderer == "Forward")
|
||||
public static var setTargetMeshes: Void->Void = RenderPathForward.setTargetMeshes;
|
||||
public static var drawMeshes: Void->Void = RenderPathForward.drawMeshes;
|
||||
public static var applyConfig: Void->Void = RenderPathForward.applyConfig;
|
||||
#elseif (rp_renderer == "Deferred")
|
||||
public static var setTargetMeshes: Void->Void = RenderPathDeferred.setTargetMeshes;
|
||||
public static var drawMeshes: Void->Void = RenderPathDeferred.drawMeshes;
|
||||
public static var applyConfig: Void->Void = RenderPathDeferred.applyConfig;
|
||||
#else
|
||||
public static var setTargetMeshes: Void->Void = function() {};
|
||||
public static var drawMeshes: Void->Void = function() {};
|
||||
public static var applyConfig: Void->Void = function() {};
|
||||
#end
|
||||
|
||||
public static function get(): RenderPath {
|
||||
path = new RenderPath();
|
||||
Inc.init(path);
|
||||
|
||||
#if rp_pp
|
||||
iron.App.notifyOnInit(function() {
|
||||
Postprocess.init();
|
||||
});
|
||||
#end
|
||||
|
||||
#if (rp_renderer == "Forward")
|
||||
RenderPathForward.init(path);
|
||||
path.commands = function() {
|
||||
RenderPathForward.commands();
|
||||
commands();
|
||||
}
|
||||
path.setupDepthTexture = RenderPathForward.setupDepthTexture;
|
||||
#elseif (rp_renderer == "Deferred")
|
||||
RenderPathDeferred.init(path);
|
||||
path.commands = function() {
|
||||
RenderPathDeferred.commands();
|
||||
commands();
|
||||
}
|
||||
path.setupDepthTexture = RenderPathDeferred.setupDepthTexture;
|
||||
#elseif (rp_renderer == "Raytracer")
|
||||
RenderPathRaytracer.init(path);
|
||||
path.commands = function() {
|
||||
RenderPathRaytracer.commands();
|
||||
commands();
|
||||
}
|
||||
#end
|
||||
return path;
|
||||
}
|
||||
|
||||
// Last target before drawing to framebuffer
|
||||
public static var finalTarget: RenderTarget = null;
|
||||
}
|
1100
leenkx/Sources/leenkx/renderpath/RenderPathDeferred.hx
Normal file
1100
leenkx/Sources/leenkx/renderpath/RenderPathDeferred.hx
Normal file
File diff suppressed because it is too large
Load Diff
736
leenkx/Sources/leenkx/renderpath/RenderPathForward.hx
Normal file
736
leenkx/Sources/leenkx/renderpath/RenderPathForward.hx
Normal file
@ -0,0 +1,736 @@
|
||||
package leenkx.renderpath;
|
||||
|
||||
import iron.RenderPath;
|
||||
import iron.Scene;
|
||||
import iron.object.Clipmap;
|
||||
|
||||
class RenderPathForward {
|
||||
|
||||
#if (rp_renderer == "Forward")
|
||||
|
||||
static var path: RenderPath;
|
||||
|
||||
#if (rp_voxels != "Off")
|
||||
static var res_pre_clear = true;
|
||||
#end
|
||||
|
||||
#if rp_bloom
|
||||
static var bloomDownsampler: Downsampler;
|
||||
static var bloomUpsampler: Upsampler;
|
||||
#end
|
||||
|
||||
public static function setTargetMeshes() {
|
||||
#if rp_render_to_texture
|
||||
{
|
||||
path.setTarget("lbuffer0", [
|
||||
#if (rp_ssr || rp_ssrefr) "lbuffer1", #end
|
||||
#if (rp_ssrefr || lnx_voxelgi_refract) "gbuffer_refraction" #end]
|
||||
);
|
||||
}
|
||||
#else
|
||||
{
|
||||
path.setTarget("");
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
public static function drawMeshes() {
|
||||
path.drawMeshes("mesh");
|
||||
|
||||
#if (rp_background == "World")
|
||||
{
|
||||
if (Scene.active.raw.world_ref != null) {
|
||||
RenderPathCreator.setTargetMeshes();
|
||||
path.drawSkydome("shader_datas/World_" + Scene.active.raw.world_ref + "/World_" + Scene.active.raw.world_ref);
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_blending
|
||||
{
|
||||
RenderPathCreator.setTargetMeshes();
|
||||
path.drawMeshes("blend");
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_translucency && !rp_ssrefr)
|
||||
{
|
||||
RenderPathCreator.setTargetMeshes();
|
||||
Inc.drawTranslucency("lbuffer0");
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
public static function applyConfig() {
|
||||
Inc.applyConfig();
|
||||
}
|
||||
|
||||
public static function init(_path: RenderPath) {
|
||||
|
||||
path = _path;
|
||||
|
||||
#if kha_metal
|
||||
{
|
||||
path.loadShader("shader_datas/clear_color_depth_pass/clear_color_depth_pass");
|
||||
path.loadShader("shader_datas/clear_color_pass/clear_color_pass");
|
||||
path.loadShader("shader_datas/clear_depth_pass/clear_depth_pass");
|
||||
path.clearShader = "shader_datas/clear_color_depth_pass/clear_color_depth_pass";
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_depth_texture
|
||||
{
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "depthtex";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "R32";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_render_to_texture)
|
||||
{
|
||||
path.createDepthBuffer("main", "DEPTH24");
|
||||
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "lbuffer0";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.format = Inc.getHdrFormat();
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.scale = Inc.getSuperSampling();
|
||||
t.depth_buffer = "main";
|
||||
path.createRenderTarget(t);
|
||||
|
||||
#if (rp_ssr || rp_ssrefr)
|
||||
{
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "lbuffer1";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.format = Inc.getHdrFormat();
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_ssrefr || lnx_voxelgi_refract)
|
||||
{
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "gbuffer_refraction";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "RGBA64";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssrefr
|
||||
{
|
||||
path.loadShader("shader_datas/ssrefr_pass/ssrefr_pass");
|
||||
path.loadShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
// holds background depth
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "gbufferD1";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "R32";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "refr";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "RGBA64";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_compositornodes
|
||||
{
|
||||
path.loadShader("shader_datas/compositor_pass/compositor_pass");
|
||||
}
|
||||
#else
|
||||
{
|
||||
path.loadShader("shader_datas/copy_pass/copy_pass");
|
||||
}
|
||||
#end
|
||||
|
||||
#if ((rp_supersampling == 4) || (rp_antialiasing == "SMAA") || (rp_antialiasing == "TAA") || (rp_depth_texture))
|
||||
{
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "buf";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.format = "RGBA32";
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.scale = Inc.getSuperSampling();
|
||||
t.depth_buffer = "main";
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_supersampling == 4)
|
||||
{
|
||||
path.loadShader("shader_datas/supersample_resolve/supersample_resolve");
|
||||
}
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_translucency && !rp_ssrefr)
|
||||
{
|
||||
Inc.initTranslucency();
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_voxels != "Off")
|
||||
{
|
||||
Inc.initGI("voxels");
|
||||
Inc.initGI("voxelsOut");
|
||||
Inc.initGI("voxelsOutB");
|
||||
#if (lnx_voxelgi_shadows || (rp_voxels == "Voxel GI"))
|
||||
Inc.initGI("voxelsSDF");
|
||||
Inc.initGI("voxelsSDFtmp");
|
||||
#end
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
Inc.initGI("voxelsLight");
|
||||
Inc.initGI("voxels_diffuse");
|
||||
Inc.initGI("voxels_specular");
|
||||
#else
|
||||
Inc.initGI("voxels_ao");
|
||||
#end
|
||||
iron.RenderPath.clipmaps = new Array<Clipmap>();
|
||||
for (i in 0...Main.voxelgiClipmapCount) {
|
||||
var clipmap = new iron.object.Clipmap();
|
||||
clipmap.voxelSize = Main.voxelgiVoxelSize * Math.pow(2.0, i);
|
||||
clipmap.extents = new iron.math.Vec3(0.0);
|
||||
clipmap.center = new iron.math.Vec3(0.0);
|
||||
clipmap.offset_prev = new iron.math.Vec3(0.0);
|
||||
iron.RenderPath.clipmaps.push(clipmap);
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
#if ((rp_antialiasing == "SMAA") || (rp_antialiasing == "TAA") || (rp_ssr && !rp_ssr_half) || (rp_water) || (rp_depth_texture))
|
||||
{
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "bufa";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "RGBA32";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "bufb";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "RGBA32";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
|
||||
#if ((rp_antialiasing == "SMAA") || (rp_antialiasing == "TAA"))
|
||||
path.loadShader("shader_datas/smaa_edge_detect/smaa_edge_detect");
|
||||
path.loadShader("shader_datas/smaa_blend_weight/smaa_blend_weight");
|
||||
path.loadShader("shader_datas/smaa_neighborhood_blend/smaa_neighborhood_blend");
|
||||
|
||||
#if (rp_antialiasing == "TAA")
|
||||
{
|
||||
path.loadShader("shader_datas/taa_pass/taa_pass");
|
||||
}
|
||||
#end
|
||||
#end
|
||||
|
||||
#if rp_volumetriclight
|
||||
{
|
||||
path.loadShader("shader_datas/volumetric_light/volumetric_light");
|
||||
path.loadShader("shader_datas/blur_bilat_pass/blur_bilat_pass_x");
|
||||
path.loadShader("shader_datas/blur_bilat_blend_pass/blur_bilat_blend_pass_y");
|
||||
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "singlea";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "R8";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "singleb";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "R8";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_water
|
||||
{
|
||||
path.loadShader("shader_datas/water_pass/water_pass");
|
||||
path.loadShader("shader_datas/copy_pass/copy_pass");
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_depth_texture
|
||||
{
|
||||
path.loadShader("shader_datas/copy_pass/copy_pass");
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_bloom
|
||||
{
|
||||
bloomDownsampler = Downsampler.create(path, "shader_datas/bloom_pass/downsample_pass", "bloom");
|
||||
bloomUpsampler = Upsampler.create(path, "shader_datas/bloom_pass/upsample_pass", bloomDownsampler.getMipmaps());
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_ssr_half || rp_ssgi_half || (rp_voxels != "Off"))
|
||||
{
|
||||
path.loadShader("shader_datas/downsample_depth/downsample_depth");
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "half";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.scale = Inc.getSuperSampling() * 0.5;
|
||||
t.format = "R32"; // R16
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssr
|
||||
{
|
||||
|
||||
path.loadShader("shader_datas/ssr_pass/ssr_pass");
|
||||
path.loadShader("shader_datas/blur_adaptive_pass/blur_adaptive_pass_x");
|
||||
path.loadShader("shader_datas/blur_adaptive_pass/blur_adaptive_pass_y3_blend");
|
||||
|
||||
#if rp_ssr_half
|
||||
{
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "ssra";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.scale = Inc.getSuperSampling() * 0.5;
|
||||
t.format = Inc.getHdrFormat();
|
||||
path.createRenderTarget(t);
|
||||
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "ssrb";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.scale = Inc.getSuperSampling() * 0.5;
|
||||
t.format = Inc.getHdrFormat();
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_chromatic_aberration
|
||||
{
|
||||
path.loadShader("shader_datas/chromatic_aberration_pass/chromatic_aberration_pass");
|
||||
path.loadShader("shader_datas/copy_pass/copy_pass");
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
public static function commands() {
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.drawShadowMapAtlas();
|
||||
#else
|
||||
Inc.drawShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
// Voxels
|
||||
#if (rp_voxels != 'Off')
|
||||
if (leenkx.data.Config.raw.rp_gi != false)
|
||||
{
|
||||
var path = RenderPath.active;
|
||||
|
||||
Inc.computeVoxelsBegin();
|
||||
|
||||
if (iron.RenderPath.pre_clear == true)
|
||||
{
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
path.clearImage("voxelsLight", 0x00000000);
|
||||
#end
|
||||
path.clearImage("voxels", 0x00000000);
|
||||
path.clearImage("voxelsOut", 0x00000000);
|
||||
path.clearImage("voxelsOutB", 0x00000000);
|
||||
#if (lnx_voxelgi_shadows || (rp_voxels == "Voxel GI"))
|
||||
path.clearImage("voxelsSDF", 0x00000000);
|
||||
path.clearImage("voxelsSDFtmp", 0x00000000);
|
||||
#end
|
||||
iron.RenderPath.pre_clear = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
path.clearImage("voxelsLight", 0x00000000);
|
||||
#end
|
||||
path.clearImage("voxels", 0x00000000);
|
||||
Inc.computeVoxelsOffsetPrev();
|
||||
}
|
||||
|
||||
path.setTarget("");
|
||||
var res = iron.RenderPath.getVoxelRes();
|
||||
path.setViewport(res, res);
|
||||
|
||||
path.bindTarget("voxels", "voxels");
|
||||
path.drawMeshes("voxel");
|
||||
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
Inc.computeVoxelsLight();
|
||||
#end
|
||||
Inc.computeVoxelsTemporal();
|
||||
|
||||
#if (lnx_voxelgi_shadows || (rp_voxels == "Voxel GI"))
|
||||
Inc.computeVoxelsSDF();
|
||||
#end
|
||||
|
||||
if (iron.RenderPath.res_pre_clear == true)
|
||||
{
|
||||
iron.RenderPath.res_pre_clear = false;
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
path.clearImage("voxels_diffuse", 0x00000000);
|
||||
path.clearImage("voxels_specular", 0x00000000);
|
||||
#else
|
||||
path.clearImage("voxels_ao", 0x00000000);
|
||||
#end
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
RenderPathCreator.setTargetMeshes();
|
||||
|
||||
#if (rp_background == "Clear")
|
||||
{
|
||||
path.clearTarget(-1, 1.0);
|
||||
}
|
||||
#else
|
||||
{
|
||||
path.clearTarget(null, 1.0);
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_ssrefr || lnx_voxelgi_refract)
|
||||
{
|
||||
path.setTarget("gbuffer_refraction"); // Only clear gbuffer0
|
||||
path.clearTarget(0xff000000);
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_depthprepass
|
||||
{
|
||||
path.drawMeshes("depth");
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssrefr
|
||||
{
|
||||
path.setTarget("gbuffer_refraction");
|
||||
path.clearTarget(0xffffff00);
|
||||
}
|
||||
#end
|
||||
|
||||
RenderPathCreator.setTargetMeshes();
|
||||
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
|
||||
#if (rp_voxels != "Off")
|
||||
if (leenkx.data.Config.raw.rp_gi != false)
|
||||
{
|
||||
#if (rp_voxels == "Voxel AO")
|
||||
Inc.resolveAO();
|
||||
path.bindTarget("voxels_ao", "voxels_ao");
|
||||
#else
|
||||
Inc.resolveDiffuse();
|
||||
Inc.resolveSpecular();
|
||||
path.bindTarget("voxels_diffuse", "voxels_diffuse");
|
||||
path.bindTarget("voxels_specular", "voxels_specular");
|
||||
#end
|
||||
#if lnx_voxelgi_shadows
|
||||
path.bindTarget("voxelsOut", "voxels");
|
||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_stereo
|
||||
{
|
||||
path.drawStereo(drawMeshes);
|
||||
}
|
||||
#else
|
||||
{
|
||||
RenderPathCreator.drawMeshes();
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_render_to_texture || rp_voxels != "Off")
|
||||
{
|
||||
#if (rp_ssr_half || rp_ssgi_half || rp_voxels != "Off")
|
||||
path.setTarget("half");
|
||||
path.bindTarget("_main", "texdepth");
|
||||
path.drawShader("shader_datas/downsample_depth/downsample_depth");
|
||||
#end
|
||||
|
||||
#if rp_ssrefr
|
||||
{
|
||||
if (leenkx.data.Config.raw.rp_ssrefr != false)
|
||||
{
|
||||
//save depth
|
||||
path.setTarget("gbufferD1");
|
||||
path.bindTarget("_main", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
//save background color
|
||||
path.setTarget("refr");
|
||||
path.bindTarget("lbuffer0", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
path.setTarget("lbuffer0", ["lbuffer1", "gbuffer_refraction"]);
|
||||
|
||||
#if (rp_voxels != "Off")
|
||||
path.bindTarget("voxelsOut", "voxels");
|
||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||
#end
|
||||
|
||||
path.drawMeshes("refraction");
|
||||
|
||||
path.setTarget("lbuffer0");
|
||||
path.bindTarget("lbuffer0", "tex");
|
||||
path.bindTarget("refr", "tex1");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("gbufferD1", "gbufferD1");
|
||||
path.bindTarget("lbuffer1", "gbuffer0");
|
||||
path.bindTarget("gbuffer_refraction", "gbuffer_refraction");
|
||||
|
||||
path.drawShader("shader_datas/ssrefr_pass/ssrefr_pass");
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssr
|
||||
{
|
||||
if (leenkx.data.Config.raw.rp_ssr != false) {
|
||||
#if rp_ssr_half
|
||||
var targeta = "ssra";
|
||||
var targetb = "ssrb";
|
||||
#else
|
||||
var targeta = "bufa";
|
||||
var targetb = "bufb";
|
||||
#end
|
||||
|
||||
path.setTarget(targeta);
|
||||
path.bindTarget("lbuffer0", "tex");
|
||||
#if rp_ssr_half
|
||||
path.bindTarget("half", "gbufferD");
|
||||
#else
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
#end
|
||||
path.bindTarget("lbuffer1", "gbuffer0");
|
||||
path.bindTarget("lbuffer0", "gbuffer1");
|
||||
path.drawShader("shader_datas/ssr_pass/ssr_pass");
|
||||
|
||||
path.setTarget(targetb);
|
||||
path.bindTarget(targeta, "tex");
|
||||
path.bindTarget("lbuffer1", "gbuffer0");
|
||||
path.drawShader("shader_datas/blur_adaptive_pass/blur_adaptive_pass_x");
|
||||
|
||||
path.setTarget("lbuffer0");
|
||||
path.bindTarget(targetb, "tex");
|
||||
path.bindTarget("lbuffer1", "gbuffer0");
|
||||
path.drawShader("shader_datas/blur_adaptive_pass/blur_adaptive_pass_y3_blend");
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_bloom
|
||||
{
|
||||
inline Inc.drawBloom("lbuffer0", bloomDownsampler, bloomUpsampler);
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_volumetriclight
|
||||
{
|
||||
path.setTarget("singlea");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
path.drawShader("shader_datas/volumetric_light/volumetric_light");
|
||||
|
||||
path.setTarget("singleb");
|
||||
path.bindTarget("singlea", "tex");
|
||||
path.drawShader("shader_datas/blur_bilat_pass/blur_bilat_pass_x");
|
||||
|
||||
path.setTarget("lbuffer0");
|
||||
path.bindTarget("singleb", "tex");
|
||||
path.drawShader("shader_datas/blur_bilat_blend_pass/blur_bilat_blend_pass_y");
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_water
|
||||
{
|
||||
path.setDepthFrom("lbuffer0", "bufa"); // Unbind depth so we can read it
|
||||
path.depthToRenderTarget.set("main", path.renderTargets.get("buf"));
|
||||
|
||||
path.setTarget("bufa");
|
||||
path.bindTarget("lbuffer0", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
path.setTarget("lbuffer0");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("bufa", "tex");
|
||||
path.drawShader("shader_datas/water_pass/water_pass");
|
||||
|
||||
path.setDepthFrom("lbuffer0", "buf"); // Re-bind depth
|
||||
path.depthToRenderTarget.set("main", path.renderTargets.get("lbuffer0"));
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_chromatic_aberration
|
||||
{
|
||||
path.setTarget("bufa");
|
||||
path.bindTarget("lbuffer0", "tex");
|
||||
path.drawShader("shader_datas/chromatic_aberration_pass/chromatic_aberration_pass");
|
||||
|
||||
path.setTarget("lbuffer0");
|
||||
path.bindTarget("bufa", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_supersampling == 4)
|
||||
var framebuffer = "buf";
|
||||
#else
|
||||
var framebuffer = "";
|
||||
#end
|
||||
|
||||
#if ((rp_antialiasing == "Off") || (rp_antialiasing == "FXAA"))
|
||||
{
|
||||
RenderPathCreator.finalTarget = path.currentTarget;
|
||||
path.setTarget(framebuffer);
|
||||
}
|
||||
#else
|
||||
{
|
||||
path.setTarget("buf");
|
||||
RenderPathCreator.finalTarget = path.currentTarget;
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_compositordepth
|
||||
{
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_compositornodes
|
||||
{
|
||||
path.bindTarget("lbuffer0", "tex");
|
||||
path.drawShader("shader_datas/compositor_pass/compositor_pass");
|
||||
}
|
||||
#else
|
||||
{
|
||||
path.bindTarget("lbuffer0", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
}
|
||||
#end
|
||||
|
||||
#if ((rp_antialiasing == "SMAA") || (rp_antialiasing == "TAA"))
|
||||
{
|
||||
path.setTarget("bufa");
|
||||
path.clearTarget(0x00000000);
|
||||
path.bindTarget("buf", "colorTex");
|
||||
path.drawShader("shader_datas/smaa_edge_detect/smaa_edge_detect");
|
||||
|
||||
path.setTarget("bufb");
|
||||
path.clearTarget(0x00000000);
|
||||
path.bindTarget("bufa", "edgesTex");
|
||||
path.drawShader("shader_datas/smaa_blend_weight/smaa_blend_weight");
|
||||
|
||||
path.setTarget(framebuffer);
|
||||
path.bindTarget("buf", "colorTex");
|
||||
path.bindTarget("bufb", "blendTex");
|
||||
path.drawShader("shader_datas/smaa_neighborhood_blend/smaa_neighborhood_blend");
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_supersampling == 4)
|
||||
{
|
||||
var finalTarget = "";
|
||||
path.setTarget(finalTarget);
|
||||
path.bindTarget(framebuffer, "tex");
|
||||
path.drawShader("shader_datas/supersample_resolve/supersample_resolve");
|
||||
}
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_overlays
|
||||
{
|
||||
path.clearTarget(null, 1.0);
|
||||
path.drawMeshes("overlay");
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
public static function setupDepthTexture() {
|
||||
// When render to texture is off, lbuffer0 does not exist, so for
|
||||
// now do nothing then and pass an empty uniform to the shader
|
||||
#if rp_render_to_texture
|
||||
#if (!kha_opengl)
|
||||
path.setDepthFrom("lbuffer0", "bufa"); // Unbind depth so we can read it
|
||||
path.depthToRenderTarget.set("main", path.renderTargets.get("buf"));
|
||||
#end
|
||||
|
||||
// Copy the depth buffer to the depth texture
|
||||
path.setTarget("depthtex");
|
||||
path.bindTarget("_main", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
#if (!kha_opengl)
|
||||
path.setDepthFrom("lbuffer0", "buf"); // Re-bind depth
|
||||
path.depthToRenderTarget.set("main", path.renderTargets.get("lbuffer0"));
|
||||
#end
|
||||
#end // rp_render_to_texture
|
||||
|
||||
setTargetMeshes();
|
||||
path.bindTarget("depthtex", "depthtex");
|
||||
}
|
||||
#end
|
||||
}
|
150
leenkx/Sources/leenkx/renderpath/RenderPathRaytracer.hx
Normal file
150
leenkx/Sources/leenkx/renderpath/RenderPathRaytracer.hx
Normal file
@ -0,0 +1,150 @@
|
||||
package leenkx.renderpath;
|
||||
|
||||
#if kha_dxr
|
||||
|
||||
import kha.graphics5.CommandList;
|
||||
import kha.graphics5.ConstantBuffer;
|
||||
import kha.graphics5.RayTraceTarget;
|
||||
import kha.graphics5.RayTracePipeline;
|
||||
import kha.graphics5.AccelerationStructure;
|
||||
import kha.graphics5.VertexBuffer;
|
||||
import kha.graphics5.IndexBuffer;
|
||||
import kha.graphics5.VertexStructure;
|
||||
import kha.graphics5.VertexData;
|
||||
import kha.graphics5.TextureFormat;
|
||||
|
||||
import iron.RenderPath;
|
||||
|
||||
class RenderPathRaytracer {
|
||||
|
||||
#if (rp_renderer == "Raytracer")
|
||||
|
||||
static var path: RenderPath;
|
||||
static var ready = false;
|
||||
|
||||
static inline var bufferCount = 2;
|
||||
static var currentBuffer = -1;
|
||||
static var commandList: CommandList;
|
||||
static var framebuffers = new haxe.ds.Vector<kha.graphics5.RenderTarget>(bufferCount);
|
||||
static var constantBuffer: ConstantBuffer;
|
||||
static var target: RayTraceTarget;
|
||||
static var pipeline: RayTracePipeline;
|
||||
static var accel: AccelerationStructure;
|
||||
static var frame = 0.0;
|
||||
|
||||
@:access(iron.data.Geometry)
|
||||
public static function init(_path: RenderPath) {
|
||||
path = _path;
|
||||
|
||||
kha.Assets.loadBlobFromPath("raytrace.cso", function(rayTraceShader: kha.Blob) {
|
||||
ready = true;
|
||||
|
||||
// Command list
|
||||
commandList = new CommandList();
|
||||
for (i in 0...bufferCount) {
|
||||
framebuffers[i] = new kha.graphics5.RenderTarget(iron.App.w(), iron.App.h(), 16, false, TextureFormat.RGBA32,
|
||||
-1, -i - 1 /* hack in an index for backbuffer render targets */);
|
||||
}
|
||||
commandList.end(); // TODO: Otherwise "Reset fails because the command list was not closed"
|
||||
|
||||
// Pipeline
|
||||
constantBuffer = new ConstantBuffer(21 * 4);
|
||||
pipeline = new RayTracePipeline(commandList, rayTraceShader, constantBuffer);
|
||||
|
||||
// Acceleration structure
|
||||
var structure = new VertexStructure();
|
||||
structure.add("pos", VertexData.Float3);
|
||||
structure.add("nor", VertexData.Float3);
|
||||
structure.add("tex", VertexData.Float2);
|
||||
var md = iron.Scene.active.meshes[0].data;
|
||||
var geom = md.geom;
|
||||
var verts = Std.int(geom.positions.length / 4);
|
||||
var vb = new VertexBuffer(verts, structure, kha.graphics5.Usage.StaticUsage);
|
||||
var vba = vb.lock();
|
||||
// iron.data.Geometry.buildVertices(vba, geom.positions, geom.normals);
|
||||
for (i in 0...verts) {
|
||||
vba[i * 8 ] = (geom.positions[i * 4 ] / 32767) * md.scalePos;
|
||||
vba[i * 8 + 1] = (geom.positions[i * 4 + 1] / 32767) * md.scalePos;
|
||||
vba[i * 8 + 2] = (geom.positions[i * 4 + 2] / 32767) * md.scalePos;
|
||||
vba[i * 8 + 3] = geom.normals [i * 2 ] / 32767;
|
||||
vba[i * 8 + 4] = geom.normals [i * 2 + 1] / 32767;
|
||||
vba[i * 8 + 5] = geom.positions[i * 4 + 3] / 32767;
|
||||
vba[i * 8 + 6] = (geom.uvs[i * 2 ] / 32767) * md.scaleTex;
|
||||
vba[i * 8 + 7] = (geom.uvs[i * 2 + 1] / 32767) * md.scaleTex;
|
||||
}
|
||||
vb.unlock();
|
||||
|
||||
var id = geom.indices[0];
|
||||
var ib = new IndexBuffer(id.length, kha.graphics5.Usage.StaticUsage);
|
||||
var iba = ib.lock();
|
||||
for (i in 0...iba.length) iba[i] = id[i];
|
||||
ib.unlock();
|
||||
|
||||
accel = new AccelerationStructure(commandList, vb, ib);
|
||||
|
||||
// Output
|
||||
target = new RayTraceTarget(iron.App.w(), iron.App.h());
|
||||
});
|
||||
}
|
||||
|
||||
public static function commands() {
|
||||
if (!ready) return;
|
||||
|
||||
var g = iron.App.framebuffer.g5;
|
||||
currentBuffer = (currentBuffer + 1) % bufferCount;
|
||||
|
||||
constantBuffer.lock();
|
||||
|
||||
var cam = iron.Scene.active.camera;
|
||||
var ct = cam.transform;
|
||||
var helpMat = iron.math.Mat4.identity();
|
||||
helpMat.setFrom(cam.V);
|
||||
helpMat.multmat(cam.P);
|
||||
helpMat.getInverse(helpMat);
|
||||
constantBuffer.setFloat(0, ct.worldx());
|
||||
constantBuffer.setFloat(4, ct.worldy());
|
||||
constantBuffer.setFloat(8, ct.worldz());
|
||||
constantBuffer.setFloat(12, 1);
|
||||
|
||||
constantBuffer.setFloat(16, helpMat._00);
|
||||
constantBuffer.setFloat(20, helpMat._01);
|
||||
constantBuffer.setFloat(24, helpMat._02);
|
||||
constantBuffer.setFloat(28, helpMat._03);
|
||||
constantBuffer.setFloat(32, helpMat._10);
|
||||
constantBuffer.setFloat(36, helpMat._11);
|
||||
constantBuffer.setFloat(40, helpMat._12);
|
||||
constantBuffer.setFloat(44, helpMat._13);
|
||||
constantBuffer.setFloat(48, helpMat._20);
|
||||
constantBuffer.setFloat(52, helpMat._21);
|
||||
constantBuffer.setFloat(56, helpMat._22);
|
||||
constantBuffer.setFloat(60, helpMat._23);
|
||||
constantBuffer.setFloat(64, helpMat._30);
|
||||
constantBuffer.setFloat(68, helpMat._31);
|
||||
constantBuffer.setFloat(72, helpMat._32);
|
||||
constantBuffer.setFloat(76, helpMat._33);
|
||||
|
||||
constantBuffer.setFloat(80, frame);
|
||||
frame += 1.0;
|
||||
constantBuffer.unlock();
|
||||
|
||||
g.begin(framebuffers[currentBuffer]);
|
||||
|
||||
commandList.begin();
|
||||
|
||||
g.setAccelerationStructure(accel);
|
||||
g.setRayTracePipeline(pipeline);
|
||||
g.setRayTraceTarget(target);
|
||||
|
||||
g.dispatchRays(commandList);
|
||||
g.copyRayTraceTarget(commandList, framebuffers[currentBuffer], target);
|
||||
commandList.end();
|
||||
|
||||
g.end();
|
||||
// g.swapBuffers();
|
||||
|
||||
if (iron.system.Input.getMouse().down()) frame = 1.0;
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
#end
|
21
leenkx/Sources/leenkx/renderpath/RenderToTexture.hx
Normal file
21
leenkx/Sources/leenkx/renderpath/RenderToTexture.hx
Normal file
@ -0,0 +1,21 @@
|
||||
package leenkx.renderpath;
|
||||
|
||||
class RenderToTexture{
|
||||
/**
|
||||
The current kha g2 object to be rendered to.
|
||||
**/
|
||||
public static var g: Null<kha.graphics2.Graphics> = null;
|
||||
|
||||
public static inline function ensureEmptyRenderTarget(location: String){
|
||||
assert(Error, g == null,
|
||||
'render texture already exists at $location. Please clear the texture before setting.
|
||||
If used in logic node, please consult its documentation.'
|
||||
);
|
||||
}
|
||||
|
||||
public static inline function ensure2DContext(location: String) {
|
||||
assert(Error, g != null,
|
||||
'$location must be executed inside of a render2D callback. If used in logic node, please consult its documentation.'
|
||||
);
|
||||
}
|
||||
}
|
83
leenkx/Sources/leenkx/renderpath/Upsampler.hx
Normal file
83
leenkx/Sources/leenkx/renderpath/Upsampler.hx
Normal file
@ -0,0 +1,83 @@
|
||||
package leenkx.renderpath;
|
||||
|
||||
import haxe.ds.ReadOnlyArray;
|
||||
|
||||
import iron.RenderPath;
|
||||
import iron.data.MaterialData;
|
||||
import iron.object.Object;
|
||||
|
||||
import leenkx.math.Helper;
|
||||
|
||||
abstract class Upsampler {
|
||||
|
||||
public static var currentMipLevel(default, null) = 0;
|
||||
public static var numMipLevels(default, null) = 0;
|
||||
|
||||
static var isRegistered = false;
|
||||
|
||||
final path: RenderPath;
|
||||
final shaderPassHandle: String;
|
||||
final mipmaps: ReadOnlyArray<RenderTarget>;
|
||||
|
||||
function new(path: RenderPath, shaderPassHandle: String, mipmaps: ReadOnlyArray<RenderTarget>) {
|
||||
this.path = path;
|
||||
this.shaderPassHandle = shaderPassHandle;
|
||||
this.mipmaps = mipmaps;
|
||||
}
|
||||
|
||||
public static function create(path: RenderPath, shaderPassHandle: String, mipmaps: ReadOnlyArray<RenderTarget>): Upsampler {
|
||||
if (!isRegistered) {
|
||||
isRegistered = true;
|
||||
iron.object.Uniforms.externalIntLinks.push(intLink);
|
||||
}
|
||||
|
||||
// TODO, see Downsampler.hx
|
||||
// if (RenderPath.hasComputeSupport()) {
|
||||
// return new UpsamplerCompute(path, shaderPassHandle, mipmaps);
|
||||
// }
|
||||
// else {
|
||||
return new UpsamplerFragment(path, shaderPassHandle, mipmaps);
|
||||
// }
|
||||
}
|
||||
|
||||
static function intLink(object: Object, mat: MaterialData, link: String): Null<Int> {
|
||||
return switch (link) {
|
||||
case "_upsampleCurrentMip": Upsampler.currentMipLevel;
|
||||
case "_upsampleNumMips": Upsampler.numMipLevels;
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
|
||||
abstract public function dispatch(dstImageName: String, numMips: Int = 0): Void;
|
||||
}
|
||||
|
||||
private class UpsamplerFragment extends Upsampler {
|
||||
|
||||
public function new(path: RenderPath, shaderPassHandle: String, mipmaps: ReadOnlyArray<RenderTarget>) {
|
||||
super(path, shaderPassHandle, mipmaps);
|
||||
path.loadShader(shaderPassHandle);
|
||||
}
|
||||
|
||||
public function dispatch(dstImageName: String, numMips: Int = 0) {
|
||||
Helper.clampInt(numMips, 0, mipmaps.length);
|
||||
if (numMips == 0) {
|
||||
numMips = mipmaps.length;
|
||||
}
|
||||
|
||||
final srcImageRT = path.renderTargets.get(dstImageName);
|
||||
assert(Error, srcImageRT != null);
|
||||
|
||||
final srcImage = srcImageRT.image;
|
||||
assert(Error, srcImage != null);
|
||||
|
||||
Upsampler.numMipLevels = numMips;
|
||||
for (i in 0...Upsampler.numMipLevels) {
|
||||
final mipLevel = Upsampler.numMipLevels - 1 - i;
|
||||
Upsampler.currentMipLevel = mipLevel;
|
||||
|
||||
path.setTarget(mipLevel == 0 ? dstImageName : mipmaps[mipLevel - 1].raw.name);
|
||||
path.bindTarget(mipmaps[mipLevel].raw.name, "tex");
|
||||
path.drawShader(shaderPassHandle);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user