forked from LeenkxTeam/LNXSDK
Compare commits
132 Commits
00493bed9c
...
main
Author | SHA1 | Date | |
---|---|---|---|
8ac567b57b | |||
43b7ae7060 | |||
29e9e71a6a | |||
bfb85b0a3b | |||
ef99b800e0 | |||
7cca955fc5 | |||
7e7bbd5eae | |||
c31b2a18ad | |||
fb47bf2564 | |||
7ae6750620 | |||
5b87010f76 | |||
97e952fc15 | |||
b440539d65 | |||
60a9db6459 | |||
3b5a93c92a | |||
4af990796e | |||
9fb4916c3c | |||
f61d5833bb | |||
40b52be713 | |||
07d8422f22 | |||
7179d42b27 | |||
99a5d7d445 | |||
5e0acd3d5d | |||
f4077e461b | |||
28943f1522 | |||
df4feac132 | |||
82412dbf81 | |||
6afc209db7 | |||
e9aae53be9 | |||
a65675ef75 | |||
8f073c5ae1 | |||
08d08e42d9 | |||
a1ee335c68 | |||
de6bf8a08a | |||
b9848cd2dc | |||
e922cc38e6 | |||
57f0e937d0 | |||
e234c8615c | |||
e594518e57 | |||
a41be0f436 | |||
1306033b36 | |||
eee0011cdd | |||
315ac0bd16 | |||
f289e6f89c | |||
700d236bf1 | |||
f228eab8d3 | |||
863d884b76 | |||
34e0f5a282 | |||
45e2e52008 | |||
444a215e63 | |||
fb2d2a1a7c | |||
f88c04abea | |||
6fdd4b3f70 | |||
a389c27d75 | |||
1909c3da9f | |||
5824bd91aa | |||
43fe559eef | |||
12c09545ce | |||
0e60951ec9 | |||
ccb8b358d3 | |||
1a8586777b | |||
3721c774a1 | |||
a58fba408d | |||
268fba6cd5 | |||
4ab14ce6c8 | |||
9023e8d1da | |||
b58c7a9632 | |||
99b70622f5 | |||
647b73b746 | |||
935c30ec08 | |||
0b0d597f89 | |||
d5878afb30 | |||
96b55a1a56 | |||
91b3072305 | |||
1d0b338d92 | |||
8e83c0d0d0 | |||
927baec4df | |||
f5c9e70d1a | |||
0423a735fc | |||
bd413917fc | |||
852377f60d | |||
e17e9a8e35 | |||
4055c979a1 | |||
06b003ecdb | |||
fd7f215bb2 | |||
6a1df9ec46 | |||
deccac3c46 | |||
432b0210b2 | |||
14cf5cebed | |||
2307e1504f | |||
1ebfecb644 | |||
175b575b23 | |||
63943a9cbf | |||
224d9be76f | |||
62d3c8757b | |||
3785f93573 | |||
ffb276745f | |||
d1c9258da5 | |||
3e0cd2be35 | |||
1fd1973470 | |||
a01c72ef76 | |||
4b01a562c9 | |||
6972d9abc4 | |||
63c6b9d98b | |||
313d24bbc8 | |||
6d2812306d | |||
e84d6ada84 | |||
5057f2b946 | |||
2715fe3398 | |||
7cb8b8a2d2 | |||
cd606009e0 | |||
965162b101 | |||
c61a57bfb3 | |||
cdc425fbcb | |||
846bb28c86 | |||
7fabd77ef8 | |||
fb1a5c88bf | |||
e05c83a8bb | |||
ee4f62e881 | |||
59f8dff22f | |||
5572226ac5 | |||
d04874e0b3 | |||
ef8b3a99ab | |||
1d3254a237 | |||
188af4a50f | |||
c45baaf396 | |||
4b1da08819 | |||
aeb353fb20 | |||
65961b1593 | |||
1c472155e2 | |||
4238f0b2a0 | |||
b40aadf76c |
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.hdr binary
|
||||
blender/lnx/props.py ident
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.DS_Store
|
@ -2,10 +2,12 @@
|
||||
-cp ../Kha/Backends/Krom
|
||||
-cp ../leenkx/Sources
|
||||
-cp ../iron/Sources
|
||||
-cp ../lib/aura/Sources
|
||||
-cp ../lib/haxebullet/Sources
|
||||
-cp ../lib/haxerecast/Sources
|
||||
-cp ../lib/zui/Sources
|
||||
--macro include('iron', true, null, ['../iron/Sources'])
|
||||
--macro include('aura', true, null, ['../lib/aura/Sources'])
|
||||
--macro include('haxebullet', true, null, ['../lib/haxebullet/Sources'])
|
||||
--macro include('haxerecast', true, null, ['../lib/haxerecast/Sources'])
|
||||
--macro include('leenkx', true, ['leenkx.network'], ['../leenkx/Sources','../iron/Sources'])
|
||||
|
@ -29,11 +29,10 @@ uniform sampler2D gbuffer1;
|
||||
#ifdef _VoxelGI
|
||||
uniform sampler2D voxels_diffuse;
|
||||
uniform sampler2D voxels_specular;
|
||||
#else
|
||||
#endif
|
||||
#ifdef _VoxelAOvar
|
||||
uniform sampler2D voxels_ao;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _VoxelShadow
|
||||
uniform sampler3D voxels;
|
||||
uniform sampler3D voxelsSDF;
|
||||
@ -57,10 +56,6 @@ uniform vec3 backgroundCol;
|
||||
|
||||
#ifdef _SSAO
|
||||
uniform sampler2D ssaotex;
|
||||
#else
|
||||
#ifdef _SSGI
|
||||
uniform sampler2D ssaotex;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _SSS
|
||||
@ -118,15 +113,11 @@ uniform vec2 cameraPlane;
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
//!uniform sampler2DShadow shadowMapSpot[1];
|
||||
#ifdef _ShadowMapTransparent
|
||||
//!uniform sampler2D shadowMapSpotTransparent[1];
|
||||
#endif
|
||||
//!uniform mat4 LWVPSpot[1];
|
||||
#else
|
||||
//!uniform samplerCubeShadow shadowMapPoint[1];
|
||||
#ifdef _ShadowMapTransparent
|
||||
//!uniform samplerCube shadowMapPointTransparent[1];
|
||||
#endif
|
||||
//!uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
@ -134,40 +125,30 @@ uniform vec2 cameraPlane;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifdef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlas;
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform sampler2D shadowMapAtlasTransparent;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
#ifdef _ShadowMapTransparent
|
||||
//!uniform sampler2D shadowMapAtlasPointTransparent;
|
||||
#endif
|
||||
#endif
|
||||
//!uniform vec4 pointLightDataArray[maxLightsCluster * 6];
|
||||
//!uniform vec4 pointLightDataArray[4];
|
||||
#else
|
||||
//!uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#ifdef _ShadowMapTransparent
|
||||
//!uniform samplerCube shadowMapPointTransparent[4];
|
||||
#endif
|
||||
#endif
|
||||
//!uniform vec2 lightProj;
|
||||
#ifdef _Spot
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
#ifdef _ShadowMapTransparent
|
||||
//!uniform sampler2D shadowMapAtlasSpotTransparent;
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
//!uniform sampler2DShadow shadowMapSpot[4];
|
||||
#ifdef _ShadowMapTransparent
|
||||
//!uniform sampler2D shadowMapSpotTransparent[4];
|
||||
#endif
|
||||
#endif
|
||||
//!uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
@ -180,16 +161,12 @@ uniform vec3 sunCol;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSun;
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform sampler2D shadowMapAtlasSunTransparent;
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMap;
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform sampler2D shadowMapTransparent;
|
||||
#endif
|
||||
#endif
|
||||
uniform float shadowsBias;
|
||||
#ifdef _CSM
|
||||
//!uniform vec4 casData[shadowmapCascades * 4 + 4];
|
||||
@ -250,22 +227,17 @@ void main() {
|
||||
vec4 g2 = textureLod(gbuffer2, texCoord, 0.0);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MicroShadowing
|
||||
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
|
||||
#endif
|
||||
|
||||
#ifdef _Brdf
|
||||
vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
|
||||
vec3 F = f0 * envBRDF.x + envBRDF.y;
|
||||
#else
|
||||
vec3 F = f0;
|
||||
#endif
|
||||
|
||||
#ifndef _VoxelAOvar
|
||||
#ifndef _VoxelGI
|
||||
// Envmap
|
||||
#ifdef _Irr
|
||||
|
||||
vec3 envl = shIrradiance(n, shirr);
|
||||
|
||||
#ifdef _gbuffer2
|
||||
@ -299,33 +271,33 @@ void main() {
|
||||
envl.rgb *= albedo;
|
||||
|
||||
#ifdef _Brdf
|
||||
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
|
||||
envl.rgb *= 1.0 - (f0 * envBRDF.x + envBRDF.y); //LV: We should take refracted light into account
|
||||
#endif
|
||||
|
||||
#ifdef _Rad // Indirect specular
|
||||
envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
|
||||
envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y); //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
|
||||
#else
|
||||
#ifdef _EnvCol
|
||||
envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
|
||||
envl.rgb += backgroundCol * (f0 * envBRDF.x + envBRDF.y); //LV: Eh, what's the point of weighting it only by F0?
|
||||
#endif
|
||||
#endif
|
||||
|
||||
envl.rgb *= envmapStrength * occspec.x;
|
||||
|
||||
#ifdef _VoxelGI
|
||||
vec4 indirect_diffuse = textureLod(voxels_diffuse, texCoord, 0.0);
|
||||
fragColor.rgb = (indirect_diffuse.rgb * albedo + envl.rgb * (1.0 - indirect_diffuse.a)) * voxelgiDiff;
|
||||
if(roughness < 1.0 && occspec.y > 0.0)
|
||||
fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * occspec.y * voxelgiRefl;
|
||||
#endif
|
||||
|
||||
#ifdef _VoxelAOvar
|
||||
envl.rgb *= textureLod(voxels_ao, texCoord, 0.0).r;
|
||||
#endif
|
||||
|
||||
#ifndef _VoxelGI
|
||||
fragColor.rgb = envl;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _VoxelGI
|
||||
fragColor.rgb = textureLod(voxels_diffuse, texCoord, 0.0).rgb * voxelgiDiff;
|
||||
if(roughness < 1.0 && occspec.y > 0.0)
|
||||
fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * F * voxelgiRefl;
|
||||
#else
|
||||
#ifdef _VoxelAOvar
|
||||
fragColor.rgb = textureLod(voxels_ao, texCoord, 0.0).rgb * voxelgiOcc;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Show voxels
|
||||
// vec3 origin = vec3(texCoord * 2.0 - 1.0, 0.99);
|
||||
// vec3 direction = vec3(0.0, 0.0, -1.0);
|
||||
@ -345,10 +317,6 @@ void main() {
|
||||
// #else
|
||||
fragColor.rgb *= textureLod(ssaotex, texCoord, 0.0).r;
|
||||
// #endif
|
||||
#else
|
||||
#ifdef _SSGI
|
||||
fragColor.rgb += textureLod(ssaotex, texCoord, 0.0).rgb;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _EmissionShadeless
|
||||
@ -381,70 +349,40 @@ void main() {
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _CSM
|
||||
svisibility = shadowTestCascade(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifdef _ShadowMapTransparent
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun, shadowMapAtlasSunTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMap, shadowMapTransparent
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
#endif
|
||||
, eye, p + n * shadowsBias * 10, shadowsBias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, false
|
||||
#endif
|
||||
);
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun, shadowMapAtlasSunTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
shadowMap, shadowMapTransparent
|
||||
#endif
|
||||
, eye, p + n * shadowsBias * 10, shadowsBias, false
|
||||
);
|
||||
#else
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
if (lPos.w > 0.0) {
|
||||
svisibility = shadowTest(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifdef _ShadowMapTransparent
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun, shadowMapAtlasSunTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMap, shadowMapTransparent
|
||||
#else
|
||||
shadowMap
|
||||
#endif
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, shadowsBias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, false
|
||||
#endif
|
||||
);
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun, shadowMapAtlasSunTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
shadowMap, shadowMapTransparent
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, shadowsBias, false
|
||||
);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _VoxelShadow
|
||||
svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy, -g2.rg).r) * voxelgiShad;
|
||||
svisibility *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps, gl_FragCoord.xy).r) * voxelgiShad;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _SSRS
|
||||
// vec2 coords = getProjectedCoord(hitCoord);
|
||||
// vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy);
|
||||
@ -501,16 +439,13 @@ void main() {
|
||||
fragColor.rgb += sampleLight(
|
||||
p, n, v, dotNV, pointPos, pointCol, albedo, roughness, occspec.y, f0
|
||||
#ifdef _ShadowMap
|
||||
, 0, pointBias, true
|
||||
#ifdef _ShadowMapTransparent
|
||||
, false
|
||||
#endif
|
||||
, 0, pointBias, true, false
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight
|
||||
#endif
|
||||
#ifdef _VoxelShadow
|
||||
, voxels, voxelsSDF, clipmaps, -g2.rg
|
||||
, voxels, voxelsSDF, clipmaps
|
||||
#endif
|
||||
#ifdef _MicroShadowing
|
||||
, occspec.x
|
||||
@ -557,10 +492,7 @@ void main() {
|
||||
f0
|
||||
#ifdef _ShadowMap
|
||||
// light index, shadow bias, cast_shadows
|
||||
, li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0
|
||||
#ifdef _ShadowMapTransparent
|
||||
, false
|
||||
#endif
|
||||
, li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0, false
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
, lightsArray[li * 3 + 2].y != 0.0
|
||||
@ -571,7 +503,7 @@ void main() {
|
||||
, lightsArraySpot[li * 2 + 1].xyz // right
|
||||
#endif
|
||||
#ifdef _VoxelShadow
|
||||
, voxels, voxelsSDF, clipmaps, -g2.rg
|
||||
, voxels, voxelsSDF, clipmaps
|
||||
#endif
|
||||
#ifdef _MicroShadowing
|
||||
, occspec.x
|
||||
@ -582,5 +514,14 @@ void main() {
|
||||
);
|
||||
}
|
||||
#endif // _Clusters
|
||||
|
||||
/*
|
||||
#ifdef _VoxelRefract
|
||||
if(opac < 1.0) {
|
||||
vec3 refraction = traceRefraction(p, n, voxels, v, ior, roughness, eye) * voxelgiRefr;
|
||||
fragColor.rgb = mix(refraction, fragColor.rgb, opac);
|
||||
}
|
||||
#endif
|
||||
*/
|
||||
fragColor.a = 1.0; // Mark as opaque
|
||||
}
|
||||
|
@ -1,506 +1,107 @@
|
||||
#version 450
|
||||
|
||||
#include "compiled.inc"
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/brdf.glsl"
|
||||
#include "std/math.glsl"
|
||||
#ifdef _Clusters
|
||||
#include "std/clusters.glsl"
|
||||
#endif
|
||||
#ifdef _ShadowMap
|
||||
#include "std/shadows.glsl"
|
||||
#endif
|
||||
#ifdef _LTC
|
||||
#include "std/ltc.glsl"
|
||||
#endif
|
||||
#ifdef _LightIES
|
||||
#include "std/ies.glsl"
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
#include "std/light_common.glsl"
|
||||
#endif
|
||||
#include "std/constants.glsl"
|
||||
#include "std/gbuffer.glsl"
|
||||
|
||||
uniform sampler2D gbuffer0;
|
||||
uniform sampler2D gbuffer1;
|
||||
uniform sampler2D gbufferD;
|
||||
#ifdef _EmissionShaded
|
||||
uniform sampler2D gbufferEmission;
|
||||
#endif
|
||||
uniform sampler2D sveloc;
|
||||
uniform sampler2D gbuffer0; // Normal
|
||||
// #ifdef _RTGI
|
||||
// uniform sampler2D gbuffer1; // Basecol
|
||||
// #endif
|
||||
uniform mat4 P;
|
||||
uniform mat3 V3;
|
||||
|
||||
uniform vec2 cameraProj;
|
||||
uniform vec3 eye;
|
||||
uniform vec3 eyeLook;
|
||||
uniform vec2 screenSize;
|
||||
uniform mat4 invVP;
|
||||
|
||||
in vec2 texCoord;
|
||||
const float angleMix = 0.5f;
|
||||
#ifdef _SSGICone9
|
||||
const float strength = 2.0 * (1.0 / ssgiStrength);
|
||||
#else
|
||||
const float strength = 2.0 * (1.0 / ssgiStrength) * 1.8;
|
||||
#endif
|
||||
|
||||
in vec3 viewRay;
|
||||
out vec3 fragColor;
|
||||
in vec2 texCoord;
|
||||
out float fragColor;
|
||||
|
||||
float metallic;
|
||||
uint matid;
|
||||
vec3 hitCoord;
|
||||
vec2 coord;
|
||||
float depth;
|
||||
// #ifdef _RTGI
|
||||
// vec3 col = vec3(0.0);
|
||||
// #endif
|
||||
vec3 vpos;
|
||||
|
||||
#ifdef _SMSizeUniform
|
||||
//!uniform vec2 smSizeUniform;
|
||||
#endif
|
||||
vec2 getProjectedCoord(vec3 hitCoord) {
|
||||
vec4 projectedCoord = P * vec4(hitCoord, 1.0);
|
||||
projectedCoord.xy /= projectedCoord.w;
|
||||
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
|
||||
#ifdef _InvY
|
||||
projectedCoord.y = 1.0 - projectedCoord.y;
|
||||
#endif
|
||||
return projectedCoord.xy;
|
||||
}
|
||||
|
||||
#ifdef _Clusters
|
||||
uniform vec4 lightsArray[maxLights * 3];
|
||||
#ifdef _Spot
|
||||
uniform vec4 lightsArraySpot[maxLights * 2];
|
||||
#endif
|
||||
uniform sampler2D clustersData;
|
||||
uniform vec2 cameraPlane;
|
||||
#endif
|
||||
float getDeltaDepth(vec3 hitCoord) {
|
||||
coord = getProjectedCoord(hitCoord);
|
||||
depth = textureLod(gbufferD, coord, 0.0).r * 2.0 - 1.0;
|
||||
vec3 p = getPosView(viewRay, depth, cameraProj);
|
||||
return p.z - hitCoord.z;
|
||||
}
|
||||
|
||||
#ifdef _SinglePoint // Fast path for single light
|
||||
uniform vec3 pointPos;
|
||||
uniform vec3 pointCol;
|
||||
#ifdef _ShadowMap
|
||||
uniform float pointBias;
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
uniform vec3 spotDir;
|
||||
uniform vec3 spotRight;
|
||||
uniform vec4 spotData;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _CPostprocess
|
||||
uniform vec3 PPComp12;
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
#ifndef _LTC
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform sampler2D shadowMapSpotTransparent[1];
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform samplerCube shadowMapPointTransparent[1];
|
||||
uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
#ifdef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlas;
|
||||
uniform sampler2D shadowMapAtlasTransparent;
|
||||
#endif
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
uniform sampler2D shadowMapAtlasPointTransparent;
|
||||
//!uniform vec4 pointLightDataArray[maxLightsCluster * 6];
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
uniform samplerCube shadowMapPointTransparent[4];
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
uniform sampler2D shadowMapAtlasSpotTransparent;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
uniform sampler2D shadowMapSpotTransparent[4];
|
||||
#endif
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _LTC
|
||||
uniform vec3 lightArea0;
|
||||
uniform vec3 lightArea1;
|
||||
uniform vec3 lightArea2;
|
||||
uniform vec3 lightArea3;
|
||||
uniform sampler2D sltcMat;
|
||||
uniform sampler2D sltcMag;
|
||||
#ifdef _ShadowMap
|
||||
#ifndef _Spot
|
||||
#ifdef _SinglePoint
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform sampler2D shadowMapSpotTransparent[1];
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _Sun
|
||||
uniform vec3 sunDir;
|
||||
uniform vec3 sunCol;
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSun;
|
||||
uniform sampler2D shadowMapAtlasSunTransparent;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMap;
|
||||
uniform sampler2D shadowMapTransparent;
|
||||
#endif
|
||||
uniform float shadowsBias;
|
||||
#ifdef _CSM
|
||||
//!uniform vec4 casData[shadowmapCascades * 4 + 4];
|
||||
#else
|
||||
uniform mat4 LWVP;
|
||||
#endif
|
||||
#endif // _ShadowMap
|
||||
#endif
|
||||
|
||||
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 lp, const vec3 lightCol
|
||||
#ifdef _ShadowMap
|
||||
, int index, float bias, bool receiveShadow, bool transparent
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||
#endif
|
||||
) {
|
||||
|
||||
vec3 ld = lp - p;
|
||||
vec3 l = normalize(ld);
|
||||
|
||||
vec3 visibility = lightCol;
|
||||
visibility *= attenuate(distance(p, lp));
|
||||
|
||||
#ifdef _LTC
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
|
||||
visibility *= shadowTest(shadowMapSpot[0],
|
||||
shadowMapSpotTransparent[0],
|
||||
lPos.xyz / lPos.w, bias, transparent);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||
if (index == 0) visibility *= shadowTest(shadowMapSpot[0],
|
||||
shadowMapSpotTransparent[0],
|
||||
lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 1) visibility *= shadowTest(shadowMapSpot[1],
|
||||
shadowMapSpotTransparent[1],
|
||||
, lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 2) visibility *= shadowTest(shadowMapSpot[2],
|
||||
shadowMapSpotTransparent[2],
|
||||
lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 3) visibility *= shadowTest(shadowMapSpot[3],
|
||||
shadowMapSpotTransparent[3],
|
||||
lPos.xyz / lPos.w, bias, transparent);
|
||||
#endif
|
||||
void rayCast(vec3 dir) {
|
||||
hitCoord = vpos;
|
||||
dir *= ssgiRayStep * 2;
|
||||
float dist = 0.15;
|
||||
for (int i = 0; i < ssgiMaxSteps; i++) {
|
||||
hitCoord += dir;
|
||||
float delta = getDeltaDepth(hitCoord);
|
||||
if (delta > 0.0 && delta < 0.2) {
|
||||
dist = distance(vpos, hitCoord);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return visibility;
|
||||
#endif
|
||||
|
||||
#ifdef _Spot
|
||||
if (isSpot) {
|
||||
visibility *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
|
||||
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
visibility *= shadowTest(shadowMapSpot[0],
|
||||
shadowMapSpotTransparent[0],
|
||||
lPos.xyz / lPos.w, bias, transparent);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||
#ifdef _ShadowMapAtlas
|
||||
visibility *= shadowTest(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, bias, transparent
|
||||
);
|
||||
#else
|
||||
if (index == 0) visibility *= shadowTest(shadowMapSpot[0],
|
||||
shadowMapSpotTransparent[0],
|
||||
lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 1) visibility *= shadowTest(shadowMapSpot[1],
|
||||
shadowMapSpotTransparent[1],
|
||||
lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 2) visibility *= shadowTest(shadowMapSpot[2],
|
||||
shadowMapSpotTransparent[2],
|
||||
lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 3) visibility *= shadowTest(shadowMapSpot[3],
|
||||
shadowMapSpotTransparent[3],
|
||||
lPos.xyz / lPos.w, bias, transparent);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return visibility;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _LightIES
|
||||
visibility *= iesAttenuation(-l);
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
#ifndef _Spot
|
||||
visibility *= PCFCube(shadowMapPoint[0],
|
||||
shadowMapPointTransparent[0],
|
||||
ld, -l, bias, lightProj, n, transparent);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
#ifdef _ShadowMapAtlas
|
||||
visibility *= PCFFakeCube(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasPoint, shadowMapAtlasPointTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
, ld, -l, bias, lightProj, n, index, transparent
|
||||
);
|
||||
#else
|
||||
if (index == 0) visibility *= PCFCube(shadowMapPoint[0],
|
||||
shadowMapPointTransparent[0],
|
||||
ld, -l, bias, lightProj, n, transparent);
|
||||
else if (index == 1) visibility *= PCFCube(shadowMapPoint[1],
|
||||
shadowMapPointTransparent[1],
|
||||
ld, -l, bias, lightProj, n, transparent);
|
||||
else if (index == 2) visibility *= PCFCube(shadowMapPoint[2],
|
||||
shadowMapPointTransparent[2],
|
||||
ld, -l, bias, lightProj, n, transparent);
|
||||
else if (index == 3) visibility *= PCFCube(shadowMapPoint[3],
|
||||
shadowMapPointTransparent[3],
|
||||
ld, -l, bias, lightProj, n, transparent);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return visibility;
|
||||
fragColor += dist;
|
||||
// #ifdef _RTGI
|
||||
// col += textureLod(gbuffer1, coord, 0.0).rgb * ((ssgiRayStep * ssgiMaxSteps) - dist);
|
||||
// #endif
|
||||
}
|
||||
|
||||
vec3 getVisibility(vec3 p, vec3 n, float depth, vec2 uv) {
|
||||
vec3 visibility = vec3(0.0);
|
||||
#ifdef _Sun
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _CSM
|
||||
visibility = shadowTestCascade(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun, shadowMapAtlasSunTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
shadowMap, shadowMapTransparent
|
||||
#endif
|
||||
, eye, p + n * shadowsBias * 10, shadowsBias, false
|
||||
);
|
||||
#else
|
||||
vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0);
|
||||
if (lPos.w > 0.0) {
|
||||
visibility = shadowTest(
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSun, shadowMapAtlasSunTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
shadowMap, shadowMapTransparent
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, shadowsBias, false
|
||||
);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _SinglePoint
|
||||
visibility += sampleLight(
|
||||
p, n, pointPos, pointCol
|
||||
#ifdef _ShadowMap
|
||||
, 0, pointBias, true, false
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
, true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
|
||||
#ifdef _Clusters
|
||||
float viewz = linearize(depth, cameraProj);
|
||||
int clusterI = getClusterI(uv, viewz, cameraPlane);
|
||||
int numLights = int(texelFetch(clustersData, ivec2(clusterI, 0), 0).r * 255);
|
||||
|
||||
#ifdef HLSL
|
||||
viewz += textureLod(clustersData, vec2(0.0), 0.0).r * 1e-9; // TODO: krafix bug, needs to generate sampler
|
||||
#endif
|
||||
|
||||
#ifdef _Spot
|
||||
int numSpots = int(texelFetch(clustersData, ivec2(clusterI, 1 + maxLightsCluster), 0).r * 255);
|
||||
int numPoints = numLights - numSpots;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < min(numLights, maxLightsCluster); i++) {
|
||||
int li = int(texelFetch(clustersData, ivec2(clusterI, i + 1), 0).r * 255);
|
||||
visibility += sampleLight(
|
||||
p,
|
||||
n,
|
||||
lightsArray[li * 3].xyz, // lp
|
||||
lightsArray[li * 3 + 1].xyz // lightCol
|
||||
#ifdef _ShadowMap
|
||||
// light index, shadow bias, cast_shadows
|
||||
, li, lightsArray[li * 3 + 2].x, lightsArray[li * 3 + 2].z != 0.0, false
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
, lightsArray[li * 3 + 2].y != 0.0
|
||||
, lightsArray[li * 3 + 2].y // spot size (cutoff)
|
||||
, lightsArraySpot[li * 2].w // spot blend (exponent)
|
||||
, lightsArraySpot[li * 2].xyz // spotDir
|
||||
, vec2(lightsArray[li * 3].w, lightsArray[li * 3 + 1].w) // scale
|
||||
, lightsArraySpot[li * 2 + 1].xyz // right
|
||||
#endif
|
||||
);
|
||||
}
|
||||
#endif // _Clusters
|
||||
return visibility;
|
||||
vec3 tangent(const vec3 n) {
|
||||
vec3 t1 = cross(n, vec3(0, 0, 1));
|
||||
vec3 t2 = cross(n, vec3(0, 1, 0));
|
||||
if (length(t1) > length(t2)) return normalize(t1);
|
||||
else return normalize(t2);
|
||||
}
|
||||
|
||||
vec3 getWorldPos(vec2 uv, float depth) {
|
||||
vec4 pos = invVP * vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
|
||||
return pos.xyz / pos.w;
|
||||
}
|
||||
|
||||
vec3 getNormal(vec2 uv) {
|
||||
vec4 g0 = textureLod(gbuffer0, uv, 0.0);
|
||||
vec2 enc = g0.rg;
|
||||
vec3 n;
|
||||
n.z = 1.0 - abs(enc.x) - abs(enc.y);
|
||||
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
|
||||
return normalize(n);
|
||||
}
|
||||
|
||||
vec3 calculateIndirectLight(vec2 uv, vec3 pos, vec3 normal, float depth) {
|
||||
// Simplified visibility - replace with your full visibility function if needed
|
||||
vec3 sampleColor = textureLod(gbuffer1, uv, 0.0).rgb * getVisibility(pos, normal, depth, uv);
|
||||
|
||||
#ifdef _EmissionShadeless
|
||||
if (matid == 1) { // pure emissive material, color stored in basecol
|
||||
sampleColor += textureLod(gbuffer1, uv, 0.0).rgb;
|
||||
}
|
||||
#endif
|
||||
#ifdef _EmissionShaded
|
||||
#ifdef _EmissionShadeless
|
||||
else {
|
||||
#endif
|
||||
vec3 sampleEmission = textureLod(gbufferEmission, uv, 0.0).rgb;
|
||||
sampleColor += sampleEmission; // Emission should be added directly
|
||||
#ifdef _EmissionShadeless
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return sampleColor;
|
||||
}
|
||||
|
||||
// Improved sampling parameters
|
||||
const float GOLDEN_ANGLE = 2.39996323;
|
||||
const float MAX_DEPTH_DIFFERENCE = 0.9; // More conservative depth threshold
|
||||
const float SAMPLE_BIAS = 0.01; // Small offset to avoid self-occlusion
|
||||
|
||||
void main() {
|
||||
float depth = textureLod(gbufferD, texCoord, 0.0).r;
|
||||
if (depth >= 1.0) {
|
||||
fragColor = vec3(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0); // Normal.xy, roughness, metallic/matid
|
||||
unpackFloatInt16(g0.a, metallic, matid);
|
||||
|
||||
vec2 velocity = -textureLod(sveloc, texCoord, 0.0).rg;
|
||||
fragColor = 0;
|
||||
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
|
||||
float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0;
|
||||
|
||||
vec2 enc = g0.rg;
|
||||
vec3 n;
|
||||
n.z = 1.0 - abs(g0.x) - abs(g0.y);
|
||||
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
|
||||
n = normalize(n);
|
||||
n.z = 1.0 - abs(enc.x) - abs(enc.y);
|
||||
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
|
||||
n = normalize(V3 * n);
|
||||
|
||||
vec3 pos = getWorldPos(texCoord, depth);
|
||||
vec3 normal = getNormal(texCoord);
|
||||
vec3 centerColor = textureLod(gbuffer1, texCoord, 0.0).rgb;
|
||||
vpos = getPosView(viewRay, d, cameraProj);
|
||||
|
||||
float radius = ssaoRadius;
|
||||
rayCast(n);
|
||||
vec3 o1 = normalize(tangent(n));
|
||||
vec3 o2 = (cross(o1, n));
|
||||
vec3 c1 = 0.5f * (o1 + o2);
|
||||
vec3 c2 = 0.5f * (o1 - o2);
|
||||
rayCast(mix(n, o1, angleMix));
|
||||
rayCast(mix(n, o2, angleMix));
|
||||
rayCast(mix(n, -c1, angleMix));
|
||||
rayCast(mix(n, -c2, angleMix));
|
||||
|
||||
vec3 gi = vec3(0.0);
|
||||
float totalWeight = 0.0;
|
||||
float angle = fract(sin(dot(texCoord, vec2(12.9898, 78.233))) * 100.0);
|
||||
|
||||
for (int i = 0; i < ssgiSamples; i++) {
|
||||
// Use quasi-random sequence for better coverage
|
||||
float r = sqrt((float(i) + 0.5) / float(ssgiSamples)) * radius;
|
||||
float a = (float(i) * GOLDEN_ANGLE) + angle;
|
||||
|
||||
vec2 offset = vec2(cos(a), sin(a)) * r * radius;
|
||||
vec2 sampleUV = clamp(texCoord + offset * (BayerMatrix8[int(gl_FragCoord.x + velocity.x) % 8][int(gl_FragCoord.y + velocity.y) % 8] - 0.5) / screenSize, vec2(0.001), vec2(0.999));
|
||||
|
||||
float sampleDepth = textureLod(gbufferD, sampleUV, 0.0).r;
|
||||
if (sampleDepth >= 1.0) continue;
|
||||
|
||||
vec3 samplePos = getWorldPos(sampleUV, sampleDepth);
|
||||
vec3 sampleNormal = getNormal(sampleUV);
|
||||
|
||||
// Apply small bias to sample position to avoid self-occlusion
|
||||
samplePos += sampleNormal * SAMPLE_BIAS;
|
||||
|
||||
vec3 dir = pos - samplePos;
|
||||
float dist = length(dir);
|
||||
|
||||
if (abs(pos.z - samplePos.z) > MAX_DEPTH_DIFFERENCE) continue;;
|
||||
|
||||
vec3 sampleColor = calculateIndirectLight(sampleUV, samplePos, sampleNormal, sampleDepth);
|
||||
float weight = 1.0 / (1.0 + dist * dist * 2.0) * max(dot(sampleNormal, n), 0.0);
|
||||
|
||||
gi += sampleColor * weight;
|
||||
totalWeight += weight;
|
||||
}
|
||||
|
||||
// Normalize and apply intensity
|
||||
if (totalWeight > 0.0) {
|
||||
gi /= totalWeight;
|
||||
#ifdef _CPostprocess
|
||||
gi *= PPComp12.x;
|
||||
#else
|
||||
gi *= ssaoStrength;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _EmissionShadeless
|
||||
if (matid == 1) { // pure emissive material, color stored in basecol
|
||||
gi += textureLod(gbuffer1, texCoord, 0.0).rgb;
|
||||
}
|
||||
#ifdef _SSGICone9
|
||||
rayCast(mix(n, -o1, angleMix));
|
||||
rayCast(mix(n, -o2, angleMix));
|
||||
rayCast(mix(n, c1, angleMix));
|
||||
rayCast(mix(n, c2, angleMix));
|
||||
#endif
|
||||
#ifdef _EmissionShaded
|
||||
#ifdef _EmissionShadeless
|
||||
else {
|
||||
#endif
|
||||
gi += textureLod(gbufferEmission, texCoord, 0.0).rgb;
|
||||
#ifdef _EmissionShadeless
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
fragColor = gi / (gi + vec3(1.0)); // Reinhard tone mapping
|
||||
}
|
||||
|
@ -6,10 +6,6 @@
|
||||
"compare_mode": "always",
|
||||
"cull_mode": "none",
|
||||
"links": [
|
||||
{
|
||||
"name": "invVP",
|
||||
"link": "_inverseViewProjectionMatrix"
|
||||
},
|
||||
{
|
||||
"name": "P",
|
||||
"link": "_projectionMatrix"
|
||||
@ -19,180 +15,16 @@
|
||||
"link": "_viewMatrix3"
|
||||
},
|
||||
{
|
||||
"name": "eye",
|
||||
"link": "_cameraPosition"
|
||||
},
|
||||
{
|
||||
"name": "eyeLook",
|
||||
"link": "_cameraLook"
|
||||
"name": "invP",
|
||||
"link": "_inverseProjectionMatrix"
|
||||
},
|
||||
{
|
||||
"name": "cameraProj",
|
||||
"link": "_cameraPlaneProj"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "screenSize",
|
||||
"link": "_screenSize"
|
||||
},
|
||||
{
|
||||
"name": "PPComp12",
|
||||
"link": "_PPComp12",
|
||||
"ifdef": ["_CPostprocess"]
|
||||
},
|
||||
{
|
||||
"name": "lightsArraySpot",
|
||||
"link": "_lightsArraySpot",
|
||||
"ifdef": ["_Clusters", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "lightsArray",
|
||||
"link": "_lightsArray",
|
||||
"ifdef": ["_Clusters"]
|
||||
},
|
||||
{
|
||||
"name": "clustersData",
|
||||
"link": "_clustersData",
|
||||
"ifdef": ["_Clusters"]
|
||||
},
|
||||
{
|
||||
"name": "cameraPlane",
|
||||
"link": "_cameraPlane",
|
||||
"ifdef": ["_Clusters"]
|
||||
},
|
||||
{
|
||||
"name": "sunDir",
|
||||
"link": "_sunDirection",
|
||||
"ifdef": ["_Sun"]
|
||||
},
|
||||
{
|
||||
"name": "sunCol",
|
||||
"link": "_sunColor",
|
||||
"ifdef": ["_Sun"]
|
||||
},
|
||||
{
|
||||
"name": "shadowsBias",
|
||||
"link": "_sunShadowsBias",
|
||||
"ifdef": ["_Sun", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVP",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSun",
|
||||
"ifndef": ["_CSM"],
|
||||
"ifdef": ["_Sun", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "casData",
|
||||
"link": "_cascadeData",
|
||||
"ifdef": ["_Sun", "_ShadowMap", "_CSM"]
|
||||
},
|
||||
{
|
||||
"name": "lightArea0",
|
||||
"link": "_lightArea0",
|
||||
"ifdef": ["_LTC"]
|
||||
},
|
||||
{
|
||||
"name": "lightArea1",
|
||||
"link": "_lightArea1",
|
||||
"ifdef": ["_LTC"]
|
||||
},
|
||||
{
|
||||
"name": "lightArea2",
|
||||
"link": "_lightArea2",
|
||||
"ifdef": ["_LTC"]
|
||||
},
|
||||
{
|
||||
"name": "lightArea3",
|
||||
"link": "_lightArea3",
|
||||
"ifdef": ["_LTC"]
|
||||
},
|
||||
{
|
||||
"name": "sltcMat",
|
||||
"link": "_ltcMat",
|
||||
"ifdef": ["_LTC"]
|
||||
},
|
||||
{
|
||||
"name": "sltcMag",
|
||||
"link": "_ltcMag",
|
||||
"ifdef": ["_LTC"]
|
||||
},
|
||||
{
|
||||
"name": "smSizeUniform",
|
||||
"link": "_shadowMapSize",
|
||||
"ifdef": ["_SMSizeUniform"]
|
||||
},
|
||||
{
|
||||
"name": "lightProj",
|
||||
"link": "_lightPlaneProj",
|
||||
"ifdef": ["_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "pointPos",
|
||||
"link": "_pointPosition",
|
||||
"ifdef": ["_SinglePoint"]
|
||||
},
|
||||
{
|
||||
"name": "pointCol",
|
||||
"link": "_pointColor",
|
||||
"ifdef": ["_SinglePoint"]
|
||||
},
|
||||
{
|
||||
"name": "pointBias",
|
||||
"link": "_pointShadowsBias",
|
||||
"ifdef": ["_SinglePoint", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "spotDir",
|
||||
"link": "_spotDirection",
|
||||
"ifdef": ["_SinglePoint", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "spotData",
|
||||
"link": "_spotData",
|
||||
"ifdef": ["_SinglePoint", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "spotRight",
|
||||
"link": "_spotRight",
|
||||
"ifdef": ["_SinglePoint", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpotArray",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpotArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_Spot"]
|
||||
},
|
||||
{
|
||||
"name": "pointLightDataArray",
|
||||
"link": "_pointLightsAtlasArray",
|
||||
"ifdef": ["_Clusters", "_ShadowMap", "_ShadowMapAtlas"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot[0]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot0",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot[1]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot1",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot[2]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot2",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
},
|
||||
{
|
||||
"name": "LWVPSpot[3]",
|
||||
"link": "_biasLightWorldViewProjectionMatrixSpot3",
|
||||
"ifndef": ["_ShadowMapAtlas"],
|
||||
"ifdef": ["_LTC", "_ShadowMap"]
|
||||
}
|
||||
],
|
||||
"texture_params": [],
|
||||
"vertex_shader": "../include/pass_viewray.vert.glsl",
|
||||
"vertex_shader": "../include/pass_viewray2.vert.glsl",
|
||||
"fragment_shader": "ssgi_pass.frag.glsl"
|
||||
}
|
||||
]
|
||||
|
@ -64,7 +64,7 @@ vec4 rayCast(vec3 dir) {
|
||||
ddepth = getDeltaDepth(hitCoord);
|
||||
if (ddepth > 0.0) return binarySearch(dir);
|
||||
}
|
||||
return vec4(getProjectedCoord(hitCoord), 0.0, 1.0);
|
||||
return vec4(texCoord, 0.0, 1.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
@ -86,7 +86,7 @@ void main() {
|
||||
|
||||
vec3 viewNormal = V3 * n;
|
||||
vec3 viewPos = getPosView(viewRay, d, cameraProj);
|
||||
vec3 refracted = refract(viewPos, viewNormal, 1.0 / ior);
|
||||
vec3 refracted = refract(normalize(viewPos), viewNormal, 1.0 / ior);
|
||||
hitCoord = viewPos;
|
||||
|
||||
vec3 dir = refracted * (1.0 - rand(texCoord) * ss_refractionJitter * roughness) * 2.0;
|
||||
|
@ -1,18 +0,0 @@
|
||||
#ifndef _AABB_GLSL
|
||||
#define _AABB_GLSL
|
||||
|
||||
bool IntersectAABB(vec3[2] a, vec3[2] b) {
|
||||
const float EPSILON = 0.001; // Small tolerance to prevent false negatives
|
||||
if (abs(a[0].x - b[0].x) > (a[1].x + b[1].x + EPSILON)) return false;
|
||||
if (abs(a[0].y - b[0].y) > (a[1].y + b[1].y + EPSILON)) return false;
|
||||
if (abs(a[0].z - b[0].z) > (a[1].z + b[1].z + EPSILON)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AABBfromMinMax(inout vec3[2] aabb, vec3 _min, vec3 _max)
|
||||
{
|
||||
aabb[0] = (_min + _max) * 0.5f;
|
||||
aabb[1] = abs(_max - aabb[0]);
|
||||
}
|
||||
|
||||
#endif
|
@ -22,7 +22,7 @@ THE SOFTWARE.
|
||||
#ifndef _CONETRACE_GLSL_
|
||||
#define _CONETRACE_GLSL_
|
||||
|
||||
#include "std/constants.glsl"
|
||||
#include "std/voxels_constants.glsl"
|
||||
|
||||
// References
|
||||
// https://github.com/Friduric/voxel-cone-tracing
|
||||
@ -92,14 +92,14 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
|
||||
float dist = voxelSize0;
|
||||
float step_dist = dist;
|
||||
vec3 samplePos;
|
||||
vec3 start_pos = origin + n * voxelSize0;
|
||||
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
|
||||
int clipmap_index0 = 0;
|
||||
|
||||
vec3 aniso_direction = -dir;
|
||||
vec3 face_offset = vec3(
|
||||
aniso_direction.x > 0.0 ? 0 : 1,
|
||||
aniso_direction.y > 0.0 ? 2 : 3,
|
||||
aniso_direction.z > 0.0 ? 4 : 5
|
||||
aniso_direction.x > 0.0 ? 0.0 : 1.0,
|
||||
aniso_direction.y > 0.0 ? 2.0 : 3.0,
|
||||
aniso_direction.z > 0.0 ? 4.0 : 5.0
|
||||
) / (6 + DIFFUSE_CONE_COUNT);
|
||||
vec3 direction_weight = abs(dir);
|
||||
|
||||
@ -125,7 +125,7 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
|
||||
|
||||
if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
|
||||
vec4 mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
|
||||
mipSample = mix(mipSample, mipSampleNext, clipmap_blend);
|
||||
mipSample = mix(mipSample, mipSampleNext, smoothstep(0.0, 1.0, clipmap_blend));
|
||||
}
|
||||
|
||||
sampleCol += (1.0 - sampleCol.a) * mipSample;
|
||||
@ -148,9 +148,8 @@ vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 ori
|
||||
vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
|
||||
float sum = 0.0;
|
||||
vec4 amount = vec4(0.0);
|
||||
mat3 TBN = makeTangentBasis(normal);
|
||||
for (int i = 0; i < DIFFUSE_CONE_COUNT; ++i) {
|
||||
vec3 coneDir = TBN * DIFFUSE_CONE_DIRECTIONS[i];
|
||||
vec3 coneDir = DIFFUSE_CONE_DIRECTIONS[i];
|
||||
const float cosTheta = dot(normal, coneDir);
|
||||
if (cosTheta <= 0)
|
||||
continue;
|
||||
@ -167,7 +166,7 @@ vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels,
|
||||
}
|
||||
|
||||
vec4 traceSpecular(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 viewDir, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
|
||||
vec3 specularDir = reflect(normalize(-viewDir), normal);
|
||||
vec3 specularDir = reflect(-viewDir, normal);
|
||||
vec3 P = origin + specularDir * ((BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5)) * voxelgiStep;
|
||||
vec4 amount = traceCone(voxels, voxelsSDF, P, normal, specularDir, 0, true, roughness, voxelgiStep, clipmaps);
|
||||
|
||||
@ -177,9 +176,9 @@ vec4 traceSpecular(const vec3 origin, const vec3 normal, const sampler3D voxels,
|
||||
return amount * voxelgiOcc;
|
||||
}
|
||||
|
||||
vec4 traceRefraction(const vec3 origin, const vec3 normal, sampler3D voxels, sampler3D voxelsSDF, const vec3 viewDir, const float ior, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity, const float opacity) {
|
||||
const float transmittance = 1.0 - opacity;
|
||||
vec3 refractionDir = refract(normalize(-viewDir), normal, 1.0 / ior);
|
||||
vec4 traceRefraction(const vec3 origin, const vec3 normal, sampler3D voxels, sampler3D voxelsSDF, const vec3 viewDir, const float ior, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
|
||||
const float transmittance = 1.0;
|
||||
vec3 refractionDir = refract(-viewDir, normal, 1.0 / ior);
|
||||
vec3 P = origin + refractionDir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
|
||||
vec4 amount = transmittance * traceCone(voxels, voxelsSDF, P, normal, refractionDir, 0, true, roughness, voxelgiStep, clipmaps);
|
||||
|
||||
@ -197,14 +196,14 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const
|
||||
float dist = voxelSize0;
|
||||
float step_dist = dist;
|
||||
vec3 samplePos;
|
||||
vec3 start_pos = origin + n * voxelSize0;
|
||||
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
|
||||
int clipmap_index0 = 0;
|
||||
|
||||
vec3 aniso_direction = -dir;
|
||||
vec3 face_offset = vec3(
|
||||
aniso_direction.x > 0.0 ? 0 : 1,
|
||||
aniso_direction.y > 0.0 ? 2 : 3,
|
||||
aniso_direction.z > 0.0 ? 4 : 5
|
||||
aniso_direction.x > 0.0 ? 0.0 : 1.0,
|
||||
aniso_direction.y > 0.0 ? 2.0 : 3.0,
|
||||
aniso_direction.z > 0.0 ? 4.0 : 5.0
|
||||
) / (6 + DIFFUSE_CONE_COUNT);
|
||||
vec3 direction_weight = abs(dir);
|
||||
|
||||
@ -260,6 +259,7 @@ float traceAO(const vec3 origin, const vec3 normal, const sampler3D voxels, cons
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _VoxelShadow
|
||||
float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 origin, const vec3 n, const vec3 dir, const float aperture, const float step_size, const float clipmaps[voxelgiClipmapCount * 10]) {
|
||||
float sampleCol = 0.0;
|
||||
@ -267,14 +267,14 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
|
||||
float dist = voxelSize0;
|
||||
float step_dist = dist;
|
||||
vec3 samplePos;
|
||||
vec3 start_pos = origin + n * voxelSize0;
|
||||
vec3 start_pos = origin + n * voxelSize0 * voxelgiOffset;
|
||||
int clipmap_index0 = 0;
|
||||
|
||||
vec3 aniso_direction = -dir;
|
||||
vec3 face_offset = vec3(
|
||||
aniso_direction.x > 0.0 ? 0 : 1,
|
||||
aniso_direction.y > 0.0 ? 2 : 3,
|
||||
aniso_direction.z > 0.0 ? 4 : 5
|
||||
aniso_direction.x > 0.0 ? 0.0 : 1.0,
|
||||
aniso_direction.y > 0.0 ? 2.0 : 3.0,
|
||||
aniso_direction.z > 0.0 ? 4.0 : 5.0
|
||||
) / (6 + DIFFUSE_CONE_COUNT);
|
||||
vec3 direction_weight = abs(dir);
|
||||
float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
||||
@ -287,7 +287,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
|
||||
float clipmap_blend = fract(lod);
|
||||
vec3 p0 = start_pos + dir * dist;
|
||||
|
||||
samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
|
||||
samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution.x);
|
||||
samplePos = samplePos * 0.5 + 0.5;
|
||||
|
||||
if ((any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0))))) {
|
||||
@ -328,9 +328,9 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v
|
||||
}
|
||||
|
||||
|
||||
float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
|
||||
vec3 P = origin + dir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
|
||||
float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, SHADOW_CONE_APERTURE, voxelgiStep, clipmaps);
|
||||
float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel) {
|
||||
vec3 P = origin + dir * (BayerMatrix8[int(pixel.x) % 8][int(pixel.y) % 8] - 0.5) * voxelgiStep;
|
||||
float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, DIFFUSE_CONE_APERTURE, voxelgiStep, clipmaps);
|
||||
amount = clamp(amount, 0.0, 1.0);
|
||||
return amount * voxelgiOcc;
|
||||
}
|
||||
|
@ -1,679 +1,239 @@
|
||||
#ifndef _LIGHT_GLSL_
|
||||
#define _LIGHT_GLSL_
|
||||
|
||||
#include "compiled.inc"
|
||||
#include "std/brdf.glsl"
|
||||
#include "std/math.glsl"
|
||||
#ifdef _ShadowMap
|
||||
#include "std/shadows.glsl"
|
||||
#endif
|
||||
#ifdef _VoxelShadow
|
||||
#include "std/conetrace.glsl"
|
||||
#endif
|
||||
#ifdef _LTC
|
||||
#include "std/ltc.glsl"
|
||||
#endif
|
||||
#ifdef _LightIES
|
||||
#include "std/ies.glsl"
|
||||
#endif
|
||||
#ifdef _SSRS
|
||||
#include "std/ssrs.glsl"
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
#include "std/light_common.glsl"
|
||||
#endif
|
||||
#ifdef _VoxelShadow
|
||||
#include "std/conetrace.glsl"
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
#ifndef _LTC
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform sampler2D shadowMapSpotTransparent[1];
|
||||
#endif
|
||||
uniform mat4 LWVPSpotArray[1];
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform samplerCube shadowMapPointTransparent[1];
|
||||
#endif
|
||||
uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
#ifdef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlas;
|
||||
#ifdef _ShadowMapTransparent
|
||||
//!uniform sampler2D shadowMapAtlasTransparent;
|
||||
#endif
|
||||
#endif
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform sampler2D shadowMapAtlasPointTransparent;
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform samplerCube shadowMapPointTransparent[4];
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform sampler2D shadowMapAtlasSpotTransparent;
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform sampler2D shadowMapSpotTransparent[4];
|
||||
#endif
|
||||
#endif
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _LTC
|
||||
uniform vec3 lightArea0;
|
||||
uniform vec3 lightArea1;
|
||||
uniform vec3 lightArea2;
|
||||
uniform vec3 lightArea3;
|
||||
uniform sampler2D sltcMat;
|
||||
uniform sampler2D sltcMag;
|
||||
#ifdef _ShadowMap
|
||||
#ifndef _Spot
|
||||
#ifdef _SinglePoint
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform sampler2D shadowMapSpotTransparent[1];
|
||||
#endif
|
||||
uniform mat4 LWVPSpotArray[1];
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
|
||||
#ifdef _ShadowMapTransparent
|
||||
uniform sampler2D shadowMapSpotTransparent[maxLightsCluster];
|
||||
#endif
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
||||
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
||||
#ifdef _ShadowMap
|
||||
, int index, float bias, bool receiveShadow
|
||||
#ifdef _ShadowMapTransparent
|
||||
, bool transparent
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||
#endif
|
||||
#ifdef _VoxelShadow
|
||||
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount], vec2 velocity
|
||||
#endif
|
||||
#ifdef _MicroShadowing
|
||||
, float occ
|
||||
#endif
|
||||
#ifdef _SSRS
|
||||
, sampler2D gbufferD, mat4 invVP, vec3 eye
|
||||
#endif
|
||||
) {
|
||||
vec3 ld = lp - p;
|
||||
vec3 l = normalize(ld);
|
||||
vec3 h = normalize(v + l);
|
||||
float dotNH = max(0.0, dot(n, h));
|
||||
float dotVH = max(0.0, dot(v, h));
|
||||
float dotNL = max(0.0, dot(n, l));
|
||||
|
||||
#ifdef _LTC
|
||||
float theta = acos(dotNV);
|
||||
vec2 tuv = vec2(rough, theta / (0.5 * PI));
|
||||
tuv = tuv * LUT_SCALE + LUT_BIAS;
|
||||
vec4 t = textureLod(sltcMat, tuv, 0.0);
|
||||
mat3 invM = mat3(
|
||||
vec3(1.0, 0.0, t.y),
|
||||
vec3(0.0, t.z, 0.0),
|
||||
vec3(t.w, 0.0, t.x));
|
||||
float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3);
|
||||
ltcspec *= textureLod(sltcMag, tuv, 0.0).a;
|
||||
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
|
||||
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
|
||||
#else
|
||||
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||
#endif
|
||||
|
||||
direct *= attenuate(distance(p, lp));
|
||||
direct *= lightCol;
|
||||
|
||||
#ifdef _MicroShadowing
|
||||
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
#ifdef _SSRS
|
||||
direct *= traceShadowSS(l, p, gbufferD, invVP, eye);
|
||||
#endif
|
||||
|
||||
#ifdef _VoxelShadow
|
||||
vec3 lightDir = l;
|
||||
#ifdef _Spot
|
||||
if (isSpot)
|
||||
lightDir = spotDir;
|
||||
#endif
|
||||
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, lightDir, clipmaps, gl_FragCoord.xy, velocity).r) * voxelgiShad;
|
||||
#endif
|
||||
|
||||
#ifdef _LTC
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[0],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 10, 1.0);
|
||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[0],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[1],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[2],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[3],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return direct;
|
||||
#endif
|
||||
|
||||
#ifdef _Spot
|
||||
if (isSpot) {
|
||||
direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
|
||||
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[0],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= shadowTest(
|
||||
#ifdef _ShadowMapTransparent
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSpot
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[0],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[1],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[2],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[3],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return direct;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _LightIES
|
||||
direct *= iesAttenuation(-l);
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
#ifndef _Spot
|
||||
direct *= PCFCube(shadowMapPoint[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapPointTransparent[0],
|
||||
#endif
|
||||
ld, -l, bias, lightProj, n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= PCFFakeCube(
|
||||
#ifdef _ShadowMapTransparent
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasPoint, shadowMapAtlasPointTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasPoint
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#endif
|
||||
, ld, -l, bias, lightProj, n, index
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapPointTransparent[0],
|
||||
#endif
|
||||
ld, -l, bias, lightProj, n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapPointTransparent[1],
|
||||
#endif
|
||||
ld, -l, bias, lightProj, n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapPointTransparent[2],
|
||||
#endif
|
||||
ld, -l, bias, lightProj, n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapPointTransparent[3],
|
||||
#endif
|
||||
ld, -l, bias, lightProj, n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return direct;
|
||||
}
|
||||
|
||||
#ifdef _VoxelGI
|
||||
vec3 sampleLightVoxels(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
||||
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
||||
#ifdef _ShadowMap
|
||||
, int index, float bias, bool receiveShadow
|
||||
#ifdef _ShadowMapTransparent
|
||||
, bool transparent
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||
#endif
|
||||
) {
|
||||
vec3 ld = lp - p;
|
||||
vec3 l = normalize(ld);
|
||||
vec3 h = normalize(v + l);
|
||||
float dotNH = max(0.0, dot(n, h));
|
||||
float dotVH = max(0.0, dot(v, h));
|
||||
float dotNL = max(0.0, dot(n, l));
|
||||
|
||||
#ifdef _LTC
|
||||
float theta = acos(dotNV);
|
||||
vec2 tuv = vec2(rough, theta / (0.5 * PI));
|
||||
tuv = tuv * LUT_SCALE + LUT_BIAS;
|
||||
vec4 t = textureLod(sltcMat, tuv, 0.0);
|
||||
mat3 invM = mat3(
|
||||
vec3(1.0, 0.0, t.y),
|
||||
vec3(0.0, t.z, 0.0),
|
||||
vec3(t.w, 0.0, t.x));
|
||||
float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3);
|
||||
ltcspec *= textureLod(sltcMag, tuv, 0.0).a;
|
||||
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
|
||||
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
|
||||
#else
|
||||
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||
#endif
|
||||
|
||||
direct *= attenuate(distance(p, lp));
|
||||
direct *= lightCol;
|
||||
|
||||
#ifdef _LTC
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[0],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
vec4 lPos = LWVPSpot[index] * vec4(p + n * bias * 10, 1.0);
|
||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[0],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[1],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[2],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[3],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return direct;
|
||||
#endif
|
||||
|
||||
#ifdef _Spot
|
||||
if (isSpot) {
|
||||
direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
|
||||
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[0],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= shadowTest(
|
||||
#ifdef _ShadowMapTransparent
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSpot
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[0],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[1],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[2],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapSpotTransparent[3],
|
||||
#endif
|
||||
lPos.xyz / lPos.w, bias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return direct;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _LightIES
|
||||
direct *= iesAttenuation(-l);
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
#ifndef _Spot
|
||||
direct *= PCFCube(shadowMapPoint[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapPointTransparent[0],
|
||||
#endif
|
||||
ld, -l, bias, lightProj, n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= PCFFakeCube(
|
||||
#ifdef _ShadowMapTransparent
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasPoint, shadowMapAtlasPointTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
#else
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasPoint
|
||||
#else
|
||||
shadowMapAtlas
|
||||
#endif
|
||||
#endif
|
||||
, ld, -l, bias, lightProj, n, index
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapPointTransparent[0],
|
||||
#endif
|
||||
ld, -l, bias, lightProj, n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapPointTransparent[1],
|
||||
#endif
|
||||
ld, -l, bias, lightProj, n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapPointTransparent[2],
|
||||
#endif
|
||||
ld, -l, bias, lightProj, n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3],
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapPointTransparent[3],
|
||||
#endif
|
||||
ld, -l, bias, lightProj, n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return direct;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#ifndef _LIGHT_GLSL_
|
||||
#define _LIGHT_GLSL_
|
||||
|
||||
#include "compiled.inc"
|
||||
#include "std/brdf.glsl"
|
||||
#include "std/math.glsl"
|
||||
#ifdef _ShadowMap
|
||||
#include "std/shadows.glsl"
|
||||
#endif
|
||||
#ifdef _VoxelShadow
|
||||
#include "std/conetrace.glsl"
|
||||
//!uniform sampler2D voxels_shadows;
|
||||
#endif
|
||||
#ifdef _LTC
|
||||
#include "std/ltc.glsl"
|
||||
#endif
|
||||
#ifdef _LightIES
|
||||
#include "std/ies.glsl"
|
||||
#endif
|
||||
#ifdef _SSRS
|
||||
#include "std/ssrs.glsl"
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
#include "std/light_common.glsl"
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
#ifdef _SinglePoint
|
||||
#ifdef _Spot
|
||||
#ifndef _LTC
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform sampler2D shadowMapSpotTransparent[1];
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[1];
|
||||
uniform samplerCube shadowMapPointTransparent[1];
|
||||
uniform vec2 lightProj;
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
#ifdef _SingleAtlas
|
||||
//!uniform sampler2DShadow shadowMapAtlas;
|
||||
//!uniform sampler2D shadowMapAtlasTransparent;
|
||||
#endif
|
||||
uniform vec2 lightProj;
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasPoint;
|
||||
uniform sampler2D shadowMapAtlasPointTransparent;
|
||||
#endif
|
||||
#else
|
||||
uniform samplerCubeShadow shadowMapPoint[4];
|
||||
uniform samplerCube shadowMapPointTransparent[4];
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
#ifdef _ShadowMapAtlas
|
||||
#ifndef _SingleAtlas
|
||||
uniform sampler2DShadow shadowMapAtlasSpot;
|
||||
uniform sampler2D shadowMapAtlasSpotTransparent;
|
||||
#endif
|
||||
#else
|
||||
uniform sampler2DShadow shadowMapSpot[4];
|
||||
uniform sampler2D shadowMapSpotTransparent[4];
|
||||
#endif
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _LTC
|
||||
uniform vec3 lightArea0;
|
||||
uniform vec3 lightArea1;
|
||||
uniform vec3 lightArea2;
|
||||
uniform vec3 lightArea3;
|
||||
uniform sampler2D sltcMat;
|
||||
uniform sampler2D sltcMag;
|
||||
#ifdef _ShadowMap
|
||||
#ifndef _Spot
|
||||
#ifdef _SinglePoint
|
||||
uniform sampler2DShadow shadowMapSpot[1];
|
||||
uniform sampler2D shadowMapSpotTransparent[1];
|
||||
uniform mat4 LWVPSpot[1];
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
uniform sampler2DShadow shadowMapSpot[maxLightsCluster];
|
||||
uniform sampler2D shadowMapSpotTransparent[maxLightsCluster];
|
||||
uniform mat4 LWVPSpotArray[maxLightsCluster];
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, const vec3 lp, const vec3 lightCol,
|
||||
const vec3 albedo, const float rough, const float spec, const vec3 f0
|
||||
#ifdef _ShadowMap
|
||||
, int index, float bias, bool receiveShadow, bool transparent
|
||||
#endif
|
||||
#ifdef _Spot
|
||||
, const bool isSpot, const float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right
|
||||
#endif
|
||||
#ifdef _VoxelShadow
|
||||
, sampler3D voxels, sampler3D voxelsSDF, float clipmaps[10 * voxelgiClipmapCount]
|
||||
#endif
|
||||
#ifdef _MicroShadowing
|
||||
, float occ
|
||||
#endif
|
||||
#ifdef _SSRS
|
||||
, sampler2D gbufferD, mat4 invVP, vec3 eye
|
||||
#endif
|
||||
) {
|
||||
vec3 ld = lp - p;
|
||||
vec3 l = normalize(ld);
|
||||
vec3 h = normalize(v + l);
|
||||
float dotNH = max(0.0, dot(n, h));
|
||||
float dotVH = max(0.0, dot(v, h));
|
||||
float dotNL = max(0.0, dot(n, l));
|
||||
|
||||
#ifdef _LTC
|
||||
float theta = acos(dotNV);
|
||||
vec2 tuv = vec2(rough, theta / (0.5 * PI));
|
||||
tuv = tuv * LUT_SCALE + LUT_BIAS;
|
||||
vec4 t = textureLod(sltcMat, tuv, 0.0);
|
||||
mat3 invM = mat3(
|
||||
vec3(1.0, 0.0, t.y),
|
||||
vec3(0.0, t.z, 0.0),
|
||||
vec3(t.w, 0.0, t.x));
|
||||
float ltcspec = ltcEvaluate(n, v, dotNV, p, invM, lightArea0, lightArea1, lightArea2, lightArea3);
|
||||
ltcspec *= textureLod(sltcMag, tuv, 0.0).a;
|
||||
float ltcdiff = ltcEvaluate(n, v, dotNV, p, mat3(1.0), lightArea0, lightArea1, lightArea2, lightArea3);
|
||||
vec3 direct = albedo * ltcdiff + ltcspec * spec * 0.05;
|
||||
#else
|
||||
vec3 direct = lambertDiffuseBRDF(albedo, dotNL) +
|
||||
specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec;
|
||||
#endif
|
||||
|
||||
direct *= attenuate(distance(p, lp));
|
||||
direct *= lightCol;
|
||||
|
||||
#ifdef _MicroShadowing
|
||||
direct *= clamp(dotNL + 2.0 * occ * occ - 1.0, 0.0, 1.0);
|
||||
#endif
|
||||
|
||||
#ifdef _SSRS
|
||||
direct *= traceShadowSS(l, p, gbufferD, invVP, eye);
|
||||
#endif
|
||||
|
||||
#ifdef _VoxelShadow
|
||||
direct *= (1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps, gl_FragCoord.xy).r) * voxelgiShad;
|
||||
#endif
|
||||
|
||||
#ifdef _LTC
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpotArray[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return direct;
|
||||
#endif
|
||||
|
||||
#ifdef _Spot
|
||||
if (isSpot) {
|
||||
direct *= spotlightMask(l, spotDir, right, scale, spotSize, spotBlend);
|
||||
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
vec4 lPos = LWVPSpot[0] * vec4(p + n * bias * 10, 1.0);
|
||||
direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
vec4 lPos = LWVPSpotArray[index] * vec4(p + n * bias * 10, 1.0);
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= shadowTest(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasSpot, shadowMapAtlasSpotTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
, lPos.xyz / lPos.w, bias, transparent
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= shadowTest(shadowMapSpot[0], shadowMapSpotTransparent[0], lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 1) direct *= shadowTest(shadowMapSpot[1], shadowMapSpotTransparent[1], lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 2) direct *= shadowTest(shadowMapSpot[2], shadowMapSpotTransparent[2], lPos.xyz / lPos.w, bias, transparent);
|
||||
else if (index == 3) direct *= shadowTest(shadowMapSpot[3], shadowMapSpotTransparent[3], lPos.xyz / lPos.w, bias, transparent);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
return direct;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _LightIES
|
||||
direct *= iesAttenuation(-l);
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMap
|
||||
if (receiveShadow) {
|
||||
#ifdef _SinglePoint
|
||||
#ifndef _Spot
|
||||
direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef _Clusters
|
||||
#ifdef _ShadowMapAtlas
|
||||
direct *= PCFFakeCube(
|
||||
#ifndef _SingleAtlas
|
||||
shadowMapAtlasPoint, shadowMapAtlasPointTransparent
|
||||
#else
|
||||
shadowMapAtlas, shadowMapAtlasTransparent
|
||||
#endif
|
||||
, ld, -l, bias, lightProj, n, index, transparent
|
||||
);
|
||||
#else
|
||||
if (index == 0) direct *= PCFCube(shadowMapPoint[0], shadowMapPointTransparent[0], ld, -l, bias, lightProj, n, transparent);
|
||||
else if (index == 1) direct *= PCFCube(shadowMapPoint[1], shadowMapPointTransparent[1], ld, -l, bias, lightProj, n, transparent);
|
||||
else if (index == 2) direct *= PCFCube(shadowMapPoint[2], shadowMapPointTransparent[2], ld, -l, bias, lightProj, n, transparent);
|
||||
else if (index == 3) direct *= PCFCube(shadowMapPoint[3], shadowMapPointTransparent[3], ld, -l, bias, lightProj, n, transparent);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
return direct;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -58,15 +58,7 @@ vec2 sampleCube(vec3 dir, out int faceIndex) {
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 PCF(sampler2DShadow shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
sampler2D shadowMapTransparent,
|
||||
#endif
|
||||
const vec2 uv, const float compare, const vec2 smSize
|
||||
#ifdef _ShadowMapTransparent
|
||||
, const bool transparent
|
||||
#endif
|
||||
) {
|
||||
vec3 PCF(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec2 uv, const float compare, const vec2 smSize, const bool transparent) {
|
||||
vec3 result = vec3(0.0);
|
||||
result.x = texture(shadowMap, vec3(uv + (vec2(-1.0, -1.0) / smSize), compare));
|
||||
result.x += texture(shadowMap, vec3(uv + (vec2(-1.0, 0.0) / smSize), compare));
|
||||
@ -79,13 +71,11 @@ vec3 PCF(sampler2DShadow shadowMap,
|
||||
result.x += texture(shadowMap, vec3(uv + (vec2(1.0, 1.0) / smSize), compare));
|
||||
result = result.xxx / 9.0;
|
||||
|
||||
#ifdef _ShadowMapTransparent
|
||||
if (transparent == false) {
|
||||
vec4 shadowmap_transparent = texture(shadowMapTransparent, uv);
|
||||
if (shadowmap_transparent.a < compare)
|
||||
result *= shadowmap_transparent.rgb;
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -97,15 +87,41 @@ float lpToDepth(vec3 lp, const vec2 lightProj) {
|
||||
return zcomp * 0.5 + 0.5;
|
||||
}
|
||||
|
||||
vec3 PCFCube(samplerCubeShadow shadowMapCube,
|
||||
#ifdef _ShadowMapTransparent
|
||||
samplerCube shadowMapCubeTransparent,
|
||||
#endif
|
||||
const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n
|
||||
#ifdef _ShadowMapTransparent
|
||||
, const bool transparent
|
||||
#endif
|
||||
) {
|
||||
#ifndef _ShadowMapAtlas
|
||||
vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTransparent, vec3 lp, vec3 ml, float bias, vec2 lightProj, vec3 n, const bool transparent) {
|
||||
const float s = shadowmapCubePcfSize;
|
||||
float compare = lpToDepth(lp, lightProj) - bias * 1.5;
|
||||
ml = ml + n * bias * 20;
|
||||
#ifdef _InvY
|
||||
ml.y = -ml.y;
|
||||
#endif
|
||||
|
||||
float shadowFactor = 0.0;
|
||||
shadowFactor = texture(shadowMapCube, vec4(ml, compare));
|
||||
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, s, s), compare));
|
||||
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, s, s), compare));
|
||||
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, -s, s), compare));
|
||||
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, s, -s), compare));
|
||||
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, -s, s), compare));
|
||||
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(s, -s, -s), compare));
|
||||
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, s, -s), compare));
|
||||
shadowFactor += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare));
|
||||
shadowFactor /= 9.0;
|
||||
|
||||
vec3 result = vec3(shadowFactor);
|
||||
|
||||
if (transparent == false) {
|
||||
vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml);
|
||||
if (shadowmap_transparent.a < compare)
|
||||
result *= shadowmap_transparent.rgb;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMapAtlas
|
||||
vec3 PCFCube(samplerCubeShadow shadowMapCube, samplerCube shadowMapCubeTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const bool transparent) {
|
||||
const float s = shadowmapCubePcfSize; // TODO: incorrect...
|
||||
float compare = lpToDepth(lp, lightProj) - bias * 1.5;
|
||||
ml = ml + n * bias * 20;
|
||||
@ -124,18 +140,16 @@ vec3 PCFCube(samplerCubeShadow shadowMapCube,
|
||||
result.x += texture(shadowMapCube, vec4(ml + vec3(-s, -s, -s), compare));
|
||||
result = result.xxx / 9.0;
|
||||
|
||||
#ifdef _ShadowMapTransparent
|
||||
if (transparent == false) {
|
||||
vec4 shadowmap_transparent = texture(shadowMapCubeTransparent, ml);
|
||||
if (shadowmap_transparent.a < compare)
|
||||
result *= shadowmap_transparent.rgb;
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef _ShadowMapAtlas
|
||||
|
||||
// transform "out-of-bounds" coordinates to the correct face/coordinate system
|
||||
// https://www.khronos.org/opengl/wiki/File:CubeMapAxes.png
|
||||
vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 uv) {
|
||||
@ -229,50 +243,89 @@ vec2 transformOffsetedUV(const int faceIndex, out int newFaceIndex, vec2 uv) {
|
||||
return uv;
|
||||
}
|
||||
|
||||
vec3 PCFFakeCube(sampler2DShadow shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
sampler2D shadowMapTransparent,
|
||||
#endif
|
||||
const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const int index
|
||||
#ifdef _ShadowMapTransparent
|
||||
, const bool transparent
|
||||
#endif
|
||||
) {
|
||||
vec3 PCFFakeCube(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 lp, vec3 ml, const float bias, const vec2 lightProj, const vec3 n, const int index, const bool transparent) {
|
||||
const vec2 smSize = smSizeUniform; // TODO: incorrect...
|
||||
const float compare = lpToDepth(lp, lightProj) - bias * 1.5;
|
||||
ml = ml + n * bias * 20;
|
||||
|
||||
int faceIndex = 0;
|
||||
const int lightIndex = index * 6;
|
||||
const vec2 uv = sampleCube(ml, faceIndex);
|
||||
|
||||
vec4 pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
|
||||
vec2 uvtiled = pointLightTile.z * uv + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
|
||||
if (any(lessThan(uvtiled, vec2(0.0))) || any(greaterThan(uvtiled, vec2(1.0)))) {
|
||||
return vec3(1.0); // Or handle edge cases differently
|
||||
}
|
||||
|
||||
vec3 result = vec3(0.0);
|
||||
// In PCFFakeCube(), modify the sampling pattern to be more robust:
|
||||
const vec2 offsets[9] = vec2[](
|
||||
vec2(0, 0),
|
||||
vec2(1, 0), vec2(-1, 0), vec2(0, 1), vec2(0, -1),
|
||||
vec2(1, 1), vec2(-1, 1), vec2(1, -1), vec2(-1, -1)
|
||||
);
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
// soft shadowing
|
||||
int newFaceIndex = 0;
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, 0.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, 1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.0, -1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(-1.0, -1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(0.0, 1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(1.0, -1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(1.0, 0.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
uvtiled = transformOffsetedUV(faceIndex, newFaceIndex, vec2(uv + (vec2(1.0, 1.0) / smSize)));
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * uvtiled + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
vec2 sampleUV = uv + offsets[i] / smSize;
|
||||
int newFaceIndex;
|
||||
vec2 transformedUV = transformOffsetedUV(faceIndex, newFaceIndex, sampleUV);
|
||||
pointLightTile = pointLightDataArray[lightIndex + newFaceIndex];
|
||||
uvtiled = pointLightTile.z * transformedUV + pointLightTile.xy;
|
||||
#ifdef _FlipY
|
||||
uvtiled.y = 1.0 - uvtiled.y;
|
||||
#endif
|
||||
result.x += texture(shadowMap, vec3(uvtiled, compare));
|
||||
}
|
||||
result = result.xxx / 9.0;
|
||||
|
||||
pointLightTile = pointLightDataArray[lightIndex + faceIndex]; // x: tile X offset, y: tile Y offset, z: tile size relative to atlas
|
||||
@ -281,47 +334,30 @@ vec3 PCFFakeCube(sampler2DShadow shadowMap,
|
||||
uvtiled.y = 1.0 - uvtiled.y; // invert Y coordinates for direct3d coordinate system
|
||||
#endif
|
||||
|
||||
#ifdef _ShadowMapTransparent
|
||||
if (transparent == false) {
|
||||
vec4 shadowmap_transparent = texture(shadowMapTransparent, uvtiled);
|
||||
if (shadowmap_transparent.a < compare)
|
||||
result *= shadowmap_transparent.rgb;
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
vec3 shadowTest(sampler2DShadow shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
sampler2D shadowMapTransparent,
|
||||
#endif
|
||||
const vec3 lPos, const float shadowsBias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, const bool transparent
|
||||
#endif
|
||||
) {
|
||||
vec3 shadowTest(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 lPos, const float shadowsBias, const bool transparent) {
|
||||
#ifdef _SMSizeUniform
|
||||
vec2 smSize = smSizeUniform;
|
||||
#else
|
||||
const vec2 smSize = shadowmapSize;
|
||||
#endif
|
||||
if (lPos.x < 0.0 || lPos.y < 0.0 || lPos.x > 1.0 || lPos.y > 1.0) return vec3(1.0);
|
||||
return PCF(shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapTransparent,
|
||||
#endif
|
||||
lPos.xy, lPos.z - shadowsBias, smSize
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
return PCF(shadowMap, shadowMapTransparent, lPos.xy, lPos.z - shadowsBias, smSize, transparent);
|
||||
}
|
||||
|
||||
#ifdef _CSM
|
||||
mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
|
||||
const int c = shadowmapCascades;
|
||||
|
||||
// Get cascade index
|
||||
// TODO: use bounding box slice selection instead of sphere
|
||||
const vec4 ci = vec4(float(c > 0), float(c > 1), float(c > 2), float(c > 3));
|
||||
@ -337,26 +373,21 @@ mat4 getCascadeMat(const float d, out int casi, out int casIndex) {
|
||||
float(d > casData[c * 4].z),
|
||||
float(d > casData[c * 4].w));
|
||||
casi = int(min(dot(ci, comp), c));
|
||||
|
||||
// Get cascade mat
|
||||
casIndex = casi * 4;
|
||||
|
||||
return mat4(
|
||||
casData[casIndex ],
|
||||
casData[casIndex + 1],
|
||||
casData[casIndex + 2],
|
||||
casData[casIndex + 3]);
|
||||
|
||||
// if (casIndex == 0) return mat4(casData[0], casData[1], casData[2], casData[3]);
|
||||
// ..
|
||||
}
|
||||
|
||||
vec3 shadowTestCascade(sampler2DShadow shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
sampler2D shadowMapTransparent,
|
||||
#endif
|
||||
const vec3 eye, const vec3 p, const float shadowsBias
|
||||
#ifdef _ShadowMapTransparent
|
||||
, const bool transparent
|
||||
#endif
|
||||
) {
|
||||
vec3 shadowTestCascade(sampler2DShadow shadowMap, sampler2D shadowMapTransparent, const vec3 eye, const vec3 p, const float shadowsBias, const bool transparent) {
|
||||
#ifdef _SMSizeUniform
|
||||
vec2 smSize = smSizeUniform;
|
||||
#else
|
||||
@ -364,22 +395,16 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
|
||||
#endif
|
||||
const int c = shadowmapCascades;
|
||||
float d = distance(eye, p);
|
||||
|
||||
int casi;
|
||||
int casIndex;
|
||||
mat4 LWVP = getCascadeMat(d, casi, casIndex);
|
||||
|
||||
vec4 lPos = LWVP * vec4(p, 1.0);
|
||||
lPos.xyz /= lPos.w;
|
||||
|
||||
vec3 visibility = vec3(1.0);
|
||||
if (lPos.w > 0.0) visibility = PCF(shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapTransparent,
|
||||
#endif
|
||||
lPos.xy, lPos.z - shadowsBias, smSize
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
if (lPos.w > 0.0) visibility = PCF(shadowMap, shadowMapTransparent, lPos.xy, lPos.z - shadowsBias, smSize, transparent);
|
||||
|
||||
// Blend cascade
|
||||
// https://github.com/TheRealMJP/Shadows
|
||||
@ -398,20 +423,13 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
|
||||
vec4 lPos2 = LWVP2 * vec4(p, 1.0);
|
||||
lPos2.xyz /= lPos2.w;
|
||||
vec3 visibility2 = vec3(1.0);
|
||||
if (lPos2.w > 0.0) visibility2 = PCF(shadowMap,
|
||||
#ifdef _ShadowMapTransparent
|
||||
shadowMapTransparent,
|
||||
#endif
|
||||
lPos.xy, lPos.z - shadowsBias, smSize
|
||||
#ifdef _ShadowMapTransparent
|
||||
, transparent
|
||||
#endif
|
||||
);
|
||||
if (lPos2.w > 0.0) visibility2 = PCF(shadowMap, shadowMapTransparent, lPos2.xy, lPos2.z - shadowsBias, smSize, transparent);
|
||||
|
||||
float lerpAmt = smoothstep(0.0, blendThres, splitDist);
|
||||
return mix(visibility2, visibility, lerpAmt);
|
||||
}
|
||||
return visibility;
|
||||
|
||||
// Visualize cascades
|
||||
// if (ci == 0) albedo.rgb = vec3(1.0, 0.0, 0.0);
|
||||
// if (ci == 4) albedo.rgb = vec3(0.0, 1.0, 0.0);
|
||||
@ -419,4 +437,4 @@ vec3 shadowTestCascade(sampler2DShadow shadowMap,
|
||||
// if (ci == 12) albedo.rgb = vec3(1.0, 1.0, 0.0);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
@ -21,42 +21,29 @@ THE SOFTWARE.
|
||||
*/
|
||||
|
||||
const int DIFFUSE_CONE_COUNT = 16;
|
||||
const float DIFFUSE_CONE_APERTURE = radians(45.0);
|
||||
|
||||
const float SHADOW_CONE_APERTURE = radians(15.0);
|
||||
const vec3 DIFFUSE_CONE_DIRECTIONS[16] = {
|
||||
vec3(0.0000, 0.0000, 1.0000), // Central direction
|
||||
vec3(0.3827, 0.0000, 0.9239), // Ring 1
|
||||
vec3(-0.3827, 0.0000, 0.9239),
|
||||
vec3(0.0000, 0.3827, 0.9239),
|
||||
vec3(0.0000, -0.3827, 0.9239),
|
||||
vec3(0.2706, 0.2706, 0.9239), // Ring 2
|
||||
vec3(-0.2706, 0.2706, 0.9239),
|
||||
vec3(0.2706, -0.2706, 0.9239),
|
||||
vec3(-0.2706, -0.2706, 0.9239),
|
||||
vec3(0.1802, 0.3604, 0.9239), // Ring 3
|
||||
vec3(-0.1802, 0.3604, 0.9239),
|
||||
vec3(0.1802, -0.3604, 0.9239),
|
||||
vec3(-0.1802, -0.3604, 0.9239),
|
||||
vec3(0.3604, 0.1802, 0.9239),
|
||||
vec3(-0.3604, 0.1802, 0.9239),
|
||||
vec3(0.3604, -0.1802, 0.9239)
|
||||
};
|
||||
|
||||
const float DIFFUSE_CONE_APERTURE = radians(50.0);
|
||||
|
||||
const vec3 DIFFUSE_CONE_DIRECTIONS[DIFFUSE_CONE_COUNT] = vec3[](
|
||||
vec3(0.0, 0.0, 1.0), // center
|
||||
|
||||
vec3(0.0, 0.5, 0.866),
|
||||
vec3(0.5, 0.0, 0.866),
|
||||
vec3(0.0, -0.5, 0.866),
|
||||
vec3(-0.5, 0.0, 0.866),
|
||||
|
||||
vec3(0.353, 0.353, 0.866),
|
||||
vec3(0.353, -0.353, 0.866),
|
||||
vec3(-0.353, -0.353, 0.866),
|
||||
vec3(-0.353, 0.353, 0.866),
|
||||
|
||||
vec3(0.707, 0.0, 0.707),
|
||||
vec3(0.0, 0.707, 0.707),
|
||||
vec3(-0.707, 0.0, 0.707),
|
||||
vec3(0.0, -0.707, 0.707),
|
||||
|
||||
vec3(0.5, 0.5, 0.707),
|
||||
vec3(-0.5, 0.5, 0.707),
|
||||
vec3(-0.5, -0.5, 0.707)
|
||||
);
|
||||
|
||||
mat3 makeTangentBasis(vec3 normal) {
|
||||
vec3 tangent = normalize(abs(normal.y) < 0.999 ? cross(normal, vec3(0, 1, 0)) : cross(normal, vec3(1, 0, 0)));
|
||||
vec3 bitangent = cross(normal, tangent);
|
||||
return mat3(tangent, bitangent, normal);
|
||||
}
|
||||
|
||||
// TO DO - Disabled momentarily instead of changing formulas
|
||||
const float off_BayerMatrix8[8][8] =
|
||||
const float BayerMatrix8[8][8] =
|
||||
{
|
||||
{ 1.0 / 65.0, 49.0 / 65.0, 13.0 / 65.0, 61.0 / 65.0, 4.0 / 65.0, 52.0 / 65.0, 16.0 / 65.0, 64.0 / 65.0 },
|
||||
{ 33.0 / 65.0, 17.0 / 65.0, 45.0 / 65.0, 29.0 / 65.0, 36.0 / 65.0, 20.0 / 65.0, 48.0 / 65.0, 32.0 / 65.0 },
|
||||
@ -67,15 +54,3 @@ const float off_BayerMatrix8[8][8] =
|
||||
{ 11.0 / 65.0, 59.0 / 65.0, 7.0 / 65.0, 55.0 / 65.0, 10.0 / 65.0, 58.0 / 65.0, 6.0 / 65.0, 54.0 / 65.0 },
|
||||
{ 43.0 / 65.0, 27.0 / 65.0, 39.0 / 65.0, 23.0 / 65.0, 42.0 / 65.0, 26.0 / 65.0, 38.0 / 65.0, 22.0 / 65.0 }
|
||||
};
|
||||
const float BayerMatrix8[8][8] =
|
||||
{
|
||||
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
|
||||
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
|
||||
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
|
||||
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
|
||||
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
|
||||
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
|
||||
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 },
|
||||
{ 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 }
|
||||
};
|
||||
|
@ -33,7 +33,6 @@ uniform layout(r32ui) uimage3D voxelsLight;
|
||||
|
||||
#ifdef _ShadowMap
|
||||
uniform sampler2DShadow shadowMap;
|
||||
uniform sampler2D shadowMapTransparent;
|
||||
uniform sampler2DShadow shadowMapSpot;
|
||||
#ifdef _ShadowMapAtlas
|
||||
uniform sampler2DShadow shadowMapPoint;
|
||||
@ -87,28 +86,30 @@ float lpToDepth(vec3 lp, const vec2 lightProj) {
|
||||
|
||||
void main() {
|
||||
int res = voxelgiResolution.x;
|
||||
|
||||
ivec3 dst = ivec3(gl_GlobalInvocationID.xyz);
|
||||
dst.y += clipmapLevel * res;
|
||||
|
||||
vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
|
||||
wposition = wposition * 2.0 - 1.0;
|
||||
wposition *= float(clipmaps[int(clipmapLevel * 10)]);
|
||||
wposition *= voxelgiResolution.x;
|
||||
wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]);
|
||||
vec3 P = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution;
|
||||
P = P * 2.0 - 1.0;
|
||||
P *= clipmaps[int(clipmapLevel * 10)];
|
||||
P *= voxelgiResolution;
|
||||
P += vec3(clipmaps[int(clipmapLevel * 10 + 4)], clipmaps[int(clipmapLevel * 10 + 5)], clipmaps[int(clipmapLevel * 10 + 6)]);
|
||||
|
||||
float visibility;
|
||||
vec3 lp = lightPos -wposition;
|
||||
vec3 visibility;
|
||||
vec3 lp = lightPos - P;
|
||||
vec3 l;
|
||||
if (lightType == 0) { l = lightDir; visibility = 1.0; }
|
||||
else { l = normalize(lp); visibility = attenuate(distance(wposition, lightPos)); }
|
||||
if (lightType == 0) { l = lightDir; visibility = vec3(1.0); }
|
||||
else { l = normalize(lp); visibility = vec3(attenuate(distance(P, lightPos))); }
|
||||
|
||||
#ifdef _ShadowMap
|
||||
if (lightShadow == 1) {
|
||||
vec4 lightPosition = LVP * vec4(wposition, 1.0);
|
||||
vec4 lightPosition = LVP * vec4(P, 1.0);
|
||||
vec3 lPos = lightPosition.xyz / lightPosition.w;
|
||||
visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).r;
|
||||
visibility = texture(shadowMap, vec3(lPos.xy, lPos.z - shadowsBias)).rrr;
|
||||
}
|
||||
else if (lightShadow == 2) {
|
||||
vec4 lightPosition = LVP * vec4(wposition, 1.0);
|
||||
vec4 lightPosition = LVP * vec4(P, 1.0);
|
||||
vec3 lPos = lightPosition.xyz / lightPosition.w;
|
||||
visibility *= texture(shadowMapSpot, vec3(lPos.xy, lPos.z - shadowsBias)).r;
|
||||
}
|
||||
@ -129,7 +130,9 @@ void main() {
|
||||
}
|
||||
#endif
|
||||
|
||||
imageAtomicAdd(voxelsLight, dst, uint(visibility * lightColor.r * 255));
|
||||
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x), uint(visibility * lightColor.g * 255));
|
||||
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x * 2), uint(visibility * lightColor.b * 255));
|
||||
vec3 light = visibility * lightColor;
|
||||
|
||||
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, 0), uint(light.r * 255));
|
||||
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x), uint(light.g * 255));
|
||||
imageAtomicAdd(voxelsLight, dst + ivec3(0, 0, voxelgiResolution.x * 2), uint(light.b * 255));
|
||||
}
|
||||
|
@ -27,14 +27,14 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in;
|
||||
#include "std/math.glsl"
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/imageatomic.glsl"
|
||||
#include "std/constants.glsl"
|
||||
#include "std/voxels_constants.glsl"
|
||||
|
||||
#ifdef _VoxelGI
|
||||
uniform layout(rgba8) image3D voxelsB;
|
||||
uniform layout(rgba8) image3D voxelsOut;
|
||||
#else
|
||||
uniform layout(r8) image3D voxelsB;
|
||||
uniform layout(r8) image3D voxelsOut;
|
||||
uniform layout(r16) image3D voxelsB;
|
||||
uniform layout(r16) image3D voxelsOut;
|
||||
#endif
|
||||
|
||||
uniform int clipmapLevel;
|
||||
|
@ -29,38 +29,19 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/imageatomic.glsl"
|
||||
#include "std/conetrace.glsl"
|
||||
#include "std/brdf.glsl"
|
||||
#include "std/shirr.glsl"
|
||||
|
||||
uniform sampler3D voxels;
|
||||
uniform sampler2D gbufferD;
|
||||
uniform sampler2D gbuffer0;
|
||||
uniform layout(rgba8) image2D voxels_ao;
|
||||
uniform layout(r8) image2D voxels_ao;
|
||||
|
||||
uniform float clipmaps[voxelgiClipmapCount * 10];
|
||||
uniform mat4 InvVP;
|
||||
uniform vec2 cameraProj;
|
||||
uniform vec3 eye;
|
||||
uniform vec3 eyeLook;
|
||||
uniform vec2 postprocess_resolution;
|
||||
|
||||
uniform sampler2D gbuffer1;
|
||||
#ifdef _gbuffer2
|
||||
uniform sampler2D gbuffer2;
|
||||
#endif
|
||||
uniform float envmapStrength;
|
||||
#ifdef _Irr
|
||||
uniform float shirr[7 * 4];
|
||||
#endif
|
||||
#ifdef _Brdf
|
||||
uniform sampler2D senvmapBrdf;
|
||||
#endif
|
||||
#ifdef _Rad
|
||||
uniform sampler2D senvmapRadiance;
|
||||
uniform int envmapNumMipmaps;
|
||||
#endif
|
||||
#ifdef _EnvCol
|
||||
uniform vec3 backgroundCol;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
const vec2 pixel = gl_GlobalInvocationID.xy;
|
||||
vec2 uv = (pixel + 0.5) / postprocess_resolution;
|
||||
@ -73,11 +54,12 @@ void main() {
|
||||
|
||||
float x = uv.x * 2 - 1;
|
||||
float y = uv.y * 2 - 1;
|
||||
vec4 clipPos = vec4(x, y, depth, 1.0);
|
||||
vec4 worldPos = InvVP * clipPos;
|
||||
vec3 P = worldPos.xyz / worldPos.w;
|
||||
vec4 v = vec4(x, y, 1.0, 1.0);
|
||||
v = vec4(InvVP * v);
|
||||
v.xyz /= v.w;
|
||||
vec3 viewRay = v.xyz - eye;
|
||||
|
||||
vec3 v = normalize(eye - P);
|
||||
vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
|
||||
|
||||
vec4 g0 = textureLod(gbuffer0, uv, 0.0);
|
||||
vec3 n;
|
||||
@ -85,89 +67,7 @@ void main() {
|
||||
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
|
||||
n = normalize(n);
|
||||
|
||||
float roughness = g0.b;
|
||||
float metallic;
|
||||
uint matid;
|
||||
unpackFloatInt16(g0.a, metallic, matid);
|
||||
float occ = 1.0 - traceAO(P, n, voxels, clipmaps);
|
||||
|
||||
vec4 g1 = textureLod(gbuffer1, uv, 0.0); // Basecolor.rgb, spec/occ
|
||||
vec2 occspec = unpackFloat2(g1.a);
|
||||
vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
|
||||
vec3 f0 = surfaceF0(g1.rgb, metallic);
|
||||
float dotNV = max(dot(n, v), 0.0);
|
||||
|
||||
#ifdef _gbuffer2
|
||||
vec4 g2 = textureLod(gbuffer2, uv, 0.0);
|
||||
#endif
|
||||
|
||||
#ifdef _MicroShadowing
|
||||
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
|
||||
#endif
|
||||
|
||||
#ifdef _Brdf
|
||||
vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
|
||||
vec3 F = f0 * envBRDF.x + envBRDF.y;
|
||||
#endif
|
||||
|
||||
// Envmap
|
||||
#ifdef _Irr
|
||||
vec4 shPacked[7];
|
||||
for (int i = 0; i < 7; i++) {
|
||||
int base = i * 4;
|
||||
shPacked[i] = vec4(
|
||||
shirr[base],
|
||||
shirr[base + 1],
|
||||
shirr[base + 2],
|
||||
shirr[base + 3]
|
||||
);
|
||||
}
|
||||
vec3 envl = shIrradiance(n, shPacked);
|
||||
|
||||
#ifdef _gbuffer2
|
||||
if (g2.b < 0.5) {
|
||||
envl = envl;
|
||||
} else {
|
||||
envl = vec3(0.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _EnvTex
|
||||
envl /= PI;
|
||||
#endif
|
||||
#else
|
||||
vec3 envl = vec3(0.0);
|
||||
#endif
|
||||
|
||||
#ifdef _Rad
|
||||
vec3 reflectionWorld = reflect(-v, n);
|
||||
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
|
||||
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
|
||||
#endif
|
||||
|
||||
#ifdef _EnvLDR
|
||||
envl.rgb = pow(envl.rgb, vec3(2.2));
|
||||
#ifdef _Rad
|
||||
prefilteredColor = pow(prefilteredColor, vec3(2.2));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
envl.rgb *= albedo;
|
||||
|
||||
#ifdef _Brdf
|
||||
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
|
||||
#endif
|
||||
|
||||
#ifdef _Rad // Indirect specular
|
||||
envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
|
||||
#else
|
||||
#ifdef _EnvCol
|
||||
envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
|
||||
#endif
|
||||
#endif
|
||||
|
||||
envl.rgb *= envmapStrength * occspec.x;
|
||||
|
||||
vec3 occ = envl * (1.0 - traceAO(P, n, voxels, clipmaps));
|
||||
|
||||
imageStore(voxels_ao, ivec2(pixel), vec4(occ, 1.0));
|
||||
imageStore(voxels_ao, ivec2(pixel), vec4(occ));
|
||||
}
|
||||
|
@ -29,8 +29,6 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/imageatomic.glsl"
|
||||
#include "std/conetrace.glsl"
|
||||
#include "std/brdf.glsl"
|
||||
#include "std/shirr.glsl"
|
||||
|
||||
uniform sampler3D voxels;
|
||||
uniform sampler2D gbufferD;
|
||||
@ -39,44 +37,29 @@ uniform layout(rgba8) image2D voxels_diffuse;
|
||||
|
||||
uniform float clipmaps[voxelgiClipmapCount * 10];
|
||||
uniform mat4 InvVP;
|
||||
uniform vec2 cameraProj;
|
||||
uniform vec3 eye;
|
||||
uniform vec3 eyeLook;
|
||||
uniform vec2 postprocess_resolution;
|
||||
|
||||
uniform sampler2D gbuffer1;
|
||||
#ifdef _gbuffer2
|
||||
uniform sampler2D gbuffer2;
|
||||
#endif
|
||||
uniform float envmapStrength;
|
||||
#ifdef _Irr
|
||||
uniform float shirr[7 * 4];
|
||||
#endif
|
||||
#ifdef _Brdf
|
||||
uniform sampler2D senvmapBrdf;
|
||||
#endif
|
||||
#ifdef _Rad
|
||||
uniform sampler2D senvmapRadiance;
|
||||
uniform int envmapNumMipmaps;
|
||||
#endif
|
||||
#ifdef _EnvCol
|
||||
uniform vec3 backgroundCol;
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
const vec2 pixel = gl_GlobalInvocationID.xy;
|
||||
vec2 uv = (pixel + 0.5) / postprocess_resolution;
|
||||
#ifdef _InvY
|
||||
uv.y = 1.0 - uv.y;
|
||||
uv.y = 1.0 - uv.y
|
||||
#endif
|
||||
|
||||
float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
|
||||
if (depth == 0.0) return;
|
||||
if (depth == 0) return;
|
||||
|
||||
float x = uv.x * 2 - 1;
|
||||
float y = uv.y * 2 - 1;
|
||||
vec4 clipPos = vec4(x, y, depth, 1.0);
|
||||
vec4 worldPos = InvVP * clipPos;
|
||||
vec3 P = worldPos.xyz / worldPos.w;
|
||||
vec3 v = normalize(eye - P);
|
||||
vec4 v = vec4(x, y, 1.0, 1.0);
|
||||
v = vec4(InvVP * v);
|
||||
v.xyz /= v.w;
|
||||
vec3 viewRay = v.xyz - eye;
|
||||
|
||||
vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
|
||||
|
||||
vec4 g0 = textureLod(gbuffer0, uv, 0.0);
|
||||
vec3 n;
|
||||
@ -84,91 +67,7 @@ void main() {
|
||||
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
|
||||
n = normalize(n);
|
||||
|
||||
float roughness = g0.b;
|
||||
float metallic;
|
||||
uint matid;
|
||||
unpackFloatInt16(g0.a, metallic, matid);
|
||||
vec4 color = traceDiffuse(P, n, voxels, clipmaps);
|
||||
|
||||
vec4 g1 = textureLod(gbuffer1, uv, 0.0); // Basecolor.rgb, spec/occ
|
||||
vec2 occspec = unpackFloat2(g1.a);
|
||||
vec3 albedo = surfaceAlbedo(g1.rgb, metallic); // g1.rgb - basecolor
|
||||
vec3 f0 = surfaceF0(g1.rgb, metallic);
|
||||
float dotNV = max(dot(n, v), 0.0);
|
||||
|
||||
#ifdef _gbuffer2
|
||||
vec4 g2 = textureLod(gbuffer2, uv, 0.0);
|
||||
#endif
|
||||
|
||||
#ifdef _MicroShadowing
|
||||
occspec.x = mix(1.0, occspec.x, dotNV); // AO Fresnel
|
||||
#endif
|
||||
|
||||
#ifdef _Brdf
|
||||
vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;
|
||||
vec3 F = f0 * envBRDF.x + envBRDF.y;
|
||||
#endif
|
||||
|
||||
// Envmap
|
||||
#ifdef _Irr
|
||||
vec4 shPacked[7];
|
||||
for (int i = 0; i < 7; i++) {
|
||||
int base = i * 4;
|
||||
shPacked[i] = vec4(
|
||||
shirr[base],
|
||||
shirr[base + 1],
|
||||
shirr[base + 2],
|
||||
shirr[base + 3]
|
||||
);
|
||||
}
|
||||
vec3 envl = shIrradiance(n, shPacked);
|
||||
|
||||
#ifdef _gbuffer2
|
||||
if (g2.b < 0.5) {
|
||||
envl = envl;
|
||||
} else {
|
||||
envl = vec3(0.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _EnvTex
|
||||
envl /= PI;
|
||||
#endif
|
||||
#else
|
||||
vec3 envl = vec3(0.0);
|
||||
#endif
|
||||
|
||||
#ifdef _Rad
|
||||
vec3 reflectionWorld = reflect(-v, n);
|
||||
float lod = getMipFromRoughness(roughness, envmapNumMipmaps);
|
||||
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
|
||||
#endif
|
||||
|
||||
#ifdef _EnvLDR
|
||||
envl.rgb = pow(envl.rgb, vec3(2.2));
|
||||
#ifdef _Rad
|
||||
prefilteredColor = pow(prefilteredColor, vec3(2.2));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
envl.rgb *= albedo;
|
||||
|
||||
#ifdef _Brdf
|
||||
envl.rgb *= 1.0 - F; //LV: We should take refracted light into account
|
||||
#endif
|
||||
|
||||
#ifdef _Rad // Indirect specular
|
||||
envl.rgb += prefilteredColor * F; //LV: Removed "1.5 * occspec.y". Specular should be weighted only by FV LUT
|
||||
#else
|
||||
#ifdef _EnvCol
|
||||
envl.rgb += backgroundCol * F; //LV: Eh, what's the point of weighting it only by F0?
|
||||
#endif
|
||||
#endif
|
||||
|
||||
envl.rgb *= envmapStrength * occspec.x;
|
||||
|
||||
vec4 trace = traceDiffuse(P, n, voxels, clipmaps);
|
||||
vec3 color = trace.rgb * albedo * (1.0 - F);
|
||||
color += envl * (1.0 - trace.a);
|
||||
|
||||
imageStore(voxels_diffuse, ivec2(pixel), vec4(color, 1.0));
|
||||
imageStore(voxels_diffuse, ivec2(pixel), color);
|
||||
}
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright (c) 2024 Turánszki János
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#version 450
|
||||
|
||||
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
|
||||
#include "compiled.inc"
|
||||
#include "std/math.glsl"
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/imageatomic.glsl"
|
||||
#include "std/conetrace.glsl"
|
||||
|
||||
uniform sampler2D gbufferD;
|
||||
uniform sampler2D gbuffer0;
|
||||
uniform sampler3D voxels;
|
||||
uniform sampler3D voxelsSDF;
|
||||
uniform sampler2D gbuffer_refraction;
|
||||
uniform layout(rgba8) image2D voxels_refraction;
|
||||
|
||||
uniform float clipmaps[voxelgiClipmapCount * 10];
|
||||
uniform mat4 InvVP;
|
||||
uniform vec2 cameraProj;
|
||||
uniform vec3 eye;
|
||||
uniform vec3 eyeLook;
|
||||
uniform vec2 postprocess_resolution;
|
||||
|
||||
void main() {
|
||||
const vec2 pixel = gl_GlobalInvocationID.xy;
|
||||
vec2 uv = (pixel + 0.5) / postprocess_resolution;
|
||||
#ifdef _InvY
|
||||
uv.y = 1.0 - uv.y
|
||||
#endif
|
||||
|
||||
float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
|
||||
if (depth == 0) return;
|
||||
|
||||
vec2 ior_opac = textureLod(gbuffer_refraction, uv, 0.0).xy;
|
||||
|
||||
float x = uv.x * 2 - 1;
|
||||
float y = uv.y * 2 - 1;
|
||||
vec4 v = vec4(x, y, 1.0, 1.0);
|
||||
v = vec4(InvVP * v);
|
||||
v.xyz /= v.w;
|
||||
vec3 viewRay = v.xyz - eye;
|
||||
|
||||
vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
|
||||
|
||||
vec4 g0 = textureLod(gbuffer0, uv, 0.0);
|
||||
vec3 n;
|
||||
n.z = 1.0 - abs(g0.x) - abs(g0.y);
|
||||
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
|
||||
n = normalize(n);
|
||||
|
||||
vec3 color = vec3(0.0);
|
||||
if(ior_opac.y < 1.0)
|
||||
color = traceRefraction(P, n, voxels, voxelsSDF, normalize(eye - P), ior_opac.x, g0.b, clipmaps, pixel).rgb;
|
||||
|
||||
imageStore(voxels_refraction, ivec2(pixel), vec4(color, 1.0));
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright (c) 2024 Turánszki János
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#version 450
|
||||
|
||||
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
|
||||
#include "compiled.inc"
|
||||
#include "std/math.glsl"
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/imageatomic.glsl"
|
||||
#include "std/conetrace.glsl"
|
||||
|
||||
uniform sampler3D voxels;
|
||||
uniform sampler3D voxelsSDF;
|
||||
uniform sampler2D gbufferD;
|
||||
uniform sampler2D gbuffer0;
|
||||
uniform layout(r16) image2D voxels_shadows;
|
||||
|
||||
uniform float clipmaps[voxelgiClipmapCount * 10];
|
||||
uniform mat4 InvVP;
|
||||
uniform vec2 cameraProj;
|
||||
uniform vec3 eye;
|
||||
uniform vec3 eyeLook;
|
||||
uniform vec2 postprocess_resolution;
|
||||
uniform vec3 lPos;
|
||||
|
||||
void main() {
|
||||
const vec2 pixel = gl_GlobalInvocationID.xy;
|
||||
vec2 uv = (pixel + 0.5) / postprocess_resolution;
|
||||
#ifdef _InvY
|
||||
uv.y = 1.0 - uv.y;
|
||||
#endif
|
||||
|
||||
float depth = textureLod(gbufferD, uv, 0.0).r * 2.0 - 1.0;
|
||||
if (depth == 0) return;
|
||||
|
||||
float x = uv.x * 2 - 1;
|
||||
float y = uv.y * 2 - 1;
|
||||
vec4 v = vec4(x, y, 1.0, 1.0);
|
||||
v = vec4(InvVP * v);
|
||||
v.xyz /= v.w;
|
||||
vec3 viewRay = v.xyz - eye;
|
||||
|
||||
vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
|
||||
|
||||
vec4 g0 = textureLod(gbuffer0, uv, 0.0);
|
||||
vec3 n;
|
||||
n.z = 1.0 - abs(g0.x) - abs(g0.y);
|
||||
n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);
|
||||
n = normalize(n);
|
||||
|
||||
float occ = 1.0 - traceShadow(P, n, voxels, voxelsSDF, normalize(lPos - P), clipmaps, pixel);
|
||||
|
||||
imageStore(voxels_shadows, ivec2(pixel), vec4(occ));
|
||||
}
|
@ -29,7 +29,6 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
#include "std/gbuffer.glsl"
|
||||
#include "std/imageatomic.glsl"
|
||||
#include "std/conetrace.glsl"
|
||||
#include "std/brdf.glsl"
|
||||
|
||||
uniform sampler2D gbufferD;
|
||||
uniform sampler2D gbuffer0;
|
||||
@ -39,7 +38,9 @@ uniform layout(rgba8) image2D voxels_specular;
|
||||
|
||||
uniform float clipmaps[voxelgiClipmapCount * 10];
|
||||
uniform mat4 InvVP;
|
||||
uniform vec2 cameraProj;
|
||||
uniform vec3 eye;
|
||||
uniform vec3 eyeLook;
|
||||
uniform vec2 postprocess_resolution;
|
||||
uniform sampler2D sveloc;
|
||||
|
||||
@ -55,10 +56,12 @@ void main() {
|
||||
|
||||
float x = uv.x * 2 - 1;
|
||||
float y = uv.y * 2 - 1;
|
||||
vec4 clipPos = vec4(x, y, depth, 1.0);
|
||||
vec4 worldPos = InvVP * clipPos;
|
||||
vec3 P = worldPos.xyz / worldPos.w;
|
||||
vec4 v = vec4(x, y, 1.0, 1.0);
|
||||
v = vec4(InvVP * v);
|
||||
v.xyz /= v.w;
|
||||
|
||||
vec3 viewRay = v.xyz - eye;
|
||||
vec3 P = getPos(eye, eyeLook, normalize(viewRay), depth, cameraProj);
|
||||
vec4 g0 = textureLod(gbuffer0, uv, 0.0);
|
||||
|
||||
vec3 n;
|
||||
@ -68,7 +71,7 @@ void main() {
|
||||
|
||||
vec2 velocity = -textureLod(sveloc, uv, 0.0).rg;
|
||||
|
||||
vec3 color = traceSpecular(P, n, voxels, voxelsSDF, normalize(eye - P), g0.z * g0.z, clipmaps, pixel, velocity).rgb;
|
||||
vec3 color = traceSpecular(P, n, voxels, voxelsSDF, normalize(eye - P), g0.z, clipmaps, pixel, velocity).rgb;
|
||||
|
||||
imageStore(voxels_specular, ivec2(pixel), vec4(color, 1.0));
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ THE SOFTWARE.
|
||||
|
||||
#include "compiled.inc"
|
||||
|
||||
uniform layout(r8) image3D input_sdf;
|
||||
uniform layout(r8) image3D output_sdf;
|
||||
uniform layout(r16) image3D input_sdf;
|
||||
uniform layout(r16) image3D output_sdf;
|
||||
|
||||
uniform float jump_size;
|
||||
uniform int clipmapLevel;
|
||||
|
@ -46,15 +46,15 @@ uniform layout(r32ui) uimage3D voxels;
|
||||
uniform layout(r32ui) uimage3D voxelsLight;
|
||||
uniform layout(rgba8) image3D voxelsB;
|
||||
uniform layout(rgba8) image3D voxelsOut;
|
||||
uniform layout(r8) image3D SDF;
|
||||
uniform layout(r16) image3D SDF;
|
||||
#else
|
||||
#ifdef _VoxelAOvar
|
||||
#ifdef _VoxelShadow
|
||||
uniform layout(r8) image3D SDF;
|
||||
uniform layout(r16) image3D SDF;
|
||||
#endif
|
||||
uniform layout(r32ui) uimage3D voxels;
|
||||
uniform layout(r8) image3D voxelsB;
|
||||
uniform layout(r8) image3D voxelsOut;
|
||||
uniform layout(r16) image3D voxelsB;
|
||||
uniform layout(r16) image3D voxelsOut;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -74,8 +74,14 @@ void main() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
mat3 TBN = mat3(1.0);
|
||||
vec3 avgNormal = vec3(0.0);
|
||||
ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
|
||||
#ifdef _VoxelGI
|
||||
vec3 light = vec3(0.0);
|
||||
light.r = float(imageLoad(voxelsLight, src)) / 255;
|
||||
light.g = float(imageLoad(voxelsLight, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
|
||||
light.b = float(imageLoad(voxelsLight, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
|
||||
light /= 3;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++)
|
||||
{
|
||||
@ -85,7 +91,7 @@ void main() {
|
||||
float aniso_colors[6];
|
||||
#endif
|
||||
|
||||
ivec3 src = ivec3(gl_GlobalInvocationID.xyz);
|
||||
src = ivec3(gl_GlobalInvocationID.xyz);
|
||||
src.x += i * res;
|
||||
ivec3 dst = src;
|
||||
dst.y += clipmapLevel * res;
|
||||
@ -98,59 +104,44 @@ void main() {
|
||||
|
||||
if (i < 6) {
|
||||
#ifdef _VoxelGI
|
||||
int count = int(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 15)));
|
||||
if (count > 0) {
|
||||
vec4 basecol = vec4(0.0);
|
||||
basecol.r = float(imageLoad(voxels, src)) / 255;
|
||||
basecol.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
|
||||
basecol.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
|
||||
basecol.a = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 3))) / 255;
|
||||
basecol /= count;
|
||||
vec3 emission = vec3(0.0);
|
||||
emission.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 4))) / 255;
|
||||
emission.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 5))) / 255;
|
||||
emission.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 6))) / 255;
|
||||
emission /= count;
|
||||
vec3 N = vec3(0.0);
|
||||
N.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 7))) / 255;
|
||||
N.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 8))) / 255;
|
||||
N /= count;
|
||||
N = decode_oct(N.rg * 2.0 - 1.0);
|
||||
avgNormal += N;
|
||||
vec4 basecol = vec4(0.0);
|
||||
basecol.r = float(imageLoad(voxels, src)) / 255;
|
||||
basecol.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x))) / 255;
|
||||
basecol.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 2))) / 255;
|
||||
basecol.a = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 3))) / 255;
|
||||
basecol /= 4;
|
||||
vec3 emission = vec3(0.0);
|
||||
emission.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 4))) / 255;
|
||||
emission.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 5))) / 255;
|
||||
emission.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 6))) / 255;
|
||||
emission /= 3;
|
||||
vec3 N = vec3(0.0);
|
||||
N.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 7))) / 255;
|
||||
N.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 8))) / 255;
|
||||
N /= 2;
|
||||
vec3 wnormal = decode_oct(N.rg * 2 - 1);
|
||||
vec3 envl = vec3(0.0);
|
||||
envl.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 9))) / 255;
|
||||
envl.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 10))) / 255;
|
||||
envl.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255;
|
||||
envl /= 3;
|
||||
envl *= 100;
|
||||
|
||||
if (i == 5)
|
||||
TBN = makeTangentBasis(normalize(avgNormal));
|
||||
//clipmap to world
|
||||
vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
|
||||
wposition = wposition * 2.0 - 1.0;
|
||||
wposition *= float(clipmaps[int(clipmapLevel * 10)]);
|
||||
wposition *= voxelgiResolution.x;
|
||||
wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]);
|
||||
|
||||
vec3 envl = vec3(0.0);
|
||||
envl.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 9))) / 255;
|
||||
envl.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 10))) / 255;
|
||||
envl.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 11))) / 255;
|
||||
envl /= count;
|
||||
vec3 light = vec3(0.0);
|
||||
light.r = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 12))) / 255;
|
||||
light.g = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 13))) / 255;
|
||||
light.b = float(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x * 14))) / 255;
|
||||
light /= count;
|
||||
radiance = basecol;
|
||||
vec4 trace = traceDiffuse(wposition, wnormal, voxelsSampler, clipmaps);
|
||||
vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a);
|
||||
radiance.rgb *= light + indirect;
|
||||
radiance.rgb += emission.rgb;
|
||||
|
||||
//clipmap to world
|
||||
vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x;
|
||||
wposition = wposition * 2.0 - 1.0;
|
||||
wposition *= float(clipmaps[int(clipmapLevel * 10)]);
|
||||
wposition *= voxelgiResolution.x;
|
||||
wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]);
|
||||
|
||||
radiance = basecol;
|
||||
vec4 trace = traceDiffuse(wposition, N, voxelsSampler, clipmaps);
|
||||
vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a);
|
||||
radiance.rgb *= light + indirect;
|
||||
radiance.rgb += emission.rgb;
|
||||
}
|
||||
#else
|
||||
int count = int(imageLoad(voxels, src + ivec3(0, 0, voxelgiResolution.x)));
|
||||
if (count > 0) {
|
||||
opac = float(imageLoad(voxels, src)) / 255;
|
||||
opac /= count;
|
||||
}
|
||||
opac = float(imageLoad(voxels, src)) / 255;
|
||||
#endif
|
||||
|
||||
#ifdef _VoxelGI
|
||||
@ -204,7 +195,7 @@ void main() {
|
||||
}
|
||||
else {
|
||||
// precompute cone sampling:
|
||||
vec3 coneDirection = TBN * DIFFUSE_CONE_DIRECTIONS[i - 6];
|
||||
vec3 coneDirection = DIFFUSE_CONE_DIRECTIONS[i - 6];
|
||||
vec3 aniso_direction = -coneDirection;
|
||||
uvec3 face_offsets = uvec3(
|
||||
aniso_direction.x > 0 ? 0 : 1,
|
||||
|
@ -75,17 +75,16 @@ vec4 binarySearch(vec3 dir) {
|
||||
}
|
||||
|
||||
vec4 rayCast(vec3 dir) {
|
||||
float ddepth;
|
||||
dir *= ss_refractionRayStep;
|
||||
for (int i = 0; i < maxSteps; i++) {
|
||||
hitCoord += dir;
|
||||
ddepth = getDeltaDepth(hitCoord);
|
||||
if (ddepth > 0.0)
|
||||
return binarySearch(dir);
|
||||
}
|
||||
// No hit — fallback to projecting the ray to UV space
|
||||
vec2 fallbackUV = getProjectedCoord(hitCoord);
|
||||
return vec4(fallbackUV, 0.0, 0.5); // We set .w lower to indicate fallback
|
||||
#ifdef _CPostprocess
|
||||
dir *= PPComp9.x;
|
||||
#else
|
||||
dir *= ssrRayStep;
|
||||
#endif
|
||||
for (int i = 0; i < maxSteps; i++) {
|
||||
hitCoord += dir;
|
||||
if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir);
|
||||
}
|
||||
return vec4(0.0);
|
||||
}
|
||||
#endif //SSR
|
||||
|
||||
|
@ -54,6 +54,22 @@ class App {
|
||||
if (Scene.active == null || !Scene.active.ready) return;
|
||||
|
||||
iron.system.Time.update();
|
||||
|
||||
if (lastw == -1) {
|
||||
lastw = App.w();
|
||||
lasth = App.h();
|
||||
}
|
||||
if (lastw != App.w() || lasth != App.h()) {
|
||||
if (onResize != null) onResize();
|
||||
else {
|
||||
if (Scene.active != null && Scene.active.camera != null) {
|
||||
Scene.active.camera.buildProjection();
|
||||
}
|
||||
}
|
||||
}
|
||||
lastw = App.w();
|
||||
lasth = App.h();
|
||||
|
||||
if (pauseUpdates) return;
|
||||
|
||||
#if lnx_debug
|
||||
@ -98,22 +114,6 @@ class App {
|
||||
for (cb in endFrameCallbacks) cb();
|
||||
updateTime = kha.Scheduler.realTime() - startTime;
|
||||
#end
|
||||
|
||||
// Rebuild projection on window resize
|
||||
if (lastw == -1) {
|
||||
lastw = App.w();
|
||||
lasth = App.h();
|
||||
}
|
||||
if (lastw != App.w() || lasth != App.h()) {
|
||||
if (onResize != null) onResize();
|
||||
else {
|
||||
if (Scene.active != null && Scene.active.camera != null) {
|
||||
Scene.active.camera.buildProjection();
|
||||
}
|
||||
}
|
||||
}
|
||||
lastw = App.w();
|
||||
lasth = App.h();
|
||||
}
|
||||
|
||||
static function render(frames: Array<kha.Framebuffer>) {
|
||||
|
@ -518,12 +518,44 @@ class RenderPath {
|
||||
return Reflect.field(kha.Shaders, handle + "_comp");
|
||||
}
|
||||
|
||||
#if (kha_krom && lnx_vr)
|
||||
public function drawStereo(drawMeshes: Int->Void) {
|
||||
for (eye in 0...2) {
|
||||
Krom.vrBeginRender(eye);
|
||||
drawMeshes(eye);
|
||||
Krom.vrEndRender(eye);
|
||||
#if lnx_vr
|
||||
public function drawStereo(drawMeshes: Void->Void) {
|
||||
var vr = kha.vr.VrInterface.instance;
|
||||
var appw = iron.App.w();
|
||||
var apph = iron.App.h();
|
||||
var halfw = Std.int(appw / 2);
|
||||
var g = currentG;
|
||||
|
||||
if (vr != null && vr.IsPresenting()) {
|
||||
// Left eye
|
||||
Scene.active.camera.V.setFrom(Scene.active.camera.leftV);
|
||||
Scene.active.camera.P.self = vr.GetProjectionMatrix(0);
|
||||
g.viewport(0, 0, halfw, apph);
|
||||
drawMeshes();
|
||||
|
||||
// Right eye
|
||||
begin(g, additionalTargets);
|
||||
Scene.active.camera.V.setFrom(Scene.active.camera.rightV);
|
||||
Scene.active.camera.P.self = vr.GetProjectionMatrix(1);
|
||||
g.viewport(halfw, 0, halfw, apph);
|
||||
drawMeshes();
|
||||
}
|
||||
else { // Simulate
|
||||
Scene.active.camera.buildProjection(halfw / apph);
|
||||
|
||||
// Left eye
|
||||
g.viewport(0, 0, halfw, apph);
|
||||
drawMeshes();
|
||||
|
||||
// Right eye
|
||||
begin(g, additionalTargets);
|
||||
Scene.active.camera.transform.move(Scene.active.camera.right(), 0.032);
|
||||
Scene.active.camera.buildMatrix();
|
||||
g.viewport(halfw, 0, halfw, apph);
|
||||
drawMeshes();
|
||||
|
||||
Scene.active.camera.transform.move(Scene.active.camera.right(), -0.032);
|
||||
Scene.active.camera.buildMatrix();
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
@ -783,6 +783,11 @@ class Scene {
|
||||
if (o.tilesheet_ref != null) {
|
||||
cast(object, MeshObject).setupTilesheet(sceneName, o.tilesheet_ref, o.tilesheet_action_ref);
|
||||
}
|
||||
|
||||
if (o.camera_list != null){
|
||||
cast(object, MeshObject).cameraList = o.camera_list;
|
||||
}
|
||||
|
||||
returnObject(object, o, done);
|
||||
});
|
||||
}
|
||||
@ -882,8 +887,12 @@ class Scene {
|
||||
var ptype: String = t.props[i * 3 + 1];
|
||||
var pval: Dynamic = t.props[i * 3 + 2];
|
||||
|
||||
if (StringTools.endsWith(ptype, "Object") && pval != "") {
|
||||
if (StringTools.endsWith(ptype, "Object") && pval != "" && pval != null) {
|
||||
Reflect.setProperty(traitInst, pname, Scene.active.getChild(pval));
|
||||
} else if (ptype == "TSceneFormat" && pval != "") {
|
||||
Data.getSceneRaw(pval, function (r: TSceneFormat) {
|
||||
Reflect.setProperty(traitInst, pname, r);
|
||||
});
|
||||
}
|
||||
else {
|
||||
switch (ptype) {
|
||||
|
@ -441,6 +441,7 @@ typedef TObj = {
|
||||
@:optional public var traits: Array<TTrait>;
|
||||
@:optional public var properties: Array<TProperty>;
|
||||
@:optional public var vertex_groups: Array<TVertex_groups>;
|
||||
@:optional public var camera_list: Array<String>;
|
||||
@:optional public var constraints: Array<TConstraint>;
|
||||
@:optional public var dimensions: Float32Array; // Geometry objects
|
||||
@:optional public var object_actions: Array<String>;
|
||||
|
@ -30,12 +30,22 @@ class CameraObject extends Object {
|
||||
static var sphereCenter = new Vec4();
|
||||
static var vcenter = new Vec4();
|
||||
static var vup = new Vec4();
|
||||
|
||||
|
||||
#if lnx_vr
|
||||
var helpMat = Mat4.identity();
|
||||
public var leftV = Mat4.identity();
|
||||
public var rightV = Mat4.identity();
|
||||
#end
|
||||
|
||||
public function new(data: CameraData) {
|
||||
super();
|
||||
|
||||
this.data = data;
|
||||
|
||||
#if lnx_vr
|
||||
iron.system.VR.initButton();
|
||||
#end
|
||||
|
||||
buildProjection();
|
||||
|
||||
V = Mat4.identity();
|
||||
@ -117,6 +127,26 @@ class CameraObject extends Object {
|
||||
V.getInverse(transform.world);
|
||||
VP.multmats(P, V);
|
||||
|
||||
|
||||
#if lnx_vr
|
||||
var vr = kha.vr.VrInterface.instance;
|
||||
if (vr != null && vr.IsPresenting()) {
|
||||
leftV.setFrom(V);
|
||||
helpMat.self = vr.GetViewMatrix(0);
|
||||
leftV.multmat(helpMat);
|
||||
|
||||
rightV.setFrom(V);
|
||||
helpMat.self = vr.GetViewMatrix(1);
|
||||
rightV.multmat(helpMat);
|
||||
}
|
||||
else {
|
||||
leftV.setFrom(V);
|
||||
}
|
||||
VP.multmats(P, leftV);
|
||||
#else
|
||||
VP.multmats(P, V);
|
||||
#end
|
||||
|
||||
if (data.raw.frustum_culling) {
|
||||
buildViewFrustum(VP, frustumPlanes);
|
||||
}
|
||||
|
@ -155,8 +155,13 @@ class LightObject extends Object {
|
||||
}
|
||||
|
||||
public function setCascade(camera: CameraObject, cascade: Int) {
|
||||
m.setFrom(camera.V);
|
||||
|
||||
#if lnx_vr
|
||||
m.setFrom(camera.leftV);
|
||||
#else
|
||||
m.setFrom(camera.V);
|
||||
#end
|
||||
|
||||
#if lnx_csm
|
||||
if (camSlicedP == null) {
|
||||
camSlicedP = [];
|
||||
|
@ -24,6 +24,7 @@ class MeshObject extends Object {
|
||||
public var render_emitter = true;
|
||||
#end
|
||||
public var cameraDistance: Float;
|
||||
public var cameraList: Array<String> = null;
|
||||
public var screenSize = 0.0;
|
||||
public var frustumCulling = true;
|
||||
public var activeTilesheet: Tilesheet = null;
|
||||
@ -235,6 +236,8 @@ class MeshObject extends Object {
|
||||
if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return;
|
||||
var meshContext = raw != null ? context == "mesh" : false;
|
||||
|
||||
if (cameraList != null && cameraList.indexOf(Scene.active.camera.name) < 0) return;
|
||||
|
||||
#if lnx_particles
|
||||
if (raw != null && raw.is_particle && particleOwner == null) return; // Instancing not yet set-up by particle system owner
|
||||
if (particleSystems != null && meshContext) {
|
||||
@ -245,6 +248,7 @@ class MeshObject extends Object {
|
||||
Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
|
||||
if (o != null) {
|
||||
var c: MeshObject = cast o;
|
||||
c.cameraList = this.cameraList;
|
||||
particleChildren.push(c);
|
||||
c.particleOwner = this;
|
||||
c.particleIndex = particleChildren.length - 1;
|
||||
|
@ -181,15 +181,11 @@ class Uniforms {
|
||||
// Multiple voxel volumes, always set params
|
||||
g.setImageTexture(context.textureUnits[j], rt.image); // image2D/3D
|
||||
if (rt.raw.name.startsWith("voxels_")) {
|
||||
g.setTextureParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.LinearMipFilter);
|
||||
}
|
||||
else if (rt.raw.name.startsWith("voxelsSDF"))
|
||||
{
|
||||
g.setTexture3DParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.PointFilter, TextureFilter.PointFilter, MipMapFilter.NoMipFilter);
|
||||
g.setTextureParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.NoMipFilter);
|
||||
}
|
||||
else if (rt.raw.name.startsWith("voxels"))
|
||||
{
|
||||
g.setTexture3DParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.PointMipFilter);
|
||||
g.setTexture3DParameters(context.textureUnits[j], TextureAddressing.Clamp, TextureAddressing.Clamp, TextureAddressing.Clamp, TextureFilter.LinearFilter, TextureFilter.LinearFilter, MipMapFilter.NoMipFilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -14,7 +14,7 @@ class Time {
|
||||
return 1 / frequency;
|
||||
}
|
||||
|
||||
static var _fixedStep: Null<Float>;
|
||||
static var _fixedStep: Null<Float> = 1/60;
|
||||
public static var fixedStep(get, never): Float;
|
||||
static function get_fixedStep(): Float {
|
||||
return _fixedStep;
|
||||
|
52
leenkx/Sources/iron/system/VR.hx
Normal file
52
leenkx/Sources/iron/system/VR.hx
Normal file
@ -0,0 +1,52 @@
|
||||
package iron.system;
|
||||
|
||||
import iron.math.Mat4;
|
||||
|
||||
#if lnx_vr
|
||||
class VR {
|
||||
|
||||
static var undistortionMatrix: Mat4 = null;
|
||||
|
||||
public function new() {}
|
||||
|
||||
public static function getUndistortionMatrix(): Mat4 {
|
||||
if (undistortionMatrix == null) {
|
||||
undistortionMatrix = Mat4.identity();
|
||||
}
|
||||
|
||||
return undistortionMatrix;
|
||||
}
|
||||
|
||||
public static function getMaxRadiusSq(): Float {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
public static function initButton() {
|
||||
function vrDownListener(index: Int, x: Float, y: Float) {
|
||||
var vr = kha.vr.VrInterface.instance;
|
||||
if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return;
|
||||
var w: Float = iron.App.w();
|
||||
var h: Float = iron.App.h();
|
||||
if (x < w - 150 || y < h - 150) return;
|
||||
vr.onVRRequestPresent();
|
||||
}
|
||||
|
||||
function vrRender2D(g: kha.graphics2.Graphics) {
|
||||
var vr = kha.vr.VrInterface.instance;
|
||||
if (vr == null || !vr.IsVrEnabled() || vr.IsPresenting()) return;
|
||||
var w: Float = iron.App.w();
|
||||
var h: Float = iron.App.h();
|
||||
g.color = 0xffff0000;
|
||||
g.fillRect(w - 150, h - 150, 140, 140);
|
||||
}
|
||||
|
||||
kha.input.Mouse.get().notify(vrDownListener, null, null, null);
|
||||
iron.App.notifyOnRender2D(vrRender2D);
|
||||
|
||||
var vr = kha.vr.VrInterface.instance; // Straight to VR (Oculus Carmel)
|
||||
if (vr != null && vr.IsVrEnabled()) {
|
||||
vr.onVRRequestPresent();
|
||||
}
|
||||
}
|
||||
}
|
||||
#end
|
@ -62,7 +62,7 @@ class DrawStringNode extends LogicNode {
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
|
||||
return from == 1 ? RenderToTexture.g.font.height(RenderToTexture.g.fontSize) : RenderToTexture.g.font.width(RenderToTexture.g.fontSize, string);
|
||||
|
||||
return from == 1 ? RenderToTexture.g.font.width(RenderToTexture.g.fontSize, string) : RenderToTexture.g.font.height(RenderToTexture.g.fontSize);
|
||||
|
||||
}
|
||||
}
|
||||
|
17
leenkx/Sources/leenkx/logicnode/GetAudioPositionNode.hx
Normal file
17
leenkx/Sources/leenkx/logicnode/GetAudioPositionNode.hx
Normal file
@ -0,0 +1,17 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import aura.Aura;
|
||||
import aura.Types;
|
||||
|
||||
class GetAudioPositionNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var audio = inputs[0].get();
|
||||
if (audio == null || audio.channel == null) return 0.0;
|
||||
return audio.channel.floatPosition / audio.channel.sampleRate;
|
||||
}
|
||||
}
|
19
leenkx/Sources/leenkx/logicnode/GetCameraRenderFilterNode.hx
Normal file
19
leenkx/Sources/leenkx/logicnode/GetCameraRenderFilterNode.hx
Normal file
@ -0,0 +1,19 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.MeshObject;
|
||||
import iron.object.CameraObject;
|
||||
|
||||
class GetCameraRenderFilterNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var mo: MeshObject = cast inputs[0].get();
|
||||
|
||||
if (mo == null) return null;
|
||||
|
||||
return mo.cameraList;
|
||||
}
|
||||
}
|
33
leenkx/Sources/leenkx/logicnode/GetPositionSpeakerNode.hx
Normal file
33
leenkx/Sources/leenkx/logicnode/GetPositionSpeakerNode.hx
Normal file
@ -0,0 +1,33 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
#if lnx_audio
|
||||
import iron.object.SpeakerObject;
|
||||
import kha.audio1.AudioChannel;
|
||||
#end
|
||||
|
||||
class GetPositionSpeakerNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
#if lnx_audio
|
||||
var object: SpeakerObject = cast(inputs[0].get(), SpeakerObject);
|
||||
if (object == null || object.sound == null) return 0.0;
|
||||
|
||||
if (object.channels.length == 0) return 0.0;
|
||||
|
||||
var channel = object.channels[0];
|
||||
|
||||
var position = 0.0;
|
||||
if (channel != null) {
|
||||
position = @:privateAccess channel.get_position();
|
||||
}
|
||||
|
||||
return position;
|
||||
#else
|
||||
return 0.0;
|
||||
#end
|
||||
}
|
||||
}
|
@ -1,26 +1,12 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
import iron.math.Vec4;
|
||||
|
||||
class GetWorldNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: Object = inputs[0].get();
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
return switch (property0) {
|
||||
case "Right": object.transform.world.right();
|
||||
case "Look": object.transform.world.look();
|
||||
case "Up": object.transform.world.up();
|
||||
default: null;
|
||||
}
|
||||
return iron.Scene.active.raw.world_ref;
|
||||
}
|
||||
}
|
||||
}
|
26
leenkx/Sources/leenkx/logicnode/GetWorldOrientationNode.hx
Normal file
26
leenkx/Sources/leenkx/logicnode/GetWorldOrientationNode.hx
Normal file
@ -0,0 +1,26 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
import iron.math.Vec4;
|
||||
|
||||
class GetWorldOrientationNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
var object: Object = inputs[0].get();
|
||||
|
||||
if (object == null) return null;
|
||||
|
||||
return switch (property0) {
|
||||
case "Right": object.transform.world.right();
|
||||
case "Look": object.transform.world.look();
|
||||
case "Up": object.transform.world.up();
|
||||
default: null;
|
||||
}
|
||||
}
|
||||
}
|
233
leenkx/Sources/leenkx/logicnode/MouseLookNode.hx
Normal file
233
leenkx/Sources/leenkx/logicnode/MouseLookNode.hx
Normal file
@ -0,0 +1,233 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.system.Input;
|
||||
import iron.object.Object;
|
||||
import kha.System;
|
||||
import kha.FastFloat;
|
||||
|
||||
/**
|
||||
* MouseLookNode - FPS-style mouse look camera controller
|
||||
*
|
||||
* This node provides smooth, resolution-independent mouse look functionality for
|
||||
* first-person perspective controls. It supports separate body and head objects,
|
||||
* allowing for realistic FPS camera movement where the body rotates horizontally
|
||||
* and the head/camera rotates vertically.
|
||||
*
|
||||
* Key Features:
|
||||
* - Resolution-adaptive scaling for consistent feel across different screen sizes
|
||||
* - Configurable axis orientations (X, Y, Z as front)
|
||||
* - Optional mouse cursor locking and hiding
|
||||
* - Invertible X/Y axes
|
||||
* - Rotation capping/limiting for both horizontal and vertical movement
|
||||
* - Smoothing support for smoother camera movement
|
||||
* - Physics integration with automatic rigid body synchronization
|
||||
* - Support for both local and world space head rotation
|
||||
*/
|
||||
class MouseLookNode extends LogicNode {
|
||||
// Configuration properties (set from Blender node interface)
|
||||
public var property0: String; // Front axis: "X", "Y", or "Z"
|
||||
public var property1: Bool; // Hide Locked: auto-lock mouse cursor
|
||||
public var property2: Bool; // Invert X: invert horizontal mouse movement
|
||||
public var property3: Bool; // Invert Y: invert vertical mouse movement
|
||||
public var property4: Bool; // Cap Left/Right: limit horizontal rotation
|
||||
public var property5: Bool; // Cap Up/Down: limit vertical rotation
|
||||
public var property6: Bool; // Head Local Space: use local space for head rotation
|
||||
|
||||
// Smoothing state variables - maintain previous frame values for interpolation
|
||||
var smoothX: Float = 0.0; // Smoothed horizontal mouse delta
|
||||
var smoothY: Float = 0.0; // Smoothed vertical mouse delta
|
||||
|
||||
// Rotation limits (in radians)
|
||||
var maxHorizontal: Float = Math.PI; // Maximum horizontal rotation (180 degrees)
|
||||
var maxVertical: Float = Math.PI / 2; // Maximum vertical rotation (90 degrees)
|
||||
|
||||
// Current rotation tracking for capping calculations
|
||||
var currentHorizontal: Float = 0.0; // Accumulated horizontal rotation
|
||||
var currentVertical: Float = 0.0; // Accumulated vertical rotation
|
||||
|
||||
// Resolution scaling reference - base resolution for consistent sensitivity
|
||||
var baseResolutionWidth: Float = 1920.0;
|
||||
|
||||
// Sensitivity scaling constants
|
||||
static inline var BASE_SCALE: Float = 1500.0; // Base sensitivity scale factor
|
||||
static var RADIAN_SCALING_FACTOR: Float = Math.PI * 50.0 / 180.0; // Degrees to radians conversion with sensitivity scaling
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main execution function called every frame when the node is active
|
||||
*
|
||||
* Input connections:
|
||||
* [0] - Action trigger (not used in current implementation)
|
||||
* [1] - Body Object: the main object that rotates horizontally
|
||||
* [2] - Head Object: optional object that rotates vertically (typically camera)
|
||||
* [3] - Sensitivity: mouse sensitivity multiplier
|
||||
* [4] - Smoothing: movement smoothing factor (0.0 = no smoothing, 0.99 = maximum smoothing)
|
||||
*/
|
||||
override function run(from: Int) {
|
||||
// Get input values from connected nodes
|
||||
var bodyObject: Object = inputs[1].get();
|
||||
var headObject: Object = inputs[2].get();
|
||||
var sensitivity: FastFloat = inputs[3].get();
|
||||
var smoothing: FastFloat = inputs[4].get();
|
||||
|
||||
// Early exit if no body object is provided
|
||||
if (bodyObject == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get mouse input state
|
||||
var mouse = Input.getMouse();
|
||||
|
||||
// Handle automatic mouse cursor locking for FPS controls
|
||||
if (property1) {
|
||||
if (mouse.started() && !mouse.locked) {
|
||||
mouse.lock(); // Center and hide cursor, enable unlimited movement
|
||||
}
|
||||
}
|
||||
|
||||
// Only process mouse look when cursor is locked or mouse button is held
|
||||
// This prevents unwanted camera movement when UI elements are being used
|
||||
if (!mouse.locked && !mouse.down()) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get raw mouse movement delta (pixels moved since last frame)
|
||||
var deltaX: Float = mouse.movementX;
|
||||
var deltaY: Float = mouse.movementY;
|
||||
|
||||
// Apply axis inversion if configured
|
||||
if (property2) deltaX = -deltaX; // Invert horizontal movement
|
||||
if (property3) deltaY = -deltaY; // Invert vertical movement
|
||||
|
||||
// Calculate resolution-adaptive scaling to maintain consistent sensitivity
|
||||
// across different screen resolutions. Higher resolutions will have proportionally
|
||||
// higher scaling to compensate for increased pixel density.
|
||||
var resolutionMultiplier: Float = System.windowWidth() / baseResolutionWidth;
|
||||
|
||||
// Apply movement smoothing if enabled
|
||||
// This creates a weighted average between current and previous movement values
|
||||
// to reduce jittery camera movement, especially useful for low framerates
|
||||
if (smoothing > 0.0) {
|
||||
var smoothingFactor: Float = Math.min(smoothing, 0.99); // Cap smoothing to prevent complete freeze
|
||||
smoothX = smoothX * smoothingFactor + deltaX * (1.0 - smoothingFactor);
|
||||
smoothY = smoothY * smoothingFactor + deltaY * (1.0 - smoothingFactor);
|
||||
deltaX = smoothX;
|
||||
deltaY = smoothY;
|
||||
}
|
||||
|
||||
// Define rotation axes based on the configured front axis
|
||||
// These determine which 3D axes are used for horizontal and vertical rotation
|
||||
var horizontalAxis = new Vec4(); // Axis for left/right body rotation
|
||||
var verticalAxis = new Vec4(); // Axis for up/down head rotation
|
||||
|
||||
switch (property0) {
|
||||
case "X": // X-axis forward (e.g., for side-scrolling or specific orientations)
|
||||
horizontalAxis.set(0, 0, 1); // Z-axis for horizontal rotation
|
||||
verticalAxis.set(0, 1, 0); // Y-axis for vertical rotation
|
||||
case "Y": // Y-axis forward (most common for 3D games)
|
||||
#if lnx_yaxisup
|
||||
// Y-up coordinate system (Blender default)
|
||||
horizontalAxis.set(0, 0, 1); // Z-axis for horizontal rotation
|
||||
verticalAxis.set(1, 0, 0); // X-axis for vertical rotation
|
||||
#else
|
||||
// Z-up coordinate system
|
||||
horizontalAxis.set(0, 0, 1); // Z-axis for horizontal rotation
|
||||
verticalAxis.set(1, 0, 0); // X-axis for vertical rotation
|
||||
#end
|
||||
case "Z": // Z-axis forward (top-down or specific orientations)
|
||||
horizontalAxis.set(0, 1, 0); // Y-axis for horizontal rotation
|
||||
verticalAxis.set(1, 0, 0); // X-axis for vertical rotation
|
||||
}
|
||||
|
||||
// Calculate final sensitivity scaling combining base scale and resolution adaptation
|
||||
var finalScale: Float = BASE_SCALE * resolutionMultiplier;
|
||||
|
||||
// Apply user-defined sensitivity multiplier
|
||||
deltaX *= sensitivity;
|
||||
deltaY *= sensitivity;
|
||||
|
||||
// Convert pixel movement to rotation angles (radians)
|
||||
// Negative values ensure natural movement direction (moving mouse right rotates right)
|
||||
var horizontalRotation: Float = (-deltaX / finalScale) * RADIAN_SCALING_FACTOR;
|
||||
var verticalRotation: Float = (-deltaY / finalScale) * RADIAN_SCALING_FACTOR;
|
||||
|
||||
// Apply horizontal rotation capping if enabled
|
||||
// This prevents the character from rotating beyond specified limits
|
||||
if (property4) {
|
||||
currentHorizontal += horizontalRotation;
|
||||
// Clamp rotation to maximum horizontal range and adjust current frame rotation
|
||||
if (currentHorizontal > maxHorizontal) {
|
||||
horizontalRotation -= (currentHorizontal - maxHorizontal);
|
||||
currentHorizontal = maxHorizontal;
|
||||
} else if (currentHorizontal < -maxHorizontal) {
|
||||
horizontalRotation -= (currentHorizontal + maxHorizontal);
|
||||
currentHorizontal = -maxHorizontal;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply vertical rotation capping if enabled
|
||||
// This prevents looking too far up or down (like human neck limitations)
|
||||
if (property5) {
|
||||
currentVertical += verticalRotation;
|
||||
// Clamp rotation to maximum vertical range and adjust current frame rotation
|
||||
if (currentVertical > maxVertical) {
|
||||
verticalRotation -= (currentVertical - maxVertical);
|
||||
currentVertical = maxVertical;
|
||||
} else if (currentVertical < -maxVertical) {
|
||||
verticalRotation -= (currentVertical + maxVertical);
|
||||
currentVertical = -maxVertical;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply horizontal rotation to body object (character turning left/right)
|
||||
if (horizontalRotation != 0.0) {
|
||||
bodyObject.transform.rotate(horizontalAxis, horizontalRotation);
|
||||
|
||||
// Synchronize physics rigid body if present
|
||||
// This ensures physics simulation stays in sync with visual transform
|
||||
#if lnx_physics
|
||||
var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody);
|
||||
if (rigidBody != null) rigidBody.syncTransform();
|
||||
#end
|
||||
}
|
||||
|
||||
// Apply vertical rotation to head object (camera looking up/down)
|
||||
if (headObject != null && verticalRotation != 0.0) {
|
||||
if (property6) {
|
||||
// Local space rotation - recommended when head is a child of body
|
||||
// This prevents gimbal lock and rotation inheritance issues
|
||||
headObject.transform.rotate(verticalAxis, verticalRotation);
|
||||
} else {
|
||||
// World space rotation - uses head object's current right vector
|
||||
// More accurate for independent head objects but can cause issues with parenting
|
||||
var headVerticalAxis = headObject.transform.world.right();
|
||||
headObject.transform.rotate(headVerticalAxis, verticalRotation);
|
||||
}
|
||||
|
||||
// Synchronize head physics rigid body if present
|
||||
#if lnx_physics
|
||||
var headRigidBody = headObject.getTrait(leenkx.trait.physics.RigidBody);
|
||||
if (headRigidBody != null) headRigidBody.syncTransform();
|
||||
#end
|
||||
} else if (headObject == null && verticalRotation != 0.0) {
|
||||
// Fallback: if no separate head object, apply vertical rotation to body
|
||||
// This creates a simpler single-object camera control
|
||||
bodyObject.transform.rotate(verticalAxis, verticalRotation);
|
||||
|
||||
// Synchronize body physics rigid body
|
||||
#if lnx_physics
|
||||
var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody);
|
||||
if (rigidBody != null) rigidBody.syncTransform();
|
||||
#end
|
||||
}
|
||||
|
||||
// Continue to next connected node in the logic tree
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
23
leenkx/Sources/leenkx/logicnode/OnceNode.hx
Normal file
23
leenkx/Sources/leenkx/logicnode/OnceNode.hx
Normal file
@ -0,0 +1,23 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class OnceNode extends LogicNode {
|
||||
|
||||
var triggered:Bool = false;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
if(from == 1){
|
||||
triggered = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!triggered) {
|
||||
triggered = true;
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -9,19 +9,38 @@ import iron.Scene;
|
||||
|
||||
class PlayAnimationTreeNode extends LogicNode {
|
||||
|
||||
var object: Object;
|
||||
var action: Dynamic;
|
||||
var init: Bool = false;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var object: Object = inputs[1].get();
|
||||
var action: Dynamic = inputs[2].get();
|
||||
|
||||
object = inputs[1].get();
|
||||
action = inputs[2].get();
|
||||
assert(Error, object != null, "The object input not be null");
|
||||
init = true;
|
||||
tree.notifyOnUpdate(playAnim);
|
||||
// TO DO: Investigate AnimAction get and PlayAnimationTree notifiers
|
||||
}
|
||||
|
||||
function playAnim() {
|
||||
if (init = false) return;
|
||||
|
||||
init = false;
|
||||
tree.removeUpdate(playAnim);
|
||||
|
||||
var animation = object.animation;
|
||||
if(animation == null) {
|
||||
#if lnx_skin
|
||||
animation = object.getBoneAnimation(object.uid);
|
||||
if (animation == null) {
|
||||
tree.notifyOnUpdate(playAnim);
|
||||
init = true;
|
||||
return;
|
||||
}
|
||||
cast(animation, BoneAnimation).setAnimationLoop(function f(mats) {
|
||||
action(mats);
|
||||
});
|
||||
@ -32,7 +51,6 @@ class PlayAnimationTreeNode extends LogicNode {
|
||||
action(mats);
|
||||
});
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
||||
|
16
leenkx/Sources/leenkx/logicnode/ResolutionGetNode.hx
Normal file
16
leenkx/Sources/leenkx/logicnode/ResolutionGetNode.hx
Normal file
@ -0,0 +1,16 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class ResolutionGetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function get(from:Int):Dynamic {
|
||||
return switch (from) {
|
||||
case 0: leenkx.renderpath.Postprocess.resolution_uniforms[0];
|
||||
case 1: leenkx.renderpath.Postprocess.resolution_uniforms[1];
|
||||
default: 0;
|
||||
}
|
||||
}
|
||||
}
|
33
leenkx/Sources/leenkx/logicnode/ResolutionSetNode.hx
Normal file
33
leenkx/Sources/leenkx/logicnode/ResolutionSetNode.hx
Normal file
@ -0,0 +1,33 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import kha.graphics4.TextureFilter;
|
||||
|
||||
class ResolutionSetNode extends LogicNode {
|
||||
|
||||
public function new(tree:LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from:Int) {
|
||||
|
||||
var size: Int = inputs[1].get();
|
||||
var filter: Int = inputs[2].get();
|
||||
|
||||
#if rp_resolution_filter
|
||||
if (filter == 0)
|
||||
iron.object.Uniforms.defaultFilter = TextureFilter.LinearFilter;
|
||||
else
|
||||
iron.object.Uniforms.defaultFilter = TextureFilter.PointFilter;
|
||||
|
||||
leenkx.renderpath.Postprocess.resolution_uniforms[0] = size;
|
||||
leenkx.renderpath.Postprocess.resolution_uniforms[1] = filter;
|
||||
|
||||
var npath = leenkx.renderpath.RenderPathCreator.get();
|
||||
var world = iron.Scene.active.raw.world_ref;
|
||||
npath.loadShader("shader_datas/World_" + world + "/World_" + world);
|
||||
iron.RenderPath.setActive(npath);
|
||||
#end
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
23
leenkx/Sources/leenkx/logicnode/SetAudioPositionNode.hx
Normal file
23
leenkx/Sources/leenkx/logicnode/SetAudioPositionNode.hx
Normal file
@ -0,0 +1,23 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import aura.Aura;
|
||||
import aura.Types;
|
||||
|
||||
class SetAudioPositionNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var audio = inputs[1].get();
|
||||
if (audio == null) return;
|
||||
|
||||
var positionInSeconds:Float = inputs[2].get();
|
||||
if (positionInSeconds < 0.0) positionInSeconds = 0.0;
|
||||
|
||||
audio.channel.floatPosition = positionInSeconds * audio.channel.sampleRate;
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
38
leenkx/Sources/leenkx/logicnode/SetCameraRenderFilterNode.hx
Normal file
38
leenkx/Sources/leenkx/logicnode/SetCameraRenderFilterNode.hx
Normal file
@ -0,0 +1,38 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.MeshObject;
|
||||
import iron.object.CameraObject;
|
||||
|
||||
class SetCameraRenderFilterNode extends LogicNode {
|
||||
|
||||
public var property0: String;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var mo: MeshObject = cast inputs[1].get();
|
||||
var camera: CameraObject = inputs[2].get();
|
||||
|
||||
assert(Error, Std.isOfType(camera, CameraObject), "Camera must be a camera object!");
|
||||
|
||||
if (camera == null || mo == null) return;
|
||||
|
||||
if (property0 == 'Add'){
|
||||
if (mo.cameraList == null || mo.cameraList.indexOf(camera.name) == -1){
|
||||
if (mo.cameraList == null) mo.cameraList = [];
|
||||
mo.cameraList.push(camera.name);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (mo.cameraList != null){
|
||||
mo.cameraList.remove(camera.name);
|
||||
if (mo.cameraList.length == 0)
|
||||
mo.cameraList = null;
|
||||
}
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
21
leenkx/Sources/leenkx/logicnode/SetLightShadowNode.hx
Normal file
21
leenkx/Sources/leenkx/logicnode/SetLightShadowNode.hx
Normal file
@ -0,0 +1,21 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.LightObject;
|
||||
|
||||
class SetLightShadowNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var light: LightObject = inputs[1].get();
|
||||
var shadow: Bool = inputs[2].get();
|
||||
|
||||
if (light == null) return;
|
||||
|
||||
light.data.raw.cast_shadow = shadow;
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
206
leenkx/Sources/leenkx/logicnode/SetLookAtRotationNode.hx
Normal file
206
leenkx/Sources/leenkx/logicnode/SetLookAtRotationNode.hx
Normal file
@ -0,0 +1,206 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Mat4;
|
||||
import iron.object.Object;
|
||||
|
||||
class SetLookAtRotationNode extends LogicNode {
|
||||
|
||||
public var property0: String; // Axis to align
|
||||
public var property1: String; // Use vector for target (true/false)
|
||||
public var property2: String; // Use vector for source (true/false)
|
||||
public var property3: String; // Damping value (backward compatibility, now input socket)
|
||||
public var property4: String; // Disable rotation on aligning axis (true/false)
|
||||
public var property5: String; // Use local space (true/false)
|
||||
|
||||
// Store the calculated rotation for output
|
||||
var calculatedRotation: Quat = null;
|
||||
// Store the previous rotation for smooth interpolation
|
||||
var previousRotation: Quat = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
previousRotation = new Quat();
|
||||
}
|
||||
|
||||
override function run(from: Int): Void {
|
||||
// Determine if we're using a vector or an object as source
|
||||
var useSourceVector: Bool = property2 == "true";
|
||||
var objectToUse: Object = null;
|
||||
var objectLoc: Vec4 = null;
|
||||
|
||||
if (useSourceVector) {
|
||||
// Use tree.object as the object to rotate
|
||||
objectToUse = tree.object;
|
||||
if (objectToUse == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the source location directly
|
||||
objectLoc = inputs[1].get();
|
||||
if (objectLoc == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Get the source object (or fallback to tree.object)
|
||||
objectToUse = (inputs.length > 1 && inputs[1] != null) ? inputs[1].get() : tree.object;
|
||||
if (objectToUse == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get source object's WORLD position (important for child objects)
|
||||
objectLoc = new Vec4(objectToUse.transform.worldx(), objectToUse.transform.worldy(), objectToUse.transform.worldz());
|
||||
}
|
||||
|
||||
// Determine if we're using a vector or an object as target
|
||||
var useTargetVector: Bool = property1 == "true";
|
||||
var targetLoc: Vec4 = null;
|
||||
|
||||
if (useTargetVector) {
|
||||
// Get the target location directly
|
||||
targetLoc = inputs[2].get();
|
||||
if (targetLoc == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Get the target object
|
||||
var targetObject: Object = inputs[2].get();
|
||||
if (targetObject == null) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get target object's WORLD position (important for child objects)
|
||||
targetLoc = new Vec4(targetObject.transform.worldx(), targetObject.transform.worldy(), targetObject.transform.worldz());
|
||||
}
|
||||
|
||||
// Calculate direction to target
|
||||
var direction = new Vec4(
|
||||
targetLoc.x - objectLoc.x,
|
||||
targetLoc.y - objectLoc.y,
|
||||
targetLoc.z - objectLoc.z
|
||||
);
|
||||
direction.normalize();
|
||||
|
||||
// Calculate target rotation based on selected axis
|
||||
calculatedRotation = new Quat();
|
||||
switch (property0) {
|
||||
case "X":
|
||||
calculatedRotation.fromTo(new Vec4(1, 0, 0), direction);
|
||||
case "-X":
|
||||
calculatedRotation.fromTo(new Vec4(-1, 0, 0), direction);
|
||||
case "Y":
|
||||
calculatedRotation.fromTo(new Vec4(0, 1, 0), direction);
|
||||
case "-Y":
|
||||
calculatedRotation.fromTo(new Vec4(0, -1, 0), direction);
|
||||
case "Z":
|
||||
calculatedRotation.fromTo(new Vec4(0, 0, 1), direction);
|
||||
case "-Z":
|
||||
calculatedRotation.fromTo(new Vec4(0, 0, -1), direction);
|
||||
}
|
||||
|
||||
// If disable rotation on aligning axis is enabled, constrain the target rotation
|
||||
if (property4 == "true") {
|
||||
// Apply constraint to the target rotation BEFORE damping to avoid jiggling
|
||||
var eulerAngles = calculatedRotation.toEulerOrdered("XYZ");
|
||||
|
||||
// Set the rotation around the selected axis to 0
|
||||
switch (property0) {
|
||||
case "X", "-X":
|
||||
eulerAngles.x = 0.0;
|
||||
case "Y", "-Y":
|
||||
eulerAngles.y = 0.0;
|
||||
case "Z", "-Z":
|
||||
eulerAngles.z = 0.0;
|
||||
}
|
||||
|
||||
// Convert back to quaternion
|
||||
calculatedRotation.fromEulerOrdered(eulerAngles, "XYZ");
|
||||
}
|
||||
|
||||
// Convert world rotation to local rotation if local space is enabled and object has a parent
|
||||
var targetRotation = new Quat();
|
||||
if (property5 == "true" && objectToUse.parent != null) {
|
||||
// Get parent's world rotation
|
||||
var parentWorldLoc = new Vec4();
|
||||
var parentWorldRot = new Quat();
|
||||
var parentWorldScale = new Vec4();
|
||||
objectToUse.parent.transform.world.decompose(parentWorldLoc, parentWorldRot, parentWorldScale);
|
||||
|
||||
// Convert world rotation to local space by removing parent's rotation influence
|
||||
// local_rotation = inverse(parent_world_rotation) * world_rotation
|
||||
var invParentRot = new Quat().setFrom(parentWorldRot);
|
||||
invParentRot.x = -invParentRot.x;
|
||||
invParentRot.y = -invParentRot.y;
|
||||
invParentRot.z = -invParentRot.z;
|
||||
|
||||
targetRotation.multquats(invParentRot, calculatedRotation);
|
||||
} else {
|
||||
// No local space conversion needed, use world rotation directly
|
||||
targetRotation.setFrom(calculatedRotation);
|
||||
}
|
||||
|
||||
// Apply rotation with damping
|
||||
var dampingValue: Float = 0.0;
|
||||
|
||||
// Try to get damping from input socket first (index 3), fallback to property
|
||||
if (inputs.length > 3 && inputs[3] != null) {
|
||||
var dampingInput: Dynamic = inputs[3].get();
|
||||
if (dampingInput != null) {
|
||||
dampingValue = dampingInput;
|
||||
}
|
||||
} else {
|
||||
// Fallback to property for backward compatibility
|
||||
dampingValue = Std.parseFloat(property3);
|
||||
}
|
||||
|
||||
if (dampingValue > 0.0) {
|
||||
// Create a fixed interpolation rate that never reaches exactly 1.0
|
||||
// Higher damping = slower rotation (smaller step)
|
||||
var step = Math.max(0.001, (1.0 - dampingValue) * 0.2); // 0.001 to 0.2 range
|
||||
|
||||
// Get current local rotation as quaternion
|
||||
var currentLocalRot = new Quat().setFrom(objectToUse.transform.rot);
|
||||
|
||||
// Calculate the difference between current and target rotation
|
||||
var diffQuat = new Quat();
|
||||
// q1 * inverse(q2) gives the rotation from q2 to q1
|
||||
var invCurrent = new Quat().setFrom(currentLocalRot);
|
||||
invCurrent.x = -invCurrent.x;
|
||||
invCurrent.y = -invCurrent.y;
|
||||
invCurrent.z = -invCurrent.z;
|
||||
diffQuat.multquats(targetRotation, invCurrent);
|
||||
|
||||
// Convert to axis-angle representation
|
||||
var axis = new Vec4();
|
||||
var angle = diffQuat.toAxisAngle(axis);
|
||||
|
||||
// Apply only a portion of this rotation (step)
|
||||
var partialAngle = angle * step;
|
||||
|
||||
// Create partial rotation quaternion
|
||||
var partialRot = new Quat().fromAxisAngle(axis, partialAngle);
|
||||
|
||||
// Apply this partial rotation to current local rotation
|
||||
var newLocalRot = new Quat();
|
||||
newLocalRot.multquats(partialRot, currentLocalRot);
|
||||
|
||||
// Apply the new local rotation
|
||||
objectToUse.transform.rot.setFrom(newLocalRot);
|
||||
} else {
|
||||
// No damping, apply instant rotation
|
||||
objectToUse.transform.rot.setFrom(targetRotation);
|
||||
}
|
||||
|
||||
objectToUse.transform.buildMatrix();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
// No output sockets needed - this node only performs actions
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.MeshObject;
|
||||
import iron.data.MaterialData;
|
||||
|
||||
class SetMaterialTextureFilterNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var object: MeshObject = inputs[1].get();
|
||||
var mat: MaterialData = inputs[2].get();
|
||||
var slot: Int = inputs[3].get();
|
||||
var name: String = inputs[4].get();
|
||||
var filter: Int = inputs[5].get();
|
||||
|
||||
if (object == null) return;
|
||||
if (slot >= object.materials.length) return;
|
||||
|
||||
var mo = cast(object, iron.object.MeshObject);
|
||||
|
||||
for (i => node in mo.materials[slot].contexts[0].raw.bind_textures)
|
||||
if (node.name == name){
|
||||
var moImgt = mo.materials[slot].contexts[0].raw.bind_textures[i];
|
||||
switch(filter){
|
||||
case 0: //Linear
|
||||
moImgt.min_filter = null;
|
||||
moImgt.mag_filter = null;
|
||||
moImgt.mipmap_filter = null;
|
||||
moImgt.generate_mipmaps = null;
|
||||
case 1: //Closest
|
||||
moImgt.min_filter = 'point';
|
||||
moImgt.mag_filter = 'point';
|
||||
moImgt.mipmap_filter = null;
|
||||
moImgt.generate_mipmaps = null;
|
||||
case 2: //Cubic
|
||||
moImgt.min_filter = null;
|
||||
moImgt.mag_filter = null;
|
||||
moImgt.mipmap_filter = 'linear';
|
||||
moImgt.generate_mipmaps = true;
|
||||
case 3: //Smart
|
||||
moImgt.min_filter = 'anisotropic';
|
||||
moImgt.mag_filter = null;
|
||||
moImgt.mipmap_filter = 'linear';
|
||||
moImgt.generate_mipmaps = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
import iron.object.Object;
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Mat4;
|
||||
import iron.system.Time;
|
||||
|
||||
class SetObjectDelayedLocationNode extends LogicNode {
|
||||
public var use_local_space: Bool = false;
|
||||
|
||||
private var initialOffset: Vec4 = null;
|
||||
private var targetPos: Vec4 = new Vec4();
|
||||
private var currentPos: Vec4 = new Vec4();
|
||||
private var deltaVec: Vec4 = new Vec4();
|
||||
private var tempVec: Vec4 = new Vec4();
|
||||
|
||||
private var lastParent: Object = null;
|
||||
private var invParentMatrix: Mat4 = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var follower: Object = inputs[1].get();
|
||||
var target: Object = inputs[2].get();
|
||||
var delay: Float = inputs[3].get();
|
||||
|
||||
if (follower == null || target == null) return runOutput(0);
|
||||
|
||||
if (initialOffset == null) {
|
||||
initialOffset = new Vec4();
|
||||
var followerPos = follower.transform.world.getLoc();
|
||||
var targetPos = target.transform.world.getLoc();
|
||||
initialOffset.setFrom(followerPos);
|
||||
initialOffset.sub(targetPos);
|
||||
}
|
||||
|
||||
targetPos.setFrom(target.transform.world.getLoc());
|
||||
currentPos.setFrom(follower.transform.world.getLoc());
|
||||
|
||||
tempVec.setFrom(targetPos).add(initialOffset);
|
||||
|
||||
deltaVec.setFrom(tempVec).sub(currentPos);
|
||||
|
||||
if (deltaVec.length() < 0.001 && delay < 0.01) {
|
||||
runOutput(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (delay == 0.0) {
|
||||
currentPos.setFrom(tempVec);
|
||||
} else {
|
||||
var smoothFactor = Math.exp(-Time.delta / Math.max(0.0001, delay));
|
||||
currentPos.x = tempVec.x + (currentPos.x - tempVec.x) * smoothFactor;
|
||||
currentPos.y = tempVec.y + (currentPos.y - tempVec.y) * smoothFactor;
|
||||
currentPos.z = tempVec.z + (currentPos.z - tempVec.z) * smoothFactor;
|
||||
}
|
||||
if (use_local_space && follower.parent != null) {
|
||||
if (follower.parent != lastParent || invParentMatrix == null) {
|
||||
lastParent = follower.parent;
|
||||
invParentMatrix = Mat4.identity();
|
||||
invParentMatrix.getInverse(follower.parent.transform.world);
|
||||
}
|
||||
tempVec.setFrom(currentPos);
|
||||
tempVec.applymat(invParentMatrix);
|
||||
follower.transform.loc.set(tempVec.x, tempVec.y, tempVec.z);
|
||||
} else {
|
||||
follower.transform.loc.set(currentPos.x, currentPos.y, currentPos.z);
|
||||
}
|
||||
follower.transform.buildMatrix();
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
@ -55,9 +55,9 @@ class SetParticleDataNode extends LogicNode {
|
||||
@:privateAccess psys.aligny = vel.y;
|
||||
@:privateAccess psys.alignz = vel.z;
|
||||
case 'Velocity Random':
|
||||
psys.r.factor_random = inputs[3].get();
|
||||
@:privateAccess psys.r.factor_random = inputs[3].get();
|
||||
case 'Weight Gravity':
|
||||
psys.r.weight_gravity = inputs[3].get();
|
||||
@:privateAccess psys.r.weight_gravity = inputs[3].get();
|
||||
if (iron.Scene.active.raw.gravity != null) {
|
||||
@:privateAccess psys.gx = iron.Scene.active.raw.gravity[0] * @:privateAccess psys.r.weight_gravity;
|
||||
@:privateAccess psys.gy = iron.Scene.active.raw.gravity[1] * @:privateAccess psys.r.weight_gravity;
|
||||
|
39
leenkx/Sources/leenkx/logicnode/SetPositionSpeakerNode.hx
Normal file
39
leenkx/Sources/leenkx/logicnode/SetPositionSpeakerNode.hx
Normal file
@ -0,0 +1,39 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
#if lnx_audio
|
||||
import iron.object.SpeakerObject;
|
||||
import kha.audio1.AudioChannel;
|
||||
import iron.system.Audio;
|
||||
#end
|
||||
|
||||
class SetPositionSpeakerNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
#if lnx_audio
|
||||
var object: SpeakerObject = cast(inputs[1].get(), SpeakerObject);
|
||||
if (object == null || object.sound == null) return;
|
||||
|
||||
var positionInSeconds:Float = inputs[2].get();
|
||||
if (positionInSeconds < 0) positionInSeconds = 0;
|
||||
|
||||
var volume = object.data.volume;
|
||||
var loop = object.data.loop;
|
||||
var stream = object.data.stream;
|
||||
|
||||
object.stop();
|
||||
|
||||
var channel = Audio.play(object.sound, loop, stream);
|
||||
if (channel != null) {
|
||||
object.channels.push(channel);
|
||||
channel.volume = volume;
|
||||
@:privateAccess channel.set_position(positionInSeconds);
|
||||
}
|
||||
|
||||
#end
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
40
leenkx/Sources/leenkx/logicnode/SetWorldNode.hx
Normal file
40
leenkx/Sources/leenkx/logicnode/SetWorldNode.hx
Normal file
@ -0,0 +1,40 @@
|
||||
package leenkx.logicnode;
|
||||
|
||||
class SetWorldNode extends LogicNode {
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
var world: String = inputs[1].get();
|
||||
|
||||
if (world != null){
|
||||
|
||||
//check if world shader data exists
|
||||
var file: String = 'World_'+world+'_data';
|
||||
#if lnx_json
|
||||
file += ".json";
|
||||
#elseif lnx_compress
|
||||
file += ".lz4";
|
||||
#else
|
||||
file += '.lnx';
|
||||
#end
|
||||
|
||||
var exists: Bool = false;
|
||||
|
||||
iron.data.Data.getBlob(file, function(b: kha.Blob) {
|
||||
if (b != null) exists = true;
|
||||
});
|
||||
|
||||
assert(Error, exists == true, "World must be either associated to a scene or have fake user");
|
||||
|
||||
iron.Scene.active.raw.world_ref = world;
|
||||
var npath = leenkx.renderpath.RenderPathCreator.get();
|
||||
npath.loadShader("shader_datas/World_" + world + "/World_" + world);
|
||||
iron.RenderPath.setActive(npath);
|
||||
}
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
}
|
@ -34,10 +34,10 @@ class Inc {
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
static var voxel_td1:kha.compute.TextureUnit;
|
||||
static var voxel_te1:kha.compute.TextureUnit;
|
||||
static var voxel_cc1:kha.compute.ConstantLocation;
|
||||
static var voxel_tf1:kha.compute.TextureUnit;
|
||||
#else
|
||||
#if lnx_voxelgi_shadows
|
||||
static var voxel_te1:kha.compute.TextureUnit;
|
||||
static var voxel_tf1:kha.compute.TextureUnit;
|
||||
#end
|
||||
#end
|
||||
#if (lnx_voxelgi_shadows || rp_voxels == "Voxel GI")
|
||||
@ -53,28 +53,12 @@ class Inc {
|
||||
static var voxel_tb3:kha.compute.TextureUnit;
|
||||
static var voxel_tc3:kha.compute.TextureUnit;
|
||||
static var voxel_td3:kha.compute.TextureUnit;
|
||||
static var voxel_te3:kha.compute.TextureUnit;
|
||||
static var voxel_tf3:kha.compute.TextureUnit;
|
||||
#if lnx_brdf
|
||||
static var voxel_tg3:kha.compute.TextureUnit;
|
||||
#end
|
||||
#if lnx_radiance
|
||||
static var voxel_th3:kha.compute.TextureUnit;
|
||||
#end
|
||||
static var voxel_ca3:kha.compute.ConstantLocation;
|
||||
static var voxel_cb3:kha.compute.ConstantLocation;
|
||||
static var voxel_cc3:kha.compute.ConstantLocation;
|
||||
static var voxel_cd3:kha.compute.ConstantLocation;
|
||||
static var voxel_ce3:kha.compute.ConstantLocation;
|
||||
#if lnx_irradiance
|
||||
static var voxel_cf3:kha.compute.ConstantLocation;
|
||||
#end
|
||||
#if lnx_radiance
|
||||
static var voxel_cg3:kha.compute.ConstantLocation;
|
||||
#end
|
||||
#if lnx_envcol
|
||||
static var voxel_ch3:kha.compute.ConstantLocation;
|
||||
#end
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
static var voxel_sh4:kha.compute.Shader = null;
|
||||
static var voxel_ta4:kha.compute.TextureUnit;
|
||||
@ -87,6 +71,33 @@ class Inc {
|
||||
static var voxel_cb4:kha.compute.ConstantLocation;
|
||||
static var voxel_cc4:kha.compute.ConstantLocation;
|
||||
static var voxel_cd4:kha.compute.ConstantLocation;
|
||||
static var voxel_ce4:kha.compute.ConstantLocation;
|
||||
static var voxel_cf4:kha.compute.ConstantLocation;
|
||||
#end
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
static var voxel_sh5:kha.compute.Shader = null;
|
||||
static var voxel_ta5:kha.compute.TextureUnit;
|
||||
static var voxel_ca5:kha.compute.ConstantLocation;
|
||||
static var voxel_cb5:kha.compute.ConstantLocation;
|
||||
static var voxel_cc5:kha.compute.ConstantLocation;
|
||||
static var voxel_cd5:kha.compute.ConstantLocation;
|
||||
static var voxel_ce5:kha.compute.ConstantLocation;
|
||||
static var voxel_cf5:kha.compute.ConstantLocation;
|
||||
static var voxel_cg5:kha.compute.ConstantLocation;
|
||||
#if rp_shadowmap
|
||||
static var voxel_tb5:kha.compute.TextureUnit;
|
||||
static var voxel_tc5:kha.compute.TextureUnit;
|
||||
static var voxel_td5:kha.compute.TextureUnit;
|
||||
static var voxel_ch5:kha.compute.ConstantLocation;
|
||||
static var voxel_ci5:kha.compute.ConstantLocation;
|
||||
static var voxel_cj5:kha.compute.ConstantLocation;
|
||||
static var voxel_ck5:kha.compute.ConstantLocation;
|
||||
static var voxel_cl5:kha.compute.ConstantLocation;
|
||||
static var voxel_cm5:kha.compute.ConstantLocation;
|
||||
#if lnx_shadowmap_atlas
|
||||
static var m2 = iron.math.Mat4.identity();
|
||||
#end
|
||||
#end
|
||||
#end
|
||||
#end //rp_voxels
|
||||
|
||||
@ -152,11 +163,9 @@ class Inc {
|
||||
for (atlas in ShadowMapAtlas.shadowMapAtlases) {
|
||||
path.bindTarget(atlas.target, atlas.target);
|
||||
}
|
||||
#if rp_shadowmap_transparent
|
||||
for (atlas in ShadowMapAtlas.shadowMapAtlasesTransparent) {
|
||||
path.bindTarget(atlas.target, atlas.target);
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
static function getShadowMapAtlas(atlas:ShadowMapAtlas, transparent: Bool):String {
|
||||
@ -197,30 +206,24 @@ class Inc {
|
||||
for (atlas in ShadowMapAtlas.shadowMapAtlases) {
|
||||
atlas.rejectedLights = [];
|
||||
}
|
||||
#if rp_shadowmap_transparent
|
||||
for (atlas in ShadowMapAtlas.shadowMapAtlasesTransparent) {
|
||||
atlas.rejectedLights = [];
|
||||
}
|
||||
#end
|
||||
#end
|
||||
|
||||
for (light in iron.Scene.active.lights) {
|
||||
if (!light.lightInAtlas && !light.culledLight && light.visible && light.shadowMapScale > 0.0
|
||||
&& light.data.raw.strength > 0.0 && light.data.raw.cast_shadow) {
|
||||
ShadowMapAtlas.addLight(light, false);
|
||||
}
|
||||
#if rp_shadowmap_transparent
|
||||
if (!light.lightInAtlasTransparent && !light.culledLight && light.visible && light.shadowMapScale > 0.0
|
||||
&& light.data.raw.strength > 0.0 && light.data.raw.cast_shadow) {
|
||||
ShadowMapAtlas.addLight(light, true);
|
||||
}
|
||||
#end
|
||||
}
|
||||
// update point light data before rendering
|
||||
updatePointLightAtlasData(false);
|
||||
#if rp_shadowmap_transparent
|
||||
updatePointLightAtlasData(true);
|
||||
#end
|
||||
updatePointLightAtlasData(false);
|
||||
|
||||
for (atlas in ShadowMapAtlas.shadowMapAtlases) {
|
||||
var tilesToRemove = [];
|
||||
@ -298,7 +301,6 @@ class Inc {
|
||||
path.endStream();
|
||||
}
|
||||
|
||||
#if rp_shadowmap_transparent
|
||||
for (atlas in ShadowMapAtlas.shadowMapAtlasesTransparent) {
|
||||
var tilesToRemove = [];
|
||||
#if lnx_shadowmap_atlas_lod
|
||||
@ -393,8 +395,10 @@ class Inc {
|
||||
tile.freeTile();
|
||||
}
|
||||
}
|
||||
#if lnx_debug
|
||||
endShadowsLogicProfile();
|
||||
#end
|
||||
#end
|
||||
#end // rp_shadowmap
|
||||
}
|
||||
#else
|
||||
public static function bindShadowMap() {
|
||||
@ -497,7 +501,6 @@ class Inc {
|
||||
else if (l.data.raw.type == "spot" || l.data.raw.type == "area") spotIndex++;
|
||||
}
|
||||
|
||||
#if rp_shadowmap_transparent
|
||||
pointIndex = 0;
|
||||
spotIndex = 0;
|
||||
for (l in iron.Scene.active.lights) {
|
||||
@ -519,7 +522,6 @@ class Inc {
|
||||
if (l.data.raw.type == "point") pointIndex++;
|
||||
else if (l.data.raw.type == "spot" || l.data.raw.type == "area") spotIndex++;
|
||||
}
|
||||
#end
|
||||
#end // rp_shadowmap
|
||||
}
|
||||
#end
|
||||
@ -587,7 +589,7 @@ class Inc {
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = getDisplayp();
|
||||
t.format = "R16";
|
||||
t.format = "R32";
|
||||
t.scale = getSuperSampling();
|
||||
t.depth_buffer = "main";
|
||||
path.createRenderTarget(t);
|
||||
@ -613,14 +615,10 @@ class Inc {
|
||||
#end
|
||||
|
||||
#if (rp_voxels != "Off")
|
||||
path.bindTarget("voxelsOut", "voxels");
|
||||
#if (rp_voxels == "Voxel GI" || lnx_voxelgi_shadows)
|
||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||
#end
|
||||
#end
|
||||
|
||||
#if rp_ssrs
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
{
|
||||
path.bindTarget("voxelsOut", "voxels");
|
||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||
}
|
||||
#end
|
||||
|
||||
path.drawMeshes("translucent");
|
||||
@ -681,11 +679,12 @@ class Inc {
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = getDisplayp();
|
||||
t.format = "RGBA32";
|
||||
//t.scale = Inc.getSuperSampling();
|
||||
t.format = t.name == "voxels_ao" ? "R8" : "RGBA32";
|
||||
}
|
||||
else {
|
||||
if (t.name == "voxelsSDF" || t.name == "voxelsSDFtmp") {
|
||||
t.format = "R8";
|
||||
t.format = "R16";
|
||||
t.width = res;
|
||||
t.height = res * Main.voxelgiClipmapCount;
|
||||
t.depth = res;
|
||||
@ -694,16 +693,16 @@ class Inc {
|
||||
#if (rp_voxels == "Voxel AO")
|
||||
{
|
||||
if (t.name == "voxelsOut" || t.name == "voxelsOutB") {
|
||||
t.format = "R8";
|
||||
t.format = "R16";
|
||||
t.width = res * (6 + 16);
|
||||
t.height = res * Main.voxelgiClipmapCount;
|
||||
t.depth = res;
|
||||
}
|
||||
else {
|
||||
t.format = "R32UI";
|
||||
t.format = "R32";
|
||||
t.width = res * 6;
|
||||
t.height = res;
|
||||
t.depth = res * 2;
|
||||
t.depth = res;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@ -714,11 +713,17 @@ class Inc {
|
||||
t.height = res * Main.voxelgiClipmapCount;
|
||||
t.depth = res;
|
||||
}
|
||||
else if (t.name == "voxelsLight") {
|
||||
t.format = "R32";
|
||||
t.width = res;
|
||||
t.height = res;
|
||||
t.depth = res * 3;
|
||||
}
|
||||
else {
|
||||
t.format = "R32UI";
|
||||
t.format = "R32";
|
||||
t.width = res * 6;
|
||||
t.height = res;
|
||||
t.depth = res * 16;
|
||||
t.depth = res * 12;
|
||||
}
|
||||
}
|
||||
#end
|
||||
@ -780,7 +785,11 @@ class Inc {
|
||||
|
||||
public static inline function getDisplayp(): Null<Int> {
|
||||
#if rp_resolution_filter // Custom resolution set
|
||||
#if rp_pp
|
||||
return leenkx.renderpath.Postprocess.resolution_uniforms[0];
|
||||
#else
|
||||
return Main.resolutionSize;
|
||||
#end
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
@ -826,15 +835,14 @@ class Inc {
|
||||
|
||||
voxel_ca1 = voxel_sh1.getConstantLocation("clipmaps");
|
||||
voxel_cb1 = voxel_sh1.getConstantLocation("clipmapLevel");
|
||||
voxel_cc1 = voxel_sh1.getConstantLocation("envmapStrength");
|
||||
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
voxel_td1 = voxel_sh1.getTextureUnit("voxelsSampler");
|
||||
voxel_te1 = voxel_sh1.getTextureUnit("SDF");
|
||||
voxel_cc1 = voxel_sh1.getConstantLocation("envmapStrength");
|
||||
voxel_te1 = voxel_sh1.getTextureUnit("voxelsLight");
|
||||
voxel_tf1 = voxel_sh1.getTextureUnit("SDF");
|
||||
#else
|
||||
#if lnx_voxelgi_shadows
|
||||
voxel_te1 = voxel_sh1.getTextureUnit("SDF");
|
||||
voxel_tf1 = voxel_sh1.getTextureUnit("SDF");
|
||||
#end
|
||||
#end
|
||||
}
|
||||
@ -865,28 +873,12 @@ class Inc {
|
||||
#else
|
||||
voxel_td3 = voxel_sh3.getTextureUnit("voxels_diffuse");
|
||||
#end
|
||||
voxel_te3 = voxel_sh3.getTextureUnit("gbuffer1");
|
||||
voxel_tf3 = voxel_sh3.getTextureUnit("gbuffer2");
|
||||
#if lnx_brdf
|
||||
voxel_tg3 = voxel_sh3.getTextureUnit("senvmapBrdf");
|
||||
#end
|
||||
#if lnx_radiance
|
||||
voxel_th3 = voxel_sh3.getTextureUnit("senvmapRadiance");
|
||||
#end
|
||||
voxel_ca3 = voxel_sh3.getConstantLocation("clipmaps");
|
||||
voxel_ca3 = voxel_sh3.getConstantLocation("clipmaps");
|
||||
voxel_cb3 = voxel_sh3.getConstantLocation("InvVP");
|
||||
voxel_cc3 = voxel_sh3.getConstantLocation("eye");
|
||||
voxel_cd3 = voxel_sh3.getConstantLocation("postprocess_resolution");
|
||||
voxel_ce3 = voxel_sh3.getConstantLocation("envmapStrength");
|
||||
#if lnx_irradiance
|
||||
voxel_cf3 = voxel_sh3.getConstantLocation("shirr");
|
||||
#end
|
||||
#if lnx_radiance
|
||||
voxel_cg3 = voxel_sh3.getConstantLocation("envmapNumMipmaps");
|
||||
#end
|
||||
#if lnx_envcol
|
||||
voxel_ch3 = voxel_sh3.getConstantLocation("backgroundCol");
|
||||
#end
|
||||
voxel_cc3 = voxel_sh3.getConstantLocation("cameraProj");
|
||||
voxel_cd3 = voxel_sh3.getConstantLocation("eye");
|
||||
voxel_ce3 = voxel_sh3.getConstantLocation("eyeLook");
|
||||
voxel_cf3 = voxel_sh3.getConstantLocation("postprocess_resolution");
|
||||
}
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
if (voxel_sh4 == null)
|
||||
@ -900,8 +892,40 @@ class Inc {
|
||||
voxel_tf4 = voxel_sh4.getTextureUnit("sveloc");
|
||||
voxel_ca4 = voxel_sh4.getConstantLocation("clipmaps");
|
||||
voxel_cb4 = voxel_sh4.getConstantLocation("InvVP");
|
||||
voxel_cc4 = voxel_sh4.getConstantLocation("eye");
|
||||
voxel_cd4 = voxel_sh4.getConstantLocation("postprocess_resolution");
|
||||
voxel_cc4 = voxel_sh4.getConstantLocation("cameraProj");
|
||||
voxel_cd4 = voxel_sh4.getConstantLocation("eye");
|
||||
voxel_ce4 = voxel_sh4.getConstantLocation("eyeLook");
|
||||
voxel_cf4 = voxel_sh4.getConstantLocation("postprocess_resolution");
|
||||
}
|
||||
#end
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
if (voxel_sh5 == null)
|
||||
{
|
||||
voxel_sh5 = path.getComputeShader("voxel_light");
|
||||
voxel_ta5 = voxel_sh5.getTextureUnit("voxelsLight");
|
||||
|
||||
voxel_ca5 = voxel_sh5.getConstantLocation("clipmaps");
|
||||
voxel_cb5 = voxel_sh5.getConstantLocation("clipmapLevel");
|
||||
|
||||
voxel_cc5 = voxel_sh5.getConstantLocation("lightPos");
|
||||
voxel_cd5 = voxel_sh5.getConstantLocation("lightColor");
|
||||
voxel_ce5 = voxel_sh5.getConstantLocation("lightType");
|
||||
voxel_cf5 = voxel_sh5.getConstantLocation("lightDir");
|
||||
voxel_cg5 = voxel_sh5.getConstantLocation("spotData");
|
||||
#if rp_shadowmap
|
||||
voxel_tb5 = voxel_sh5.getTextureUnit("shadowMap");
|
||||
voxel_tc5 = voxel_sh5.getTextureUnit("shadowMapSpot");
|
||||
voxel_td5 = voxel_sh5.getTextureUnit("shadowMapPoint");
|
||||
|
||||
voxel_ch5 = voxel_sh5.getConstantLocation("lightShadow");
|
||||
voxel_ci5 = voxel_sh5.getConstantLocation("lightProj");
|
||||
voxel_cj5 = voxel_sh5.getConstantLocation("LVP");
|
||||
voxel_ck5 = voxel_sh5.getConstantLocation("shadowsBias");
|
||||
#if lnx_shadowmap_atlas
|
||||
voxel_cl5 = voxel_sh5.getConstantLocation("index");
|
||||
voxel_cm5 = voxel_sh5.getConstantLocation("pointLightDataArray");
|
||||
#end
|
||||
#end
|
||||
}
|
||||
#end
|
||||
}
|
||||
@ -952,11 +976,11 @@ class Inc {
|
||||
kha.compute.Compute.setTexture(voxel_tc1, rts.get("voxelsOut").image, kha.compute.Access.Write);
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
kha.compute.Compute.setSampledTexture(voxel_td1, rts.get("voxelsOutB").image);
|
||||
kha.compute.Compute.setTexture(voxel_te1, rts.get("voxelsSDF").image, kha.compute.Access.Write);
|
||||
kha.compute.Compute.setFloat(voxel_cc1, iron.Scene.active.world == null ? 0.0 : iron.Scene.active.world.probe.raw.strength);
|
||||
kha.compute.Compute.setTexture(voxel_te1, rts.get("voxelsLight").image, kha.compute.Access.Read);
|
||||
kha.compute.Compute.setTexture(voxel_tf1, rts.get("voxelsSDF").image, kha.compute.Access.Write);
|
||||
#else
|
||||
#if lnx_voxelgi_shadows
|
||||
kha.compute.Compute.setTexture(voxel_te1, rts.get("voxelsSDF").image, kha.compute.Access.Write);
|
||||
kha.compute.Compute.setTexture(voxel_tf1, rts.get("voxelsSDF").image, kha.compute.Access.Write);
|
||||
#end
|
||||
#end
|
||||
|
||||
@ -978,8 +1002,6 @@ class Inc {
|
||||
|
||||
kha.compute.Compute.setInt(voxel_cb1, iron.RenderPath.clipmapLevel);
|
||||
|
||||
kha.compute.Compute.setFloat(voxel_cc1, iron.Scene.active.world == null ? 0.0 : iron.Scene.active.world.probe.raw.strength);
|
||||
|
||||
kha.compute.Compute.compute(Std.int(res / 8), Std.int(res / 8), Std.int(res / 8));
|
||||
}
|
||||
|
||||
@ -1032,7 +1054,6 @@ class Inc {
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_voxels == "Voxel AO")
|
||||
public static function resolveAO() {
|
||||
var rts = path.renderTargets;
|
||||
@ -1045,20 +1066,13 @@ class Inc {
|
||||
|
||||
kha.compute.Compute.setSampledTexture(voxel_ta3, rts.get("voxelsOut").image);
|
||||
kha.compute.Compute.setSampledTexture(voxel_tb3, rts.get("half").image);
|
||||
#if lnx_deferred
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc3, rts.get("gbuffer0").image);
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc3, rts.get("lbuffer1").image);
|
||||
#end
|
||||
kha.compute.Compute.setTexture(voxel_td3, rts.get("voxels_ao").image, kha.compute.Access.Write);
|
||||
|
||||
kha.compute.Compute.setSampledTexture(voxel_te3, rts.get("gbuffer1").image);
|
||||
#if rp_gbuffer2
|
||||
kha.compute.Compute.setSampledTexture(voxel_tf3, rts.get("gbuffer2").image);
|
||||
#end
|
||||
#if lnx_brdf
|
||||
kha.compute.Compute.setSampledTexture(voxel_tg3, iron.Scene.active.embedded.get("brdf.png"));
|
||||
#end
|
||||
#if lnx_radiance
|
||||
kha.compute.Compute.setSampledTexture(voxel_th3, iron.Scene.active.world.probe.radiance);
|
||||
#end
|
||||
|
||||
var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10);
|
||||
for (i in 0...Main.voxelgiClipmapCount) {
|
||||
fa[i * 10] = clipmaps[i].voxelSize;
|
||||
@ -1085,7 +1099,18 @@ class Inc {
|
||||
|
||||
kha.compute.Compute.setMatrix(voxel_cb3, m.self);
|
||||
|
||||
kha.compute.Compute.setFloat3(voxel_cc3, camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz());
|
||||
var near = camera.data.raw.near_plane;
|
||||
var far = camera.data.raw.far_plane;
|
||||
var v = new iron.math.Vec2();
|
||||
v.x = far / (far - near);
|
||||
v.y = (-far * near) / (far - near);
|
||||
|
||||
kha.compute.Compute.setFloat2(voxel_cc3, v.x, v.y);
|
||||
|
||||
|
||||
kha.compute.Compute.setFloat3(voxel_cd3, camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz());
|
||||
var eyeLook = camera.lookWorld().normalize();
|
||||
kha.compute.Compute.setFloat3(voxel_ce3, eyeLook.x, eyeLook.y, eyeLook.z);
|
||||
|
||||
var width = iron.App.w();
|
||||
var height = iron.App.h();
|
||||
@ -1100,32 +1125,7 @@ class Inc {
|
||||
width = Std.int(dp * Inc.getSuperSampling());
|
||||
}
|
||||
}
|
||||
kha.compute.Compute.setFloat2(voxel_cd3, width, height);
|
||||
|
||||
kha.compute.Compute.setFloat(voxel_ce3, iron.Scene.active.world == null ? 0.0 : iron.Scene.active.world.probe.raw.strength);
|
||||
#if lnx_irradiance
|
||||
var irradiance = iron.Scene.active.world == null ?
|
||||
iron.data.WorldData.getEmptyIrradiance() :
|
||||
iron.Scene.active.world.probe.irradiance;
|
||||
kha.compute.Compute.setFloats(voxel_cf3, irradiance);
|
||||
#end
|
||||
#if lnx_radiance
|
||||
kha.compute.Compute.setFloat(voxel_cg3, iron.Scene.active.world != null ? iron.Scene.active.world.probe.raw.radiance_mipmaps + 1 - 2 : 1);
|
||||
#end
|
||||
|
||||
#if lnx_envcol
|
||||
var x: kha.FastFloat = 0.0;
|
||||
var y: kha.FastFloat = 0.0;
|
||||
var z: kha.FastFloat = 0.0;
|
||||
|
||||
if (camera.data.raw.clear_color != null) {
|
||||
x = camera.data.raw.clear_color[0];
|
||||
y = camera.data.raw.clear_color[1];
|
||||
z = camera.data.raw.clear_color[2];
|
||||
}
|
||||
|
||||
kha.compute.Compute.setFloat3(voxel_ch3, x, y, z);
|
||||
#end
|
||||
kha.compute.Compute.setFloat2(voxel_cf3, width, height);
|
||||
|
||||
kha.compute.Compute.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1);
|
||||
}
|
||||
@ -1141,18 +1141,12 @@ class Inc {
|
||||
|
||||
kha.compute.Compute.setSampledTexture(voxel_ta3, rts.get("voxelsOut").image);
|
||||
kha.compute.Compute.setSampledTexture(voxel_tb3, rts.get("half").image);
|
||||
#if lnx_deferred
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc3, rts.get("gbuffer0").image);
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc3, rts.get("lbuffer1").image);
|
||||
#end
|
||||
kha.compute.Compute.setTexture(voxel_td3, rts.get("voxels_diffuse").image, kha.compute.Access.Write);
|
||||
kha.compute.Compute.setSampledTexture(voxel_te3, rts.get("gbuffer1").image);
|
||||
#if rp_gbuffer2
|
||||
kha.compute.Compute.setSampledTexture(voxel_tf3, rts.get("gbuffer2").image);
|
||||
#end
|
||||
#if lnx_brdf
|
||||
kha.compute.Compute.setSampledTexture(voxel_tg3, iron.Scene.active.embedded.get("brdf.png"));
|
||||
#end
|
||||
#if lnx_radiance
|
||||
kha.compute.Compute.setSampledTexture(voxel_th3, iron.Scene.active.world.probe.radiance);
|
||||
#end
|
||||
|
||||
var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10);
|
||||
for (i in 0...Main.voxelgiClipmapCount) {
|
||||
@ -1180,7 +1174,18 @@ class Inc {
|
||||
|
||||
kha.compute.Compute.setMatrix(voxel_cb3, m.self);
|
||||
|
||||
kha.compute.Compute.setFloat3(voxel_cc3, camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz());
|
||||
var near = camera.data.raw.near_plane;
|
||||
var far = camera.data.raw.far_plane;
|
||||
var v = new iron.math.Vec2();
|
||||
v.x = far / (far - near);
|
||||
v.y = (-far * near) / (far - near);
|
||||
|
||||
kha.compute.Compute.setFloat2(voxel_cc3, v.x, v.y);
|
||||
|
||||
|
||||
kha.compute.Compute.setFloat3(voxel_cd3, camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz());
|
||||
var eyeLook = camera.lookWorld().normalize();
|
||||
kha.compute.Compute.setFloat3(voxel_ce3, eyeLook.x, eyeLook.y, eyeLook.z);
|
||||
|
||||
var width = iron.App.w();
|
||||
var height = iron.App.h();
|
||||
@ -1195,32 +1200,7 @@ class Inc {
|
||||
width = Std.int(dp * Inc.getSuperSampling());
|
||||
}
|
||||
}
|
||||
kha.compute.Compute.setFloat2(voxel_cd3, width, height);
|
||||
|
||||
kha.compute.Compute.setFloat(voxel_ce3, iron.Scene.active.world == null ? 0.0 : iron.Scene.active.world.probe.raw.strength);
|
||||
#if lnx_irradiance
|
||||
var irradiance = iron.Scene.active.world == null ?
|
||||
iron.data.WorldData.getEmptyIrradiance() :
|
||||
iron.Scene.active.world.probe.irradiance;
|
||||
kha.compute.Compute.setFloats(voxel_cf3, irradiance);
|
||||
#end
|
||||
#if lnx_radiance
|
||||
kha.compute.Compute.setFloat(voxel_cg3, iron.Scene.active.world != null ? iron.Scene.active.world.probe.raw.radiance_mipmaps + 1 - 2 : 1);
|
||||
#end
|
||||
|
||||
#if lnx_envcol
|
||||
var x: kha.FastFloat = 0.0;
|
||||
var y: kha.FastFloat = 0.0;
|
||||
var z: kha.FastFloat = 0.0;
|
||||
|
||||
if (camera.data.raw.clear_color != null) {
|
||||
x = camera.data.raw.clear_color[0];
|
||||
y = camera.data.raw.clear_color[1];
|
||||
z = camera.data.raw.clear_color[2];
|
||||
}
|
||||
|
||||
kha.compute.Compute.setFloat3(voxel_ch3, x, y, z);
|
||||
#end
|
||||
kha.compute.Compute.setFloat2(voxel_cf3, width, height);
|
||||
|
||||
kha.compute.Compute.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1);
|
||||
}
|
||||
@ -1236,12 +1216,15 @@ class Inc {
|
||||
|
||||
kha.compute.Compute.setSampledTexture(voxel_ta4, rts.get("voxelsOut").image);
|
||||
kha.compute.Compute.setSampledTexture(voxel_tb4, rts.get("half").image);
|
||||
#if lnx_deferred
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc4, rts.get("gbuffer0").image);
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc4, rts.get("lbuffer1").image);
|
||||
#end
|
||||
kha.compute.Compute.setSampledTexture(voxel_td4, rts.get("voxelsSDF").image);
|
||||
kha.compute.Compute.setTexture(voxel_te4, rts.get("voxels_specular").image, kha.compute.Access.Write);
|
||||
#if rp_gbuffer2
|
||||
kha.compute.Compute.setSampledTexture(voxel_tf4, rts.get("gbuffer2").image);
|
||||
#end
|
||||
|
||||
//kha.compute.Compute.setSampledTexture(voxel_tf4, rts.get("gbuffer2").image);
|
||||
|
||||
var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10);
|
||||
for (i in 0...Main.voxelgiClipmapCount) {
|
||||
@ -1269,7 +1252,18 @@ class Inc {
|
||||
|
||||
kha.compute.Compute.setMatrix(voxel_cb4, m.self);
|
||||
|
||||
kha.compute.Compute.setFloat3(voxel_cc4, camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz());
|
||||
var near = camera.data.raw.near_plane;
|
||||
var far = camera.data.raw.far_plane;
|
||||
var v = new iron.math.Vec2();
|
||||
v.x = far / (far - near);
|
||||
v.y = (-far * near) / (far - near);
|
||||
|
||||
kha.compute.Compute.setFloat2(voxel_cc4, v.x, v.y);
|
||||
|
||||
|
||||
kha.compute.Compute.setFloat3(voxel_cd4, camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz());
|
||||
var eyeLook = camera.lookWorld().normalize();
|
||||
kha.compute.Compute.setFloat3(voxel_ce4, eyeLook.x, eyeLook.y, eyeLook.z);
|
||||
|
||||
var width = iron.App.w();
|
||||
var height = iron.App.h();
|
||||
@ -1284,10 +1278,146 @@ class Inc {
|
||||
width = Std.int(dp * Inc.getSuperSampling());
|
||||
}
|
||||
}
|
||||
kha.compute.Compute.setFloat2(voxel_cd4, width, height);
|
||||
kha.compute.Compute.setFloat2(voxel_cf4, width, height);
|
||||
|
||||
kha.compute.Compute.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1);
|
||||
}
|
||||
public static function computeVoxelsLight() {
|
||||
var rts = path.renderTargets;
|
||||
var res = iron.RenderPath.getVoxelRes();
|
||||
var camera = iron.Scene.active.camera;
|
||||
var clipmaps = iron.RenderPath.clipmaps;
|
||||
var clipmap = clipmaps[iron.RenderPath.clipmapLevel];
|
||||
var lights = iron.Scene.active.lights;
|
||||
|
||||
pointIndex = spotIndex = 0;
|
||||
for (i in 0...lights.length) {
|
||||
var l = lights[i];
|
||||
if (!l.visible) continue;
|
||||
path.light = l;
|
||||
|
||||
kha.compute.Compute.setShader(voxel_sh5);
|
||||
|
||||
kha.compute.Compute.setTexture(voxel_ta5, rts.get("voxelsLight").image, kha.compute.Access.Write);
|
||||
|
||||
var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10);
|
||||
for (i in 0...Main.voxelgiClipmapCount) {
|
||||
fa[i * 10] = clipmaps[i].voxelSize;
|
||||
fa[i * 10 + 1] = clipmaps[i].extents.x;
|
||||
fa[i * 10 + 2] = clipmaps[i].extents.y;
|
||||
fa[i * 10 + 3] = clipmaps[i].extents.z;
|
||||
fa[i * 10 + 4] = clipmaps[i].center.x;
|
||||
fa[i * 10 + 5] = clipmaps[i].center.y;
|
||||
fa[i * 10 + 6] = clipmaps[i].center.z;
|
||||
fa[i * 10 + 7] = clipmaps[i].offset_prev.x;
|
||||
fa[i * 10 + 8] = clipmaps[i].offset_prev.y;
|
||||
fa[i * 10 + 9] = clipmaps[i].offset_prev.z;
|
||||
}
|
||||
|
||||
kha.compute.Compute.setFloats(voxel_ca5, fa);
|
||||
|
||||
kha.compute.Compute.setInt(voxel_cb5, iron.RenderPath.clipmapLevel);
|
||||
|
||||
#if rp_shadowmap
|
||||
if (l.data.raw.type == "sun") {
|
||||
#if lnx_shadowmap_atlas
|
||||
#if lnx_shadowmap_atlas_single_map
|
||||
kha.compute.Compute.setSampledTexture(voxel_tb5, rts.get("shadowMapAtlas").image);
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tb5, rts.get("shadowMapAtlasSun").image);
|
||||
#end
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tb5, rts.get("shadowMap").image);
|
||||
#end
|
||||
kha.compute.Compute.setInt(voxel_ch5, 1); // lightShadow
|
||||
}
|
||||
else if (l.data.raw.type == "spot" || l.data.raw.type == "area") {
|
||||
#if lnx_shadowmap_atlas
|
||||
#if lnx_shadowmap_atlas_single_map
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc5, rts.get("shadowMapAtlas").image);
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc5, rts.get("shadowMapAtlasSpot").image);
|
||||
#end
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_tc5, rts.get("shadowMapSpot[" + spotIndex + "]").image);
|
||||
spotIndex++;
|
||||
#end
|
||||
kha.compute.Compute.setInt(voxel_ch5, 2);
|
||||
}
|
||||
else {
|
||||
#if lnx_shadowmap_atlas
|
||||
#if lnx_shadowmap_atlas_single_map
|
||||
kha.compute.Compute.setSampledTexture(voxel_td5, rts.get("shadowMapAtlas").image);
|
||||
#else
|
||||
kha.compute.Compute.setSampledTexture(voxel_td5, rts.get("shadowMapAtlasPoint").image);
|
||||
kha.compute.Compute.setInt(voxel_cl5, i);
|
||||
kha.compute.Compute.setFloats(voxel_cm5, iron.object.LightObject.pointLightsData);
|
||||
#end
|
||||
#else
|
||||
kha.compute.Compute.setSampledCubeMap(voxel_td5, rts.get("shadowMapPoint[" + pointIndex + "]").cubeMap);
|
||||
pointIndex++;
|
||||
#end
|
||||
kha.compute.Compute.setInt(voxel_ch5, 3);
|
||||
}
|
||||
|
||||
// lightProj
|
||||
var near = l.data.raw.near_plane;
|
||||
var far = l.data.raw.far_plane;
|
||||
var a:kha.FastFloat = far + near;
|
||||
var b:kha.FastFloat = far - near;
|
||||
var f2:kha.FastFloat = 2.0;
|
||||
var c:kha.FastFloat = f2 * far * near;
|
||||
var vx:kha.FastFloat = a / b;
|
||||
var vy:kha.FastFloat = c / b;
|
||||
kha.compute.Compute.setFloat2(voxel_ci5, vx, vy);
|
||||
// LVP
|
||||
m.setFrom(l.VP);
|
||||
m.multmat(iron.object.Uniforms.biasMat);
|
||||
#if lnx_shadowmap_atlas
|
||||
if (l.data.raw.type == "sun")
|
||||
{
|
||||
// tile matrix
|
||||
m.setIdentity();
|
||||
// scale [0-1] coords to [0-tilescale]
|
||||
m2._00 = l.tileScale[0];
|
||||
m2._11 = l.tileScale[0];
|
||||
// offset coordinate start from [0, 0] to [tile-start-x, tile-start-y]
|
||||
m2._30 = l.tileOffsetX[0];
|
||||
m2._31 = l.tileOffsetY[0];
|
||||
m.multmat(m2);
|
||||
#if (!kha_opengl)
|
||||
m2.setIdentity();
|
||||
m2._11 = -1.0;
|
||||
m2._31 = 1.0;
|
||||
m.multmat(m2);
|
||||
#end
|
||||
}
|
||||
#end
|
||||
kha.compute.Compute.setMatrix(voxel_cj5, m.self);
|
||||
// shadowsBias
|
||||
kha.compute.Compute.setFloat(voxel_ck5, l.data.raw.shadows_bias);
|
||||
#end // rp_shadowmap
|
||||
|
||||
// lightPos
|
||||
kha.compute.Compute.setFloat3(voxel_cc5, l.transform.worldx(), l.transform.worldy(), l.transform.worldz());
|
||||
// lightCol
|
||||
var f = l.data.raw.strength;
|
||||
kha.compute.Compute.setFloat3(voxel_cd5, l.data.raw.color[0] * f, l.data.raw.color[1] * f, l.data.raw.color[2] * f);
|
||||
// lightType
|
||||
kha.compute.Compute.setInt(voxel_ce5, iron.data.LightData.typeToInt(l.data.raw.type));
|
||||
// lightDir
|
||||
var v = l.look();
|
||||
kha.compute.Compute.setFloat3(voxel_cf5, v.x, v.y, v.z);
|
||||
// spotData
|
||||
if (l.data.raw.type == "spot") {
|
||||
var vx = l.data.raw.spot_size;
|
||||
var vy = vx - l.data.raw.spot_blend;
|
||||
kha.compute.Compute.setFloat2(voxel_cg5, vx, vy);
|
||||
}
|
||||
|
||||
kha.compute.Compute.compute(Std.int(res / 8), Std.int(res / 8), Std.int(res / 8));
|
||||
}
|
||||
}
|
||||
#end // GI
|
||||
#end // Voxels
|
||||
}
|
||||
|
@ -133,6 +133,11 @@ class Postprocess {
|
||||
[50.0] //2: Volumetric Fog Amount B
|
||||
];
|
||||
|
||||
public static var resolution_uniforms = [
|
||||
720, //0: Size
|
||||
0 //1: Filter
|
||||
];
|
||||
|
||||
public static function vec3Link(object: Object, mat: MaterialData, link: String): iron.math.Vec4 {
|
||||
var v:Vec4 = null;
|
||||
|
||||
|
@ -15,11 +15,6 @@ class RenderPathDeferred {
|
||||
static var bloomUpsampler: Upsampler;
|
||||
#end
|
||||
|
||||
#if (rp_ssgi == "SSGI")
|
||||
static var ssgitex = "singleb";
|
||||
static var ssgitexb = "singleb";
|
||||
#end
|
||||
|
||||
public static inline function setTargetMeshes() {
|
||||
//Always keep the order of render targets the same as defined in compiled.inc
|
||||
path.setTarget("gbuffer0", [
|
||||
@ -62,11 +57,12 @@ class RenderPathDeferred {
|
||||
Inc.initGI("voxels");
|
||||
Inc.initGI("voxelsOut");
|
||||
Inc.initGI("voxelsOutB");
|
||||
#if (rp_voxels == "Voxel GI" || lnx_voxelgi_shadows)
|
||||
#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
|
||||
@ -199,26 +195,16 @@ class RenderPathDeferred {
|
||||
path.loadShader("shader_datas/blur_edge_pass/blur_edge_pass_x");
|
||||
path.loadShader("shader_datas/blur_edge_pass/blur_edge_pass_y");
|
||||
}
|
||||
#elseif (rp_ssgi == "SSGI")
|
||||
{
|
||||
path.loadShader("shader_datas/ssgi_pass/ssgi_pass");
|
||||
path.loadShader("shader_datas/blur_edge_pass/blur_edge_pass_x");
|
||||
path.loadShader("shader_datas/blur_edge_pass/blur_edge_pass_y");
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_ssgi != "Off")
|
||||
#if ((rp_ssgi != "Off") || rp_volumetriclight)
|
||||
{
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "singlea";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
#if (rp_ssgi == "SSGI")
|
||||
t.format = "RGBA32";
|
||||
#else
|
||||
t.format = "R8";
|
||||
#end
|
||||
t.scale = Inc.getSuperSampling();
|
||||
#if rp_ssgi_half
|
||||
t.scale *= 0.5;
|
||||
@ -230,66 +216,6 @@ class RenderPathDeferred {
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
#if (rp_ssgi == "SSGI")
|
||||
t.format = "RGBA32";
|
||||
#else
|
||||
t.format = "R8";
|
||||
#end
|
||||
t.scale = Inc.getSuperSampling();
|
||||
#if rp_ssgi_half
|
||||
t.scale *= 0.5;
|
||||
#end
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_volumetriclight
|
||||
{
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "volumetrica";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "R8";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
#if rp_ssgi_half // Do we keep this ?
|
||||
t.scale *= 0.5;
|
||||
#end
|
||||
path.createRenderTarget(t);
|
||||
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "volumetricb";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "R8";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
#if rp_ssgi_half
|
||||
t.scale *= 0.5;
|
||||
#end
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_volumetriclight
|
||||
{
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "volumetrica";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "R8";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
#if rp_ssgi_half // Do we keep this ?
|
||||
t.scale *= 0.5;
|
||||
#end
|
||||
path.createRenderTarget(t);
|
||||
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "volumetricb";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "R8";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
#if rp_ssgi_half
|
||||
@ -442,7 +368,7 @@ class RenderPathDeferred {
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
|
||||
// holds background color
|
||||
// holds background depth
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "refr";
|
||||
t.width = 0;
|
||||
@ -535,7 +461,7 @@ class RenderPathDeferred {
|
||||
|
||||
#if (rp_ssrefr || lnx_voxelgi_refract)
|
||||
{
|
||||
path.setTarget("gbuffer_refraction");
|
||||
path.setTarget("gbuffer_refraction"); // Only clear gbuffer0
|
||||
path.clearTarget(0xffffff00);
|
||||
}
|
||||
#end
|
||||
@ -591,16 +517,30 @@ class RenderPathDeferred {
|
||||
path.drawShader("shader_datas/downsample_depth/downsample_depth");
|
||||
#end
|
||||
|
||||
#if (rp_shadowmap)
|
||||
// atlasing is exclusive for now
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.drawShadowMapAtlas();
|
||||
#else
|
||||
Inc.drawShadowMap();
|
||||
#end
|
||||
#end
|
||||
#if ((rp_ssgi == "RTGI") || (rp_ssgi == "RTAO"))
|
||||
{
|
||||
if (leenkx.data.Config.raw.rp_ssgi != false) {
|
||||
path.setTarget("singlea");
|
||||
#if rp_ssgi_half
|
||||
path.bindTarget("half", "gbufferD");
|
||||
#else
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
#end
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.drawShader("shader_datas/ssgi_pass/ssgi_pass");
|
||||
|
||||
#if (rp_ssgi == "SSAO")
|
||||
path.setTarget("singleb");
|
||||
path.bindTarget("singlea", "tex");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.drawShader("shader_datas/blur_edge_pass/blur_edge_pass_x");
|
||||
|
||||
path.setTarget("singlea");
|
||||
path.bindTarget("singleb", "tex");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.drawShader("shader_datas/blur_edge_pass/blur_edge_pass_y");
|
||||
}
|
||||
}
|
||||
#elseif (rp_ssgi == "SSAO")
|
||||
{
|
||||
if (leenkx.data.Config.raw.rp_ssgi != false) {
|
||||
path.setTarget("singlea");
|
||||
@ -619,43 +559,15 @@ class RenderPathDeferred {
|
||||
path.drawShader("shader_datas/blur_edge_pass/blur_edge_pass_y");
|
||||
}
|
||||
}
|
||||
#elseif (rp_ssgi == "SSGI")
|
||||
{
|
||||
if (leenkx.data.Config.raw.rp_ssgi != false) {
|
||||
path.setTarget("singlea");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.bindTarget("gbuffer1", "gbuffer1");
|
||||
#if rp_gbuffer_emission
|
||||
{
|
||||
path.bindTarget("gbuffer_emission", "gbufferEmission");
|
||||
}
|
||||
#end
|
||||
#if rp_gbuffer2
|
||||
path.bindTarget("gbuffer2", "sveloc");
|
||||
#end
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
#end
|
||||
|
||||
path.drawShader("shader_datas/ssgi_pass/ssgi_pass");
|
||||
path.setTarget("singleb");
|
||||
path.bindTarget("singlea", "tex");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.drawShader("shader_datas/blur_edge_pass/blur_edge_pass_x");
|
||||
|
||||
path.setTarget("singlea");
|
||||
path.bindTarget("singleb", "tex");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.drawShader("shader_datas/blur_edge_pass/blur_edge_pass_y");
|
||||
}
|
||||
}
|
||||
#if (rp_shadowmap)
|
||||
// atlasing is exclusive for now
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.drawShadowMapAtlas();
|
||||
#else
|
||||
Inc.drawShadowMap();
|
||||
#end
|
||||
#end
|
||||
|
||||
// Voxels
|
||||
@ -668,6 +580,9 @@ class RenderPathDeferred {
|
||||
|
||||
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);
|
||||
@ -679,30 +594,26 @@ class RenderPathDeferred {
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
path.clearImage("voxelsLight", 0x00000000);
|
||||
#end
|
||||
path.clearImage("voxels", 0x00000000);
|
||||
Inc.computeVoxelsOffsetPrev();
|
||||
}
|
||||
|
||||
path.setTarget("");
|
||||
path.bindTarget("voxels", "voxels");
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
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 (rp_voxels == "Voxel GI")
|
||||
#if (lnx_voxelgi_shadows || rp_voxels == "Voxel GI")
|
||||
Inc.computeVoxelsSDF();
|
||||
#end
|
||||
|
||||
@ -717,6 +628,7 @@ class RenderPathDeferred {
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
// ---
|
||||
// Deferred light
|
||||
// ---
|
||||
@ -848,9 +760,15 @@ class RenderPathDeferred {
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_translucency && !rp_ssrefr)
|
||||
{
|
||||
Inc.drawTranslucency("tex");
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_volumetriclight
|
||||
{
|
||||
path.setTarget("volumetrica");
|
||||
path.setTarget("singlea");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
@ -859,16 +777,85 @@ class RenderPathDeferred {
|
||||
#end
|
||||
path.drawShader("shader_datas/volumetric_light/volumetric_light");
|
||||
|
||||
path.setTarget("volumetricb");
|
||||
path.bindTarget("volumetrica", "tex");
|
||||
path.setTarget("singleb");
|
||||
path.bindTarget("singlea", "tex");
|
||||
path.drawShader("shader_datas/blur_bilat_pass/blur_bilat_pass_x");
|
||||
|
||||
path.setTarget("tex");
|
||||
path.bindTarget("volumetricb", "tex");
|
||||
path.bindTarget("singleb", "tex");
|
||||
path.drawShader("shader_datas/blur_bilat_blend_pass/blur_bilat_blend_pass_y");
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_bloom
|
||||
{
|
||||
inline Inc.drawBloom("tex", bloomDownsampler, bloomUpsampler);
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_sss
|
||||
{
|
||||
#if (!kha_opengl)
|
||||
path.setDepthFrom("tex", "gbuffer1"); // Unbind depth so we can read it
|
||||
#end
|
||||
|
||||
path.setTarget("buf");
|
||||
path.bindTarget("tex", "tex");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.drawShader("shader_datas/sss_pass/sss_pass_x");
|
||||
|
||||
path.setTarget("tex");
|
||||
path.bindTarget("buf", "tex");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.drawShader("shader_datas/sss_pass/sss_pass_y");
|
||||
|
||||
#if (!kha_opengl)
|
||||
path.setDepthFrom("tex", "gbuffer0");
|
||||
#end
|
||||
}
|
||||
#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("tex", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
path.setTarget("gbuffer0", ["tex", "gbuffer_refraction"]);
|
||||
|
||||
#if (rp_voxels != "Off")
|
||||
{
|
||||
path.bindTarget("voxelsOut", "voxels");
|
||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||
path.bindTarget("gbuffer2", "sveloc");
|
||||
}
|
||||
#end
|
||||
|
||||
path.drawMeshes("refraction");
|
||||
|
||||
path.setTarget("tex");
|
||||
path.bindTarget("tex", "tex");
|
||||
path.bindTarget("refr", "tex1");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("gbufferD1", "gbufferD1");
|
||||
path.bindTarget("gbuffer0", "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) {
|
||||
@ -913,88 +900,6 @@ class RenderPathDeferred {
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_sss
|
||||
{
|
||||
#if (!kha_opengl)
|
||||
path.setDepthFrom("tex", "gbuffer1"); // Unbind depth so we can read it
|
||||
#end
|
||||
|
||||
path.setTarget("buf");
|
||||
path.bindTarget("tex", "tex");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.drawShader("shader_datas/sss_pass/sss_pass_x");
|
||||
|
||||
path.setTarget("tex");
|
||||
path.bindTarget("buf", "tex");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.drawShader("shader_datas/sss_pass/sss_pass_y");
|
||||
|
||||
#if (!kha_opengl)
|
||||
path.setDepthFrom("tex", "gbuffer0");
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_translucency && !rp_ssrefr)
|
||||
{
|
||||
Inc.drawTranslucency("tex");
|
||||
}
|
||||
#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("tex", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
path.setTarget("gbuffer0", ["tex", "gbuffer_refraction"]);
|
||||
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_voxels != "Off")
|
||||
path.bindTarget("voxelsOut", "voxels");
|
||||
#if (rp_voxels == "Voxel GI" || lnx_voxelgi_shadows)
|
||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||
#end
|
||||
#end
|
||||
|
||||
#if rp_ssrs
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
#end
|
||||
|
||||
path.drawMeshes("refraction");
|
||||
|
||||
path.setTarget("tex");
|
||||
path.bindTarget("tex", "tex");
|
||||
path.bindTarget("refr", "tex1");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
path.bindTarget("gbufferD1", "gbufferD1");
|
||||
path.bindTarget("gbuffer0", "gbuffer0");
|
||||
path.bindTarget("gbuffer_refraction", "gbuffer_refraction");
|
||||
|
||||
path.drawShader("shader_datas/ssrefr_pass/ssrefr_pass");
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
#if ((rp_motionblur == "Camera") || (rp_motionblur == "Object"))
|
||||
{
|
||||
if (leenkx.data.Config.raw.rp_motionblur != false) {
|
||||
@ -1059,12 +964,6 @@ class RenderPathDeferred {
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_bloom
|
||||
{
|
||||
inline Inc.drawBloom("tex", bloomDownsampler, bloomUpsampler);
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_supersampling == 4)
|
||||
var framebuffer = "buf";
|
||||
#else
|
||||
|
@ -142,17 +142,16 @@ class RenderPathForward {
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = "DEPTH24";
|
||||
t.format = "R32";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
|
||||
//holds colors before refractive meshes are drawn
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "refr";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
t.format = Inc.getHdrFormat();
|
||||
t.format = "RGBA64";
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
@ -201,10 +200,17 @@ class RenderPathForward {
|
||||
Inc.initGI("voxels");
|
||||
Inc.initGI("voxelsOut");
|
||||
Inc.initGI("voxelsOutB");
|
||||
#if (rp_voxels == "Voxel GI" || lnx_voxelgi_shadows)
|
||||
#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();
|
||||
@ -251,25 +257,18 @@ class RenderPathForward {
|
||||
#end
|
||||
#end
|
||||
|
||||
#if (rp_volumetriclight || rp_ssgi != "Off")
|
||||
#if rp_volumetriclight
|
||||
{
|
||||
#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");
|
||||
#end
|
||||
|
||||
|
||||
var t = new RenderTargetRaw();
|
||||
t.name = "singlea";
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
#if (rp_ssgi == "SSGI")
|
||||
t.format = "RGBA32";
|
||||
#else
|
||||
t.format = "R8";
|
||||
#end
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
|
||||
@ -278,11 +277,7 @@ class RenderPathForward {
|
||||
t.width = 0;
|
||||
t.height = 0;
|
||||
t.displayp = Inc.getDisplayp();
|
||||
#if (rp_ssgi == "SSGI")
|
||||
t.format = "RGBA32";
|
||||
#else
|
||||
t.format = "R8";
|
||||
#end
|
||||
t.scale = Inc.getSuperSampling();
|
||||
path.createRenderTarget(t);
|
||||
}
|
||||
@ -379,6 +374,9 @@ class RenderPathForward {
|
||||
|
||||
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);
|
||||
@ -390,6 +388,9 @@ class RenderPathForward {
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (rp_voxels == "Voxel GI")
|
||||
path.clearImage("voxelsLight", 0x00000000);
|
||||
#end
|
||||
path.clearImage("voxels", 0x00000000);
|
||||
Inc.computeVoxelsOffsetPrev();
|
||||
}
|
||||
@ -399,12 +400,27 @@ class RenderPathForward {
|
||||
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
|
||||
|
||||
@ -423,7 +439,7 @@ class RenderPathForward {
|
||||
#if (rp_ssrefr || lnx_voxelgi_refract)
|
||||
{
|
||||
path.setTarget("gbuffer_refraction"); // Only clear gbuffer0
|
||||
path.clearTarget(0xffffff00);
|
||||
path.clearTarget(0xff000000);
|
||||
}
|
||||
#end
|
||||
|
||||
@ -433,6 +449,13 @@ class RenderPathForward {
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssrefr
|
||||
{
|
||||
path.setTarget("gbuffer_refraction");
|
||||
path.clearTarget(0xffffff00);
|
||||
}
|
||||
#end
|
||||
|
||||
RenderPathCreator.setTargetMeshes();
|
||||
|
||||
#if rp_shadowmap
|
||||
@ -449,11 +472,18 @@ class RenderPathForward {
|
||||
#if (rp_voxels != "Off")
|
||||
if (leenkx.data.Config.raw.rp_gi != false)
|
||||
{
|
||||
#if (rp_voxels != "Off")
|
||||
path.bindTarget("voxelsOut", "voxels");
|
||||
#if (rp_voxels == "Voxel GI" || lnx_voxelgi_shadows)
|
||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||
#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
|
||||
@ -492,31 +522,14 @@ class RenderPathForward {
|
||||
|
||||
path.setTarget("lbuffer0", ["lbuffer1", "gbuffer_refraction"]);
|
||||
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
#if (rp_voxels != "Off")
|
||||
path.bindTarget("voxelsOut", "voxels");
|
||||
#if (rp_voxels == "Voxel GI" || lnx_voxelgi_shadows)
|
||||
path.bindTarget("voxelsSDF", "voxelsSDF");
|
||||
#end
|
||||
#end
|
||||
|
||||
#if rp_ssrs
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
#end
|
||||
|
||||
path.drawMeshes("refraction");
|
||||
|
||||
path.setTarget("lbuffer0");
|
||||
|
||||
path.bindTarget("lbuffer0", "tex");
|
||||
path.bindTarget("refr", "tex1");
|
||||
path.bindTarget("_main", "gbufferD");
|
||||
@ -564,50 +577,6 @@ class RenderPathForward {
|
||||
}
|
||||
#end
|
||||
|
||||
#if rp_ssrefr
|
||||
{
|
||||
if (leenkx.data.Config.raw.rp_ssrefr != false)
|
||||
{
|
||||
path.setTarget("gbufferD1");
|
||||
path.bindTarget("_main", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
path.setTarget("refr");
|
||||
path.bindTarget("lbuffer0", "tex");
|
||||
path.drawShader("shader_datas/copy_pass/copy_pass");
|
||||
|
||||
path.setTarget("lbuffer0", ["lbuffer1", "gbuffer_refraction"]);
|
||||
|
||||
#if rp_shadowmap
|
||||
{
|
||||
#if lnx_shadowmap_atlas
|
||||
Inc.bindShadowMapAtlas();
|
||||
#else
|
||||
Inc.bindShadowMap();
|
||||
#end
|
||||
}
|
||||
#end
|
||||
|
||||
#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_bloom
|
||||
{
|
||||
inline Inc.drawBloom("lbuffer0", bloomDownsampler, bloomUpsampler);
|
||||
|
@ -41,11 +41,7 @@ class Starter {
|
||||
try {
|
||||
#end
|
||||
|
||||
kha.System.start({title: Main.projectName, width: c.window_w, height: c.window_h, window: {
|
||||
#if lnx_render_viewport
|
||||
visible: false,
|
||||
#end
|
||||
mode: windowMode, windowFeatures: windowFeatures}, framebuffer: {samplesPerPixel: c.window_msaa, verticalSync: c.window_vsync}}, function(window: kha.Window) {
|
||||
kha.System.start({title: Main.projectName, width: c.window_w, height: c.window_h, window: {mode: windowMode, windowFeatures: windowFeatures}, framebuffer: {samplesPerPixel: c.window_msaa, verticalSync: c.window_vsync}}, function(window: kha.Window) {
|
||||
|
||||
iron.App.init(function() {
|
||||
#if lnx_loadscreen
|
||||
|
@ -73,7 +73,17 @@ class PhysicsBreak extends Trait {
|
||||
collisionMargin: 0.04,
|
||||
linearDeactivationThreshold: 0.0,
|
||||
angularDeactivationThrshold: 0.0,
|
||||
deactivationTime: 0.0
|
||||
deactivationTime: 0.0,
|
||||
linearVelocityMin: 0.0,
|
||||
linearVelocityMax: 0.0,
|
||||
angularVelocityMin: 0.0,
|
||||
angularVelocityMax: 0.0,
|
||||
lockTranslationX: false,
|
||||
lockTranslationY: false,
|
||||
lockTranslationZ: false,
|
||||
lockRotationX: false,
|
||||
lockRotationY: false,
|
||||
lockRotationZ: false
|
||||
};
|
||||
o.addTrait(new RigidBody(Shape.ConvexHull, ud.mass, ud.friction, 0, 1, params));
|
||||
if (cast(o, MeshObject).data.geom.positions.values.length < 600) {
|
||||
|
@ -280,7 +280,11 @@ class DebugConsole extends Trait {
|
||||
|
||||
function drawObjectNameInList(object: iron.object.Object, selected: Bool) {
|
||||
var _y = ui._y;
|
||||
ui.text(object.uid+'_'+object.name);
|
||||
|
||||
if (object.parent.name == 'Root' && object.raw == null)
|
||||
ui.text(object.uid+'_'+object.name+' ('+iron.Scene.active.raw.world_ref+')');
|
||||
else
|
||||
ui.text(object.uid+'_'+object.name);
|
||||
|
||||
if (object == iron.Scene.active.camera) {
|
||||
var tagWidth = 100;
|
||||
|
@ -36,6 +36,18 @@ class RigidBody extends iron.Trait {
|
||||
var useDeactivation: Bool;
|
||||
var deactivationParams: Array<Float>;
|
||||
var ccd = false; // Continuous collision detection
|
||||
// New velocity limiting properties
|
||||
var linearVelocityMin: Float;
|
||||
var linearVelocityMax: Float;
|
||||
var angularVelocityMin: Float;
|
||||
var angularVelocityMax: Float;
|
||||
// New lock properties
|
||||
var lockTranslationX: Bool;
|
||||
var lockTranslationY: Bool;
|
||||
var lockTranslationZ: Bool;
|
||||
var lockRotationX: Bool;
|
||||
var lockRotationY: Bool;
|
||||
var lockRotationZ: Bool;
|
||||
public var group = 1;
|
||||
public var mask = 1;
|
||||
var trigger = false;
|
||||
@ -120,7 +132,17 @@ class RigidBody extends iron.Trait {
|
||||
collisionMargin: 0.0,
|
||||
linearDeactivationThreshold: 0.0,
|
||||
angularDeactivationThrshold: 0.0,
|
||||
deactivationTime: 0.0
|
||||
deactivationTime: 0.0,
|
||||
linearVelocityMin: 0.0,
|
||||
linearVelocityMax: 0.0,
|
||||
angularVelocityMin: 0.0,
|
||||
angularVelocityMax: 0.0,
|
||||
lockTranslationX: false,
|
||||
lockTranslationY: false,
|
||||
lockTranslationZ: false,
|
||||
lockRotationX: false,
|
||||
lockRotationY: false,
|
||||
lockRotationZ: false
|
||||
};
|
||||
|
||||
if (flags == null) flags = {
|
||||
@ -139,6 +161,18 @@ class RigidBody extends iron.Trait {
|
||||
this.angularFactors = [params.angularFactorsX, params.angularFactorsY, params.angularFactorsZ];
|
||||
this.collisionMargin = params.collisionMargin;
|
||||
this.deactivationParams = [params.linearDeactivationThreshold, params.angularDeactivationThrshold, params.deactivationTime];
|
||||
// New velocity limiting properties
|
||||
this.linearVelocityMin = params.linearVelocityMin;
|
||||
this.linearVelocityMax = params.linearVelocityMax;
|
||||
this.angularVelocityMin = params.angularVelocityMin;
|
||||
this.angularVelocityMax = params.angularVelocityMax;
|
||||
// New lock properties
|
||||
this.lockTranslationX = params.lockTranslationX;
|
||||
this.lockTranslationY = params.lockTranslationY;
|
||||
this.lockTranslationZ = params.lockTranslationZ;
|
||||
this.lockRotationX = params.lockRotationX;
|
||||
this.lockRotationY = params.lockRotationY;
|
||||
this.lockRotationZ = params.lockRotationZ;
|
||||
this.animated = flags.animated;
|
||||
this.trigger = flags.trigger;
|
||||
this.ccd = flags.ccd;
|
||||
@ -291,11 +325,25 @@ class RigidBody extends iron.Trait {
|
||||
}
|
||||
|
||||
if (linearFactors != null) {
|
||||
setLinearFactor(linearFactors[0], linearFactors[1], linearFactors[2]);
|
||||
// Apply lock properties by overriding factors
|
||||
var lx = linearFactors[0];
|
||||
var ly = linearFactors[1];
|
||||
var lz = linearFactors[2];
|
||||
if (lockTranslationX) lx = 0.0;
|
||||
if (lockTranslationY) ly = 0.0;
|
||||
if (lockTranslationZ) lz = 0.0;
|
||||
setLinearFactor(lx, ly, lz);
|
||||
}
|
||||
|
||||
if (angularFactors != null) {
|
||||
setAngularFactor(angularFactors[0], angularFactors[1], angularFactors[2]);
|
||||
// Apply lock properties by overriding factors
|
||||
var ax = angularFactors[0];
|
||||
var ay = angularFactors[1];
|
||||
var az = angularFactors[2];
|
||||
if (lockRotationX) ax = 0.0;
|
||||
if (lockRotationY) ay = 0.0;
|
||||
if (lockRotationZ) az = 0.0;
|
||||
setAngularFactor(ax, ay, az);
|
||||
}
|
||||
|
||||
if (trigger) bodyColl.setCollisionFlags(bodyColl.getCollisionFlags() | CF_NO_CONTACT_RESPONSE);
|
||||
@ -411,6 +459,55 @@ class RigidBody extends iron.Trait {
|
||||
var rbs = physics.getContacts(this);
|
||||
if (rbs != null) for (rb in rbs) for (f in onContact) f(rb);
|
||||
}
|
||||
|
||||
// Apply velocity limiting if enabled
|
||||
if (!animated && !staticObj) {
|
||||
applyVelocityLimits();
|
||||
}
|
||||
}
|
||||
|
||||
function applyVelocityLimits() {
|
||||
if (!ready) return;
|
||||
|
||||
// Check linear velocity limits
|
||||
if (linearVelocityMin > 0.0 || linearVelocityMax > 0.0) {
|
||||
var velocity = getLinearVelocity();
|
||||
var speed = velocity.length();
|
||||
|
||||
if (linearVelocityMin > 0.0 && speed < linearVelocityMin) {
|
||||
// Increase velocity to minimum
|
||||
if (speed > 0.0) {
|
||||
velocity.normalize();
|
||||
velocity.mult(linearVelocityMin);
|
||||
setLinearVelocity(velocity.x, velocity.y, velocity.z);
|
||||
}
|
||||
} else if (linearVelocityMax > 0.0 && speed > linearVelocityMax) {
|
||||
// Clamp velocity to maximum
|
||||
velocity.normalize();
|
||||
velocity.mult(linearVelocityMax);
|
||||
setLinearVelocity(velocity.x, velocity.y, velocity.z);
|
||||
}
|
||||
}
|
||||
|
||||
// Check angular velocity limits
|
||||
if (angularVelocityMin > 0.0 || angularVelocityMax > 0.0) {
|
||||
var angularVel = getAngularVelocity();
|
||||
var angularSpeed = angularVel.length();
|
||||
|
||||
if (angularVelocityMin > 0.0 && angularSpeed < angularVelocityMin) {
|
||||
// Increase angular velocity to minimum
|
||||
if (angularSpeed > 0.0) {
|
||||
angularVel.normalize();
|
||||
angularVel.mult(angularVelocityMin);
|
||||
setAngularVelocity(angularVel.x, angularVel.y, angularVel.z);
|
||||
}
|
||||
} else if (angularVelocityMax > 0.0 && angularSpeed > angularVelocityMax) {
|
||||
// Clamp angular velocity to maximum
|
||||
angularVel.normalize();
|
||||
angularVel.mult(angularVelocityMax);
|
||||
setAngularVelocity(angularVel.x, angularVel.y, angularVel.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function disableCollision() {
|
||||
@ -745,6 +842,16 @@ typedef RigidBodyParams = {
|
||||
var linearDeactivationThreshold: Float;
|
||||
var angularDeactivationThrshold: Float;
|
||||
var deactivationTime: Float;
|
||||
var linearVelocityMin: Float;
|
||||
var linearVelocityMax: Float;
|
||||
var angularVelocityMin: Float;
|
||||
var angularVelocityMax: Float;
|
||||
var lockTranslationX: Bool;
|
||||
var lockTranslationY: Bool;
|
||||
var lockTranslationZ: Bool;
|
||||
var lockRotationX: Bool;
|
||||
var lockRotationY: Bool;
|
||||
var lockRotationZ: Bool;
|
||||
}
|
||||
|
||||
typedef RigidBodyFlags = {
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -151,7 +151,7 @@ class LeenkxExporter:
|
||||
self.default_part_material_objects = []
|
||||
self.material_to_lnx_object_dict = {}
|
||||
# Stores the link between a blender object and its
|
||||
# corresponding export data (arm object)
|
||||
# corresponding export data (lnx object)
|
||||
self.object_to_lnx_object_dict: Dict[bpy.types.Object, Dict] = {}
|
||||
|
||||
self.bone_tracks = []
|
||||
@ -540,8 +540,16 @@ class LeenkxExporter:
|
||||
o['material_refs'].append(lnx.utils.asset_name(material))
|
||||
|
||||
def export_particle_system_ref(self, psys: bpy.types.ParticleSystem, out_object):
|
||||
if psys.settings.instance_object is None or psys.settings.render_type != 'OBJECT' or not psys.settings.instance_object.lnx_export or not bpy.data.objects[out_object['name']].modifiers[psys.name].show_render:
|
||||
if psys.settings.instance_object is None or psys.settings.render_type != 'OBJECT' or not psys.settings.instance_object.lnx_export:
|
||||
return
|
||||
|
||||
for obj in bpy.data.objects:
|
||||
if obj.name == out_object['name']:
|
||||
for mod in obj.modifiers:
|
||||
if mod.type == 'PARTICLE_SYSTEM':
|
||||
if mod.particle_system.name == psys.name:
|
||||
if not mod.show_render:
|
||||
return
|
||||
|
||||
self.particle_system_array[psys.settings] = {"structName": psys.settings.name}
|
||||
pref = {
|
||||
@ -630,7 +638,10 @@ class LeenkxExporter:
|
||||
continue
|
||||
|
||||
for slot in bobject.material_slots:
|
||||
if slot.material is None or slot.material.library is not None:
|
||||
if slot.material is None:
|
||||
continue
|
||||
if slot.material.library is not None:
|
||||
slot.material.lnx_particle_flag = True
|
||||
continue
|
||||
if slot.material.name.endswith(variant_suffix):
|
||||
continue
|
||||
@ -835,6 +846,13 @@ class LeenkxExporter:
|
||||
}
|
||||
out_object['vertex_groups'].append(out_vertex_groups)
|
||||
|
||||
if len(bobject.lnx_camera_list) > 0:
|
||||
out_camera_list = []
|
||||
for camera in bobject.lnx_camera_list:
|
||||
if camera.lnx_camera_object_ptr != None:
|
||||
out_camera_list.append(camera.lnx_camera_object_ptr.name)
|
||||
if len(out_camera_list) > 0:
|
||||
out_object['camera_list'] = out_camera_list
|
||||
|
||||
if len(bobject.lnx_propertylist) > 0:
|
||||
out_object['properties'] = []
|
||||
@ -910,8 +928,12 @@ class LeenkxExporter:
|
||||
out_object['particle_refs'] = []
|
||||
out_object['render_emitter'] = bobject.show_instancer_for_render
|
||||
for i in range(num_psys):
|
||||
if bobject.modifiers[bobject.particle_systems[i].name].show_render:
|
||||
self.export_particle_system_ref(bobject.particle_systems[i], out_object)
|
||||
for obj in bpy.data.objects:
|
||||
for mod in obj.modifiers:
|
||||
if mod.type == 'PARTICLE_SYSTEM':
|
||||
if mod.particle_system.name == bobject.particle_systems[i].name:
|
||||
if mod.show_render:
|
||||
self.export_particle_system_ref(bobject.particle_systems[i], out_object)
|
||||
|
||||
aabb = bobject.data.lnx_aabb
|
||||
if aabb[0] == 0 and aabb[1] == 0 and aabb[2] == 0:
|
||||
@ -2282,12 +2304,12 @@ class LeenkxExporter:
|
||||
self.output['particle_datas'] = []
|
||||
for particleRef in self.particle_system_array.items():
|
||||
padd = False;
|
||||
for obj in self.output['objects']:
|
||||
if 'particle_refs' in obj:
|
||||
for pref in obj['particle_refs']:
|
||||
if pref['particle'] == particleRef[1]["structName"]:
|
||||
if bpy.data.objects[obj['name']].modifiers[pref['name']].show_render == True:
|
||||
padd = True;
|
||||
for obj in bpy.data.objects:
|
||||
for mod in obj.modifiers:
|
||||
if mod.type == 'PARTICLE_SYSTEM':
|
||||
if mod.particle_system.settings.name == particleRef[1]["structName"]:
|
||||
if mod.show_render:
|
||||
padd = True
|
||||
if not padd:
|
||||
continue;
|
||||
psettings = particleRef[0]
|
||||
@ -2821,6 +2843,18 @@ class LeenkxExporter:
|
||||
body_params['linearDeactivationThreshold'] = deact_lv
|
||||
body_params['angularDeactivationThrshold'] = deact_av
|
||||
body_params['deactivationTime'] = deact_time
|
||||
# New velocity limit properties
|
||||
body_params['linearVelocityMin'] = bobject.lnx_rb_linear_velocity_min
|
||||
body_params['linearVelocityMax'] = bobject.lnx_rb_linear_velocity_max
|
||||
body_params['angularVelocityMin'] = bobject.lnx_rb_angular_velocity_min
|
||||
body_params['angularVelocityMax'] = bobject.lnx_rb_angular_velocity_max
|
||||
# New lock properties
|
||||
body_params['lockTranslationX'] = bobject.lnx_rb_lock_translation_x
|
||||
body_params['lockTranslationY'] = bobject.lnx_rb_lock_translation_y
|
||||
body_params['lockTranslationZ'] = bobject.lnx_rb_lock_translation_z
|
||||
body_params['lockRotationX'] = bobject.lnx_rb_lock_rotation_x
|
||||
body_params['lockRotationY'] = bobject.lnx_rb_lock_rotation_y
|
||||
body_params['lockRotationZ'] = bobject.lnx_rb_lock_rotation_z
|
||||
body_flags = {}
|
||||
body_flags['animated'] = rb.kinematic
|
||||
body_flags['trigger'] = bobject.lnx_rb_trigger
|
||||
@ -2981,7 +3015,10 @@ class LeenkxExporter:
|
||||
# mesh = obj.data
|
||||
# for face in mesh.faces:
|
||||
# face.v.reverse()
|
||||
# bpy.ops.export_scene.obj(override, use_selection=True, filepath=nav_filepath, check_existing=False, use_normals=False, use_uvs=False, use_materials=False)
|
||||
# if bpy.app.version[0] >= 4:
|
||||
# bpy.ops.wm.obj_export(override, use_selection=True, filepath=nav_filepath, check_existing=False, use_normals=False, use_uvs=False, use_materials=False)
|
||||
# else:
|
||||
# bpy.ops.export_scene.obj(override, use_selection=True, filepath=nav_filepath, check_existing=False, use_normals=False, use_uvs=False, use_materials=False)
|
||||
# bobject.scale.y *= -1
|
||||
armature = bobject.find_armature()
|
||||
apply_modifiers = not armature
|
||||
@ -3020,6 +3057,8 @@ class LeenkxExporter:
|
||||
|
||||
if trait_prop.type.endswith("Object"):
|
||||
value = lnx.utils.asset_name(trait_prop.value_object)
|
||||
elif trait_prop.type == "TSceneFormat":
|
||||
value = lnx.utils.asset_name(trait_prop.value_scene)
|
||||
else:
|
||||
value = trait_prop.get_value()
|
||||
|
||||
|
@ -2,7 +2,10 @@ import importlib
|
||||
import os
|
||||
import queue
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import types
|
||||
from typing import Dict, Tuple, Callable, Set
|
||||
|
||||
import bpy
|
||||
from bpy.app.handlers import persistent
|
||||
@ -30,6 +33,10 @@ if lnx.is_reload(__name__):
|
||||
else:
|
||||
lnx.enable_reload(__name__)
|
||||
|
||||
# Module-level storage for active threads (eliminates re-queuing overhead)
|
||||
_active_threads: Dict[threading.Thread, Callable] = {}
|
||||
_last_poll_time = 0.0
|
||||
_consecutive_empty_polls = 0
|
||||
|
||||
@persistent
|
||||
def on_depsgraph_update_post(self):
|
||||
@ -135,35 +142,113 @@ def always() -> float:
|
||||
|
||||
|
||||
def poll_threads() -> float:
|
||||
"""Polls the thread callback queue and if a thread has finished, it
|
||||
is joined with the main thread and the corresponding callback is
|
||||
executed in the main thread.
|
||||
"""
|
||||
Improved thread polling with:
|
||||
- No re-queuing overhead
|
||||
- Batch processing of completed threads
|
||||
- Adaptive timing based on activity
|
||||
- Better memory management
|
||||
- Simplified logic flow
|
||||
"""
|
||||
global _last_poll_time, _consecutive_empty_polls
|
||||
current_time = time.time()
|
||||
|
||||
# Process all new threads from queue at once (batch processing)
|
||||
new_threads_added = 0
|
||||
try:
|
||||
thread, callback = make.thread_callback_queue.get(block=False)
|
||||
while True:
|
||||
thread, callback = make.thread_callback_queue.get(block=False)
|
||||
_active_threads[thread] = callback
|
||||
new_threads_added += 1
|
||||
except queue.Empty:
|
||||
pass
|
||||
|
||||
# Early return if no active threads
|
||||
if not _active_threads:
|
||||
_consecutive_empty_polls += 1
|
||||
# Adaptive timing: longer intervals when consistently empty
|
||||
if _consecutive_empty_polls > 10:
|
||||
return 0.5 # Back off when no activity
|
||||
return 0.25
|
||||
if thread.is_alive():
|
||||
try:
|
||||
make.thread_callback_queue.put((thread, callback), block=False)
|
||||
except queue.Full:
|
||||
return 0.5
|
||||
return 0.1
|
||||
|
||||
# Reset empty poll counter when we have active threads
|
||||
_consecutive_empty_polls = 0
|
||||
|
||||
# Find completed threads (single pass, no re-queuing)
|
||||
completed_threads = []
|
||||
for thread in list(_active_threads.keys()):
|
||||
if not thread.is_alive():
|
||||
completed_threads.append(thread)
|
||||
|
||||
# Batch process all completed threads
|
||||
if completed_threads:
|
||||
_process_completed_threads(completed_threads)
|
||||
|
||||
# Adaptive timing based on activity level
|
||||
active_count = len(_active_threads)
|
||||
if active_count == 0:
|
||||
return 0.25
|
||||
elif active_count <= 3:
|
||||
return 0.05 # Medium frequency for low activity
|
||||
else:
|
||||
return 0.01 # High frequency for high activity
|
||||
|
||||
def _process_completed_threads(completed_threads: list) -> None:
|
||||
"""Process a batch of completed threads with robust error handling."""
|
||||
for thread in completed_threads:
|
||||
callback = _active_threads.pop(thread) # Remove from tracking
|
||||
|
||||
try:
|
||||
thread.join()
|
||||
thread.join() # Should be instant since thread is dead
|
||||
callback()
|
||||
except Exception as e:
|
||||
# If there is an exception, we can no longer return the time to
|
||||
# the next call to this polling function, so to keep it running
|
||||
# we re-register it and then raise the original exception.
|
||||
try:
|
||||
bpy.app.timers.unregister(poll_threads)
|
||||
except ValueError:
|
||||
pass
|
||||
bpy.app.timers.register(poll_threads, first_interval=0.01, persistent=True)
|
||||
# Quickly check if another thread has finished
|
||||
return 0.01
|
||||
# Robust error recovery
|
||||
_handle_callback_error(e)
|
||||
continue # Continue processing other threads
|
||||
|
||||
# Explicit cleanup for better memory management
|
||||
del thread, callback
|
||||
|
||||
def _handle_callback_error(exception: Exception) -> None:
|
||||
"""Centralized error handling with better recovery."""
|
||||
try:
|
||||
# Try to unregister existing timer
|
||||
bpy.app.timers.unregister(poll_threads)
|
||||
except ValueError:
|
||||
pass # Timer wasn't registered, that's fine
|
||||
|
||||
# Re-register timer with slightly longer interval for stability
|
||||
bpy.app.timers.register(poll_threads, first_interval=0.1, persistent=True)
|
||||
|
||||
# Re-raise the original exception after ensuring timer continuity
|
||||
raise exception
|
||||
|
||||
def cleanup_polling_system() -> None:
|
||||
"""Optional cleanup function for proper shutdown."""
|
||||
global _active_threads, _consecutive_empty_polls
|
||||
|
||||
# Wait for remaining threads to complete (with timeout)
|
||||
for thread in list(_active_threads.keys()):
|
||||
if thread.is_alive():
|
||||
thread.join(timeout=1.0) # 1 second timeout
|
||||
|
||||
# Clear tracking structures
|
||||
_active_threads.clear()
|
||||
_consecutive_empty_polls = 0
|
||||
|
||||
# Unregister timer
|
||||
try:
|
||||
bpy.app.timers.unregister(poll_threads)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def get_polling_stats() -> dict:
|
||||
"""Get statistics about the polling system for monitoring."""
|
||||
return {
|
||||
'active_threads': len(_active_threads),
|
||||
'consecutive_empty_polls': _consecutive_empty_polls,
|
||||
'thread_ids': [t.ident for t in _active_threads.keys()]
|
||||
}
|
||||
|
||||
|
||||
loaded_py_libraries: dict[str, types.ModuleType] = {}
|
||||
|
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user