From 8a699f01c224e37168fda66ea795d4eac30649bd Mon Sep 17 00:00:00 2001 From: e2002e Date: Mon, 2 Sep 2024 11:52:09 +0200 Subject: [PATCH] patch voxels and refraction --- .../deferred_light/deferred_light.frag.glsl | 55 ++- Shaders/ssr_pass/ssr_pass.frag.glsl | 2 +- Shaders/ssrefr_pass/ssrefr_pass.frag.glsl | 28 +- Shaders/std/conetrace.glsl | 77 ++-- Shaders/std/light.glsl | 9 +- Shaders/voxel_light/voxel_light.comp.glsl | 19 +- .../voxel_offsetprev.comp.glsl | 4 +- .../voxel_resolve_ao.comp.glsl | 2 +- .../voxel_resolve_refraction.comp.glsl | 79 ++++ .../voxel_resolve_shadows.comp.glsl | 75 ++++ .../voxel_temporal/voxel_temporal.comp.glsl | 149 ++----- Sources/armory/logicnode/StringCharAtNode.hx | 21 + Sources/armory/network/WebSocket.hx | 6 +- Sources/armory/renderpath/Inc.hx | 386 +++++++++++++----- .../armory/renderpath/RenderPathDeferred.hx | 35 +- .../armory/renderpath/RenderPathForward.hx | 67 ++- blender/arm/exporter.py | 18 +- blender/arm/logicnode/__init__.py | 2 +- blender/arm/logicnode/arm_sockets.py | 64 ++- blender/arm/logicnode/logic/LN_select.py | 5 +- .../arm/logicnode/string/LN_string_charat.py | 18 + blender/arm/make_renderpath.py | 65 +-- .../material/cycles_nodes/nodes_converter.py | 36 +- .../arm/material/cycles_nodes/nodes_shader.py | 142 ++++--- .../material/cycles_nodes/nodes_texture.py | 33 +- blender/arm/material/make_cluster.py | 6 +- blender/arm/material/make_depth.py | 2 +- blender/arm/material/make_finalize.py | 2 +- blender/arm/material/make_mesh.py | 109 +++-- blender/arm/material/make_refract.py | 1 + .../arm/material/make_refraction_buffer.py | 54 +++ blender/arm/material/make_transluc.py | 38 +- blender/arm/material/make_voxel.py | 148 ++++--- blender/arm/material/mat_utils.py | 1 + blender/arm/material/node_meta.py | 12 +- blender/arm/nodes_logic.py | 5 +- blender/arm/props.py | 3 +- blender/arm/props_renderpath.py | 33 +- blender/arm/props_ui.py | 16 +- blender/arm/utils.py | 2 +- blender/arm/write_data.py | 38 +- blender/arm/write_probes.py | 10 +- 42 files changed, 1208 insertions(+), 669 deletions(-) create mode 100644 Shaders/voxel_resolve_refraction/voxel_resolve_refraction.comp.glsl create mode 100644 Shaders/voxel_resolve_shadows/voxel_resolve_shadows.comp.glsl create mode 100644 Sources/armory/logicnode/StringCharAtNode.hx create mode 100644 blender/arm/logicnode/string/LN_string_charat.py create mode 100644 blender/arm/material/make_refraction_buffer.py diff --git a/Shaders/deferred_light/deferred_light.frag.glsl b/Shaders/deferred_light/deferred_light.frag.glsl index 9c2acaa656..65f96b91b7 100644 --- a/Shaders/deferred_light/deferred_light.frag.glsl +++ b/Shaders/deferred_light/deferred_light.frag.glsl @@ -8,9 +8,6 @@ #ifdef _Irr #include "std/shirr.glsl" #endif -#ifdef _VoxelShadow -#include "std/conetrace.glsl" -#endif #ifdef _SSS #include "std/sss.glsl" #endif @@ -37,9 +34,7 @@ uniform sampler2D voxels_specular; uniform sampler2D voxels_ao; #endif #ifdef _VoxelShadow -uniform float clipmaps[voxelgiClipmapCount * 10]; -uniform sampler3D voxels; -uniform sampler3D voxelsSDF; +uniform sampler2D voxels_shadows; #endif uniform float envmapStrength; @@ -130,7 +125,7 @@ uniform vec2 cameraPlane; #ifndef _SingleAtlas //!uniform sampler2DShadow shadowMapAtlasPoint; #endif - //!uniform vec4 pointLightDataArray[4]; + //!uniform vec4 pointLightDataArray[maxLightsCluster * 6]; #else //!uniform samplerCubeShadow shadowMapPoint[4]; #endif @@ -143,7 +138,7 @@ uniform vec2 cameraPlane; #else //!uniform sampler2DShadow shadowMapSpot[4]; #endif - //!uniform mat4 LWVPSpotArray[4]; + //!uniform mat4 LWVPSpotArray[maxLightsCluster]; #endif #endif #endif @@ -277,13 +272,13 @@ void main() { envl.rgb *= envmapStrength * occspec.x; #ifdef _VoxelGI - fragColor.rgb = textureLod(voxels_diffuse, texCoord, 0.0).rgb * voxelgiDiff * albedo; + fragColor.rgb = textureLod(voxels_diffuse, texCoord, 0.0).rgb * albedo * voxelgiDiff; if(roughness < 1.0 && occspec.y > 0.0) - fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * voxelgiRefl * occspec.y; + fragColor.rgb += textureLod(voxels_specular, texCoord, 0.0).rgb * occspec.y * voxelgiRefl; #endif #ifdef _VoxelAOvar - envl.rgb *= 1.0 - textureLod(voxels_ao, texCoord, 0.0).r; + envl.rgb *= textureLod(voxels_ao, texCoord, 0.0).r; #endif #ifndef _VoxelGI @@ -353,23 +348,25 @@ void main() { ); #else vec4 lPos = LWVP * vec4(p + n * shadowsBias * 100, 1.0); - if (lPos.w > 0.0) svisibility = shadowTest( - #ifdef _ShadowMapAtlas - #ifndef _SingleAtlas - shadowMapAtlasSun + if (lPos.w > 0.0) { + svisibility = shadowTest( + #ifdef _ShadowMapAtlas + #ifndef _SingleAtlas + shadowMapAtlasSun + #else + shadowMapAtlas + #endif #else - shadowMapAtlas + shadowMap #endif - #else - shadowMap - #endif - , lPos.xyz / lPos.w, shadowsBias - ); + , lPos.xyz / lPos.w, shadowsBias + ); + } #endif #endif #ifdef _VoxelShadow - svisibility *= 1.0 - traceShadow(p, n, voxels, voxelsSDF, sunDir, clipmaps); + svisibility *= textureLod(voxels_shadows, texCoord, 0.0).r * voxelgiShad; #endif #ifdef _SSRS @@ -388,7 +385,7 @@ void main() { svisibility *= clamp(sdotNL + 2.0 * occspec.x * occspec.x - 1.0, 0.0, 1.0); #endif - fragColor.rgb += sdirect * svisibility * sunCol; + fragColor.rgb += sdirect * sunCol * svisibility; // #ifdef _Hair // Aniso // if (matid == 2) { @@ -417,7 +414,7 @@ void main() { #else shadowMap #endif - ); + );//TODO implement transparent shadowmaps into the SSSSTransmittance() } #endif @@ -434,9 +431,7 @@ void main() { , true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight #endif #ifdef _VoxelShadow - , voxels - , voxelsSDF - , clipmaps + , texCoord #endif #ifdef _MicroShadowing , occspec.x @@ -448,7 +443,7 @@ void main() { #ifdef _Spot #ifdef _SSS - if (matid == 2) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot0, p, n, normalize(pointPos - p), lightPlane.y, shadowMapSpot[0]); + if (matid == 2) fragColor.rgb += fragColor.rgb * SSSSTransmittance(LWVPSpot0, p, n, normalize(pointPos - p), lightPlane.y, shadowMapSpot[0]);//TODO implement transparent shadowmaps into the SSSSTransmittance() #endif #endif @@ -494,9 +489,7 @@ void main() { , lightsArraySpot[li * 2 + 1].xyz // right #endif #ifdef _VoxelShadow - , voxels - , voxelsSDF - , clipmaps + , texCoord #endif #ifdef _MicroShadowing , occspec.x diff --git a/Shaders/ssr_pass/ssr_pass.frag.glsl b/Shaders/ssr_pass/ssr_pass.frag.glsl index 138056afdd..84aa2fab3b 100644 --- a/Shaders/ssr_pass/ssr_pass.frag.glsl +++ b/Shaders/ssr_pass/ssr_pass.frag.glsl @@ -92,7 +92,7 @@ void main() { vec3 viewNormal = V3 * n; vec3 viewPos = getPosView(viewRay, d, cameraProj); - vec3 reflected = reflect(normalize(viewPos), viewNormal); + vec3 reflected = reflect(viewPos, viewNormal); hitCoord = viewPos; #ifdef _CPostprocess diff --git a/Shaders/ssrefr_pass/ssrefr_pass.frag.glsl b/Shaders/ssrefr_pass/ssrefr_pass.frag.glsl index f1b4d426d9..3505cc9e08 100644 --- a/Shaders/ssrefr_pass/ssrefr_pass.frag.glsl +++ b/Shaders/ssrefr_pass/ssrefr_pass.frag.glsl @@ -1,3 +1,6 @@ +//https://lettier.github.io/3d-game-shaders-for-beginners/screen-space-refraction.html +//Implemented by Yvain Douard. + #version 450 #include "compiled.inc" @@ -35,7 +38,7 @@ vec2 getProjectedCoord(const vec3 hit) { } float getDeltaDepth(const vec3 hit) { - depth = textureLod(gbufferD1, getProjectedCoord(hit), 0.0).r * 2.0 - 1.0; + float depth = textureLod(gbufferD1, getProjectedCoord(hit), 0.0).r * 2.0 - 1.0; vec3 viewPos = getPosView(viewRay, depth, cameraProj); return viewPos.z - hit.z; } @@ -48,7 +51,7 @@ vec4 binarySearch(vec3 dir) { ddepth = getDeltaDepth(hitCoord); if (ddepth < 0.0) hitCoord += dir; } - if (abs(ddepth) > ss_refractionSearchDist / 500) return vec4(0.0); + if (abs(ddepth) > ss_refractionSearchDist) return vec4(0.0); return vec4(getProjectedCoord(hitCoord), 0.0, 1.0); } @@ -72,7 +75,11 @@ void main() { float d = textureLod(gbufferD, texCoord, 0.0).r * 2.0 - 1.0; - if (d == 1.0 || ior == 1.0 || opac == 1.0) { + if (opac == 1.0) { + fragColor.rgb = textureLod(tex, texCoord, 0.0).rgb; + return; + } + if (d == 1.0 || d == 0.0 || ior == 1.0) { fragColor.rgb = textureLod(tex1, texCoord, 0.0).rgb; return; } @@ -85,22 +92,13 @@ void main() { vec3 viewNormal = V3 * n; vec3 viewPos = getPosView(viewRay, d, cameraProj); - vec3 refracted = refract(normalize(viewPos), viewNormal, 1.0 / ior); + vec3 refracted = refract(viewPos, viewNormal, 1.0 / ior); hitCoord = viewPos; vec3 dir = refracted * (1.0 - rand(texCoord) * ss_refractionJitter * roughness) * 2.0; - vec4 coords = rayCast(dir); - vec2 deltaCoords = abs(vec2(0.5, 0.5) - coords.xy); - float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0); - - float refractivity = 1.0; - - float intensity = pow(refractivity, ss_refractionFalloffExp) * screenEdgeFactor * clamp((ss_refractionSearchDist - length(viewPos - hitCoord)) * (1.0 / ss_refractionSearchDist), 0.0, 1.0) * coords.w; - intensity = clamp(intensity, 0.0, 1.0); vec3 refractionCol = textureLod(tex1, coords.xy, 0.0).rgb; - refractionCol = clamp(refractionCol, 0.0, 1.0); - vec3 color = textureLod(tex, texCoord.xy, 0.0).rgb; - fragColor.rgb = mix(refractionCol * intensity, color, opac); + vec3 color = textureLod(tex, texCoord.xy, 0.0).rgb; + fragColor.rgb = mix(refractionCol, color, opac); } diff --git a/Shaders/std/conetrace.glsl b/Shaders/std/conetrace.glsl index c56edae380..ea93159d77 100644 --- a/Shaders/std/conetrace.glsl +++ b/Shaders/std/conetrace.glsl @@ -33,7 +33,7 @@ THE SOFTWARE. // http://www.seas.upenn.edu/%7Epcozzi/OpenGLInsights/OpenGLInsights-SparseVoxelization.pdf // https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf -const float MAX_DISTANCE = voxelgiRange * 100.0; +const float MAX_DISTANCE = voxelgiRange; #ifdef _VoxelGI uniform sampler3D dummy; @@ -93,7 +93,7 @@ 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; @@ -157,42 +157,49 @@ vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, if (cosTheta <= 0) continue; int precomputed_direction = 6 + i; - amount += traceCone(voxels, dummy, origin, normal, coneDir, precomputed_direction, false, DIFFUSE_CONE_APERTURE, 1, clipmaps) * cosTheta; + amount += traceCone(voxels, dummy, origin, normal, coneDir, precomputed_direction, false, DIFFUSE_CONE_APERTURE, 1.0, clipmaps) * cosTheta; sum += cosTheta; } + amount /= sum; amount.rgb = max(vec3(0.0), amount.rgb); amount.a = clamp(amount.a, 0.0, 1.0); + return amount * voxelgiOcc; } 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) { - vec3 specularDir = reflect(-viewDir, normal); - vec3 P = origin;// + specularDir * (BayerMatrix8[int(pixel.x) % 8][int(pixel.y) % 8] - 0.5) * voxelgiStep; + vec3 specularDir = normalize(reflect(-viewDir, normal)); + vec3 P = origin + specularDir * (BayerMatrix8[int(pixel.x) % 8][int(pixel.y) % 8] - 0.5) * voxelgiStep; vec4 amount = traceCone(voxels, voxelsSDF, P, normal, specularDir, 0, true, roughness, voxelgiStep, clipmaps); amount.rgb = max(vec3(0.0), amount.rgb); amount.a = clamp(amount.a, 0.0, 1.0); + return amount * voxelgiOcc; } -/* -vec3 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]) { +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 float transmittance = 1.0; vec3 refractionDir = refract(viewDir, normal, 1.0 / ior); - return transmittance * traceCone(voxels, origin, normal, refractionDir, 0, roughness, voxelgiStep, clipmaps).xyz * voxelgiOcc; + vec3 P = origin + refractionDir * (BayerMatrix8[int(pixel.x) % 8][int(pixel.y) % 8] - 0.5) * voxelgiStep; + vec4 amount = transmittance * traceCone(voxels, voxelsSDF, P, normal, refractionDir, 0, true, roughness, voxelgiStep, clipmaps); + + amount.rgb = max(vec3(0.0), amount.rgb); + amount.a = clamp(amount.a, 0.0, 1.0); + + return amount * voxelgiOcc; } -*/ #endif #ifdef _VoxelAOvar -float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const vec3 dir, const int precomputed_direction, const float aperture, const float clipmaps[voxelgiClipmapCount * 10]) { - float opacity = 0.0; +float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const vec3 dir, const int precomputed_direction, const float aperture, const float step_size, const float clipmaps[voxelgiClipmapCount * 10]) { + float sampleCol = 0.0; float voxelSize0 = float(clipmaps[0]) * 2.0; 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; @@ -205,7 +212,7 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const float coneCoefficient = 2.0 * tan(aperture * 0.5); - while (opacity < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) { + while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) { float mipSample = 0.0; float diam = max(voxelSize0, dist * coneCoefficient); float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1); @@ -228,13 +235,12 @@ float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const mipSample = mix(mipSample, mipSampleNext, clipmap_blend); } - float a = 1.0 - opacity; - opacity += a * mipSample; + sampleCol += (1.0 - sampleCol) * mipSample; - step_dist = diam; + step_dist = diam * step_size; dist += step_dist; } - return opacity; + return sampleCol; } @@ -247,11 +253,11 @@ float traceAO(const vec3 origin, const vec3 normal, const sampler3D voxels, cons const float cosTheta = dot(normal, coneDir); if (cosTheta <= 0) continue; - amount += traceConeAO(voxels, origin, normal, coneDir, precomputed_direction, DIFFUSE_CONE_APERTURE, clipmaps) * cosTheta; + amount += traceConeAO(voxels, origin, normal, coneDir, precomputed_direction, DIFFUSE_CONE_APERTURE, voxelgiStep, clipmaps) * cosTheta; sum += cosTheta; } amount /= sum; - amount = max(0.0, amount); + amount = clamp(amount, 0.0, 1.0); return amount * voxelgiOcc; } #endif @@ -259,12 +265,12 @@ float traceAO(const vec3 origin, const vec3 normal, const sampler3D voxels, cons #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 opacity = 0.0; + float sampleCol = 0.0; float voxelSize0 = float(clipmaps[0]) * 2.0; 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; @@ -275,7 +281,7 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v ) / (6 + DIFFUSE_CONE_COUNT); vec3 direction_weight = abs(dir); - while (opacity < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) { + while (sampleCol < 1.0 && dist < MAX_DISTANCE * 100 && clipmap_index0 < voxelgiClipmapCount) { float mipSample = 0.0; float diam = max(voxelSize0, dist * 2.0 * tan(aperture * 0.5)); float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1); @@ -306,29 +312,28 @@ float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const v mipSample = mix(mipSample, mipSampleNext, clipmap_blend); } - float a = 1.0 - opacity; - opacity += a * mipSample; + sampleCol += (1.0 - sampleCol) * mipSample; float stepSizeCurrent = step_size; - if (true) { - // half texel correction is applied to avoid sampling over current clipmap: - const vec3 half_texel = vec3(0.5) / voxelgiResolution; - vec3 tc0 = clamp(samplePos, half_texel, 1 - half_texel); - tc0.y = (tc0.y + clipmap_index) / voxelgiClipmapCount; // remap into clipmap - float sdf = textureLod(voxelsSDF, tc0, 0.0).r; - stepSizeCurrent = max(step_size, sdf - diam); - } + // half texel correction is applied to avoid sampling over current clipmap: + const vec3 half_texel = vec3(0.5) / voxelgiResolution; + vec3 tc0 = clamp(samplePos, half_texel, 1 - half_texel); + tc0.y = (tc0.y + clipmap_index) / voxelgiClipmapCount; // remap into clipmap + float sdf = textureLod(voxelsSDF, tc0, 0.0).r; + stepSizeCurrent = max(step_size, sdf - diam); + step_dist = diam * stepSizeCurrent; dist += step_dist; } - return opacity; + return sampleCol; } -float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10]) { - float amount = traceConeShadow(voxels, voxelsSDF, origin, normal, dir, DIFFUSE_CONE_APERTURE, voxelgiStep, clipmaps); - amount = max(0.0, amount); +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; } #endif diff --git a/Shaders/std/light.glsl b/Shaders/std/light.glsl index b4f15e2194..b08a2f3fd8 100644 --- a/Shaders/std/light.glsl +++ b/Shaders/std/light.glsl @@ -8,7 +8,7 @@ #include "std/shadows.glsl" #endif #ifdef _VoxelShadow -#include "std/conetrace.glsl" +//!uniform sampler2D voxels_shadows; #endif #ifdef _LTC #include "std/ltc.glsl" @@ -90,9 +90,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co , bool isSpot, float spotSize, float spotBlend, vec3 spotDir, vec2 scale, vec3 right #endif #ifdef _VoxelShadow - , sampler3D voxels - , sampler3D voxelsSDF - , float clipmaps[voxelgiClipmapCount * 10] + , vec2 texCoord #endif #ifdef _MicroShadowing , float occ @@ -125,7 +123,6 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co vec3 direct = lambertDiffuseBRDF(albedo, dotNL) + specularBRDF(f0, rough, dotNL, dotNH, dotNV, dotVH) * spec; #endif - direct *= attenuate(distance(p, lp)); direct *= lightCol; @@ -138,7 +135,7 @@ vec3 sampleLight(const vec3 p, const vec3 n, const vec3 v, const float dotNV, co #endif #ifdef _VoxelShadow - direct *= 1.0 - traceShadow(p, n, voxels, voxelsSDF, l, clipmaps); + direct *= textureLod(voxels_shadows, texCoord, 0.0).r * voxelgiShad; //TODO: Trace shadows directly for transparent objects. #endif #ifdef _LTC diff --git a/Shaders/voxel_light/voxel_light.comp.glsl b/Shaders/voxel_light/voxel_light.comp.glsl index 182c48f2df..15e418e81d 100644 --- a/Shaders/voxel_light/voxel_light.comp.glsl +++ b/Shaders/voxel_light/voxel_light.comp.glsl @@ -27,6 +27,7 @@ uniform float clipmaps[voxelgiClipmapCount * 10]; uniform int clipmapLevel; uniform layout(r32ui) uimage3D voxelsLight; +uniform layout(r32ui) uimage3D voxels; #ifdef _ShadowMap uniform sampler2DShadow shadowMap; @@ -83,7 +84,6 @@ float lpToDepth(vec3 lp, const vec2 lightProj) { void main() { int res = voxelgiResolution.x; - ivec3 dst = ivec3(gl_GlobalInvocationID.xyz); vec3 P = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution; @@ -92,13 +92,11 @@ void main() { P *= voxelgiResolution; P += vec3(clipmaps[int(clipmapLevel * 10 + 4)], clipmaps[int(clipmapLevel * 10 + 5)], clipmaps[int(clipmapLevel * 10 + 6)]); - vec4 light = vec4(0.0); - - float visibility; + vec3 visibility; vec3 lp = lightPos - P; vec3 l; - if (lightType == 0) { l = lightDir; visibility = 1.0; } - else { l = normalize(lp); visibility = attenuate(distance(P, lightPos)); } + if (lightType == 0) { l = lightDir; visibility = vec3(1.0); } + else { l = normalize(lp); visibility = vec3(attenuate(distance(P, lightPos))); } // float dotNL = max(dot(wnormal, l), 0.0); // if (dotNL == 0.0) return; @@ -107,7 +105,7 @@ void main() { if (lightShadow == 1) { 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(P, 1.0); @@ -138,8 +136,9 @@ void main() { } } - light.rgb += visibility * lightColor; - light = clamp(light, vec4(0.0), vec4(1.0)); + vec3 light = visibility * lightColor; - imageAtomicMax(voxelsLight, dst, convVec4ToRGBA8(light)); + imageAtomicAdd(voxelsLight, dst, 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)); } diff --git a/Shaders/voxel_offsetprev/voxel_offsetprev.comp.glsl b/Shaders/voxel_offsetprev/voxel_offsetprev.comp.glsl index b93e46fda8..bf6ac52d3f 100644 --- a/Shaders/voxel_offsetprev/voxel_offsetprev.comp.glsl +++ b/Shaders/voxel_offsetprev/voxel_offsetprev.comp.glsl @@ -33,8 +33,8 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; 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; diff --git a/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl b/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl index 030e7201d1..6abf9d1275 100644 --- a/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl +++ b/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl @@ -67,7 +67,7 @@ void main() { n.xy = n.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy); n = normalize(n); - float occ = traceAO(P, n, voxels, clipmaps); + float occ = 1.0 - traceAO(P, n, voxels, clipmaps); imageStore(voxels_ao, ivec2(pixel), vec4(occ)); } diff --git a/Shaders/voxel_resolve_refraction/voxel_resolve_refraction.comp.glsl b/Shaders/voxel_resolve_refraction/voxel_resolve_refraction.comp.glsl new file mode 100644 index 0000000000..c74ebaebae --- /dev/null +++ b/Shaders/voxel_resolve_refraction/voxel_resolve_refraction.comp.glsl @@ -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)); +} diff --git a/Shaders/voxel_resolve_shadows/voxel_resolve_shadows.comp.glsl b/Shaders/voxel_resolve_shadows/voxel_resolve_shadows.comp.glsl new file mode 100644 index 0000000000..c1e0af830d --- /dev/null +++ b/Shaders/voxel_resolve_shadows/voxel_resolve_shadows.comp.glsl @@ -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(r8) 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)); +} diff --git a/Shaders/voxel_temporal/voxel_temporal.comp.glsl b/Shaders/voxel_temporal/voxel_temporal.comp.glsl index 38080a79fe..f4538bc884 100644 --- a/Shaders/voxel_temporal/voxel_temporal.comp.glsl +++ b/Shaders/voxel_temporal/voxel_temporal.comp.glsl @@ -43,38 +43,9 @@ uniform mat4 LVP; #endif uniform sampler3D voxelsSampler; uniform layout(r32ui) uimage3D voxels; -uniform layout(rgba8) image3D voxelsB; uniform layout(r32ui) uimage3D voxelsLight; +uniform layout(rgba8) image3D voxelsB; uniform layout(rgba8) image3D voxelsOut; -#ifdef _ShadowMap -uniform sampler2DShadow shadowMap; -uniform sampler2DShadow shadowMapSpot; -uniform samplerCubeShadow shadowMapPoint; -#endif -#include "std/shirr.glsl" -uniform float envmapStrength; -#ifdef _Irr -uniform vec4 shirr[7]; -#endif -#ifdef _Brdf -uniform sampler2D senvmapBrdf; -#endif -#ifdef _Rad -uniform sampler2D senvmapRadiance; -uniform int envmapNumMipmaps; -#endif -#ifdef _EnvCol -uniform vec3 backgroundCol; -#endif -uniform sampler2D gbufferD; -uniform sampler2D gbuffer0; -uniform sampler2D gbuffer1; -#ifdef _gbuffer2 -#ifdef _Deferred -uniform sampler2D gbuffer2; -#endif -#endif -uniform vec3 eye; uniform layout(r8) image3D SDF; #else #ifdef _VoxelAOvar @@ -82,8 +53,8 @@ uniform layout(r8) image3D SDF; uniform layout(r8) 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 @@ -94,12 +65,6 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; void main() { int res = voxelgiResolution.x; - #ifdef _VoxelGI - vec4 aniso_colors[6]; - #else - float opac; - float aniso_colors[6]; - #endif #ifdef _VoxelGI float sdf = float(clipmaps[int(clipmapLevel * 10)]) * 2.0 * res; @@ -110,17 +75,28 @@ void main() { #endif #ifdef _VoxelGI - vec4 light = convRGBA8ToVec4(imageLoad(voxelsLight, ivec3(gl_GlobalInvocationID.xyz)).r); + vec3 light = vec3(0.0); + light.r = float(imageLoad(voxelsLight, ivec3(gl_GlobalInvocationID.xyz))) / 255; + light.g = float(imageLoad(voxelsLight, ivec3(gl_GlobalInvocationID.xyz) + ivec3(0, 0, voxelgiResolution.x))) / 255; + light.b = float(imageLoad(voxelsLight, ivec3(gl_GlobalInvocationID.xyz) + ivec3(0, 0, voxelgiResolution.x * 2))) / 255; + light /= 3; #endif for (int i = 0; i < 6 + DIFFUSE_CONE_COUNT; i++) { + #ifdef _VoxelGI + vec4 aniso_colors[6]; + #else + float aniso_colors[6]; + #endif + ivec3 src = ivec3(gl_GlobalInvocationID.xyz); src.x += i * res; ivec3 dst = src; dst.y += clipmapLevel * res; #ifdef _VoxelGI vec4 radiance = vec4(0.0); + vec4 bounce = vec4(0.0); #else float opac = 0.0; #endif @@ -143,6 +119,15 @@ void main() { 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; + + #ifdef _HOSEK + envl *= 100; + #endif //clipmap to world vec3 wposition = (gl_GlobalInvocationID.xyz + 0.5) / voxelgiResolution.x; @@ -151,95 +136,11 @@ void main() { wposition *= voxelgiResolution.x; wposition += vec3(clipmaps[clipmapLevel * 10 + 4], clipmaps[clipmapLevel * 10 + 5], clipmaps[clipmapLevel * 10 + 6]); - #ifdef _Deferred - const vec2 pixel = gl_GlobalInvocationID.xy; - const vec2 uv = (pixel + 0.5) / voxelgiResolution.xy; - - vec4 g0 = textureLod(gbuffer0, uv, 0.0); // Normal.xy, roughness, metallic/matid - 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 roughness = g0.b; - float metallic; - uint matid; - unpackFloatInt16(g0.a, metallic, matid); - - 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); - - vec3 v = normalize(eye - wposition); - float dotNV = max(dot(wnormal, v), 0.0); - - #ifdef _gbuffer2 - vec4 g2 = textureLod(gbuffer2, uv, 0.0); - #endif - - #ifdef _Brdf - vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy; - #endif - - // Envmap - #ifdef _Irr - vec3 envl = shIrradiance(wnormal, shirr); - - #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, wnormal); - 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 - (f0 * envBRDF.x + envBRDF.y); - #endif - - #ifdef _Rad // Indirect specular - envl.rgb += prefilteredColor * (f0 * envBRDF.x + envBRDF.y); - #else - #ifdef _EnvCol - envl.rgb += backgroundCol * (f0 * envBRDF.x + envBRDF.y); - #endif - #endif - - envl.rgb *= envmapStrength * occspec.x; - #else - vec3 envl = vec3(0.0); - #endif - radiance = basecol; - vec4 trace = traceDiffuse(wposition, wnormal, voxelsSampler, clipmaps); vec3 indirect = trace.rgb + envl.rgb * (1.0 - trace.a); - radiance.rgb *= light.rgb / PI + indirect.rgb; + radiance.rgb *= light.rgb + indirect.rgb; radiance.rgb += emission.rgb; - radiance = clamp(radiance, vec4(0.0), vec4(1.0)); #else opac = float(imageLoad(voxels, src)) / 255; diff --git a/Sources/armory/logicnode/StringCharAtNode.hx b/Sources/armory/logicnode/StringCharAtNode.hx new file mode 100644 index 0000000000..a72ea82094 --- /dev/null +++ b/Sources/armory/logicnode/StringCharAtNode.hx @@ -0,0 +1,21 @@ +package armory.logicnode; + +class StringCharAtNode extends LogicNode { + public var char: String; + + public function new(tree:LogicTree) { + super(tree); + } + + override function run(from:Int) { + var string: String = inputs[1].get(); + var index: Int = inputs[2].get(); + char = string.charAt(index); + runOutput(0); + } + + override function get(from: Int): String { + return char; + } + +} diff --git a/Sources/armory/network/WebSocket.hx b/Sources/armory/network/WebSocket.hx index 1946e03123..622e59c926 100644 --- a/Sources/armory/network/WebSocket.hx +++ b/Sources/armory/network/WebSocket.hx @@ -109,7 +109,7 @@ class WebSocket { _onmessage = value; _ws.onmessage = function(message: Dynamic) { if (_onmessage != null) { - if (Std.isOfType(message.data, JsBuffer)) { + if (message.data is JsBuffer) { var buffer = new Buffer(); buffer.writeBytes(Bytes.ofData(message.data)); _onmessage(BytesMessage(buffer)); @@ -141,10 +141,10 @@ class WebSocket { } public function send(msg:Any) { - if (Std.isOfType(msg, Bytes)) { + if (msg is Bytes) { var bytes = cast(msg, Bytes); _ws.send(bytes.getData()); - } else if (Std.isOfType(msg, Buffer)) { + } else if (msg is Buffer) { var buffer = cast(msg, Buffer); _ws.send(buffer.readAllAvailableBytes().getData()); } else { diff --git a/Sources/armory/renderpath/Inc.hx b/Sources/armory/renderpath/Inc.hx index a5ddb22e05..df1c59de29 100644 --- a/Sources/armory/renderpath/Inc.hx +++ b/Sources/armory/renderpath/Inc.hx @@ -35,26 +35,6 @@ class Inc { static var voxel_td1:kha.compute.TextureUnit; static var voxel_te1:kha.compute.TextureUnit; static var voxel_tf1:kha.compute.TextureUnit; - static var voxel_tg1:kha.compute.TextureUnit; - static var voxel_th1:kha.compute.TextureUnit; - #if (rp_gbuffer2 && arm_deferred) - static var voxel_ti1:kha.compute.TextureUnit; - #end - #if arm_brdf - static var voxel_tj1:kha.compute.TextureUnit; - #end - #if arm_radiance - static var voxel_tk1:kha.compute.TextureUnit; - static var voxel_ce1:kha.compute.ConstantLocation; - #end - #if arm_irradiance - static var voxel_cc1:kha.compute.ConstantLocation; - #end - static var voxel_cd1:kha.compute.ConstantLocation; - #if arm_envldr - static var voxel_cf1:kha.compute.ConstantLocation; - #end - static var voxel_cg1:kha.compute.ConstantLocation; #else #if arm_voxelgi_shadows static var voxel_tf1:kha.compute.TextureUnit; @@ -68,7 +48,6 @@ class Inc { static var voxel_cb2:kha.compute.ConstantLocation; static var voxel_cc2:kha.compute.ConstantLocation; #end - #if arm_deferred static var voxel_sh3:kha.compute.Shader = null; static var voxel_ta3:kha.compute.TextureUnit; static var voxel_tb3:kha.compute.TextureUnit; @@ -93,7 +72,36 @@ class Inc { static var voxel_cd4:kha.compute.ConstantLocation; static var voxel_ce4:kha.compute.ConstantLocation; static var voxel_cf4:kha.compute.ConstantLocation; + #if arm_voxelgi_refract + static var voxel_sh6:kha.compute.Shader = null; + static var voxel_ta6:kha.compute.TextureUnit; + static var voxel_tb6:kha.compute.TextureUnit; + static var voxel_tc6:kha.compute.TextureUnit; + static var voxel_td6:kha.compute.TextureUnit; + static var voxel_te6:kha.compute.TextureUnit; + static var voxel_tf6:kha.compute.TextureUnit; + static var voxel_ca6:kha.compute.ConstantLocation; + static var voxel_cb6:kha.compute.ConstantLocation; + static var voxel_cc6:kha.compute.ConstantLocation; + static var voxel_cd6:kha.compute.ConstantLocation; + static var voxel_ce6:kha.compute.ConstantLocation; + static var voxel_cf6:kha.compute.ConstantLocation; + #end #end + #if arm_voxelgi_shadows + static var voxel_sh7:kha.compute.Shader = null; + static var voxel_ta7:kha.compute.TextureUnit; + static var voxel_tb7:kha.compute.TextureUnit; + static var voxel_tc7:kha.compute.TextureUnit; + static var voxel_td7:kha.compute.TextureUnit; + static var voxel_te7:kha.compute.TextureUnit; + static var voxel_ca7:kha.compute.ConstantLocation; + static var voxel_cb7:kha.compute.ConstantLocation; + static var voxel_cc7:kha.compute.ConstantLocation; + static var voxel_cd7:kha.compute.ConstantLocation; + static var voxel_ce7:kha.compute.ConstantLocation; + static var voxel_cf7:kha.compute.ConstantLocation; + static var voxel_cg7:kha.compute.ConstantLocation; #end #if (rp_voxels == "Voxel GI") static var voxel_sh5:kha.compute.Shader = null; @@ -217,7 +225,7 @@ class Inc { return; lastFrame = RenderPath.active.frame; #end - // add new lights to the atlases + #if arm_debug beginShadowsLogicProfile(); // reset data on rejected lights @@ -225,6 +233,7 @@ class Inc { atlas.rejectedLights = []; } #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) { @@ -242,6 +251,7 @@ class Inc { var shadowmap = getShadowMapAtlas(atlas); path.setTargetStream(shadowmap); + path.clearTarget(null, 1.0); for (tile in atlas.activeTiles) { @@ -424,7 +434,6 @@ class Inc { if (l.data.raw.type == "point") pointIndex++; else if (l.data.raw.type == "spot" || l.data.raw.type == "area") spotIndex++; } - #end // rp_shadowmap } #end @@ -508,13 +517,14 @@ class Inc { #end } #end + #if (rp_voxels != "Off") path.bindTarget("voxelsOut", "voxels"); - #if (rp_voxels == "Voxel GI") path.bindTarget("voxelsSDF", "voxelsSDF"); #end - #end + path.drawMeshes("translucent"); + #if rp_render_to_texture { path.setTarget(target); @@ -566,19 +576,15 @@ class Inc { var res = iron.RenderPath.getVoxelRes(); var resZ = iron.RenderPath.getVoxelResZ(); - if (t.name == "voxels_diffuse" || t.name == "voxels_specular") { + if (t.name == "voxels_diffuse" || t.name == "voxels_specular" || t.name == "voxels_refraction" || t.name == "voxels_shadows" || t.name == "voxels_ao") { t.width = 0; t.height = 0; t.displayp = getDisplayp(); - t.scale = getSuperSampling(); - t.format = getHdrFormat(); - } - else if (t.name == "voxels_ao") { - t.width = 0; - t.height = 0; - t.displayp = getDisplayp(); - t.scale = getSuperSampling(); - t.format = "R8"; + //t.scale = Inc.getSuperSampling(); + if (t.name == "voxels_ao" || t.name == "voxels_shadows") + t.format = "R8"; + else + t.format = "RGBA32"; } else { if (t.name == "voxelsSDF" || t.name == "voxelsSDFtmp") { @@ -591,7 +597,7 @@ 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; @@ -606,29 +612,29 @@ class Inc { #else { if (t.name == "voxelsOut" || t.name == "voxelsOutB") { + t.format = "RGBA32"; t.width = res * (6 + 16); t.height = res * Main.voxelgiClipmapCount; - t.format = "RGBA32"; t.depth = res; } else if (t.name == "voxelsLight") { + t.format = "R32"; t.width = res; t.height = res; - t.format = "R32"; - t.depth = res; + t.depth = res * 3; } else { + t.format = "R32"; t.width = res * 6; t.height = res; - t.format = "R32"; - t.depth = res * 9; + t.depth = res * 12; } } #end } } - t.mipmaps = true; t.is_image = true; + t.mipmaps = false; path.createRenderTarget(t); } #end @@ -734,27 +740,6 @@ class Inc { voxel_td1 = voxel_sh1.getTextureUnit("voxelsSampler"); voxel_te1 = voxel_sh1.getTextureUnit("voxelsLight"); voxel_tf1 = voxel_sh1.getTextureUnit("SDF"); - - voxel_tg1 = voxel_sh1.getTextureUnit("gbuffer0"); - voxel_th1 = voxel_sh1.getTextureUnit("gbuffer1"); - #if (rp_gbuffer2 && arm_deferred) - voxel_ti1 = voxel_sh1.getTextureUnit("gbuffer2"); - #end - #if arm_brdf - voxel_tj1 = voxel_sh1.getTextureUnit("senvmapBrdf"); - #end - #if arm_radiance - voxel_tk1 = voxel_sh1.getTextureUnit("senvmapRadiance"); - voxel_ce1 = voxel_sh1.getConstantLocation("envmapNumMipmaps"); - #end - #if arm_irradiance - voxel_cc1 = voxel_sh1.getConstantLocation("shirr"); - #end - voxel_cd1 = voxel_sh1.getConstantLocation("envmapStrength"); - #if arm_envldr - voxel_cf1 = voxel_sh1.getConstantLocation("backgroundCol"); - #end - voxel_cg1 = voxel_sh1.getConstantLocation("eye"); #else #if arm_voxelgi_shadows voxel_tf1 = voxel_sh1.getTextureUnit("SDF"); @@ -773,7 +758,6 @@ class Inc { voxel_cc2 = voxel_sh2.getConstantLocation("jump_size"); } #end - #if arm_deferred if (voxel_sh3 == null) { #if (rp_voxels == "Voxel AO") @@ -805,18 +789,50 @@ class Inc { voxel_tc4 = voxel_sh4.getTextureUnit("gbuffer0"); voxel_td4 = voxel_sh4.getTextureUnit("voxelsSDF"); voxel_te4 = voxel_sh4.getTextureUnit("voxels_specular"); - voxel_ca4 = voxel_sh4.getConstantLocation("clipmaps"); voxel_cb4 = voxel_sh4.getConstantLocation("InvVP"); 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"); + #if arm_voxelgi_refract + voxel_sh6 = path.getComputeShader("voxel_resolve_refraction"); + voxel_ta6 = voxel_sh6.getTextureUnit("voxels"); + voxel_tb6 = voxel_sh6.getTextureUnit("gbufferD"); + voxel_tc6 = voxel_sh6.getTextureUnit("gbuffer0"); + voxel_td6 = voxel_sh6.getTextureUnit("voxelsSDF"); + voxel_te6 = voxel_sh6.getTextureUnit("voxels_refraction"); + voxel_tf6 = voxel_sh6.getTextureUnit("gbuffer_refraction"); + voxel_ca6 = voxel_sh6.getConstantLocation("clipmaps"); + voxel_cb6 = voxel_sh6.getConstantLocation("InvVP"); + voxel_cc6 = voxel_sh6.getConstantLocation("cameraProj"); + voxel_cd6 = voxel_sh6.getConstantLocation("eye"); + voxel_ce6 = voxel_sh6.getConstantLocation("eyeLook"); + voxel_cf6 = voxel_sh6.getConstantLocation("postprocess_resolution"); + #end + } + #end + #if arm_voxelgi_shadows + if (voxel_sh7 == null) + { + voxel_sh7 = path.getComputeShader("voxel_resolve_shadows"); + voxel_ta7 = voxel_sh7.getTextureUnit("voxels"); + voxel_tb7 = voxel_sh7.getTextureUnit("gbufferD"); + voxel_tc7 = voxel_sh7.getTextureUnit("gbuffer0"); + voxel_td7 = voxel_sh7.getTextureUnit("voxelsSDF"); + voxel_te7 = voxel_sh7.getTextureUnit("voxels_shadows"); + voxel_ca7 = voxel_sh7.getConstantLocation("clipmaps"); + voxel_cb7 = voxel_sh7.getConstantLocation("InvVP"); + voxel_cc7 = voxel_sh7.getConstantLocation("cameraProj"); + voxel_cd7 = voxel_sh7.getConstantLocation("eye"); + voxel_ce7 = voxel_sh7.getConstantLocation("eyeLook"); + voxel_cf7 = voxel_sh7.getConstantLocation("postprocess_resolution"); + voxel_cg7 = voxel_sh7.getConstantLocation("lPos"); } #end - #end // arm_deferred #if (rp_voxels == "Voxel GI") - if (voxel_sh5 == null) { + if (voxel_sh5 == null) + { voxel_sh5 = path.getComputeShader("voxel_light"); voxel_ta5 = voxel_sh5.getTextureUnit("voxelsLight"); @@ -918,42 +934,10 @@ class Inc { kha.compute.Compute.setInt(voxel_cb1, iron.RenderPath.clipmapLevel); - #if (rp_voxels == "Voxel GI" && arm_deferred) - kha.compute.Compute.setSampledTexture(voxel_tg1, rts.get("gbuffer0").image); - kha.compute.Compute.setSampledTexture(voxel_th1, rts.get("gbuffer1").image); - #if rp_gbuffer2 - kha.compute.Compute.setSampledTexture(voxel_ti1, rts.get("gbuffer2").image); - #end - #if arm_brdf - kha.compute.Compute.setSampledTexture(voxel_tj1, iron.Scene.active.embedded.get("brdf.png")); - #end - #if arm_radiance - kha.compute.Compute.setSampledTexture(voxel_tk1, iron.Scene.active.world.probe.radiance); - var w = iron.Scene.active.world; - var i = w != null ? w.probe.raw.radiance_mipmaps + 1 - 2 : 1; - kha.compute.Compute.setFloat(voxel_ce1, i); - #end - #if arm_irradiance - fa = iron.Scene.active.world == null ? iron.data.WorldData.getEmptyIrradiance() : iron.Scene.active.world.probe.irradiance; - kha.compute.Compute.setFloats(voxel_cc1, fa); - #end - kha.compute.Compute.setFloat(voxel_cd1, iron.Scene.active.world == null ? 0.0 : iron.Scene.active.world.probe.raw.strength); - - #if arm_envldr - var envCol:iron.math.Vec3; - if (camera.data.raw.clear_color != null) - envCol = new iron.math.Vec3(camera.data.raw.clear_color[0], camera.data.raw.clear_color[1], camera.data.raw.clear_color[2]); - else - envCol = new iron.math.Vec3(0.0); - kha.compute.Compute.setFloat3(voxel_cf1, envCol.x, envCol.y, envCol.z); - #end - kha.compute.Compute.setFloat3(voxel_cg1, camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz()); - #end - kha.compute.Compute.compute(Std.int(res / 8), Std.int(res / 8), Std.int(res / 8)); } - #if (arm_voxelgi_shadows || rp_voxels == "Voxel GI") + #if (arm_voxelgi_shadows || (rp_voxels == "Voxel GI")) public static function computeVoxelsSDF() { var rts = path.renderTargets; var res = iron.RenderPath.getVoxelRes(); @@ -1002,8 +986,6 @@ class Inc { } } #end - - #if arm_deferred #if (rp_voxels == "Voxel AO") public static function resolveAO() { var rts = path.renderTargets; @@ -1016,7 +998,11 @@ class Inc { kha.compute.Compute.setSampledTexture(voxel_ta3, rts.get("voxelsOut").image); kha.compute.Compute.setSampledTexture(voxel_tb3, rts.get("half").image); + #if arm_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); var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10); @@ -1073,9 +1059,8 @@ class Inc { } kha.compute.Compute.setFloat2(voxel_cf3, width, height); - kha.compute.Compute.compute(Std.int(width / 8), Std.int(height / 8), 1); + kha.compute.Compute.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1); } - #else public static function resolveDiffuse() { var rts = path.renderTargets; @@ -1088,7 +1073,11 @@ class Inc { kha.compute.Compute.setSampledTexture(voxel_ta3, rts.get("voxelsOut").image); kha.compute.Compute.setSampledTexture(voxel_tb3, rts.get("half").image); + #if arm_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); var fa:Float32Array = new Float32Array(Main.voxelgiClipmapCount * 10); @@ -1145,7 +1134,7 @@ class Inc { } kha.compute.Compute.setFloat2(voxel_cf3, width, height); - kha.compute.Compute.compute(Std.int(width / 8), Std.int(height / 8), 1); + kha.compute.Compute.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1); } public static function resolveSpecular() { @@ -1159,7 +1148,11 @@ class Inc { kha.compute.Compute.setSampledTexture(voxel_ta4, rts.get("voxelsOut").image); kha.compute.Compute.setSampledTexture(voxel_tb4, rts.get("half").image); + #if arm_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); @@ -1217,10 +1210,175 @@ class Inc { } kha.compute.Compute.setFloat2(voxel_cf4, width, height); - kha.compute.Compute.compute(Std.int(width / 8), Std.int(height / 8), 1); + kha.compute.Compute.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1); + } + + #if arm_voxelgi_refract + public static function resolveRefraction() { + 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]; + + kha.compute.Compute.setShader(voxel_sh6); + + kha.compute.Compute.setSampledTexture(voxel_ta6, rts.get("voxelsOut").image); + kha.compute.Compute.setSampledTexture(voxel_tb6, rts.get("half").image); + #if arm_deferred + kha.compute.Compute.setSampledTexture(voxel_tc6, rts.get("gbuffer0").image); + #else + kha.compute.Compute.setSampledTexture(voxel_tc6, rts.get("lbuffer1").image); + #end + kha.compute.Compute.setSampledTexture(voxel_td6, rts.get("voxelsSDF").image); + kha.compute.Compute.setTexture(voxel_te6, rts.get("voxels_refraction").image, kha.compute.Access.Write); + kha.compute.Compute.setSampledTexture(voxel_tf6, rts.get("gbuffer_refraction").image); + + 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_ca6, fa); + + #if arm_centerworld + m.setFrom(vmat(camera.V)); + #else + m.setFrom(camera.V); + #end + m.multmat(camera.P); + m.getInverse(m); + + kha.compute.Compute.setMatrix(voxel_cb6, m.self); + + 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_cc6, v.x, v.y); + + + kha.compute.Compute.setFloat3(voxel_cd6, camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz()); + var eyeLook = camera.lookWorld().normalize(); + kha.compute.Compute.setFloat3(voxel_ce6, eyeLook.x, eyeLook.y, eyeLook.z); + + var width = iron.App.w(); + var height = iron.App.h(); + var dp = getDisplayp(); + if (dp != null) { // 1080p/.. + if (width > height) { + width = Std.int(width * (dp / height)); + height = dp; + } + else { + height = Std.int(height * (dp / width)); + width = dp; + } + } + kha.compute.Compute.setFloat2(voxel_cf6, width, height); + + kha.compute.Compute.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1); } + #end #end // voxel ao - #end // deferred + #if arm_voxelgi_shadows + public static function resolveShadows() { + 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; + + for (i in 0...lights.length) { + var l = lights[i]; + if (!l.visible) continue; + path.light = l; + + kha.compute.Compute.setShader(voxel_sh7); + + kha.compute.Compute.setSampledTexture(voxel_ta7, rts.get("voxelsOut").image); + kha.compute.Compute.setSampledTexture(voxel_tb7, rts.get("half").image); + #if arm_deferred + kha.compute.Compute.setSampledTexture(voxel_tc7, rts.get("gbuffer0").image); + #else + kha.compute.Compute.setSampledTexture(voxel_tc7, rts.get("lbuffer1").image); + #end + kha.compute.Compute.setSampledTexture(voxel_td7, rts.get("voxelsSDF").image); + kha.compute.Compute.setTexture(voxel_te7, rts.get("voxels_shadows").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_ca7, fa); + + #if arm_centerworld + m.setFrom(vmat(camera.V)); + #else + m.setFrom(camera.V); + #end + m.multmat(camera.P); + m.getInverse(m); + + kha.compute.Compute.setMatrix(voxel_cb7, m.self); + + 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_cc7, v.x, v.y); + + + kha.compute.Compute.setFloat3(voxel_cd7, camera.transform.worldx(), camera.transform.worldy(), camera.transform.worldz()); + var eyeLook = camera.lookWorld().normalize(); + kha.compute.Compute.setFloat3(voxel_ce7, eyeLook.x, eyeLook.y, eyeLook.z); + + var width = iron.App.w(); + var height = iron.App.h(); + var dp = getDisplayp(); + if (dp != null) { // 1080p/.. + if (width > height) { + width = Std.int(width * (dp / height)); + height = dp; + } + else { + height = Std.int(height * (dp / width)); + width = dp; + } + } + kha.compute.Compute.setFloat2(voxel_cf7, width, height); + + // lightPos + kha.compute.Compute.setFloat3(voxel_cg7, l.transform.worldx(), l.transform.worldy(), l.transform.worldz()); + + kha.compute.Compute.compute(Std.int((width + 7) / 8), Std.int((height + 7) / 8), 1); + } + } + #end #if (rp_voxels == "Voxel GI") public static function computeVoxelsLight() { @@ -1262,7 +1420,11 @@ class Inc { #if rp_shadowmap if (l.data.raw.type == "sun") { #if arm_shadowmap_atlas + #if arm_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 @@ -1270,7 +1432,11 @@ class Inc { } else if (l.data.raw.type == "spot" || l.data.raw.type == "area") { #if arm_shadowmap_atlas + #if arm_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++; @@ -1279,9 +1445,13 @@ class Inc { } else { #if arm_shadowmap_atlas + #if arm_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++; @@ -1302,7 +1472,6 @@ class Inc { // LVP m.setFrom(l.VP); m.multmat(iron.object.Uniforms.biasMat); - /* #if arm_shadowmap_atlas if (l.data.raw.type == "sun") { @@ -1323,7 +1492,6 @@ class Inc { #end } #end - */ kha.compute.Compute.setMatrix(voxel_cj5, m.self); // shadowsBias kha.compute.Compute.setFloat(voxel_ck5, l.data.raw.shadows_bias); diff --git a/Sources/armory/renderpath/RenderPathDeferred.hx b/Sources/armory/renderpath/RenderPathDeferred.hx index 9dd603afbd..d9c58713f9 100644 --- a/Sources/armory/renderpath/RenderPathDeferred.hx +++ b/Sources/armory/renderpath/RenderPathDeferred.hx @@ -61,6 +61,9 @@ class RenderPathDeferred { Inc.initGI("voxelsSDF"); Inc.initGI("voxelsSDFtmp"); #end + #if arm_voxelgi_shadows + Inc.initGI("voxels_shadows"); + #end #if (rp_voxels == "Voxel GI") Inc.initGI("voxelsLight"); Inc.initGI("voxels_diffuse"); @@ -327,7 +330,7 @@ class RenderPathDeferred { } #end - #if (rp_ssr_half || rp_ssgi_half || rp_voxels != "Off") + #if (rp_ssr_half || rp_ssgi_half || rp_voxels != "Off") //we need half depth for resolve voxels shaders { path.loadShader("shader_datas/downsample_depth/downsample_depth"); var t = new RenderTargetRaw(); @@ -339,18 +342,18 @@ class RenderPathDeferred { path.createRenderTarget(t); } #end - + #if rp_ssrefr { path.loadShader("shader_datas/ssrefr_pass/ssrefr_pass"); path.loadShader("shader_datas/copy_pass/copy_pass"); - //holds ior and opacity var t = new RenderTargetRaw(); t.name = "gbuffer_refraction"; t.width = 0; t.height = 0; t.displayp = Inc.getDisplayp(); + //t.depth_buffer = "main"; t.format = "RGBA64"; t.scale = Inc.getSuperSampling(); path.createRenderTarget(t); @@ -361,9 +364,8 @@ class RenderPathDeferred { t.width = 0; t.height = 0; t.displayp = Inc.getDisplayp(); - t.format = "RGBA64"; + t.format = Inc.getHdrFormat(); t.scale = Inc.getSuperSampling(); - t.depth_buffer = "main"; path.createRenderTarget(t); // holds background depth @@ -502,7 +504,7 @@ class RenderPathDeferred { } #end - #if (rp_ssr_half || rp_ssgi_half || rp_voxels != "Off") + #if (rp_ssr_half || rp_ssgi_half || (rp_voxels != "Off")) path.setTarget("half"); path.bindTarget("_main", "texdepth"); path.drawShader("shader_datas/downsample_depth/downsample_depth"); @@ -577,7 +579,7 @@ class RenderPathDeferred { path.clearImage("voxels", 0x00000000); path.clearImage("voxelsOut", 0x00000000); path.clearImage("voxelsOutB", 0x00000000); - #if (arm_voxelgi_shadows || rp_voxels == "Voxel GI") + #if (arm_voxelgi_shadows || (rp_voxels == "Voxel GI")) path.clearImage("voxelsSDF", 0x00000000); path.clearImage("voxelsSDFtmp", 0x00000000); #end @@ -585,6 +587,9 @@ class RenderPathDeferred { } else { + #if (rp_voxels == "Voxel GI") + path.clearImage("voxelsLight", 0x00000000); + #end path.clearImage("voxels", 0x00000000); Inc.computeVoxelsOffsetPrev(); } @@ -598,9 +603,10 @@ class RenderPathDeferred { #if (rp_voxels == "Voxel GI") Inc.computeVoxelsLight(); #end + Inc.computeVoxelsTemporal(); - #if (arm_voxelgi_shadows || rp_voxels == "Voxel GI") + #if (arm_voxelgi_shadows || (rp_voxels == "Voxel GI")) Inc.computeVoxelsSDF(); #end @@ -612,6 +618,9 @@ class RenderPathDeferred { #else path.clearImage("voxels_ao", 0x00000000); #end + #if arm_voxelgi_shadows + path.clearImage("voxels_shadows", 0x00000000); + #end } } #end @@ -626,7 +635,7 @@ class RenderPathDeferred { path.bindTarget("_main", "gbufferD"); path.bindTarget("gbuffer0", "gbuffer0"); path.bindTarget("gbuffer1", "gbuffer1"); - + #if rp_gbuffer2 { path.bindTarget("gbuffer2", "gbuffer2"); @@ -667,8 +676,8 @@ class RenderPathDeferred { path.bindTarget("voxels_specular", "voxels_specular"); #end #if arm_voxelgi_shadows - path.bindTarget("voxelsOut", "voxels"); - path.bindTarget("voxelsSDF", "voxelsSDF"); + Inc.resolveShadows(); + path.bindTarget("voxels_shadows", "voxels_shadows"); #end } #end @@ -821,10 +830,9 @@ class RenderPathDeferred { path.setTarget("tex", ["gbuffer0", "gbuffer_refraction"]); #if (rp_voxels != "Off") path.bindTarget("voxelsOut", "voxels"); - #if (arm_voxelgi_shadows || rp_voxels == "Voxel GI") path.bindTarget("voxelsSDF", "voxelsSDF"); #end - #end + path.drawMeshes("refraction"); path.setTarget("tex"); @@ -834,6 +842,7 @@ class RenderPathDeferred { path.bindTarget("gbufferD1", "gbufferD1"); path.bindTarget("gbuffer0", "gbuffer0"); path.bindTarget("gbuffer_refraction", "gbuffer_refraction"); + path.drawShader("shader_datas/ssrefr_pass/ssrefr_pass"); } } diff --git a/Sources/armory/renderpath/RenderPathForward.hx b/Sources/armory/renderpath/RenderPathForward.hx index 87dea914f3..ebafc7c631 100644 --- a/Sources/armory/renderpath/RenderPathForward.hx +++ b/Sources/armory/renderpath/RenderPathForward.hx @@ -105,7 +105,7 @@ class RenderPathForward { t.depth_buffer = "main"; path.createRenderTarget(t); - #if (rp_ssr || rp_ssrefr) + #if rp_ssr { var t = new RenderTargetRaw(); t.name = "lbuffer1"; @@ -120,7 +120,6 @@ class RenderPathForward { #if rp_ssrefr { - //holds ior and opacity var t = new RenderTargetRaw(); t.name = "gbuffer_refraction"; t.width = 0; @@ -128,6 +127,7 @@ class RenderPathForward { t.displayp = Inc.getDisplayp(); t.format = "RGBA64"; t.scale = Inc.getSuperSampling(); + t.depth_buffer = "main"; path.createRenderTarget(t); //holds colors before refractive meshes are drawn @@ -138,7 +138,6 @@ class RenderPathForward { t.displayp = Inc.getDisplayp(); t.format = "RGBA64"; t.scale = Inc.getSuperSampling(); - t.depth_buffer = "main"; path.createRenderTarget(t); //holds background depth @@ -196,12 +195,19 @@ class RenderPathForward { Inc.initGI("voxels"); Inc.initGI("voxelsOut"); Inc.initGI("voxelsOutB"); - #if (arm_voxelgi_shadows || rp_voxels == "Voxel GI") + #if (arm_voxelgi_shadows || (rp_voxels == "Voxel GI")) Inc.initGI("voxelsSDF"); Inc.initGI("voxelsSDFtmp"); #end + #if arm_voxelgi_shadows + Inc.initGI("voxels_shadows"); + #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(); for (i in 0...Main.voxelgiClipmapCount) { @@ -295,7 +301,7 @@ class RenderPathForward { } #end - #if (rp_ssr_half || rp_ssgi_half) + #if (rp_ssr_half || rp_ssgi_half || (rp_voxels != "Off")) { path.loadShader("shader_datas/downsample_depth/downsample_depth"); var t = new RenderTargetRaw(); @@ -352,7 +358,6 @@ class RenderPathForward { } public static function commands() { - #if rp_shadowmap { #if arm_shadowmap_atlas @@ -379,7 +384,7 @@ class RenderPathForward { path.clearImage("voxels", 0x00000000); path.clearImage("voxelsOut", 0x00000000); path.clearImage("voxelsOutB", 0x00000000); - #if (arm_voxelgi_shadows || rp_voxels == "Voxel GI") + #if (arm_voxelgi_shadows || (rp_voxels == "Voxel GI")) path.clearImage("voxelsSDF", 0x00000000); path.clearImage("voxelsSDFtmp", 0x00000000); #end @@ -387,6 +392,9 @@ class RenderPathForward { } else { + #if (rp_voxels == "Voxel GI") + path.clearImage("voxelsLight", 0x00000000); + #end path.clearImage("voxels", 0x00000000); Inc.computeVoxelsOffsetPrev(); } @@ -403,10 +411,23 @@ class RenderPathForward { #end Inc.computeVoxelsTemporal(); - #if (arm_voxelgi_shadows || rp_voxels == "Voxel GI") + #if (arm_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 + #if arm_voxelgi_shadows + path.clearImage("voxels_shadows", 0x00000000); + #end + } } #end @@ -425,10 +446,11 @@ class RenderPathForward { #if rp_depthprepass { path.drawMeshes("depth"); - RenderPathCreator.setTargetMeshes(); } #end + RenderPathCreator.setTargetMeshes(); + #if rp_shadowmap { #if arm_shadowmap_atlas @@ -443,9 +465,18 @@ class RenderPathForward { #if (rp_voxels != "Off") if (armory.data.Config.raw.rp_gi != false) { - path.bindTarget("voxelsOut", "voxels"); - #if (arm_voxelgi_shadows || rp_voxels == "Voxel GI") - 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 arm_voxelgi_shadows + Inc.resolveShadows(); + path.bindTarget("voxels_shadows", "voxels_shadows"); #end } #end @@ -460,9 +491,9 @@ class RenderPathForward { } #end - #if rp_render_to_texture + #if (rp_render_to_texture || rp_voxels != "Off") { - #if (rp_ssr_half || rp_ssgi_half) + #if (rp_ssr_half || rp_ssgi_half || rp_voxels != "Off") path.setTarget("half"); path.bindTarget("_main", "texdepth"); path.drawShader("shader_datas/downsample_depth/downsample_depth"); @@ -480,7 +511,13 @@ class RenderPathForward { path.bindTarget("lbuffer0", "tex"); path.drawShader("shader_datas/copy_pass/copy_pass"); - RenderPathCreator.setTargetMeshes(); + path.setTarget("lbuffer0", ["lbuffer1", "gbuffer_refraction"]); + + #if (rp_voxels != "Off") + path.bindTarget("voxelsOut", "voxels"); + path.bindTarget("voxelsSDF", "voxelsSDF"); + #end + path.drawMeshes("refraction"); path.setTarget("lbuffer0"); diff --git a/blender/arm/exporter.py b/blender/arm/exporter.py index bf5822e6a3..27c64399a7 100644 --- a/blender/arm/exporter.py +++ b/blender/arm/exporter.py @@ -763,10 +763,15 @@ def export_object(self, bobject: bpy.types.Object, out_parent: Dict = None) -> N if bobject.hide_render or not bobject.arm_visible: out_object['visible'] = False - if not bobject.visible_camera: - out_object['visible_mesh'] = False - if not bobject.visible_shadow: - out_object['visible_shadow'] = False + if bpy.app.version < (3, 0, 0): + if not bobject.cycles_visibility: + out_object['visible_mesh'] = False + out_object['visible_shadow'] = False + else: + if not bobject.visible_camera: + out_object['visible_mesh'] = False + if not bobject.visible_shadow: + out_object['visible_shadow'] = False if not bobject.arm_spawn: out_object['spawn'] = False @@ -1416,7 +1421,10 @@ def check_uv_precision(mesh: bpy.types.Mesh, uv_max_dim: float, max_dim_uvmap: b ) def export_mesh_data(self, export_mesh: bpy.types.Mesh, bobject: bpy.types.Object, o, has_armature=False): - export_mesh.calc_normals_split() + if bpy.app.version < (4, 1, 0): + export_mesh.calc_normals_split() + else: + updated_normals = export_mesh.corner_normals export_mesh.calc_loop_triangles() loops = export_mesh.loops diff --git a/blender/arm/logicnode/__init__.py b/blender/arm/logicnode/__init__.py index 0dae5e7d0f..daf6afa7be 100644 --- a/blender/arm/logicnode/__init__.py +++ b/blender/arm/logicnode/__init__.py @@ -45,7 +45,7 @@ def init_categories(): arm_nodes.add_category('Transform', icon='TRANSFORM_ORIGINS', section="motion") arm_nodes.add_category('Physics', icon='PHYSICS', section="motion") - arm_nodes.add_category('Array', icon='LIGHTPROBE_GRID', section="values") + arm_nodes.add_category('Array', icon='MOD_ARRAY', section="values") arm_nodes.add_category('Map', icon='SHORTDISPLAY', section="values") arm_nodes.add_category('Math', icon='FORCE_HARMONIC', section="values") arm_nodes.add_category('Random', icon='SEQ_HISTOGRAM', section="values") diff --git a/blender/arm/logicnode/arm_sockets.py b/blender/arm/logicnode/arm_sockets.py index 4604d11fb7..3c1d0014da 100644 --- a/blender/arm/logicnode/arm_sockets.py +++ b/blender/arm/logicnode/arm_sockets.py @@ -595,27 +595,51 @@ def draw_socket_layout_split(socket: bpy.types.NodeSocket, layout: bpy.types.UIL layout.prop(socket, prop_name, text='') -def _make_socket_interface(interface_name: str, bl_idname: str) -> Type[bpy.types.NodeSocketInterface]: - """Create a socket interface class that is used by Blender for node - groups. We currently don't use real node groups, but without these - classes Blender will (incorrectly) draw the socket borders in light grey. - """ - def draw(self, context, layout): - pass +if bpy.app.version < (4, 1, 0): + def _make_socket_interface(interface_name: str, bl_idname: str) -> Type[bpy.types.NodeSocketInterface]: + """Create a socket interface class that is used by Blender for node + groups. We currently don't use real node groups, but without these + classes Blender will (incorrectly) draw the socket borders in light grey. + """ + def draw(self, context, layout): + pass + + def draw_color(self, context): + # This would be used if we were using "real" node groups + return 0, 0, 0, 1 + + cls = type( + interface_name, + (bpy.types.NodeSocketInterface, ), { + 'bl_socket_idname': bl_idname, + 'draw': draw, + 'draw_color': draw_color, + } + ) + return cls +else: + def _make_socket_interface(interface_name: str, bl_idname: str) -> Type[bpy.types.NodeTreeInterfaceSocket]: + """Create a socket interface class that is used by Blender for node + groups. We currently don't use real node groups, but without these + classes Blender will (incorrectly) draw the socket borders in light grey. + """ + def draw(self, context, layout): + pass + + def draw_color(self, context): + # This would be used if we were using "real" node groups + return 0, 0, 0, 1 + + cls = type( + interface_name, + (bpy.types.NodeTreeInterfaceSocket, ), { + 'bl_socket_idname': bl_idname, + 'draw': draw, + 'draw_color': draw_color, + } + ) + return cls - def draw_color(self, context): - # This would be used if we were using "real" node groups - return 0, 0, 0, 1 - - cls = type( - interface_name, - (bpy.types.NodeSocketInterface, ), { - 'bl_socket_idname': bl_idname, - 'draw': draw, - 'draw_color': draw_color, - } - ) - return cls ArmActionSocketInterface = _make_socket_interface('ArmActionSocketInterface', 'ArmNodeSocketAction') diff --git a/blender/arm/logicnode/logic/LN_select.py b/blender/arm/logicnode/logic/LN_select.py index ccde6643fc..012e4d7443 100644 --- a/blender/arm/logicnode/logic/LN_select.py +++ b/blender/arm/logicnode/logic/LN_select.py @@ -1,4 +1,7 @@ -from bpy.types import NodeSocketInterfaceInt +try: + from bpy.types import NodeSocketInterfaceInt +except: + from bpy.types import NodeTreeInterfaceSocketInt from arm.logicnode.arm_nodes import * class SelectNode(ArmLogicTreeNode): diff --git a/blender/arm/logicnode/string/LN_string_charat.py b/blender/arm/logicnode/string/LN_string_charat.py new file mode 100644 index 0000000000..839ec5265e --- /dev/null +++ b/blender/arm/logicnode/string/LN_string_charat.py @@ -0,0 +1,18 @@ +from arm.logicnode.arm_nodes import * + + +class StringCharAtNode(ArmLogicTreeNode): + """String CharAt""" + bl_idname = 'LNStringCharAtNode' + bl_label = 'String CharAt' + bl_description = 'Returns the character at position index of the String. If the index is negative or exceeds the string.length, an empty String "" is returned.' + arm_category = 'String' + arm_version = 1 + + def arm_init(self, context): + self.add_input('ArmNodeSocketAction', 'In') + self.add_input('ArmStringSocket', 'String') + self.add_input('ArmIntSocket', 'Index') + + self.add_output('ArmNodeSocketAction', 'Out') + self.add_output('ArmStringSocket', 'Char') diff --git a/blender/arm/make_renderpath.py b/blender/arm/make_renderpath.py index f355f38c10..b66da4c5f9 100644 --- a/blender/arm/make_renderpath.py +++ b/blender/arm/make_renderpath.py @@ -84,6 +84,22 @@ def add_world_defs(): if rpdat.rp_autoexposure: wrd.world_defs += '_AutoExposure' + # Light defines + point_lights = 0 + for bo in bpy.data.objects: # TODO: temp + if bo.arm_export and bo.type == 'LIGHT': + light = bo.data + if light.type == 'AREA' and '_LTC' not in wrd.world_defs: + point_lights += 1 + wrd.world_defs += '_LTC' + assets.add_khafile_def('arm_ltc') + if light.type == 'SUN' and '_Sun' not in wrd.world_defs: + wrd.world_defs += '_Sun' + if light.type == 'POINT' or light.type == 'SPOT': + point_lights += 1 + if light.type == 'SPOT' and '_Spot' not in wrd.world_defs: + wrd.world_defs += '_Spot' + assets.add_khafile_def('arm_spot') # GI voxelgi = False voxelao = False @@ -98,24 +114,24 @@ def add_world_defs(): assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_offsetprev/voxel_offsetprev.comp.glsl') assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_temporal/voxel_temporal.comp.glsl') assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_sdf_jumpflood/voxel_sdf_jumpflood.comp.glsl') - wrd.world_defs += "_VoxelCones" + rpdat.arm_voxelgi_cones - if rpdat.arm_voxelgi_shadows: + #wrd.world_defs += "_VoxelCones" + rpdat.arm_voxelgi_cones + if rpdat.arm_voxelgi_shadows and (point_lights > 0 or '_Sun' in wrd.world_defs): wrd.world_defs += '_VoxelShadow' assets.add_khafile_def('arm_voxelgi_shadows') + assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_resolve_shadows/voxel_resolve_shadows.comp.glsl') if voxelgi: assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_light/voxel_light.comp.glsl') - if rpdat.rp_renderer == "Deferred": - assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_resolve_diffuse/voxel_resolve_diffuse.comp.glsl') - assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_resolve_specular/voxel_resolve_specular.comp.glsl') + assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_resolve_diffuse/voxel_resolve_diffuse.comp.glsl') + assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_resolve_specular/voxel_resolve_specular.comp.glsl') wrd.world_defs += '_VoxelGI' - #if rpdat.arm_voxelgi_refraction: - # wrd.world_defs += '_VoxelRefract' - # assets.add_khafile_def('rp_voxelgi_refract') + if rpdat.arm_voxelgi_refract: + wrd.world_defs += '_VoxelRefract' + assets.add_khafile_def('arm_voxelgi_refract') + assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_resolve_refraction/voxel_resolve_refraction.comp.glsl') elif voxelao: - if rpdat.rp_renderer == "Deferred": - assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl') + assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_resolve_ao/voxel_resolve_ao.comp.glsl') wrd.world_defs += '_VoxelAOvar' # Write a shader variant if rpdat.arm_voxelgi_occ == 0.0: wrd.world_defs += '_VoxelAONoTrace' @@ -125,29 +141,13 @@ def add_world_defs(): wrd.world_defs += '_Legacy' assets.add_khafile_def('arm_legacy') - # Light defines - point_lights = 0 - for bo in bpy.data.objects: # TODO: temp - if bo.arm_export and bo.type == 'LIGHT': - light = bo.data - if light.type == 'AREA' and '_LTC' not in wrd.world_defs: - point_lights += 1 - wrd.world_defs += '_LTC' - assets.add_khafile_def('arm_ltc') - if light.type == 'SUN' and '_Sun' not in wrd.world_defs: - wrd.world_defs += '_Sun' - if light.type == 'POINT' or light.type == 'SPOT': - point_lights += 1 - if light.type == 'SPOT' and '_Spot' not in wrd.world_defs: - wrd.world_defs += '_Spot' - assets.add_khafile_def('arm_spot') - if not rpdat.rp_shadowmap_atlas: if point_lights == 1: wrd.world_defs += '_SinglePoint' elif point_lights > 1: wrd.world_defs += '_Clusters' assets.add_khafile_def('arm_clusters') + # we don't reach this point if atlas is on and shadowmap off, TODO: check shadowmap else: wrd.world_defs += '_SMSizeUniform' wrd.world_defs += '_Clusters' @@ -466,7 +466,14 @@ def get_num_gbuffer_rts_deferred()-> int: wrd = bpy.data.worlds['Arm'] num = 2 - for flag in ('_gbuffer2', '_EmissionShaded', '_SSRefraction'): + refraction_flags = {'_SSRefraction', '_VoxelRefract'} + found_refraction_flag = False + + for flag in ('_gbuffer2', '_EmissionShaded', '_SSRefraction', '_VoxelRefract'): if flag in wrd.world_defs: - num += 1 + if flag in refraction_flags and not found_refraction_flag: + num += 1 + found_refraction_flag = True + else: + num += 1 return num diff --git a/blender/arm/material/cycles_nodes/nodes_converter.py b/blender/arm/material/cycles_nodes/nodes_converter.py index 8c350c5caa..db1c5c0ca9 100644 --- a/blender/arm/material/cycles_nodes/nodes_converter.py +++ b/blender/arm/material/cycles_nodes/nodes_converter.py @@ -138,15 +138,15 @@ def parse_valtorgb(node: bpy.types.ShaderNodeValToRGB, out_socket: bpy.types.Nod rel_pos = f'({fac_var} - {prev_stop_fac}) * (1.0 / ({next_stop_fac} - {prev_stop_fac}))' return f'mix({prev_stop_col}, {next_stop_col}, max({rel_pos}, 0.0))' - -def parse_combine_color(node: bpy.types.ShaderNodeCombineColor, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr: - if node.mode == 'RGB': - return parse_combrgb(node, out_socket, state) - elif node.mode == 'HSV': - return parse_combhsv(node, out_socket, state) - elif node.mode == 'HSL': - log.warn('Combine Color node: HSL mode is not supported, using default value') - return c.to_vec3((0.0, 0.0, 0.0)) +if bpy.app.version > (3, 2, 0): + def parse_combine_color(node: bpy.types.ShaderNodeCombineColor, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr: + if node.mode == 'RGB': + return parse_combrgb(node, out_socket, state) + elif node.mode == 'HSV': + return parse_combhsv(node, out_socket, state) + elif node.mode == 'HSL': + log.warn('Combine Color node: HSL mode is not supported, using default value') + return c.to_vec3((0.0, 0.0, 0.0)) def parse_combhsv(node: bpy.types.ShaderNodeCombineHSV, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: @@ -356,15 +356,15 @@ def parse_math(node: bpy.types.ShaderNodeMath, out_socket: bpy.types.NodeSocket, def parse_rgbtobw(node: bpy.types.ShaderNodeRGBToBW, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr: return c.rgb_to_bw(c.parse_vector_input(node.inputs[0])) - -def parse_separate_color(node: bpy.types.ShaderNodeSeparateColor, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr: - if node.mode == 'RGB': - return parse_seprgb(node, out_socket, state) - elif node.mode == 'HSV': - return parse_sephsv(node, out_socket, state) - elif node.mode == 'HSL': - log.warn('Separate Color node: HSL mode is not supported, using default value') - return '0.0' +if bpy.app.version > (3, 2, 0): + def parse_separate_color(node: bpy.types.ShaderNodeSeparateColor, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr: + if node.mode == 'RGB': + return parse_seprgb(node, out_socket, state) + elif node.mode == 'HSV': + return parse_sephsv(node, out_socket, state) + elif node.mode == 'HSL': + log.warn('Separate Color node: HSL mode is not supported, using default value') + return '0.0' def parse_sephsv(node: bpy.types.ShaderNodeSeparateHSV, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr: diff --git a/blender/arm/material/cycles_nodes/nodes_shader.py b/blender/arm/material/cycles_nodes/nodes_shader.py index 75c7528979..5fa0aece01 100644 --- a/blender/arm/material/cycles_nodes/nodes_shader.py +++ b/blender/arm/material/cycles_nodes/nodes_shader.py @@ -75,40 +75,83 @@ def parse_addshader(node: bpy.types.ShaderNodeAddShader, out_socket: NodeSocket, state.out_opacity = '({0} * 0.5 + {1} * 0.5)'.format(opac1, opac2) state.out_ior = '({0} * 0.5 + {1} * 0.5)'.format(ior1, ior2) -def parse_bsdfprincipled(node: bpy.types.ShaderNodeBsdfPrincipled, out_socket: NodeSocket, state: ParserState) -> None: - if state.parse_surface: - c.write_normal(node.inputs[22]) - state.out_basecol = c.parse_vector_input(node.inputs[0]) - # subsurface = c.parse_vector_input(node.inputs[1]) - # subsurface_radius = c.parse_vector_input(node.inputs[2]) - # subsurface_color = c.parse_vector_input(node.inputs[3]) - state.out_metallic = c.parse_value_input(node.inputs[6]) - state.out_specular = c.parse_value_input(node.inputs[7]) - # specular_tint = c.parse_vector_input(node.inputs[6]) - state.out_roughness = c.parse_value_input(node.inputs[9]) - # aniso = c.parse_vector_input(node.inputs[8]) - # aniso_rot = c.parse_vector_input(node.inputs[9]) - # sheen = c.parse_vector_input(node.inputs[10]) - # sheen_tint = c.parse_vector_input(node.inputs[11]) - # clearcoat = c.parse_vector_input(node.inputs[12]) - # clearcoat_rough = c.parse_vector_input(node.inputs[13]) - # ior = c.parse_vector_input(node.inputs[14]) - # transmission = c.parse_vector_input(node.inputs[15]) - # transmission_roughness = c.parse_vector_input(node.inputs[16]) - if (node.inputs['Emission Strength'].is_linked or node.inputs['Emission Strength'].default_value != 0.0)\ - and (node.inputs['Emission'].is_linked or not mat_utils.equals_color_socket(node.inputs['Emission'], (0.0, 0.0, 0.0), comp_alpha=False)): - emission_col = c.parse_vector_input(node.inputs[19]) - emission_strength = c.parse_value_input(node.inputs[20]) - state.out_emission_col = '({0} * {1})'.format(emission_col, emission_strength) - mat_state.emission_type = mat_state.EmissionType.SHADED - else: - mat_state.emission_type = mat_state.EmissionType.NO_EMISSION - # clearcoar_normal = c.parse_vector_input(node.inputs[21]) - # tangent = c.parse_vector_input(node.inputs[22]) - if state.parse_opacity: - state.out_ior = c.parse_value_input(node.inputs[16]) - if len(node.inputs) >= 21: - state.out_opacity = c.parse_value_input(node.inputs[21]) + +if bpy.app.version < (3, 0, 0): + def parse_bsdfprincipled(node: bpy.types.ShaderNodeBsdfPrincipled, out_socket: NodeSocket, state: ParserState) -> None: + if state.parse_surface: + c.write_normal(node.inputs[20]) + state.out_basecol = c.parse_vector_input(node.inputs[0]) + state.out_metallic = c.parse_value_input(node.inputs[4]) + state.out_specular = c.parse_value_input(node.inputs[5]) + state.out_roughness = c.parse_value_input(node.inputs[7]) + if (node.inputs['Emission Strength'].is_linked or node.inputs['Emission Strength'].default_value != 0.0)\ + and (node.inputs['Emission'].is_linked or not mat_utils.equals_color_socket(node.inputs['Emission'], (0.0, 0.0, 0.0), comp_alpha=False)): + emission_col = c.parse_vector_input(node.inputs[17]) + emission_strength = c.parse_value_input(node.inputs[18]) + state.out_emission_col = '({0} * {1})'.format(emission_col, emission_strength) + mat_state.emission_type = mat_state.EmissionType.SHADED + else: + mat_state.emission_type = mat_state.EmissionType.NO_EMISSION + if state.parse_opacity: + state.out_ior = c.parse_value_input(node.inputs[14]) + state.out_opacity = c.parse_value_input(node.inputs[19]) +if bpy.app.version >= (3, 0, 0) and bpy.app.version <= (4, 1, 0): + def parse_bsdfprincipled(node: bpy.types.ShaderNodeBsdfPrincipled, out_socket: NodeSocket, state: ParserState) -> None: + if state.parse_surface: + c.write_normal(node.inputs[22]) + state.out_basecol = c.parse_vector_input(node.inputs[0]) + # subsurface = c.parse_vector_input(node.inputs[1]) + # subsurface_radius = c.parse_vector_input(node.inputs[2]) + # subsurface_color = c.parse_vector_input(node.inputs[3]) + state.out_metallic = c.parse_value_input(node.inputs[6]) + state.out_specular = c.parse_value_input(node.inputs[7]) + # specular_tint = c.parse_vector_input(node.inputs[6]) + state.out_roughness = c.parse_value_input(node.inputs[9]) + # aniso = c.parse_vector_input(node.inputs[8]) + # aniso_rot = c.parse_vector_input(node.inputs[9]) + # sheen = c.parse_vector_input(node.inputs[10]) + # sheen_tint = c.parse_vector_input(node.inputs[11]) + # clearcoat = c.parse_vector_input(node.inputs[12]) + # clearcoat_rough = c.parse_vector_input(node.inputs[13]) + # ior = c.parse_vector_input(node.inputs[14]) + # transmission = c.parse_vector_input(node.inputs[15]) + # transmission_roughness = c.parse_vector_input(node.inputs[16]) + if (node.inputs['Emission Strength'].is_linked or node.inputs['Emission Strength'].default_value != 0.0)\ + and (node.inputs['Emission'].is_linked or not mat_utils.equals_color_socket(node.inputs['Emission'], (0.0, 0.0, 0.0), comp_alpha=False)): + emission_col = c.parse_vector_input(node.inputs[19]) + emission_strength = c.parse_value_input(node.inputs[20]) + state.out_emission_col = '({0} * {1})'.format(emission_col, emission_strength) + mat_state.emission_type = mat_state.EmissionType.SHADED + else: + mat_state.emission_type = mat_state.EmissionType.NO_EMISSION + # clearcoar_normal = c.parse_vector_input(node.inputs[21]) + # tangent = c.parse_vector_input(node.inputs[22]) + if state.parse_opacity: + state.out_ior = c.parse_value_input(node.inputs[16]) + if len(node.inputs) >= 21: + state.out_opacity = c.parse_value_input(node.inputs[21]) +if bpy.app.version > (4, 1, 0): + def parse_bsdfprincipled(node: bpy.types.ShaderNodeBsdfPrincipled, out_socket: NodeSocket, state: ParserState) -> None: + if state.parse_surface: + c.write_normal(node.inputs[5]) + state.out_basecol = c.parse_vector_input(node.inputs[0]) + subsurface = c.parse_value_input(node.inputs[8]) + subsurface_radius = c.parse_vector_input(node.inputs[9]) + subsurface_color = c.parse_vector_input(node.inputs[0]) + state.out_metallic = c.parse_value_input(node.inputs[1]) + state.out_specular = c.parse_value_input(node.inputs[7]) + state.out_roughness = c.parse_value_input(node.inputs[2]) + if (node.inputs['Emission Strength'].is_linked or node.inputs['Emission Strength'].default_value != 0.0)\ + and (node.inputs['Emission Color'].is_linked or not mat_utils.equals_color_socket(node.inputs['Emission Color'], (0.0, 0.0, 0.0), comp_alpha=False)): + emission_col = c.parse_vector_input(node.inputs[27]) + emission_strength = c.parse_value_input(node.inputs[28]) + state.out_emission_col = '({0} * {1})'.format(emission_col, emission_strength) + mat_state.emission_type = mat_state.EmissionType.SHADED + else: + mat_state.emission_type = mat_state.EmissionType.NO_EMISSION + if state.parse_opacity: + state.out_ior = c.parse_value_input(node.inputs[3]) + state.out_opacity = c.parse_value_input(node.inputs[4]) def parse_bsdfdiffuse(node: bpy.types.ShaderNodeBsdfDiffuse, out_socket: NodeSocket, state: ParserState) -> None: if state.parse_surface: @@ -118,12 +161,13 @@ def parse_bsdfdiffuse(node: bpy.types.ShaderNodeBsdfDiffuse, out_socket: NodeSoc state.out_specular = '0.0' -def parse_bsdfglossy(node: bpy.types.ShaderNodeBsdfGlossy, out_socket: NodeSocket, state: ParserState) -> None: - if state.parse_surface: - c.write_normal(node.inputs[2]) - state.out_basecol = c.parse_vector_input(node.inputs[0]) - state.out_roughness = c.parse_value_input(node.inputs[1]) - state.out_metallic = '1.0' +if bpy.app.version < (4, 1, 0): + def parse_bsdfglossy(node: bpy.types.ShaderNodeBsdfGlossy, out_socket: NodeSocket, state: ParserState) -> None: + if state.parse_surface: + c.write_normal(node.inputs[2]) + state.out_basecol = c.parse_vector_input(node.inputs[0]) + state.out_roughness = c.parse_value_input(node.inputs[1]) + state.out_metallic = '1.0' def parse_ambientocclusion(node: bpy.types.ShaderNodeAmbientOcclusion, out_socket: NodeSocket, state: ParserState) -> None: @@ -183,7 +227,10 @@ def parse_bsdfrefraction(node: bpy.types.ShaderNodeBsdfRefraction, out_socket: N def parse_subsurfacescattering(node: bpy.types.ShaderNodeSubsurfaceScattering, out_socket: NodeSocket, state: ParserState) -> None: if state.parse_surface: - c.write_normal(node.inputs[4]) + if bpy.app.version < (4, 1, 0): + c.write_normal(node.inputs[4]) + else: + c.write_normal(node.inputs[6]) state.out_basecol = c.parse_vector_input(node.inputs[0]) @@ -204,9 +251,10 @@ def parse_bsdftransparent(node: bpy.types.ShaderNodeBsdfTransparent, out_socket: state.out_opacity = '(1.0 - {0}.r)'.format(c.parse_vector_input(node.inputs[0])) -def parse_bsdfvelvet(node: bpy.types.ShaderNodeBsdfVelvet, out_socket: NodeSocket, state: ParserState) -> None: - if state.parse_surface: - c.write_normal(node.inputs[2]) - state.out_basecol = c.parse_vector_input(node.inputs[0]) - state.out_roughness = '1.0' - state.out_metallic = '1.0' +if bpy.app.version < (4, 1, 0): + def parse_bsdfvelvet(node: bpy.types.ShaderNodeBsdfVelvet, out_socket: NodeSocket, state: ParserState) -> None: + if state.parse_surface: + c.write_normal(node.inputs[2]) + state.out_basecol = c.parse_vector_input(node.inputs[0]) + state.out_roughness = '1.0' + state.out_metallic = '1.0' diff --git a/blender/arm/material/cycles_nodes/nodes_texture.py b/blender/arm/material/cycles_nodes/nodes_texture.py index c99c520e82..013b3eeaff 100644 --- a/blender/arm/material/cycles_nodes/nodes_texture.py +++ b/blender/arm/material/cycles_nodes/nodes_texture.py @@ -244,22 +244,22 @@ def parse_tex_magic(node: bpy.types.ShaderNodeTexMagic, out_socket: bpy.types.No return res +if bpy.app.version < (4, 1, 0): + def parse_tex_musgrave(node: bpy.types.ShaderNodeTexMusgrave, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]: + state.curshader.add_function(c_functions.str_tex_musgrave) -def parse_tex_musgrave(node: bpy.types.ShaderNodeTexMusgrave, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]: - state.curshader.add_function(c_functions.str_tex_musgrave) - - if node.inputs[0].is_linked: - co = c.parse_vector_input(node.inputs[0]) - else: - co = 'bposition' - - scale = c.parse_value_input(node.inputs['Scale']) - # detail = c.parse_value_input(node.inputs[2]) - # distortion = c.parse_value_input(node.inputs[3]) - - res = f'tex_musgrave_f({co} * {scale} * 0.5)' - - return res + if node.inputs[0].is_linked: + co = c.parse_vector_input(node.inputs[0]) + else: + co = 'bposition' + + scale = c.parse_value_input(node.inputs['Scale']) + # detail = c.parse_value_input(node.inputs[2]) + # distortion = c.parse_value_input(node.inputs[3]) + + res = f'tex_musgrave_f({co} * {scale} * 0.5)' + + return res def parse_tex_noise(node: bpy.types.ShaderNodeTexNoise, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]: @@ -310,7 +310,6 @@ def parse_tex_sky(node: bpy.types.ShaderNodeTexSky, out_socket: bpy.types.NodeSo if node.sky_type == 'PREETHAM' or node.sky_type == 'HOSEK_WILKIE': if node.sky_type == 'PREETHAM': log.info('Info: Preetham sky model is not supported, using Hosek Wilkie sky model instead') - return parse_sky_hosekwilkie(node, state) elif node.sky_type == 'NISHITA': @@ -353,6 +352,8 @@ def parse_sky_hosekwilkie(node: bpy.types.ShaderNodeTexSky, state: ParserState) rpdat = arm.utils.get_rp() mobile_mat = rpdat.arm_material_model == 'Mobile' or rpdat.arm_material_model == 'Solid' + wrd.world_defs += '_HOSEK' + if not state.radiance_written: # Irradiance json file name wname = arm.utils.safestr(world.name) diff --git a/blender/arm/material/make_cluster.py b/blender/arm/material/make_cluster.py index c46194d4af..a634a34da1 100644 --- a/blender/arm/material/make_cluster.py +++ b/blender/arm/material/make_cluster.py @@ -84,10 +84,8 @@ def write(vert: shader.Shader, frag: shader.Shader): frag.write('\t, vec2(lightsArray[li * 3].w, lightsArray[li * 3 + 1].w)') # scale frag.write('\t, lightsArraySpot[li * 2 + 1].xyz') # right if '_VoxelShadow' in wrd.world_defs: - frag.write(', voxels') - frag.write(', voxelsSDF') - frag.write(', clipmaps') - + frag.add_uniform("sampler2D voxels_shadows", top=True) + frag.write(', texCoord') if '_MicroShadowing' in wrd.world_defs and not is_mobile: frag.write('\t, occlusion') frag.write(');') diff --git a/blender/arm/material/make_depth.py b/blender/arm/material/make_depth.py index 21e3e49b94..97679fbe33 100644 --- a/blender/arm/material/make_depth.py +++ b/blender/arm/material/make_depth.py @@ -53,7 +53,7 @@ def make(context_id, rpasses, shadowmap=False): if parse_opacity: frag.write('float opacity;') frag.write('float ior;') - + if(con_depth).is_elem('morph'): make_morph_target.morph_pos(vert) diff --git a/blender/arm/material/make_finalize.py b/blender/arm/material/make_finalize.py index 65c77554dc..8b38acae7a 100644 --- a/blender/arm/material/make_finalize.py +++ b/blender/arm/material/make_finalize.py @@ -75,7 +75,7 @@ def make(con_mesh: ShaderContext): if export_wpos: vert.add_uniform('mat4 W', '_worldMatrix') vert.add_out('vec3 wposition') - vert.write_attrib('wposition = vec4(W * spos).xyz;') + vert.write('wposition = vec4(W * spos).xyz;') elif write_wpos: vert.add_uniform('mat4 W', '_worldMatrix') vert.write_attrib('vec3 wposition = vec4(W * spos).xyz;') diff --git a/blender/arm/material/make_mesh.py b/blender/arm/material/make_mesh.py index fbd1cfe851..8564f0c2d0 100644 --- a/blender/arm/material/make_mesh.py +++ b/blender/arm/material/make_mesh.py @@ -278,11 +278,8 @@ def make_deferred(con_mesh, rpasses): frag.write('fragColor[GBUF_IDX_EMISSION] = vec4(emissionCol, 0.0);') #Alpha channel is unused at the moment frag.write('#endif') - if '_SSRefraction' in wrd.world_defs: - if 'refraction' in rpasses: - frag.write('fragColor[GBUF_IDX_REFRACTION] = vec4(ior, opacity, 0.0, 0.0);') - else: - frag.write('fragColor[GBUF_IDX_REFRACTION] = vec4(1.0, 1.0, 0.0, 0.0);') + if '_SSRefraction' in wrd.world_defs or '_VoxelRefract' in wrd.world_defs: + frag.write('fragColor[GBUF_IDX_REFRACTION] = vec4(1.0, 1.0, 0.0, 0.0);') return con_mesh @@ -549,7 +546,7 @@ def make_forward(con_mesh): mrt = 0 # mrt: multiple render targets if rpdat.rp_ssr: mrt = 1 - if rpdat.rp_ss_refraction: + if rpdat.rp_ss_refraction or rpdat.arm_voxelgi_refract: mrt = 2 if mrt != 0: # Store light gbuffer for post-processing @@ -559,11 +556,8 @@ def make_forward(con_mesh): frag.write('n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);') frag.write('fragColor[0] = vec4(direct + indirect, packFloat2(occlusion, specular));') frag.write('fragColor[1] = vec4(n.xy, roughness, metallic);') - if rpdat.rp_ss_refraction: - if parse_opacity: - frag.write(f'fragColor[2] = vec4(ior, opacity, 0.0, 0.0);') - else: - frag.write(f'fragColor[2] = vec4(1.0, 1.0, 0.0, 0.0);') + if rpdat.rp_ss_refraction or rpdat.arm_voxelgi_refract: + frag.write(f'fragColor[2] = vec4(1.0, 1.0, 0.0, 0.0);') else: frag.add_out('vec4 fragColor[1]') @@ -601,6 +595,9 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): opac = '0.9999' # 1.0 - eps frag.write('if (opacity < {0}) discard;'.format(opac)) + else: + frag.write('float opacity = 1.0;') + if blend: frag.add_out('vec4 fragColor[1]') if parse_opacity: @@ -669,33 +666,52 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): frag.add_uniform('float envmapStrength', link='_envmapStrength') frag.write('envl *= envmapStrength * occlusion;') - #if '_VoxelGI' in wrd.world_defs: - # frag.write('vec3 indirect = vec3(0.0);') - #else: - frag.write('vec3 indirect = envl;') - - if '_VoxelGI' in wrd.world_defs or '_VoxelAOvar' in wrd.world_defs: - frag.add_include('std/conetrace.glsl') - frag.add_uniform('sampler3D voxels') - if '_VoxelGI' in wrd.world_defs or '_VoxelShadow' in wrd.world_defs: - frag.add_uniform('sampler3D voxelsSDF') - frag.add_uniform('float clipmaps[voxelgiClipmapCount * 10]', link='_clipmaps') + # Computing texCoord in vertex shader from pos.xy doesn't work + if '_VoxelAOvar' in wrd.world_defs or '_VoxelGI' in wrd.world_defs: + if parse_opacity: + frag.add_include("std/conetrace.glsl") + frag.add_uniform("float clipmaps[10 * voxelgiClipmapCount]", "_clipmaps") + frag.add_uniform("sampler3D voxels") + frag.add_uniform("sampler3D voxelsSDF") + if '_VoxelShadow' in wrd.world_defs: + frag.add_uniform("sampler2D voxels_shadows", top=True) #TODO remove when doing transparent shadows, this is just a dummy + else: + if '_VoxelShadow' in wrd.world_defs: + frag.add_uniform("sampler2D voxels_shadows", top=True) + vert.add_out('vec4 wvpposition') + vert.write('wvpposition = gl_Position;') + frag.write('vec2 texCoord = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;') if '_VoxelAOvar' in wrd.world_defs: - frag.write('indirect *= (1.0 - traceAO(wposition, n, voxels, clipmaps).r);') + if parse_opacity: + frag.write('envl *= traceAO(wposition, wnormal, voxels, clipmaps);') + else: + frag.add_uniform("sampler2D voxels_ao"); + frag.write('envl *= textureLod(voxels_ao, texCoord, 0.0).rrr;') if '_VoxelGI' in wrd.world_defs: - frag.write('indirect += traceDiffuse(wposition, n, voxels, clipmaps).rgb * albedo * voxelgiDiff;') - frag.write('if (roughness < 1.0 && specular > 0.0) {') - frag.write(' vec2 pixel = gl_FragCoord.xy;') - frag.write(' indirect += traceSpecular(wposition, n, voxels, voxelsSDF, vVec, roughness, clipmaps, pixel).rgb * specular * voxelgiRefl;') - frag.write('}') + frag.write('vec3 indirect = vec3(0.0);') + else: + frag.write('vec3 indirect = envl;') + + if '_VoxelGI' in wrd.world_defs: + if parse_opacity: + frag.write("indirect = traceDiffuse(wposition, wnormal, voxels, clipmaps).rgb * albedo * voxelgiDiff;") + frag.write("if (roughness < 1.0 && specular > 0.0)") + frag.write(" indirect += traceSpecular(wposition, wnormal, voxels, voxelsSDF, eyeDir, roughness, clipmaps, texCoord).rgb * specular * voxelgiRefl;") + else: + frag.add_uniform("sampler2D voxels_diffuse") + frag.add_uniform("sampler2D voxels_specular") + frag.write("indirect = textureLod(voxels_diffuse, texCoord, 0.0).rgb * albedo * voxelgiDiff;") + frag.write("if (roughness < 1.0 && specular > 0.0)") + frag.write(" indirect += textureLod(voxels_specular, texCoord, 0.0).rgb * specular * voxelgiRefl;") + frag.write('vec3 direct = vec3(0.0);') if '_Sun' in wrd.world_defs: frag.add_uniform('vec3 sunCol', '_sunColor') frag.add_uniform('vec3 sunDir', '_sunDirection') - frag.write('float svisibility = 1.0;') + frag.write('float svisibility = 0.0;') frag.write('vec3 sh = normalize(vVec + sunDir);') frag.write('float sdotNL = dot(n, sunDir);') frag.write('float sdotNH = dot(n, sh);') @@ -729,7 +745,10 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): frag.write(f'svisibility = PCF({shadowmap_sun}, lPos.xy, lPos.z - shadowsBias, smSize);') frag.write('}') # receiveShadow if '_VoxelShadow' in wrd.world_defs: - frag.write('svisibility *= 1.0 - traceShadow(wposition, n, voxels, voxelsSDF, sunDir, clipmaps);') + if parse_opacity: + frag.write('svisibility *= traceShadow(wposition, wnormal, voxels, voxelsSDF, sunDir, clipmaps, texCoord);') + else: + frag.write('svisibility *= textureLod(voxels_shadows, texCoord, 0.0).r * voxelgiShad;') frag.write('direct += (lambertDiffuseBRDF(albedo, sdotNL) + specularBRDF(f0, roughness, sdotNL, sdotNH, dotNV, sdotVH) * specular) * sunCol * svisibility;') # sun @@ -747,9 +766,11 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): # Skip world matrix, already in world-space frag.add_uniform('mat4 LWVPSpot[1]', link='_biasLightViewProjectionMatrixSpotArray', included=True) frag.add_uniform('sampler2DShadow shadowMapSpot[1]', included=True) + frag.add_uniform('sampler2D shadowMapSpotTransparent[1]', included=True) else: frag.add_uniform('vec2 lightProj', link='_lightPlaneProj', included=True) frag.add_uniform('samplerCubeShadow shadowMapPoint[1]', included=True) + frag.add_uniform('samplerCube shadowMapPointTransparent[1]', included=True) frag.write('direct += sampleLight(') frag.write(' wposition, n, vVec, dotNV, pointPos, pointCol, albedo, roughness, specular, f0') if is_shadows: @@ -757,11 +778,14 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): if '_Spot' in wrd.world_defs: frag.write(', true, spotData.x, spotData.y, spotDir, spotData.zw, spotRight') if '_VoxelShadow' in wrd.world_defs: - frag.write(', voxels') - frag.write(', voxelsSDF') - frag.write(', clipmaps') + frag.write(', texCoord') if '_MicroShadowing' in wrd.world_defs: frag.write(', occlusion') + if '_SSRS' in wrd.world_defs: + frag.add_uniform('sampler2D gbufferD', top=True) + frag.add_uniform('mat4 invVP', '_inverseViewProjectionMatrix') + frag.add_uniform('vec3 eye', '_cameraPosition') + frag.write(', gbufferD, invVP, eye') frag.write(');') if '_Clusters' in wrd.world_defs: @@ -771,12 +795,19 @@ def make_forward_base(con_mesh, parse_opacity=False, transluc_pass=False): if mat_state.emission_type == mat_state.EmissionType.SHADELESS: frag.write('direct = vec3(0.0);') frag.write('indirect += emissionCol;') - """ + if '_VoxelRefract' in wrd.world_defs and parse_opacity: - frag.write('vec3 refraction = traceRefraction(wposition, n, voxels, eyeDir, ior, roughness, eye) * voxelgiRefr;') - frag.write('indirect = mix(refraction, indirect, opacity);') - frag.write('direct = mix(refraction, direct, opacity);') - """ + frag.add_include('std/conetrace.glsl') + frag.add_uniform('float clipmaps[10 * voxelgiClipmapCount]', '_clipmaps') + frag.add_uniform('sampler3D voxels') + frag.add_uniform('sampler3D voxelsSDF') + frag.write('if (opacity < 1.0) {') + frag.write(' vec3 refraction = traceRefraction(wposition, wnormal, voxels, voxelsSDF, eyeDir, ior, roughness, clipmaps, texCoord).rgb * voxelgiRefr;') + frag.write(' indirect = mix(refraction, indirect, opacity);') + frag.write(' direct = mix(refraction, direct, opacity);') + frag.write('}') + + def _write_material_attribs_default(frag: shader.Shader, parse_opacity: bool): frag.write('vec3 basecol;') frag.write('float roughness;') @@ -788,4 +819,4 @@ def _write_material_attribs_default(frag: shader.Shader, parse_opacity: bool): frag.write('vec3 emissionCol;') if parse_opacity: frag.write('float opacity;') - frag.write('float ior = 1.450;')#case shader is arm we don't get an ior + frag.write('float ior = 1.450;') # case shader is arm we don't get an ior diff --git a/blender/arm/material/make_refract.py b/blender/arm/material/make_refract.py index 6d13230128..448f9726ae 100644 --- a/blender/arm/material/make_refract.py +++ b/blender/arm/material/make_refract.py @@ -19,6 +19,7 @@ def make(context_id): con_refract = mat_state.data.add_context({ 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' }) + con_refract.data["vertex_elements"].append({'name' : 'pos', 'data' : 'short4norm'}) make_mesh.make_forward_base(con_refract, parse_opacity=True, transluc_pass=True) diff --git a/blender/arm/material/make_refraction_buffer.py b/blender/arm/material/make_refraction_buffer.py new file mode 100644 index 0000000000..666bcd52ae --- /dev/null +++ b/blender/arm/material/make_refraction_buffer.py @@ -0,0 +1,54 @@ +import bpy + +import arm +import arm.material.cycles as cycles +import arm.material.mat_state as mat_state +import arm.material.mat_utils as mat_utils +import arm.material.make_mesh as make_mesh +import arm.material.make_finalize as make_finalize +import arm.assets as assets + +if arm.is_reload(__name__): + cycles = arm.reload_module(cycles) + mat_state = arm.reload_module(mat_state) + make_mesh = arm.reload_module(make_mesh) + make_finalize = arm.reload_module(make_finalize) + assets = arm.reload_module(assets) +else: + arm.enable_reload(__name__) + + +def make(context_id): + con_refraction_buffer = mat_state.data.add_context({ 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise' }) + + arm_discard = mat_state.material.arm_discard + blend = mat_state.material.arm_blending + is_transluc = mat_utils.is_transluc(mat_state.material) + parse_opacity = (blend and is_transluc) or arm_discard + + make_mesh.make_base(con_refraction_buffer, parse_opacity) + + vert = con_refraction_buffer.vert + frag = con_refraction_buffer.frag + tese = con_refraction_buffer.tese + + frag.add_include('std/gbuffer.glsl') + frag.add_out('vec4 fragColor') + + # Remove fragColor = ...; + frag.main = frag.main[:frag.main.rfind('fragColor')] + frag.write('\n') + + wrd = bpy.data.worlds['Arm'] + + if parse_opacity: + frag.write('fragColor = vec4(ior, opacity, 0.0, 0.0);') + else: + frag.write('fragColor = vec4(1.0, 1.0, 0.0, 0.0);') + + make_finalize.make(con_refraction_buffer) + + # assets.vs_equal(con_refract, assets.shader_cons['transluc_vert']) # shader_cons has no transluc yet + # assets.fs_equal(con_refract, assets.shader_cons['transluc_frag']) + + return con_refraction_buffer diff --git a/blender/arm/material/make_transluc.py b/blender/arm/material/make_transluc.py index 6975734523..2171eab195 100644 --- a/blender/arm/material/make_transluc.py +++ b/blender/arm/material/make_transluc.py @@ -18,34 +18,34 @@ def make(context_id): - con_transluc = mat_state.data.add_context({ 'name': context_id, 'depth_write': False, 'compare_mode': 'less', 'cull_mode': 'clockwise', \ + con_transluc = mat_state.data.add_context({ 'name': context_id, 'depth_write': False, 'compare_mode': 'less', 'cull_mode': 'clockwise', \ 'blend_source': 'blend_one', 'blend_destination': 'blend_one', 'blend_operation': 'add', \ 'alpha_blend_source': 'blend_zero', 'alpha_blend_destination': 'inverse_source_alpha', 'alpha_blend_operation': 'add' }) - make_mesh.make_forward_base(con_transluc, parse_opacity=True, transluc_pass=True) + make_mesh.make_forward_base(con_transluc, parse_opacity=True, transluc_pass=True) - vert = con_transluc.vert - frag = con_transluc.frag - tese = con_transluc.tese + vert = con_transluc.vert + frag = con_transluc.frag + tese = con_transluc.tese - frag.add_out('vec4 fragColor[2]') + frag.add_out('vec4 fragColor[2]') - # Remove fragColor = ...; - frag.main = frag.main[:frag.main.rfind('fragColor')] - frag.write('\n') + # Remove fragColor = ...; + frag.main = frag.main[:frag.main.rfind('fragColor')] + frag.write('\n') - wrd = bpy.data.worlds['Arm'] - if '_VoxelAOvar' in wrd.world_defs: - frag.write('indirect *= 0.25;') - frag.write('vec4 premultipliedReflect = vec4(vec3(direct + indirect * 0.5) * opacity, opacity);') + wrd = bpy.data.worlds['Arm'] + if '_VoxelAOvar' in wrd.world_defs: + frag.write('indirect *= 0.25;') + frag.write('vec4 premultipliedReflect = vec4(vec3(direct + indirect * 0.5) * opacity, opacity);') - frag.write('float w = clamp(pow(min(1.0, premultipliedReflect.a * 10.0) + 0.01, 3.0) * 1e8 * pow(1.0 - (gl_FragCoord.z) * 0.9, 3.0), 1e-2, 3e3);') - frag.write('fragColor[0] = vec4(premultipliedReflect.rgb * w, premultipliedReflect.a);') - frag.write('fragColor[1] = vec4(premultipliedReflect.a * w, 0.0, 0.0, 1.0);') + frag.write('float w = clamp(pow(min(1.0, premultipliedReflect.a * 10.0) + 0.01, 3.0) * 1e8 * pow(1.0 - (gl_FragCoord.z) * 0.9, 3.0), 1e-2, 3e3);') + frag.write('fragColor[0] = vec4(premultipliedReflect.rgb * w, premultipliedReflect.a);') + frag.write('fragColor[1] = vec4(premultipliedReflect.a * w, 0.0, 0.0, 1.0);') - make_finalize.make(con_transluc) + make_finalize.make(con_transluc) - # assets.vs_equal(con_transluc, assets.shader_cons['transluc_vert']) # shader_cons has no transluc yet + # assets.vs_equal(con_transluc, assets.shader_cons['transluc_vert']) # shader_cons has no transluc yet # assets.fs_equal(con_transluc, assets.shader_cons['transluc_frag']) - return con_transluc + return con_transluc diff --git a/blender/arm/material/make_voxel.py b/blender/arm/material/make_voxel.py index 1546c65673..c9a635cadb 100644 --- a/blender/arm/material/make_voxel.py +++ b/blender/arm/material/make_voxel.py @@ -29,10 +29,6 @@ import arm.material.make_particle as make_particle import arm.make_state as state -import arm.utils -import arm.assets as assets -import arm.material.mat_state as mat_state - if arm.is_reload(__name__): arm.utils = arm.reload_module(arm.utils) assets = arm.reload_module(assets) @@ -76,6 +72,7 @@ def make_gi(context_id): rpdat = arm.utils.get_rp() frag.add_uniform('layout(r32ui) uimage3D voxels') + frag.write('vec3 n;') frag.write('vec3 wposition;') frag.write('vec3 basecol;') frag.write('float roughness;') # @@ -83,7 +80,8 @@ def make_gi(context_id): frag.write('float occlusion;') # frag.write('float specular;') # frag.write('vec3 emissionCol = vec3(0.0);') - parse_opacity = rpdat.arm_voxelgi_refraction + blend = mat_state.material.arm_blending + parse_opacity = blend or mat_utils.is_transluc(mat_state.material) if parse_opacity: frag.write('float opacity;') frag.write('float ior;') @@ -91,7 +89,7 @@ def make_gi(context_id): frag.write('float opacity = 1.0;') frag.write('float dotNV = 0.0;') - cycles.parse(mat_state.nodes, con_voxel, vert, frag, geom, tesc, tese, parse_opacity=False, parse_displacement=False, basecol_only=True) + cycles.parse(mat_state.nodes, con_voxel, vert, frag, geom, tesc, tese, parse_opacity=parse_opacity, parse_displacement=False, basecol_only=True) # Voxelized particles particle = mat_state.material.arm_particle_flag @@ -137,7 +135,7 @@ def make_gi(context_id): vert.write('texCoordGeom = tex;') vert.write('voxpositionGeom = vec3(W * vec4(pos.xyz, 1.0));') - vert.write('voxnormalGeom = normalize(N * vec3(nor.xy, pos.w));') + vert.write('voxnormalGeom = N * vec3(nor.xy, pos.w);') geom.add_out('vec4 voxposition[3]') geom.add_out('vec3 P') @@ -199,60 +197,114 @@ def make_gi(context_id): frag.write('uvw = (uvw * 0.5 + 0.5);') frag.write('if(any(notEqual(uvw, clamp(uvw, 0.0, 1.0)))) return;') frag.write('vec3 writecoords = floor(uvw * voxelgiResolution);') - frag.write_attrib('vec3 n = normalize(voxnormal);') - frag.write('vec3 aniso_direction = n;') + frag.write_attrib('vec3 N = normalize(voxnormal);') + frag.write('vec3 aniso_direction = N;') frag.write('uvec3 face_offsets = uvec3(') frag.write(' aniso_direction.x > 0 ? 0 : 1,') frag.write(' aniso_direction.y > 0 ? 2 : 3,') frag.write(' aniso_direction.z > 0 ? 4 : 5') frag.write(' ) * voxelgiResolution;') - frag.write('vec3 direction_weights = abs(n);') + frag.write('vec3 direction_weights = abs(N);') + + frag.write('vec3 albedo = surfaceAlbedo(basecol, metallic);') + frag.write('vec3 f0 = surfaceF0(basecol, metallic);') + + frag.add_uniform('vec3 eye', '_cameraPosition') + frag.write('vec3 eyeDir = eye - wposition;') + + if '_Brdf' in wrd.world_defs: + frag.add_uniform('sampler2D senvmapBrdf', link='$brdf.png') + frag.write('vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(dotNV, 1.0 - roughness) * 256.0), 0).xy;') + + if '_Irr' in wrd.world_defs: + frag.add_include('std/shirr.glsl') + frag.add_uniform('vec4 shirr[7]', link='_envmapIrradiance') + frag.write('vec3 envl = shIrradiance(n, shirr);') + if '_EnvTex' in wrd.world_defs: + frag.write('envl /= PI;') + else: + frag.write('vec3 envl = vec3(0.0);') + + if '_Rad' in wrd.world_defs: + frag.add_uniform('sampler2D senvmapRadiance', link='_envmapRadiance') + frag.add_uniform('int envmapNumMipmaps', link='_envmapNumMipmaps') + frag.write('vec3 reflectionWorld = reflect(-eyeDir, n);') + frag.write('float lod = getMipFromRoughness(roughness, envmapNumMipmaps);') + frag.write('vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;') + + if '_EnvLDR' in wrd.world_defs: + frag.write('envl = pow(envl, vec3(2.2));') + if '_Rad' in wrd.world_defs: + frag.write('prefilteredColor = pow(prefilteredColor, vec3(2.2));') + + frag.write('envl *= albedo;') + + if '_Brdf' in wrd.world_defs: + frag.write('envl.rgb *= 1.0 - (f0 * envBRDF.x + envBRDF.y);') + if '_Rad' in wrd.world_defs: + frag.write('envl += prefilteredColor * (f0 * envBRDF.x + envBRDF.y);') + elif '_EnvCol' in wrd.world_defs: + frag.add_uniform('vec3 backgroundCol', link='_backgroundCol') + frag.write('envl += backgroundCol * (f0 * envBRDF.x + envBRDF.y);') + + frag.add_uniform('float envmapStrength', link='_envmapStrength') + frag.write('envl *= envmapStrength * occlusion;') frag.write('if (direction_weights.x > 0) {') frag.write(' vec4 basecol_direction = vec4(min(basecol * direction_weights.x, vec3(1.0)), opacity);') - frag.write(' vec3 emission_direction = min(emissionCol * direction_weights.x, vec3(1.0));') - frag.write(' vec2 normal_direction = encode_oct(n * direction_weights.x) * 0.5 + 0.5;') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, 0)), uint(basecol_direction.r * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x)), uint(basecol_direction.g * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 2)), uint(basecol_direction.b * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 3)), uint(basecol_direction.a * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 4)), uint(emission_direction.r * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 5)), uint(emission_direction.g * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 6)), uint(emission_direction.b * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 7)), uint(normal_direction.r * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 8)), uint(normal_direction.g * 255));') + frag.write(' vec3 emission_direction = emissionCol * direction_weights.x;') + frag.write(' vec2 normal_direction = encode_oct(N * direction_weights.x) * 0.5 + 0.5;') + frag.write(' vec3 envl_direction = envl * direction_weights.x;') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, 0)), uint(basecol_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x)), uint(basecol_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 2)), uint(basecol_direction.b * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 3)), uint(basecol_direction.a * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 4)), uint(emission_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 5)), uint(emission_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 6)), uint(emission_direction.b * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 7)), uint(normal_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 8)), uint(normal_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 9)), uint(envl_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 10)), uint(envl_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, voxelgiResolution.x * 11)), uint(envl_direction.b * 255));') frag.write('}') - frag.write('if (direction_weights.y > 0) {') frag.write(' vec4 basecol_direction = vec4(min(basecol * direction_weights.y, vec3(1.0)), opacity);') - frag.write(' vec3 emission_direction = min(emissionCol * direction_weights.y, vec3(1.0));') - frag.write(' vec2 normal_direction = encode_oct(n * direction_weights.y) * 0.5 + 0.5;') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, 0)), uint(basecol_direction.r * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x)), uint(basecol_direction.g * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 2)), uint(basecol_direction.b * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 3)), uint(basecol_direction.a * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 4)), uint(emission_direction.r * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 5)), uint(emission_direction.g * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 6)), uint(emission_direction.b * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 7)), uint(normal_direction.r * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 8)), uint(normal_direction.g * 255));') - + frag.write(' vec3 emission_direction = emissionCol * direction_weights.y;') + frag.write(' vec2 normal_direction = encode_oct(N * direction_weights.y) * 0.5 + 0.5;') + frag.write(' vec3 envl_direction = envl * direction_weights.y;') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, 0)), uint(basecol_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x)), uint(basecol_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 2)), uint(basecol_direction.b * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 3)), uint(basecol_direction.a * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 4)), uint(emission_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 5)), uint(emission_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 6)), uint(emission_direction.b * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 7)), uint(normal_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 8)), uint(normal_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 9)), uint(envl_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 10)), uint(envl_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, voxelgiResolution.x * 11)), uint(envl_direction.b * 255));') frag.write('}') frag.write('if (direction_weights.z > 0) {') frag.write(' vec4 basecol_direction = vec4(min(basecol * direction_weights.z, vec3(1.0)), opacity);') - frag.write(' vec3 emission_direction = min(emissionCol * direction_weights.z, vec3(1.0));') + frag.write(' vec3 emission_direction = emissionCol * direction_weights.z;') frag.write(' vec2 normal_direction = encode_oct(n * direction_weights.z) * 0.5 + 0.5;') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, 0)), uint(basecol_direction.r * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x)), uint(basecol_direction.g * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 2)), uint(basecol_direction.b * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 3)), uint(basecol_direction.a * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 4)), uint(emission_direction.r * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 5)), uint(emission_direction.g * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 6)), uint(emission_direction.b * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 7)), uint(normal_direction.r * 255));') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 8)), uint(normal_direction.g * 255));') + frag.write(' vec3 envl_direction = envl * direction_weights.z;') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, 0)), uint(basecol_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x)), uint(basecol_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 2)), uint(basecol_direction.b * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 3)), uint(basecol_direction.a * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 4)), uint(emission_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 5)), uint(emission_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 6)), uint(emission_direction.b * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 7)), uint(normal_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 8)), uint(normal_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 9)), uint(envl_direction.r * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 10)), uint(envl_direction.g * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, voxelgiResolution.x * 11)), uint(envl_direction.b * 255));') frag.write('}') return con_voxel @@ -390,7 +442,7 @@ def make_ao(context_id): vert.add_out('vec3 voxnormalGeom') vert.write('voxpositionGeom = vec3(W * vec4(pos.xyz, 1.0));') - vert.write('voxnormalGeom = normalize(N * vec3(nor.xy, pos.w));') + vert.write('voxnormalGeom = N * vec3(nor.xy, pos.w);') geom.add_out('vec4 voxposition[3]') geom.add_out('vec3 P') @@ -436,15 +488,15 @@ def make_ao(context_id): frag.write('vec3 direction_weights = abs(N);') frag.write('if (direction_weights.x > 0) {') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, 0)), uint(direction_weights.x * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.x, 0, 0)), uint(direction_weights.x * 255));') frag.write('}') frag.write('if (direction_weights.y > 0) {') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, 0)), uint(direction_weights.y * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.y, 0, 0)), uint(direction_weights.y * 255));') frag.write('}') frag.write('if (direction_weights.z > 0) {') - frag.write(' imageAtomicMax(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, 0)), uint(direction_weights.z * 255));') + frag.write(' imageAtomicAdd(voxels, ivec3(writecoords + ivec3(face_offsets.z, 0, 0)), uint(direction_weights.z * 255));') frag.write('}') return con_voxel diff --git a/blender/arm/material/mat_utils.py b/blender/arm/material/mat_utils.py index 8715032666..3b646ff34a 100644 --- a/blender/arm/material/mat_utils.py +++ b/blender/arm/material/mat_utils.py @@ -5,6 +5,7 @@ import arm.utils import arm.make_state as make_state import arm.material.cycles as cycles +import arm.assets as assets import arm.log as log if arm.is_reload(__name__): diff --git a/blender/arm/material/node_meta.py b/blender/arm/material/node_meta.py index 1aef0568af..9d1a468914 100644 --- a/blender/arm/material/node_meta.py +++ b/blender/arm/material/node_meta.py @@ -76,13 +76,11 @@ class MaterialNodeMeta: 'BLACKBODY': MaterialNodeMeta(parse_func=nodes_converter.parse_blackbody), 'CLAMP': MaterialNodeMeta(parse_func=nodes_converter.parse_clamp), 'COMBHSV': MaterialNodeMeta(parse_func=nodes_converter.parse_combhsv), - 'COMBINE_COLOR': MaterialNodeMeta(parse_func=nodes_converter.parse_combine_color), 'COMBRGB': MaterialNodeMeta(parse_func=nodes_converter.parse_combrgb), 'COMBXYZ': MaterialNodeMeta(parse_func=nodes_converter.parse_combxyz), 'MAP_RANGE': MaterialNodeMeta(parse_func=nodes_converter.parse_maprange), 'MATH': MaterialNodeMeta(parse_func=nodes_converter.parse_math), 'RGBTOBW': MaterialNodeMeta(parse_func=nodes_converter.parse_rgbtobw), - 'SEPARATE_COLOR': MaterialNodeMeta(parse_func=nodes_converter.parse_separate_color), 'SEPHSV': MaterialNodeMeta(parse_func=nodes_converter.parse_sephsv), 'SEPRGB': MaterialNodeMeta(parse_func=nodes_converter.parse_seprgb), 'SEPXYZ': MaterialNodeMeta(parse_func=nodes_converter.parse_sepxyz), @@ -156,12 +154,10 @@ class MaterialNodeMeta: 'BSDF_ANISOTROPIC': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfanisotropic), 'BSDF_DIFFUSE': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfdiffuse), 'BSDF_GLASS': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfglass), - 'BSDF_GLOSSY': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfglossy), 'BSDF_PRINCIPLED': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfprincipled), 'BSDF_TRANSLUCENT': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdftranslucent), 'BSDF_TRANSPARENT': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdftransparent), 'BSDF_REFRACTION': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfrefraction), - 'BSDF_VELVET': MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfvelvet), 'EMISSION': MaterialNodeMeta(parse_func=nodes_shader.parse_emission), 'HOLDOUT': MaterialNodeMeta( parse_func=nodes_shader.parse_holdout, @@ -177,7 +173,6 @@ class MaterialNodeMeta: 'TEX_GRADIENT': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_gradient), 'TEX_IMAGE': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_image), 'TEX_MAGIC': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_magic), - 'TEX_MUSGRAVE': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_musgrave), 'TEX_NOISE': MaterialNodeMeta(parse_func=nodes_texture.parse_tex_noise), 'TEX_POINTDENSITY': MaterialNodeMeta( parse_func=nodes_texture.parse_tex_pointdensity, @@ -204,6 +199,13 @@ class MaterialNodeMeta: ) } +if bpy.app.version > (3, 2, 0): + ALL_NODES['SEPARATE_COLOR'] = MaterialNodeMeta(parse_func=nodes_converter.parse_separate_color) + ALL_NODES['COMBINE_COLOR'] = MaterialNodeMeta(parse_func=nodes_converter.parse_combine_color) +if bpy.app.version < (4, 1, 0): + ALL_NODES['BSDF_GLOSSY'] = MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfglossy) + ALL_NODES['BSDF_VELVET'] = MaterialNodeMeta(parse_func=nodes_shader.parse_bsdfvelvet) + ALL_NODES['TEX_MUSGRAVE'] = MaterialNodeMeta(parse_func=nodes_texture.parse_tex_musgrave) def get_node_meta(node: bpy.types.Node) -> MaterialNodeMeta: type_identifier = node.type if node.type != 'CUSTOM' else node.bl_idname diff --git a/blender/arm/nodes_logic.py b/blender/arm/nodes_logic.py index 8d747ecf74..ae9e19cfac 100644 --- a/blender/arm/nodes_logic.py +++ b/blender/arm/nodes_logic.py @@ -395,7 +395,10 @@ def draw(cls, context): path_data = [path.node_tree.name for path in context.space_data.path] str = cls.convert_array_to_string(path_data) blf.position(0, 20, height-60, 0) - blf.size(0, 15, 72) + if bpy.app.version < (4, 1, 0): + blf.size(0, 15, 72) + else: + blf.size(15, 72) blf.draw(0, str) @classmethod diff --git a/blender/arm/props.py b/blender/arm/props.py index dd6f99d505..0e74c953a0 100644 --- a/blender/arm/props.py +++ b/blender/arm/props.py @@ -23,7 +23,7 @@ arm.enable_reload(__name__) # Armory version -arm_version = '2024.2' +arm_version = '2024.7' arm_commit = '$Id$' def get_project_html5_copy(self): @@ -343,6 +343,7 @@ def init_properties(): bpy.types.Object.arm_spawn = BoolProperty(name="Spawn", description="Auto-add this object when creating scene", default=True, override={'LIBRARY_OVERRIDABLE'}) bpy.types.Object.arm_mobile = BoolProperty(name="Mobile", description="Object moves during gameplay", default=False, override={'LIBRARY_OVERRIDABLE'}) bpy.types.Object.arm_visible = BoolProperty(name="Visible", description="Render this object", default=True, override={'LIBRARY_OVERRIDABLE'}) + bpy.types.Object.arm_lighting = BoolProperty(name="Lighting", description="Object contributes to the lighting", default=True, override={'LIBRARY_OVERRIDABLE'}) bpy.types.Object.arm_soft_body_margin = FloatProperty(name="Soft Body Margin", description="Collision margin", default=0.04) bpy.types.Object.arm_rb_linear_factor = FloatVectorProperty(name="Linear Factor", size=3, description="Set to 0 to lock axis", default=[1,1,1]) bpy.types.Object.arm_rb_angular_factor = FloatVectorProperty(name="Angular Factor", size=3, description="Set to 0 to lock axis", default=[1,1,1]) diff --git a/blender/arm/props_renderpath.py b/blender/arm/props_renderpath.py index 7e023db1b9..d8244b224c 100644 --- a/blender/arm/props_renderpath.py +++ b/blender/arm/props_renderpath.py @@ -445,25 +445,6 @@ class ArmRPListItem(bpy.types.PropertyGroup): rp_stereo: BoolProperty(name="VR", description="Stereo rendering", default=False, update=update_renderpath) rp_water: BoolProperty(name="Water", description="Enable water surface pass", default=False, update=update_renderpath) rp_pp: BoolProperty(name="Realtime postprocess", description="Realtime postprocess", default=False, update=update_renderpath) - rp_gi: EnumProperty( # TODO: remove in 0.8 - items=[('Off', 'Off', 'Off'), - ('Voxel GI', 'Voxel GI', 'Voxel GI', 'ERROR', 1), - ('Voxel AO', 'Voxel AO', 'Voxel AO') - ], - name="Global Illumination", description="Dynamic global illumination", default='Off', update=update_renderpath) - rp_voxelao: BoolProperty(name="Voxel AO", description="Voxel-based ambient occlusion", default=False, update=update_renderpath) - rp_voxelgi_resolution: EnumProperty( - items=[('32', '32', '32'), - ('64', '64', '64'), - ('128', '128', '128'), - ('256', '256', '256'), - ('512', '512', '512')], - name="Resolution", description="3D texture resolution", default='128', update=update_renderpath) - rp_voxelgi_resolution_z: EnumProperty( - items=[('1.0', '1.0', '1.0'), - ('0.5', '0.5', '0.5'), - ('0.25', '0.25', '0.25')], - name="Resolution Z", description="3D texture z resolution multiplier", default='1.0', update=update_renderpath) arm_clouds: BoolProperty(name="Clouds", description="Enable clouds pass", default=False, update=assets.invalidate_shader_cache) arm_ssrs: BoolProperty(name="SSRS", description="Screen-space ray-traced shadows", default=False, update=assets.invalidate_shader_cache) arm_micro_shadowing: BoolProperty(name="Micro Shadowing", description="Use the shaders' occlusion parameter to compute micro shadowing for the scene's sun lamp. This option is not available for render paths using mobile or solid material models", default=False, update=assets.invalidate_shader_cache) @@ -507,7 +488,8 @@ class ArmRPListItem(bpy.types.PropertyGroup): ], name="Voxels", description="Dynamic global illumination", default='Off', update=update_renderpath) rp_voxelgi_resolution: EnumProperty( - items=[('32', '32', '32'), + items=[('16', '16', '16'), + ('32', '32', '32'), ('64', '64', '64'), ('128', '128', '128'), ('256', '256', '256'), @@ -518,7 +500,7 @@ class ArmRPListItem(bpy.types.PropertyGroup): ('0.5', '0.5', '0.5'), ('0.25', '0.25', '0.25')], name="Resolution Z", description="3D texture z resolution multiplier", default='1.0', update=update_renderpath) - arm_voxelgi_refraction: BoolProperty(name="Trace Refraction", description="Use voxels to render refraction", default=False, update=update_renderpath) + arm_voxelgi_refract: BoolProperty(name="Trace Refraction", description="Use voxels to render refraction", default=False, update=update_renderpath) arm_voxelgi_bounces: EnumProperty( items=[ ('1', '1', '1'), @@ -545,12 +527,13 @@ class ArmRPListItem(bpy.types.PropertyGroup): arm_voxelgi_diff: FloatProperty(name="Diffuse", description="", default=1.0, update=assets.invalidate_shader_cache) arm_voxelgi_spec: FloatProperty(name="Reflection", description="", default=1.0, update=assets.invalidate_shader_cache) arm_voxelgi_refr: FloatProperty(name="Refraction", description="", default=1.0, update=assets.invalidate_shader_cache) - arm_voxelgi_occ: FloatProperty(name="Intensity", description="", default=1.0, update=assets.invalidate_shader_cache) + arm_voxelgi_shad: FloatProperty(name="Shadows", description="", default=1.0, update=assets.invalidate_shader_cache) + arm_voxelgi_occ: FloatProperty(name="Occlusion", description="", default=1.0, update=assets.invalidate_shader_cache) arm_voxelgi_size: FloatProperty(name="Size", description="Voxel size", default=0.25, update=assets.invalidate_shader_cache) arm_voxelgi_step: FloatProperty(name="Step", description="Step size", default=1.0, update=assets.invalidate_shader_cache) - arm_voxelgi_range: FloatProperty(name="Range", description="Maximum range", default=1.0, update=assets.invalidate_shader_cache) - arm_voxelgi_offset: FloatProperty(name="Offset", description="Offset for dealing with self occlusion", default=1.0, update=assets.invalidate_shader_cache) - arm_voxelgi_aperture: FloatProperty(name="Aperture", description="Cone aperture for shadow trace", default=0.5, update=assets.invalidate_shader_cache) + arm_voxelgi_range: FloatProperty(name="Range", description="Maximum range", default=100.0, update=assets.invalidate_shader_cache) + arm_voxelgi_offset: FloatProperty(name="Offset", description="Multiplicative Offset for dealing with self occlusion", default=1.0, update=assets.invalidate_shader_cache) + arm_voxelgi_aperture: FloatProperty(name="Aperture", description="Cone aperture for shadow trace", default=0.0, update=assets.invalidate_shader_cache) arm_sss_width: FloatProperty(name="Width", description="SSS blur strength", default=1.0, update=assets.invalidate_shader_cache) arm_water_color: FloatVectorProperty(name="Color", size=3, default=[1, 1, 1], subtype='COLOR', min=0, max=1, update=assets.invalidate_shader_cache) arm_water_level: FloatProperty(name="Level", default=0.0, update=assets.invalidate_shader_cache) diff --git a/blender/arm/props_ui.py b/blender/arm/props_ui.py index ed5652daf9..1ee947f6f7 100644 --- a/blender/arm/props_ui.py +++ b/blender/arm/props_ui.py @@ -68,6 +68,7 @@ def draw(self, context): col.prop(obj, 'arm_spawn') col.prop(obj, 'arm_mobile') col.prop(obj, 'arm_animation_enabled') + col.prop(obj, 'arm_lighting') if obj.type == 'MESH': layout.prop(obj, 'arm_instanced') @@ -724,7 +725,10 @@ def draw(self, context): if state.proc_play is None and state.proc_build is None: row.operator("arm.play", icon="PLAY") else: - row.operator("arm.stop", icon="MESH_PLANE") + if bpy.app.version < (3, 0, 0): + row.operator("arm.stop", icon="CANCEL", text="") + else: + row.operator("arm.stop", icon="SEQUENCE_COLOR_01", text="") row.operator("arm.clean_menu", icon="BRUSH_DATA") col = layout.box().column() @@ -1711,11 +1715,11 @@ def draw(self, context): col3 = col.column() col3.enabled = rpdat.rp_voxels == 'Voxel AO' col.prop(rpdat, 'arm_voxelgi_shadows', text='Shadows') - #col2.prop(rpdat, 'arm_voxelgi_refraction', text='Refraction') - #col2.prop(rpdat, 'arm_voxelgi_bounces') + col2.prop(rpdat, 'arm_voxelgi_refract', text='Refraction') col.prop(rpdat, 'arm_voxelgi_clipmap_count') #col.prop(rpdat, 'arm_voxelgi_cones') col.prop(rpdat, 'rp_voxelgi_resolution') + col.prop(rpdat, 'arm_voxelgi_size') #col.prop(rpdat, 'rp_voxelgi_resolution_z') col2.enabled = rpdat.rp_voxels == 'Voxel GI' #col.prop(rpdat, 'arm_voxelgi_temporal') @@ -1724,13 +1728,13 @@ def draw(self, context): col2.enabled = rpdat.rp_voxels == 'Voxel GI' col2.prop(rpdat, 'arm_voxelgi_diff') col2.prop(rpdat, 'arm_voxelgi_spec') - #col2.prop(rpdat, 'arm_voxelgi_refr') + col2.prop(rpdat, 'arm_voxelgi_refr') + col.prop(rpdat, 'arm_voxelgi_shad') col.prop(rpdat, 'arm_voxelgi_occ') col.label(text="Ray") - col.prop(rpdat, 'arm_voxelgi_size') + col.prop(rpdat, 'arm_voxelgi_offset') col.prop(rpdat, 'arm_voxelgi_step') col.prop(rpdat, 'arm_voxelgi_range') - #col.prop(rpdat, 'arm_voxelgi_offset') #col.prop(rpdat, 'arm_voxelgi_aperture') class ARM_PT_RenderPathWorldPanel(bpy.types.Panel): diff --git a/blender/arm/utils.py b/blender/arm/utils.py index c6a2b3cf45..a2f0b4a120 100644 --- a/blender/arm/utils.py +++ b/blender/arm/utils.py @@ -760,7 +760,7 @@ def get_render_resolution(scene): return int(render.resolution_x * scale), int(render.resolution_y * scale) def get_texture_quality_percentage() -> int: - return int(bpy.data.worlds["Arm"].arm_texture_quality * 100) + return int(bpy.data.worlds['Arm'].arm_texture_quality * 100) def get_project_scene_name(): return get_active_scene().name diff --git a/blender/arm/write_data.py b/blender/arm/write_data.py index c1123dc7bc..12c6cbf60e 100644 --- a/blender/arm/write_data.py +++ b/blender/arm/write_data.py @@ -232,7 +232,7 @@ def write_khafilejs(is_play, export_physics: bool, export_navigation: bool, expo khafile.write('project.addShaders("' + shaders_path + '", { noprocessing: true, noembed: ' + str(noembed).lower() + ' });\n') # Move assets for published game to /data folder - use_data_dir = is_publish and (state.target == 'krom-windows' or state.target == 'krom-linux' or state.target == 'windows-hl' or state.target == 'linux-hl') + use_data_dir = is_publish and (state.target == 'krom-windows' or state.target == 'krom-linux' or state.target == 'windows-hl' or state.target == 'linux-hl' or state.target == 'html5') if use_data_dir: assets.add_khafile_def('arm_data_dir') @@ -347,6 +347,9 @@ def write_khafilejs(is_play, export_physics: bool, export_navigation: bool, expo if wrd.arm_winresize or state.target == 'html5': assets.add_khafile_def('arm_resizable') + if get_winmode(wrd.arm_winmode) == 1 and state.target.startswith('html5'): + assets.add_khafile_def('kha_html5_disable_automatic_size_adjust') + # if bpy.data.scenes[0].unit_settings.system_rotation == 'DEGREES': # assets.add_khafile_def('arm_degrees') @@ -467,13 +470,14 @@ def write_mainhx(scene_name, resx, resy, is_play, is_publish): with open('Sources/Main.hx', 'w', encoding="utf-8") as f: f.write( """// Auto-generated -package ; +package;\n""") + + f.write(""" class Main { public static inline var projectName = '""" + arm.utils.safestr(wrd.arm_project_name) + """'; public static inline var projectVersion = '""" + arm.utils.safestr(wrd.arm_project_version) + """'; public static inline var projectPackage = '""" + arm.utils.safestr(wrd.arm_project_package) + """';""") - if rpdat.rp_voxels == 'Voxel GI' or rpdat.rp_voxels == 'Voxel AO': f.write(""" public static inline var voxelgiClipmapCount = """ + str(rpdat.arm_voxelgi_clipmap_count) + """; @@ -486,11 +490,13 @@ class Main { f.write(""" public static inline var resolutionSize = """ + str(rpdat.arm_rp_resolution_size) + """;""") - f.write(""" + f.write("""\n public static function main() {""") + if rpdat.arm_skin != 'Off': f.write(""" iron.object.BoneAnimation.skinMaxBones = """ + str(rpdat.arm_skin_max_bones) + """;""") + if rpdat.rp_shadows: if rpdat.rp_shadowmap_cascades != '1': f.write(""" @@ -499,6 +505,7 @@ class Main { if rpdat.arm_shadowmap_bounds != 1.0: f.write(""" iron.object.LightObject.cascadeBounds = """ + str(rpdat.arm_shadowmap_bounds) + """;""") + if is_publish and wrd.arm_loadscreen: asset_references = list(set(assets.assets)) loadscreen_class = 'armory.trait.internal.LoadingScreen' @@ -507,11 +514,15 @@ class Main { f.write(""" armory.system.Starter.numAssets = """ + str(len(asset_references)) + """; armory.system.Starter.drawLoading = """ + loadscreen_class + """.render;""") + if wrd.arm_ui == 'Enabled': if wrd.arm_canvas_img_scaling_quality == 'low': - f.write(f"armory.ui.Canvas.imageScaleQuality = kha.graphics2.ImageScaleQuality.Low;") + f.write(""" + armory.ui.Canvas.imageScaleQuality = kha.graphics2.ImageScaleQuality.Low;""") elif wrd.arm_canvas_img_scaling_quality == 'high': - f.write(f"armory.ui.Canvas.imageScaleQuality = kha.graphics2.ImageScaleQuality.High;") + f.write(""" + armory.ui.Canvas.imageScaleQuality = kha.graphics2.ImageScaleQuality.High;""") + f.write(""" armory.system.Starter.main( '""" + arm.utils.safestr(scene_name) + scene_ext + """', @@ -526,8 +537,8 @@ class Main { """ + pathpack + """.renderpath.RenderPathCreator.get ); } -} -""") +}""") + def write_indexhtml(w, h, is_publish): wrd = bpy.data.worlds['Arm'] @@ -555,7 +566,7 @@ def write_indexhtml(w, h, is_publish): """) if rpdat.rp_stereo or wrd.arm_winmode == 'Fullscreen': f.write(""" - + """) else: f.write(""" @@ -601,7 +612,7 @@ def write_compiledglsl(defs, make_variants): f.write(f'#define GBUF_IDX_EMISSION {idx_emission}\n') idx_refraction += 1 - if '_SSRefraction' in wrd.world_defs: + if '_SSRefraction' in wrd.world_defs or '_VoxelRefract' in wrd.world_defs: f.write(f'#define GBUF_IDX_REFRACTION {idx_refraction}\n') f.write("""#if defined(HLSL) || defined(METAL) @@ -773,11 +784,12 @@ def write_compiledglsl(defs, make_variants): f.write("""const ivec3 voxelgiResolution = ivec3(""" + str(rpdat.rp_voxelgi_resolution) + """, """ + str(rpdat.rp_voxelgi_resolution) + """, """ + str(rpdat.rp_voxelgi_resolution) + """); const int voxelgiClipmapCount = """ + str(rpdat.arm_voxelgi_clipmap_count) + """; const float voxelgiOcc = """ + str(round(rpdat.arm_voxelgi_occ * 100) / 100) + """; -const float voxelgiVoxelSize = """ + str(round(rpdat.arm_voxelgi_size * 100) / 100) + """; -const float voxelgiStep = """ + str(round(rpdat.arm_voxelgi_step * 100) / 100) + """; +const float voxelgiVoxelSize = """ + str(round(rpdat.arm_voxelgi_size * 1000) / 1000) + """; +const float voxelgiStep = """ + str(round(rpdat.arm_voxelgi_step * 1000) / 1000) + """; const float voxelgiRange = """ + str(round(rpdat.arm_voxelgi_range * 100) / 100) + """; -const float voxelgiOffset = """ + str(round(rpdat.arm_voxelgi_offset * 100) / 100) + """; +const float voxelgiOffset = """ + str(round(rpdat.arm_voxelgi_offset * 1000) / 1000) + """; const float voxelgiAperture = """ + str(round(rpdat.arm_voxelgi_aperture * 100) / 100) + """; +const float voxelgiShad = """ + str(round(rpdat.arm_voxelgi_shad * 100) / 100) + """; """) if rpdat.rp_voxels == 'Voxel GI': f.write(""" diff --git a/blender/arm/write_probes.py b/blender/arm/write_probes.py index 4f3bb8e13b..453a80588c 100644 --- a/blender/arm/write_probes.py +++ b/blender/arm/write_probes.py @@ -57,7 +57,10 @@ def setup_envmap_render(): scene.render.image_settings.color_depth = '32' # Export in linear space and with default color management settings - scene.display_settings.display_device = "None" + if bpy.app.version < (4, 1, 0): + scene.display_settings.display_device = "None" + else: + scene.display_settings.display_device = "sRGB" scene.view_settings.view_transform = "Standard" scene.view_settings.look = "None" scene.view_settings.exposure = 0 @@ -93,7 +96,10 @@ def setup_envmap_render(): cam_obj.location = [0.0, 0.0, 0.0] cam.type = "PANO" - cam.cycles.panorama_type = "EQUIRECTANGULAR" + if bpy.app.version < (4, 1, 0): + cam.cycles.panorama_type = "EQUIRECTANGULAR" + else: + cam.panorama_type = "EQUIRECTANGULAR" cam_obj.rotation_euler = [math.radians(90), 0, math.radians(-90)] try: