Merge pull request #2 from armory3d/master

merging latest from armory3d/armory
This commit is contained in:
Forest Collins Sharp 2020-03-07 08:44:02 -06:00 committed by GitHub
commit 8958668215
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
83 changed files with 2738 additions and 160 deletions

View file

@ -4,16 +4,27 @@
uniform sampler2D tex;
uniform vec3 PPComp10;
in vec2 texCoord;
out vec4 fragColor;
void main() {
vec3 col = textureLod(tex, texCoord, 0.0).rgb;
float brightness = dot(col, vec3(0.2126, 0.7152, 0.0722));
if (brightness > bloomThreshold) {
fragColor.rgb = col;
}
else {
fragColor.rgb = vec3(0.0);
}
#ifdef _CPostprocess
if (brightness > PPComp10.z) {
fragColor.rgb = col;
}
else {
fragColor.rgb = vec3(0.0);
}
#else
if (brightness > bloomThreshold) {
fragColor.rgb = col;
}
else {
fragColor.rgb = vec3(0.0);
}
#endif
}

View file

@ -5,7 +5,12 @@
"depth_write": false,
"compare_mode": "always",
"cull_mode": "none",
"links": [],
"links": [
{
"name": "PPComp10",
"link": "_PPComp10"
}
],
"texture_params": [],
"vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "bloom_pass.frag.glsl"

View file

@ -7,13 +7,19 @@ uniform sampler2D tex;
uniform vec2 dir;
uniform vec2 screenSize;
uniform vec3 PPComp11;
in vec2 texCoord;
out vec4 fragColor;
const float weight[10] = float[] (0.132572, 0.125472, 0.106373, 0.08078, 0.05495, 0.033482, 0.018275, 0.008934, 0.003912, 0.001535);
void main() {
vec2 step = (dir / screenSize.xy) * bloomRadius;
#ifdef _CPostprocess
vec2 step = (dir / screenSize.xy) * PPComp11.y;
#else
vec2 step = (dir / screenSize.xy) * bloomRadius;
#endif
fragColor.rgb = textureLod(tex, texCoord, 0.0).rgb * weight[0];
for (int i = 1; i < 10; i++) {
vec2 s = step * (float(i) + 0.5);
@ -21,6 +27,10 @@ void main() {
fragColor.rgb += textureLod(tex, texCoord - s, 0.0).rgb * weight[i];
}
fragColor.rgb *= bloomStrength / 5;
#ifdef _CPostprocess
fragColor.rgb *= PPComp11.x / 5;
#else
fragColor.rgb *= bloomStrength / 5;
#endif
fragColor.rgb = min(fragColor.rgb, 64.0);
}

View file

@ -13,6 +13,10 @@
{
"name": "screenSize",
"link": "_windowSize"
},
{
"name": "PPComp11",
"link": "_PPComp11"
}
],
"texture_params": [],
@ -32,6 +36,10 @@
{
"name": "screenSize",
"link": "_windowSize"
},
{
"name": "PPComp11",
"link": "_PPComp11"
}
],
"texture_params": [],
@ -54,6 +62,10 @@
{
"name": "screenSize",
"link": "_windowSize"
},
{
"name": "PPComp11",
"link": "_PPComp11"
}
],
"texture_params": [],

View file

@ -3,6 +3,7 @@
#include "compiled.inc"
uniform sampler2D tex;
uniform vec3 PPComp13;
in vec2 texCoord;
out vec4 fragColor;
@ -36,8 +37,13 @@ vec4 spectrum_offset(float t) {
void main() {
float max_distort = compoChromaticStrength;
int num_iter = compoChromaticSamples;
#ifdef _CPostprocess
float max_distort = PPComp13.x;
int num_iter = int(PPComp13.y);
#else
float max_distort = compoChromaticStrength;
int num_iter = compoChromaticSamples;
#endif
float reci_num_iter_f = 1.0 / float(num_iter);

View file

@ -6,7 +6,12 @@
"color_write_alpha": false,
"compare_mode": "always",
"cull_mode": "none",
"links": [],
"links": [
{
"name": "PPComp13",
"link": "_PPComp13"
}
],
"texture_params": [],
"vertex_shader": "../include/pass.vert.glsl",
"fragment_shader": "chromatic_aberration_pass.frag.glsl"

View file

@ -6,6 +6,9 @@
#ifdef _CDOF
#include "std/dof.glsl"
#endif
#ifdef _CPostprocess
#include "std/colorgrading.glsl"
#endif
uniform sampler2D tex;
#ifdef _CDepth
@ -24,6 +27,43 @@ uniform sampler2D lutTexture;
uniform sampler2D histogram;
#endif
#ifdef _CPostprocess
uniform vec3 globalWeight;
uniform vec3 globalTint;
uniform vec3 globalSaturation;
uniform vec3 globalContrast;
uniform vec3 globalGamma;
uniform vec3 globalGain;
uniform vec3 globalOffset;
uniform vec3 shadowSaturation;
uniform vec3 shadowContrast;
uniform vec3 shadowGamma;
uniform vec3 shadowGain;
uniform vec3 shadowOffset;
uniform vec3 midtoneSaturation;
uniform vec3 midtoneContrast;
uniform vec3 midtoneGamma;
uniform vec3 midtoneGain;
uniform vec3 midtoneOffset;
uniform vec3 highlightSaturation;
uniform vec3 highlightContrast;
uniform vec3 highlightGamma;
uniform vec3 highlightGain;
uniform vec3 highlightOffset;
uniform vec3 PPComp1;
uniform vec3 PPComp2;
uniform vec3 PPComp3;
uniform vec3 PPComp4;
uniform vec3 PPComp5;
uniform vec3 PPComp6;
uniform vec3 PPComp7;
uniform vec3 PPComp8;
#endif
// #ifdef _CPos
// uniform vec3 eye;
// uniform vec3 eyeLook;
@ -77,6 +117,25 @@ vec3 applyFog(vec3 rgb, float distance) {
}
#endif
#ifdef _CPostprocess
float ComputeEV100(const float aperture2, const float shutterTime, const float ISO) {
return log2(aperture2 / shutterTime * 100.0 / ISO);
}
float ConvertEV100ToExposure(float EV100) {
return 1/0.8 * exp2(-EV100);
}
float ComputeEV(float avgLuminance) {
const float sqAperture = PPComp1[0].x * PPComp1.x;
const float shutterTime = 1.0 / PPComp1.y;
const float ISO = PPComp1.z;
const float EC = PPComp2.x;
float EV100 = ComputeEV100(sqAperture, shutterTime, ISO);
return ConvertEV100ToExposure(EV100 - EC) * PI;
}
#endif
vec4 LUTlookup(in vec4 textureColor, in sampler2D lookupTable) {
//Clamp to prevent weird results
@ -154,7 +213,11 @@ void main() {
#endif
#ifdef _CFishEye
const float fishEyeStrength = -0.01;
#ifdef _CPostprocess
const float fishEyeStrength = -(PPComp2.y);
#else
const float fishEyeStrength = -0.01;
#endif
const vec2 m = vec2(0.5, 0.5);
vec2 d = texCo - m;
float r = sqrt(dot(d, d));
@ -225,7 +288,23 @@ void main() {
#else
#ifdef _CDOF
fragColor = vec4(dof(texCo, depth, tex, gbufferD, texStep, cameraProj), 1.0);
#ifdef _CPostprocess
bool compoAutoFocus = false;
float compoDistance = PPComp3.x;
float compoLength = PPComp3.y;
float compoStop = PPComp3.z;
if (PPComp2.z == 1){
compoAutoFocus = true;
} else {
compoAutoFocus = false;
}
fragColor.rgb = dof(texCo, depth, tex, gbufferD, texStep, cameraProj, compoAutoFocus, compoDistance, compoLength, compoStop);
#else
fragColor.rgb = dof(texCo, depth, tex, gbufferD, texStep, cameraProj, true, compoDOFDistance, compoDOFLength, compoDOFFstop);
#endif
#else
fragColor = textureLod(tex, texCo, 0.0);
#endif
@ -271,7 +350,11 @@ void main() {
#ifdef _CGrain
// const float compoGrainStrength = 4.0;
float x = (texCo.x + 4.0) * (texCo.y + 4.0) * (time * 10.0);
fragColor.rgb += vec3(mod((mod(x, 13.0) + 1.0) * (mod(x, 123.0) + 1.0), 0.01) - 0.005) * compoGrainStrength;
#ifdef _CPostprocess
fragColor.rgb += vec3(mod((mod(x, 13.0) + 1.0) * (mod(x, 123.0) + 1.0), 0.01) - 0.005) * PPComp4.y;
#else
fragColor.rgb += vec3(mod((mod(x, 13.0) + 1.0) * (mod(x, 123.0) + 1.0), 0.01) - 0.005) * compoGrainStrength;
#endif
#endif
#ifdef _CGrainStatic
@ -287,28 +370,96 @@ void main() {
fragColor.rgb += fragColor.rgb * compoExposureStrength;
#endif
#ifdef _CPostprocess
fragColor.rgb *= ComputeEV(0.0);
#endif
#ifdef _AutoExposure
float expo = 2.0 - clamp(length(textureLod(histogram, vec2(0.5, 0.5), 0).rgb), 0.0, 1.0);
fragColor.rgb *= pow(expo, autoExposureStrength * 2.0);
#endif
#ifdef _CToneFilmic
fragColor.rgb = tonemapFilmic(fragColor.rgb); // With gamma
#endif
#ifdef _CToneFilmic2
fragColor.rgb = acesFilm(fragColor.rgb);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));
#endif
#ifdef _CToneReinhard
fragColor.rgb = tonemapReinhard(fragColor.rgb);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));
#endif
#ifdef _CToneUncharted
fragColor.rgb = tonemapUncharted2(fragColor.rgb);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
#endif
#ifdef _CToneNone
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
#ifdef _CPostprocess
#ifdef _CToneCustom
fragColor.rgb = clamp((fragColor.rgb * (PPComp4.z * fragColor.rgb + PPComp5.x)) / (fragColor.rgb * (PPComp5.y * fragColor.rgb + PPComp5.z) + PPComp6.x), 0.0, 1.0);
#else
if(PPComp4.x == 0){ //Filmic 1
fragColor.rgb = tonemapFilmic(fragColor.rgb); // With gamma
} else if (PPComp4.x == 1){ //Filmic 2
fragColor.rgb = acesFilm(fragColor.rgb);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));
} else if (PPComp4.x == 2){ //Reinhard
fragColor.rgb = tonemapReinhard(fragColor.rgb);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));
} else if (PPComp4.x == 3){ //Uncharted2
fragColor.rgb = tonemapUncharted2(fragColor.rgb);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
fragColor.rgb = clamp(fragColor.rgb, 0.0, 1.0);
} else if (PPComp4.x == 4){ //None
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
} else if (PPComp4.x == 5){ //Non-Gamma / Linear
fragColor.rgb = fragColor.rgb;
} else if (PPComp4.x == 6){ //HDP
vec3 x = fragColor.rgb - 0.004;
//vec3 x = max(0, fragColor.rgb - 0.004);
fragColor.rgb = (x*(6.2*x+.5))/(x*(6.2*x+1.7)+0.06);
} else if (PPComp4.x == 7){ //Raw
vec4 vh = vec4(fragColor.rgb, 1);
vec4 va = (1.425 * vh) + 0.05;
vec4 vf = ((vh * va + 0.004) / ((vh * (va + 0.55) + 0.0491))) - 0.0821;
fragColor.rgb = vf.rgb / vf.www;
} else if (PPComp4.x == 8){ //False Colors for luminance control
vec4 c = vec4(fragColor.r,fragColor.g,fragColor.b,0); //Linear without gamma
vec3 luminanceVector = vec3(0.2125, 0.7154, 0.0721); //Relative Luminance Vector
float luminance = dot(luminanceVector, c.xyz);
vec3 maxLumColor = vec3(1,0,0); //High values (> 1.0)
//float maxLum = 2.0; Needs to read the highest pixel, but I don't know how to yet
//Probably easier with a histogram too, once it's it in place?
vec3 midLumColor = vec3(0,1,0); //Mid values (< 1.0)
float midLum = 1.0;
vec3 minLumColor = vec3(0,0,1); //Low values (< 1.0)
float minLum = 0.0;
if(luminance < midLum){
fragColor.rgb = mix(minLumColor, midLumColor, luminance);
} else {
fragColor.rgb = mix(midLumColor, maxLumColor, luminance);
}
} else {
fragColor.rgb = vec3(0,1,0); //ERROR
}
#endif
#else
#ifdef _CToneFilmic
fragColor.rgb = tonemapFilmic(fragColor.rgb); // With gamma
#endif
#ifdef _CToneFilmic2
fragColor.rgb = acesFilm(fragColor.rgb);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));
#endif
#ifdef _CToneReinhard
fragColor.rgb = tonemapReinhard(fragColor.rgb);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));
#endif
#ifdef _CToneUncharted
fragColor.rgb = tonemapUncharted2(fragColor.rgb);
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
fragColor.rgb = clamp(fragColor.rgb, 0.0, 2.2);
#endif
#ifdef _CToneNone
fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2)); // To gamma
#endif
#ifdef _CToneCustom
fragColor.rgb = clamp((fragColor.rgb * (1 * fragColor.rgb + 1)) / (fragColor.rgb * (1 * fragColor.rgb + 1 ) + 1), 0.0, 1.0);
#endif
#endif
#ifdef _CBW
@ -326,16 +477,83 @@ void main() {
// fragColor.rgb += compoBrightness;
// #endif
#ifdef _CPostprocess
//Global Values
float factor = 1;
float colorTempK = globalWeight.x;
vec3 ColorTempRGB = ColorTemperatureToRGB(colorTempK);
float originalLuminance = Luminance(fragColor.rgb);
vec3 blended = mix(fragColor.rgb, fragColor.rgb * ColorTempRGB, factor);
vec3 resultHSL = RGBtoHSL(blended);
vec3 luminancePreservedRGB = HSLtoRGB(vec3(resultHSL.x, resultHSL.y, originalLuminance));
fragColor = vec4(mix(blended, luminancePreservedRGB, LUMINANCE_PRESERVATION), 1.0);
mat3 CCSaturation = mat3 ( //Saturation
globalSaturation.r * shadowSaturation.r, globalSaturation.g * shadowSaturation.g, globalSaturation.b * shadowSaturation.b, //Shadows + Global
globalSaturation.r * midtoneSaturation.r, globalSaturation.g * midtoneSaturation.g, globalSaturation.b * midtoneSaturation.b, //Midtones + Global
globalSaturation.r * highlightSaturation.r, globalSaturation.g * highlightSaturation.g, globalSaturation.b * highlightSaturation.b //Highlights + Global
);
mat3 CCContrast = mat3 (
globalContrast.r * shadowContrast.r, globalContrast.g * shadowContrast.g, globalContrast.b * shadowContrast.b, //Shadows + Global
globalContrast.r * midtoneContrast.r, globalContrast.g * midtoneContrast.g, globalContrast.b * midtoneContrast.b, //Midtones + Global
globalContrast.r * highlightContrast.r, globalContrast.g * highlightContrast.g, globalContrast.b * highlightContrast.b //Highlights + Global
);
mat3 CCGamma = mat3 (
globalGamma.r * shadowGamma.r, globalGamma.g * shadowGamma.g, globalGamma.b * shadowGamma.b, //Shadows + Global
globalGamma.r * midtoneGamma.r, globalGamma.g * midtoneGamma.g, globalGamma.b * midtoneGamma.b, //Midtones + Global
globalGamma.r * highlightGamma.r, globalGamma.g * highlightGamma.g, globalGamma.b * highlightGamma.b //Highlights + Global
);
mat3 CCGain = mat3 (
globalGain.r * shadowGain.r, globalGain.g * shadowGain.g, globalGain.b * shadowGain.b, //Shadows + Global
globalGain.r * midtoneGain.r, globalGain.g * midtoneGain.g, globalGain.b * midtoneGain.b, //Midtones + Global
globalGain.r * highlightGain.r, globalGain.g * highlightGain.g, globalGain.b * highlightGain.b //Highlights + Global
);
mat3 CCOffset = mat3 (
globalOffset.r * shadowOffset.r, globalOffset.g * shadowOffset.g, globalOffset.b * shadowOffset.b, //Shadows + Global
globalOffset.r * midtoneOffset.r, globalOffset.g * midtoneOffset.g, globalOffset.b * midtoneOffset.b, //Midtones + Global
globalOffset.r * highlightOffset.r, globalOffset.g * highlightOffset.g, globalOffset.b * highlightOffset.b //Highlights + Global
);
vec2 ToneWeights = vec2(globalWeight.y, globalWeight.z);
fragColor.rgb = FinalizeColorCorrection(
fragColor.rgb,
CCSaturation,
CCContrast,
CCGamma,
CCGain,
CCOffset,
ToneWeights
);
//Tint
fragColor.rgb *= vec3(globalTint.r,globalTint.g,globalTint.b);
#endif
#ifdef _CLensTex
#ifdef _CLensTexMasking
vec4 scratches = texture(lensTexture, texCo);
vec3 scratchBlend = fragColor.rgb + scratches.rgb;
float centerMaxClip = compoCenterMaxClip;
float centerMinClip = compoCenterMinClip;
float luminanceMax = compoLuminanceMax;
float luminanceMin = compoLuminanceMin;
float brightnessExp = compoBrightnessExponent;
#ifdef _CPostprocess
float centerMaxClip = PPComp6.y;
float centerMinClip = PPComp6.z;
float luminanceMax = PPComp7.x;
float luminanceMin = PPComp7.y;
float brightnessExp = PPComp7.z;
#else
float centerMaxClip = compoCenterMaxClip;
float centerMinClip = compoCenterMinClip;
float luminanceMax = compoLuminanceMax;
float luminanceMin = compoLuminanceMin;
float brightnessExp = compoBrightnessExponent;
#endif
float center = smoothstep(centerMaxClip, centerMinClip, length(texCo - 0.5));
float luminance = dot(fragColor.rgb, vec3(0.299, 0.587, 0.114));

View file

@ -75,6 +75,156 @@
"name": "lutTexture",
"link": "$luttexture.jpg",
"ifdef": ["_CLUT"]
},
{
"name": "globalWeight",
"link": "_globalWeight",
"ifdef": ["_CPostprocess"]
},
{
"name": "globalTint",
"link": "_globalTint",
"ifdef": ["_CPostprocess"]
},
{
"name": "globalSaturation",
"link": "_globalSaturation",
"ifdef": ["_CPostprocess"]
},
{
"name": "globalContrast",
"link": "_globalContrast",
"ifdef": ["_CPostprocess"]
},
{
"name": "globalGamma",
"link": "_globalGamma",
"ifdef": ["_CPostprocess"]
},
{
"name": "globalGain",
"link": "_globalGain",
"ifdef": ["_CPostprocess"]
},
{
"name": "globalOffset",
"link": "_globalOffset",
"ifdef": ["_CPostprocess"]
},
{
"name": "shadowSaturation",
"link": "_shadowSaturation",
"ifdef": ["_CPostprocess"]
},
{
"name": "shadowContrast",
"link": "_shadowContrast",
"ifdef": ["_CPostprocess"]
},
{
"name": "shadowGamma",
"link": "_shadowGamma",
"ifdef": ["_CPostprocess"]
},
{
"name": "shadowGain",
"link": "_shadowGain",
"ifdef": ["_CPostprocess"]
},
{
"name": "shadowOffset",
"link": "_shadowOffset",
"ifdef": ["_CPostprocess"]
},
{
"name": "midtoneSaturation",
"link": "_midtoneSaturation",
"ifdef": ["_CPostprocess"]
},
{
"name": "midtoneContrast",
"link": "_midtoneContrast",
"ifdef": ["_CPostprocess"]
},
{
"name": "midtoneGamma",
"link": "_midtoneGamma",
"ifdef": ["_CPostprocess"]
},
{
"name": "midtoneGain",
"link": "_midtoneGain",
"ifdef": ["_CPostprocess"]
},
{
"name": "midtoneOffset",
"link": "_midtoneOffset",
"ifdef": ["_CPostprocess"]
},
{
"name": "highlightSaturation",
"link": "_highlightSaturation",
"ifdef": ["_CPostprocess"]
},
{
"name": "highlightContrast",
"link": "_highlightContrast",
"ifdef": ["_CPostprocess"]
},
{
"name": "highlightGamma",
"link": "_highlightGamma",
"ifdef": ["_CPostprocess"]
},
{
"name": "highlightGain",
"link": "_highlightGain",
"ifdef": ["_CPostprocess"]
},
{
"name": "highlightOffset",
"link": "_highlightOffset",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp1",
"link": "_PPComp1",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp2",
"link": "_PPComp2",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp3",
"link": "_PPComp3",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp4",
"link": "_PPComp4",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp5",
"link": "_PPComp5",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp6",
"link": "_PPComp6",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp7",
"link": "_PPComp7",
"ifdef": ["_CPostprocess"]
},
{
"name": "PPComp8",
"link": "_PPComp8",
"ifdef": ["_CPostprocess"]
}
],
"texture_params": [],

View file

@ -12,6 +12,9 @@ uniform vec3 eyeLook;
uniform vec2 screenSize;
uniform mat4 invVP;
uniform vec3 PPComp11;
uniform vec3 PPComp12;
in vec2 texCoord;
in vec3 viewRay;
out float fragColor;
@ -30,7 +33,11 @@ void main() {
vec3 currentPos = getPosNoEye(eyeLook, vray, depth, cameraProj);
// vec3 currentPos = getPos2NoEye(eye, invVP, depth, texCoord);
float currentDistance = length(currentPos);
float currentDistanceA = currentDistance * ssaoScale * (1.0 / ssaoRadius);
#ifdef _CPostprocess
float currentDistanceA = currentDistance * PPComp12.y * (1.0 / PPComp11.z);
#else
float currentDistanceA = currentDistance * ssaoScale * (1.0 / ssaoRadius);
#endif
float currentDistanceB = currentDistance * 0.0005;
ivec2 px = ivec2(texCoord * screenSize);
float phi = (3 * px.x ^ px.y + px.x * px.y) * 10;
@ -47,6 +54,10 @@ void main() {
fragColor += max(0, dot(pos, n) - currentDistanceB) / (dot(pos, pos) + 0.015);
}
fragColor *= (ssaoStrength * 0.3) / samples;
#ifdef _CPostprocess
fragColor *= (PPComp12.x * 0.3) / samples;
#else
fragColor *= (ssaoStrength * 0.3) / samples;
#endif
fragColor = 1.0 - fragColor;
}

View file

@ -25,6 +25,14 @@
{
"name": "screenSize",
"link": "_screenSize"
},
{
"name": "PPComp11",
"link": "_PPComp11"
},
{
"name": "PPComp12",
"link": "_PPComp12"
}
],
"texture_params": [],

View file

@ -12,6 +12,9 @@ uniform mat4 P;
uniform mat3 V3;
uniform vec2 cameraProj;
uniform vec3 PPComp9;
uniform vec3 PPComp10;
in vec3 viewRay;
in vec2 texCoord;
out vec4 fragColor;
@ -48,12 +51,20 @@ vec4 binarySearch(vec3 dir) {
if (ddepth < 0.0) hitCoord += dir;
}
// Ugly discard of hits too far away
if (abs(ddepth) > ssrSearchDist / 500) return vec4(0.0);
#ifdef _CPostprocess
if (abs(ddepth) > PPComp9.z / 500) return vec4(0.0);
#else
if (abs(ddepth) > ssrSearchDist / 500) return vec4(0.0);
#endif
return vec4(getProjectedCoord(hitCoord), 0.0, 1.0);
}
vec4 rayCast(vec3 dir) {
dir *= ssrRayStep;
#ifdef _CPostprocess
dir *= PPComp9.x;
#else
dir *= ssrRayStep;
#endif
for (int i = 0; i < maxSteps; i++) {
hitCoord += dir;
if (getDeltaDepth(hitCoord) > 0.0) return binarySearch(dir);
@ -63,7 +74,7 @@ vec4 rayCast(vec3 dir) {
void main() {
vec4 g0 = textureLod(gbuffer0, texCoord, 0.0);
float roughness = g0.b;
float roughness = unpackFloat(g0.b).y;
if (roughness == 1.0) { fragColor.rgb = vec3(0.0); return; }
float spec = fract(textureLod(gbuffer1, texCoord, 0.0).a);
@ -83,7 +94,12 @@ void main() {
vec3 reflected = normalize(reflect(viewPos, viewNormal));
hitCoord = viewPos;
vec3 dir = reflected * (1.0 - rand(texCoord) * ssrJitter * roughness) * 2.0;
#ifdef _CPostprocess
vec3 dir = reflected * (1.0 - rand(texCoord) * PPComp10.y * roughness) * 2.0;
#else
vec3 dir = reflected * (1.0 - rand(texCoord) * ssrJitter * roughness) * 2.0;
#endif
// * max(ssrMinRayStep, -viewPos.z)
vec4 coords = rayCast(dir);
@ -91,12 +107,11 @@ void main() {
float screenEdgeFactor = clamp(1.0 - (deltaCoords.x + deltaCoords.y), 0.0, 1.0);
float reflectivity = 1.0 - roughness;
float intensity = pow(reflectivity, ssrFalloffExp) *
screenEdgeFactor *
clamp(-reflected.z, 0.0, 1.0) *
clamp((ssrSearchDist - length(viewPos - hitCoord)) *
(1.0 / ssrSearchDist), 0.0, 1.0) *
coords.w;
#ifdef _CPostprocess
float intensity = pow(reflectivity, PPComp10.x) * screenEdgeFactor * clamp(-reflected.z, 0.0, 1.0) * clamp((PPComp9.z - length(viewPos - hitCoord)) * (1.0 / PPComp9.z), 0.0, 1.0) * coords.w;
#else
float intensity = pow(reflectivity, ssrFalloffExp) * screenEdgeFactor * clamp(-reflected.z, 0.0, 1.0) * clamp((ssrSearchDist - length(viewPos - hitCoord)) * (1.0 / ssrSearchDist), 0.0, 1.0) * coords.w;
#endif
intensity = clamp(intensity, 0.0, 1.0);
vec3 reflCol = textureLod(tex, coords.xy, 0.0).rgb;

View file

@ -21,6 +21,14 @@
{
"name": "cameraProj",
"link": "_cameraPlaneProj"
},
{
"name": "PPComp9",
"link": "_PPComp9"
},
{
"name": "PPComp10",
"link": "_PPComp10"
}
],
"texture_params": [],

View file

@ -0,0 +1,144 @@
// Colorgrading library functions - Inspired by UE4
//No specific license (maybe zlib), but just do whatever
#define LUMINANCE_PRESERVATION 0.75
#define EPSILON 1e-10
#define LUMA1 0.2722287168
#define LUMA2 0.6740817658
#define LUMA3 0.0536895174
float saturate(float v) { return clamp(v, 0.0, 1.0); }
vec2 saturate(vec2 v) { return clamp(v, vec2(0.0), vec2(1.0)); }
vec3 saturate(vec3 v) { return clamp(v, vec3(0.0), vec3(1.0)); }
vec4 saturate(vec4 v) { return clamp(v, vec4(0.0), vec4(1.0)); }
float LumaKey (vec3 color) {
return dot(color, vec3(LUMA1, LUMA2, LUMA3));
}
vec3 ColorTemperatureToRGB(float temperatureInKelvins)
{
vec3 retColor;
temperatureInKelvins = clamp(temperatureInKelvins, 1000.0, 40000.0) / 100.0;
if (temperatureInKelvins <= 66.0)
{
retColor.r = 1.0;
retColor.g = saturate(0.39008157876901960784 * log(temperatureInKelvins) - 0.63184144378862745098);
}
else
{
float t = temperatureInKelvins - 60.0;
retColor.r = saturate(1.29293618606274509804 * pow(t, -0.1332047592));
retColor.g = saturate(1.12989086089529411765 * pow(t, -0.0755148492));
}
if (temperatureInKelvins >= 66.0)
retColor.b = 1.0;
else if(temperatureInKelvins <= 19.0)
retColor.b = 0.0;
else
retColor.b = saturate(0.54320678911019607843 * log(temperatureInKelvins - 10.0) - 1.19625408914);
return retColor;
}
float Luminance(vec3 color)
{
float fmin = min(min(color.r, color.g), color.b);
float fmax = max(max(color.r, color.g), color.b);
return (fmax + fmin) / 2.0;
}
vec3 HUEtoRGB(float H)
{
float R = abs(H * 6.0 - 3.0) - 1.0;
float G = 2.0 - abs(H * 6.0 - 2.0);
float B = 2.0 - abs(H * 6.0 - 4.0);
return saturate(vec3(R,G,B));
}
vec3 HSLtoRGB(in vec3 HSL)
{
vec3 RGB = HUEtoRGB(HSL.x);
float C = (1.0 - abs(2.0 * HSL.z - 1.0)) * HSL.y;
return (RGB - 0.5) * C + vec3(HSL.z);
}
vec3 RGBtoHCV(vec3 RGB)
{
vec4 P = (RGB.g < RGB.b) ? vec4(RGB.bg, -1.0, 2.0/3.0) : vec4(RGB.gb, 0.0, -1.0/3.0);
vec4 Q = (RGB.r < P.x) ? vec4(P.xyw, RGB.r) : vec4(RGB.r, P.yzx);
float C = Q.x - min(Q.w, Q.y);
float H = abs((Q.w - Q.y) / (6.0 * C + EPSILON) + Q.z);
return vec3(H, C, Q.x);
}
vec3 RGBtoHSL(vec3 RGB)
{
vec3 HCV = RGBtoHCV(RGB);
float L = HCV.z - HCV.y * 0.5;
float S = HCV.y / (1.0 - abs(L * 2.0 - 1.0) + EPSILON);
return vec3(HCV.x, S, L);
}
vec3 ToneColorCorrection(vec3 Color, vec3 ColorSaturation, vec3 ColorContrast, vec3 ColorGamma, vec3 ColorGain, vec3 ColorOffset) {
//First initialize the colorluma key
float ColorLuma = LumaKey(Color);
//Add the saturation with the above key
Color = max(vec3(0,0,0), mix(ColorLuma.xxx, Color, ColorSaturation));
//Contrast with slight color correction (0.18 coefficient)
float ContrastCorrectionCoefficient = 0.18;
Color = pow(Color * (1.0 / ContrastCorrectionCoefficient), ColorContrast) * ContrastCorrectionCoefficient;
//Gamma
Color = pow(Color, 1.0 / ColorGamma);
//Gain and Offset
Color = Color.rgb * ColorGain + (ColorOffset - 1);
//Return the color corrected profile
return Color;
}
vec3 FinalizeColorCorrection(vec3 Color, mat3 ColorSaturation, mat3 ColorContrast, mat3 ColorGamma, mat3 ColorGain, mat3 ColorOffset, vec2 Toneweights) {
float CCShadowsMax = Toneweights.x;
float CCHighlightsMin = Toneweights.y;
//First initialize the colorluma key and set color correction weights
float ColorLuma = LumaKey(Color);
float CCWeightShadows = 1 - smoothstep(0, CCShadowsMax, ColorLuma);
float CCWeightHighlights = smoothstep(CCHighlightsMin, 1, ColorLuma);
float CCWeightMidtones = 1 - CCWeightShadows - CCWeightHighlights;
vec3 CCColorShadows = ToneColorCorrection (
Color,
ColorSaturation[0],
ColorContrast[0],
ColorGamma[0],
ColorGain[0],
ColorOffset[0]
);
vec3 CCColorMidtones = ToneColorCorrection (
Color,
ColorSaturation[1],
ColorContrast[1],
ColorGamma[1],
ColorGain[1],
ColorOffset[1]
);
vec3 CCColorHighlights = ToneColorCorrection (
Color,
ColorSaturation[2],
ColorContrast[2],
ColorGamma[2],
ColorGain[2],
ColorOffset[2]
);
vec3 CombinedCCProfile = CCColorShadows * CCWeightShadows + CCColorMidtones * CCWeightMidtones + CCColorHighlights * CCWeightHighlights;
return vec3(CombinedCCProfile);
}

View file

@ -31,17 +31,33 @@ vec3 color(vec2 coords, const float blur, const sampler2D tex, const vec2 texSte
return col + mix(vec3(0.0), col, thresh * blur);
}
vec3 dof(const vec2 texCoord, const float gdepth, const sampler2D tex, const sampler2D gbufferD, const vec2 texStep, const vec2 cameraProj) {
vec3 dof(
const vec2 texCoord,
const float gdepth,
const sampler2D tex,
const sampler2D gbufferD,
const vec2 texStep,
const vec2 cameraProj,
const bool autoFocus,
const float DOFDistance,
const float DOFLength,
const float DOFFStop) {
float depth = linearize(gdepth, cameraProj);
// const float fDepth = compoDOFDistance;
float fDepth = linearize(textureLod(gbufferD, focus, 0.0).r * 2.0 - 1.0, cameraProj); // Autofocus
const float f = compoDOFLength; // Focal length in mm
const float d = fDepth * 1000.0; // Focal plane in mm
float fDepth = 0.0;
if(autoFocus) {
fDepth = linearize(textureLod(gbufferD, focus, 0.0).r * 2.0 - 1.0, cameraProj);
} else {
fDepth = DOFDistance;
}
float f = DOFLength; // Focal length in mm
float d = fDepth * 1000.0; // Focal plane in mm
float o = depth * 1000.0; // Depth in mm
float a = (o * f) / (o - f);
float b = (d * f) / (d - f);
float c = (d - f) / (d * compoDOFFstop * coc);
float c = (d - f) / (d * DOFFStop * coc);
float blur = abs(a - b) * c;
blur = clamp(blur, 0.0, 1.0);

View file

@ -1,5 +1,7 @@
package armory.logicnode;
import kha.arrays.Float32Array;
class AddGroupNode extends LogicNode {
public function new(tree: LogicTree) {
@ -18,7 +20,7 @@ class AddGroupNode extends LogicNode {
}
}
raw.groups.push({ name: groupName, object_refs: [] });
raw.groups.push({ name: groupName, object_refs: [], instance_offset: new Float32Array(3)});
runOutput(0);
}
}

View file

@ -0,0 +1,20 @@
package armory.logicnode;
class BloomGetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
if(from == 0) {
return armory.renderpath.Postprocess.bloom_uniforms[0];
} else if (from == 1) {
return armory.renderpath.Postprocess.bloom_uniforms[1];
} else if (from == 2) {
return armory.renderpath.Postprocess.bloom_uniforms[2];
} else {
return 0.0;
}
}
}

View file

@ -0,0 +1,17 @@
package armory.logicnode;
class BloomSetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
armory.renderpath.Postprocess.bloom_uniforms[0] = inputs[1].get();
armory.renderpath.Postprocess.bloom_uniforms[1] = inputs[2].get();
armory.renderpath.Postprocess.bloom_uniforms[2] = inputs[3].get();
runOutput(0);
}
}

View file

@ -0,0 +1,32 @@
package armory.logicnode;
class CameraGetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
if(from == 0) {
return armory.renderpath.Postprocess.camera_uniforms[0];
} else if (from == 1) {
return armory.renderpath.Postprocess.camera_uniforms[1];
} else if (from == 2) {
return armory.renderpath.Postprocess.camera_uniforms[2];
} else if (from == 3) {
return armory.renderpath.Postprocess.camera_uniforms[3];
} else if (from == 4) {
return armory.renderpath.Postprocess.camera_uniforms[4];
} else if (from == 5) {
return armory.renderpath.Postprocess.camera_uniforms[5];
} else if (from == 6) {
return armory.renderpath.Postprocess.camera_uniforms[6];
} else if (from == 7) {
return armory.renderpath.Postprocess.camera_uniforms[7];
} else if (from == 8) {
return armory.renderpath.Postprocess.camera_uniforms[8];
} else {
return 0.0;
}
}
}

View file

@ -0,0 +1,25 @@
package armory.logicnode;
class CameraSetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
armory.renderpath.Postprocess.camera_uniforms[0] = inputs[1].get();
armory.renderpath.Postprocess.camera_uniforms[1] = inputs[2].get();
armory.renderpath.Postprocess.camera_uniforms[2] = inputs[3].get();
armory.renderpath.Postprocess.camera_uniforms[3] = inputs[4].get();
armory.renderpath.Postprocess.camera_uniforms[4] = inputs[5].get();
armory.renderpath.Postprocess.camera_uniforms[5] = inputs[6].get();
armory.renderpath.Postprocess.camera_uniforms[6] = inputs[7].get();
armory.renderpath.Postprocess.camera_uniforms[7] = inputs[8].get();
armory.renderpath.Postprocess.camera_uniforms[8] = inputs[9].get();
armory.renderpath.Postprocess.camera_uniforms[9] = inputs[10].get();
armory.renderpath.Postprocess.camera_uniforms[10] = inputs[11].get();
runOutput(0);
}
}

View file

@ -0,0 +1,18 @@
package armory.logicnode;
class ChromaticAberrationGetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
if(from == 0) {
return armory.renderpath.Postprocess.chromatic_aberration_uniforms[0];
} else if (from == 1) {
return armory.renderpath.Postprocess.chromatic_aberration_uniforms[1];
} else {
return 0.0;
}
}
}

View file

@ -0,0 +1,16 @@
package armory.logicnode;
class ChromaticAberrationSetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
armory.renderpath.Postprocess.chromatic_aberration_uniforms[0] = inputs[1].get();
armory.renderpath.Postprocess.chromatic_aberration_uniforms[1] = inputs[2].get();
runOutput(0);
}
}

View file

@ -0,0 +1,29 @@
package armory.logicnode;
class ColorgradingGetGlobalNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
if(from == 0) {
return armory.renderpath.Postprocess.colorgrading_global_uniforms[0][0];
} else if (from == 1) {
return armory.renderpath.Postprocess.colorgrading_global_uniforms[1];
} else if (from == 2) {
return armory.renderpath.Postprocess.colorgrading_global_uniforms[2];
} else if (from == 3) {
return armory.renderpath.Postprocess.colorgrading_global_uniforms[3];
} else if (from == 4) {
return armory.renderpath.Postprocess.colorgrading_global_uniforms[4];
} else if (from == 5) {
return armory.renderpath.Postprocess.colorgrading_global_uniforms[5];
} else if (from == 6) {
return armory.renderpath.Postprocess.colorgrading_global_uniforms[6];
} else {
return 0.0;
}
}
}

View file

@ -0,0 +1,29 @@
package armory.logicnode;
class ColorgradingGetHighlightNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
if(from == 0) {
return armory.renderpath.Postprocess.colorgrading_highlight_uniforms[0][2];
} else if (from == 1) {
return armory.renderpath.Postprocess.colorgrading_highlight_uniforms[0];
} else if (from == 2) {
return armory.renderpath.Postprocess.colorgrading_highlight_uniforms[1];
} else if (from == 3) {
return armory.renderpath.Postprocess.colorgrading_highlight_uniforms[2];
} else if (from == 4) {
return armory.renderpath.Postprocess.colorgrading_highlight_uniforms[3];
} else if (from == 5) {
return armory.renderpath.Postprocess.colorgrading_highlight_uniforms[4];
} else if (from == 6) {
return armory.renderpath.Postprocess.colorgrading_highlight_uniforms[5];
} else {
return 0.0;
}
}
}

View file

@ -0,0 +1,27 @@
package armory.logicnode;
class ColorgradingGetMidtoneNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
if(from == 0) {
return armory.renderpath.Postprocess.colorgrading_midtone_uniforms[0];
} else if (from == 1) {
return armory.renderpath.Postprocess.colorgrading_midtone_uniforms[1];
} else if (from == 2) {
return armory.renderpath.Postprocess.colorgrading_midtone_uniforms[2];
} else if (from == 3) {
return armory.renderpath.Postprocess.colorgrading_midtone_uniforms[3];
} else if (from == 4) {
return armory.renderpath.Postprocess.colorgrading_midtone_uniforms[4];
} else if (from == 5) {
return armory.renderpath.Postprocess.colorgrading_midtone_uniforms[5];
} else {
return 0.0;
}
}
}

View file

@ -0,0 +1,29 @@
package armory.logicnode;
class ColorgradingGetShadowNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
if(from == 0) {
return armory.renderpath.Postprocess.colorgrading_shadow_uniforms[0][1];
} else if (from == 1) {
return armory.renderpath.Postprocess.colorgrading_shadow_uniforms[0];
} else if (from == 2) {
return armory.renderpath.Postprocess.colorgrading_shadow_uniforms[1];
} else if (from == 3) {
return armory.renderpath.Postprocess.colorgrading_shadow_uniforms[2];
} else if (from == 4) {
return armory.renderpath.Postprocess.colorgrading_shadow_uniforms[3];
} else if (from == 5) {
return armory.renderpath.Postprocess.colorgrading_shadow_uniforms[4];
} else if (from == 6) {
return armory.renderpath.Postprocess.colorgrading_shadow_uniforms[5];
} else {
return 0.0;
}
}
}

View file

@ -0,0 +1,65 @@
package armory.logicnode;
class ColorgradingSetGlobalNode extends LogicNode {
public var property0:Dynamic;
public var property1:Dynamic;
public var property2:Dynamic;
public var property3:Dynamic;
var value:Dynamic;
var whitebalance:Dynamic;
var tint:Dynamic;
var saturation:Dynamic;
var contrast:Dynamic;
var gamma:Dynamic;
var gain:Dynamic;
var offset:Dynamic;
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
if(property0 == "Uniform"){
armory.renderpath.Postprocess.colorgrading_global_uniforms[0][0] = inputs[1].get();
armory.renderpath.Postprocess.colorgrading_global_uniforms[1][0] = inputs[2].get().x;
armory.renderpath.Postprocess.colorgrading_global_uniforms[1][1] = inputs[2].get().y;
armory.renderpath.Postprocess.colorgrading_global_uniforms[1][2] = inputs[2].get().z;
for (i in 2...7){
armory.renderpath.Postprocess.colorgrading_global_uniforms[i][0] = inputs[i+1].get();
armory.renderpath.Postprocess.colorgrading_global_uniforms[i][1] = inputs[i+1].get();
armory.renderpath.Postprocess.colorgrading_global_uniforms[i][2] = inputs[i+1].get();
}
} else if (property0 == "RGB") {
armory.renderpath.Postprocess.colorgrading_global_uniforms[0][0] = inputs[1].get();
for (i in 1...7){
armory.renderpath.Postprocess.colorgrading_global_uniforms[i][0] = inputs[i+1].get().x;
armory.renderpath.Postprocess.colorgrading_global_uniforms[i][1] = inputs[i+1].get().y;
armory.renderpath.Postprocess.colorgrading_global_uniforms[i][2] = inputs[i+1].get().z;
}
var value:Dynamic = inputs[0].get();
var whitebalance:Float = inputs[1].get();
var tint:iron.math.Vec4 = inputs[2].get();
var saturation:Float = inputs[3].get();
var contrast:Float = inputs[4].get();
var gamma:Float = inputs[5].get();
var gain:Float = inputs[6].get();
var offset:Float = inputs[7].get();
} else if (property0 == "Preset File") {
return;
} else {
return;
}
runOutput(0);
}
}

View file

@ -0,0 +1,71 @@
package armory.logicnode;
class ColorgradingSetHighlightNode extends LogicNode {
public var property0:Dynamic;
public var property1:Dynamic;
public var property2:Dynamic;
public var property3:Dynamic;
var value:Dynamic;
var whitebalance:Dynamic;
var tint:Dynamic;
var saturation:Dynamic;
var contrast:Dynamic;
var gamma:Dynamic;
var gain:Dynamic;
var offset:Dynamic;
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
if(property0 == "Uniform"){
armory.renderpath.Postprocess.colorgrading_global_uniforms[0][2] = inputs[1].get();
for (i in 0...5){
armory.renderpath.Postprocess.colorgrading_highlight_uniforms[i][0] = inputs[i+2].get();
armory.renderpath.Postprocess.colorgrading_highlight_uniforms[i][1] = inputs[i+2].get();
armory.renderpath.Postprocess.colorgrading_highlight_uniforms[i][2] = inputs[i+2].get();
}
//trace(inputs[6].get());
} else if (property0 == "RGB") {
armory.renderpath.Postprocess.colorgrading_global_uniforms[0][2] = inputs[1].get();
for (i in 0...5){
armory.renderpath.Postprocess.colorgrading_highlight_uniforms[i][0] = inputs[i+2].get().x;
armory.renderpath.Postprocess.colorgrading_highlight_uniforms[i][1] = inputs[i+2].get().y;
armory.renderpath.Postprocess.colorgrading_highlight_uniforms[i][2] = inputs[i+2].get().z;
}
} else if (property0 == "Preset File") {
var value:Dynamic = inputs[0].get();
var whitebalance:Float = inputs[1].get();
var tint:iron.math.Vec4 = inputs[2].get();
var saturation:Float = inputs[3].get();
var contrast:Float = inputs[4].get();
var gamma:Float = inputs[5].get();
var gain:Float = inputs[6].get();
var offset:Float = inputs[7].get();
} else {
var value:Dynamic = inputs[0].get();
var whitebalance:Float = inputs[1].get();
var tint:iron.math.Vec4 = inputs[2].get();
var saturation:Float = inputs[3].get();
var contrast:Float = inputs[4].get();
var gamma:Float = inputs[5].get();
var gain:Float = inputs[6].get();
var offset:Float = inputs[7].get();
}
//trace(tint.x);
runOutput(0);
}
}

View file

@ -0,0 +1,67 @@
package armory.logicnode;
class ColorgradingSetMidtoneNode extends LogicNode {
public var property0:Dynamic;
public var property1:Dynamic;
public var property2:Dynamic;
public var property3:Dynamic;
var value:Dynamic;
var whitebalance:Dynamic;
var tint:Dynamic;
var saturation:Dynamic;
var contrast:Dynamic;
var gamma:Dynamic;
var gain:Dynamic;
var offset:Dynamic;
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
if(property0 == "Uniform"){
for (i in 0...4){
armory.renderpath.Postprocess.colorgrading_midtone_uniforms[i][0] = inputs[i+2].get();
armory.renderpath.Postprocess.colorgrading_midtone_uniforms[i][1] = inputs[i+2].get();
armory.renderpath.Postprocess.colorgrading_midtone_uniforms[i][2] = inputs[i+2].get();
}
} else if (property0 == "RGB") {
armory.renderpath.Postprocess.colorgrading_highlight_uniforms[0][0] = inputs[1].get();
for (i in 0...4){
armory.renderpath.Postprocess.colorgrading_midtone_uniforms[i][0] = inputs[i+1].get().x;
armory.renderpath.Postprocess.colorgrading_midtone_uniforms[i][1] = inputs[i+1].get().y;
armory.renderpath.Postprocess.colorgrading_midtone_uniforms[i][2] = inputs[i+1].get().z;
}
} else if (property0 == "Preset File") {
var value:Dynamic = inputs[0].get();
var whitebalance:Float = inputs[1].get();
var tint:iron.math.Vec4 = inputs[2].get();
var saturation:Float = inputs[3].get();
var contrast:Float = inputs[4].get();
var gamma:Float = inputs[5].get();
var gain:Float = inputs[6].get();
var offset:Float = inputs[7].get();
} else {
var value:Dynamic = inputs[0].get();
var whitebalance:Float = inputs[1].get();
var tint:iron.math.Vec4 = inputs[2].get();
var saturation:Float = inputs[3].get();
var contrast:Float = inputs[4].get();
var gamma:Float = inputs[5].get();
var gain:Float = inputs[6].get();
var offset:Float = inputs[7].get();
}
//trace(tint.x);
runOutput(0);
}
}

View file

@ -0,0 +1,71 @@
package armory.logicnode;
class ColorgradingSetShadowNode extends LogicNode {
public var property0:Dynamic;
public var property1:Dynamic;
public var property2:Dynamic;
public var property3:Dynamic;
var value:Dynamic;
var whitebalance:Dynamic;
var tint:Dynamic;
var saturation:Dynamic;
var contrast:Dynamic;
var gamma:Dynamic;
var gain:Dynamic;
var offset:Dynamic;
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
if(property0 == "Uniform"){
armory.renderpath.Postprocess.colorgrading_global_uniforms[0][1] = inputs[1].get();
for (i in 0...5){
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][0] = inputs[i+2].get();
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][1] = inputs[i+2].get();
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][2] = inputs[i+2].get();
}
//trace(inputs[6].get());
} else if (property0 == "RGB") {
armory.renderpath.Postprocess.colorgrading_global_uniforms[0][2] = inputs[1].get();
for (i in 0...5){
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][0] = inputs[i+2].get().x;
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][1] = inputs[i+2].get().y;
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][2] = inputs[i+2].get().z;
}
} else if (property0 == "Preset File") {
var value:Dynamic = inputs[0].get();
var whitebalance:Float = inputs[1].get();
var tint:iron.math.Vec4 = inputs[2].get();
var saturation:Float = inputs[3].get();
var contrast:Float = inputs[4].get();
var gamma:Float = inputs[5].get();
var gain:Float = inputs[6].get();
var offset:Float = inputs[7].get();
} else {
var value:Dynamic = inputs[0].get();
var whitebalance:Float = inputs[1].get();
var tint:iron.math.Vec4 = inputs[2].get();
var saturation:Float = inputs[3].get();
var contrast:Float = inputs[4].get();
var gamma:Float = inputs[5].get();
var gain:Float = inputs[6].get();
var offset:Float = inputs[7].get();
}
//trace(tint.x);
runOutput(0);
}
}

View file

@ -0,0 +1,71 @@
package armory.logicnode;
class ColorgradingShadowNode extends LogicNode {
public var property0:Dynamic;
public var property1:Dynamic;
public var property2:Dynamic;
public var property3:Dynamic;
var value:Dynamic;
var whitebalance:Dynamic;
var tint:Dynamic;
var saturation:Dynamic;
var contrast:Dynamic;
var gamma:Dynamic;
var gain:Dynamic;
var offset:Dynamic;
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
if(property0 == "Uniform"){
armory.renderpath.Postprocess.colorgrading_global_uniforms[0][1] = inputs[1].get();
for (i in 0...5){
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][0] = inputs[i+2].get();
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][1] = inputs[i+2].get();
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][2] = inputs[i+2].get();
}
//trace(inputs[6].get());
} else if (property0 == "RGB") {
armory.renderpath.Postprocess.colorgrading_global_uniforms[0][2] = inputs[1].get();
for (i in 0...5){
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][0] = inputs[i+2].get().x;
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][1] = inputs[i+2].get().y;
armory.renderpath.Postprocess.colorgrading_shadow_uniforms[i][2] = inputs[i+2].get().z;
}
} else if (property0 == "Preset File") {
var value:Dynamic = inputs[0].get();
var whitebalance:Float = inputs[1].get();
var tint:iron.math.Vec4 = inputs[2].get();
var saturation:Float = inputs[3].get();
var contrast:Float = inputs[4].get();
var gamma:Float = inputs[5].get();
var gain:Float = inputs[6].get();
var offset:Float = inputs[7].get();
} else {
var value:Dynamic = inputs[0].get();
var whitebalance:Float = inputs[1].get();
var tint:iron.math.Vec4 = inputs[2].get();
var saturation:Float = inputs[3].get();
var contrast:Float = inputs[4].get();
var gamma:Float = inputs[5].get();
var gain:Float = inputs[6].get();
var offset:Float = inputs[7].get();
}
//trace(tint.x);
runOutput(0);
}
}

View file

@ -0,0 +1,30 @@
package armory.logicnode;
import iron.object.Object;
import iron.math.Vec4;
class GetWorldNode extends LogicNode {
public var property0: String;
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
var object: Object = inputs[0].get();
if (object == null) {
return null;
}
switch (property0) {
case "right":
return object.transform.world.right();
case "look":
return object.transform.world.look();
case "up":
return object.transform.world.up();
}
return null;
}
}

View file

@ -0,0 +1,24 @@
package armory.logicnode;
class LenstextureGetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
if(from == 0) {
return armory.renderpath.Postprocess.lenstexture_uniforms[0];
} else if (from == 1) {
return armory.renderpath.Postprocess.lenstexture_uniforms[1];
} else if (from == 2) {
return armory.renderpath.Postprocess.lenstexture_uniforms[2];
} else if (from == 3) {
return armory.renderpath.Postprocess.lenstexture_uniforms[3];
} else if (from == 4) {
return armory.renderpath.Postprocess.lenstexture_uniforms[4];
} else {
return 0.0;
}
}
}

View file

@ -0,0 +1,19 @@
package armory.logicnode;
class LenstextureSetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
armory.renderpath.Postprocess.lenstexture_uniforms[0] = inputs[1].get();
armory.renderpath.Postprocess.lenstexture_uniforms[1] = inputs[2].get();
armory.renderpath.Postprocess.lenstexture_uniforms[2] = inputs[3].get();
armory.renderpath.Postprocess.lenstexture_uniforms[3] = inputs[4].get();
armory.renderpath.Postprocess.lenstexture_uniforms[4] = inputs[5].get();
runOutput(0);
}
}

View file

@ -0,0 +1,20 @@
package armory.logicnode;
class SSAOGetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
if(from == 0) {
return armory.renderpath.Postprocess.ssao_uniforms[0];
} else if (from == 1) {
return armory.renderpath.Postprocess.ssao_uniforms[1];
} else if (from == 2) {
return armory.renderpath.Postprocess.ssao_uniforms[2];
} else {
return 0.0;
}
}
}

View file

@ -0,0 +1,17 @@
package armory.logicnode;
class SSAOSetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
armory.renderpath.Postprocess.ssao_uniforms[0] = inputs[1].get();
armory.renderpath.Postprocess.ssao_uniforms[1] = inputs[2].get();
armory.renderpath.Postprocess.ssao_uniforms[2] = inputs[3].get();
runOutput(0);
}
}

View file

@ -0,0 +1,24 @@
package armory.logicnode;
class SSRGetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function get(from:Int):Dynamic {
if(from == 0) {
return armory.renderpath.Postprocess.ssr_uniforms[0];
} else if (from == 1) {
return armory.renderpath.Postprocess.ssr_uniforms[1];
} else if (from == 2) {
return armory.renderpath.Postprocess.ssr_uniforms[2];
} else if (from == 3) {
return armory.renderpath.Postprocess.ssr_uniforms[3];
} else if (from == 4) {
return armory.renderpath.Postprocess.ssr_uniforms[4];
} else {
return 0.0;
}
}
}

View file

@ -0,0 +1,19 @@
package armory.logicnode;
class SSRSetNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
armory.renderpath.Postprocess.ssr_uniforms[0] = inputs[1].get();
armory.renderpath.Postprocess.ssr_uniforms[1] = inputs[2].get();
armory.renderpath.Postprocess.ssr_uniforms[2] = inputs[3].get();
armory.renderpath.Postprocess.ssr_uniforms[3] = inputs[4].get();
armory.renderpath.Postprocess.ssr_uniforms[4] = inputs[5].get();
runOutput(0);
}
}

View file

@ -2,7 +2,7 @@ package armory.logicnode;
import iron.object.Object;
import iron.math.Quat;
import iron.math.Vec3;
import iron.math.Vec4;
import armory.trait.physics.RigidBody;
class SetRotationNode extends LogicNode {
@ -18,7 +18,7 @@ class SetRotationNode extends LogicNode {
if (object == null) {
return;
}
var vec: Vec3 = inputs[2].get();
var vec: Vec4 = inputs[2].get();
var w: Float = inputs[3].get();
switch (property0) {
case "Euler Angles":
@ -30,9 +30,8 @@ class SetRotationNode extends LogicNode {
}
var angleSin = Math.sin(angle / 2);
vec = vec.normalize();
vec = new Vec3(vec.x * angleSin, vec.y * angleSin, vec.z * angleSin);
var angleCos = Math.cos(angle / 2);
object.transform.rot = new Quat(vec.x, vec.y, vec.z, angleCos);
object.transform.rot = new Quat(vec.x * angleSin, vec.y * angleSin, vec.z * angleSin, angleCos);
case "Quaternion":
object.transform.rot = new Quat(vec.x, vec.y, vec.z, w);
}

View file

@ -1,5 +1,7 @@
package armory.math;
import iron.math.Vec4;
class Helper {
/**
@ -31,7 +33,7 @@ class Helper {
return Math.PI / 180 * degrees;
}
/**
* rounds the precision of a float (default 2).
* Rounds the precision of a float (default 2).
* @return float with rounded precision
*/
public static function roundfp(f: Float, precision = 2): Float {
@ -39,16 +41,23 @@ class Helper {
return std.Math.round(f) / std.Math.pow(10, precision);
}
/**
* clamps a float within some limits.
* Clamps a float within some limits.
* @return same float, min or max if exceeded limits.
*/
public static function clamp(f: Float, min: Float, max: Float): Float {
return f < min ? min : f > max ? max : f;
}
/*
* Convenience function to map a variable from one coordinate space
* to another. Equivalent to unlerp() followed by lerp().
*/
/**
* Convenience function to map a variable from one coordinate space to
* another. Equivalent to unlerp() followed by lerp().
* @param value
* @param leftMin The lower bound of the input coordinate space
* @param leftMax The higher bound of the input coordinate space
* @param rightMin The lower bound of the output coordinate space
* @param rightMax The higher bound of the output coordinate space
* @return Float
*/
public static inline function map(value: Float, leftMin: Float, leftMax: Float, rightMin: Float, rightMax: Float): Float {
return rightMin + (value - leftMin) / (leftMax - leftMin) * (rightMax- rightMin);
}

View file

@ -1,6 +1,7 @@
package armory.math;
import kha.FastFloat;
import iron.math.Mat4;
class Rotator {
public var pitch: FastFloat; // X - look up or down around the X axis
@ -14,16 +15,16 @@ class Rotator {
}
public function toDegrees(): Rotator {
pitch = Math.toDegrees(pitch);
roll = Math.toDegrees(roll);
yaw = Math.toDegrees(yaw);
pitch = Helper.radToDeg(pitch);
roll = Helper.radToDeg(roll);
yaw = Helper.radToDeg(yaw);
return this;
}
public function toRadians(): Rotator {
pitch = Math.toRadians(pitch);
roll = Math.toRadians(roll);
yaw = Math.toRadians(yaw);
pitch = Helper.degToRad(pitch);
roll = Helper.degToRad(roll);
yaw = Helper.degToRad(yaw);
return this;
}
@ -182,7 +183,7 @@ class Rotator {
}
public static inline function clampAxis(angle: FastFloat): FastFloat {
angle = Math.mod(angle, 360); // Makes the angle between -360 and +360
angle = angle % 360; // Makes the angle between -360 and +360
if (angle < 0.0) angle += 360.0;
return angle;
}

View file

@ -35,6 +35,6 @@ class TransformExtension {
* @return Vec4
*/
public static inline function getLocalVecFromWorld(t: Transform, worldVec: Vec4): Vec4 {
return worldVec.clone().applymat4(t.local);
return worldVec.clone().applymat4(Mat4.identity().getInverse(t.worldUnpack));
}
}

View file

@ -0,0 +1,366 @@
package armory.renderpath;
import iron.Scene;
import iron.object.Object;
import iron.data.MaterialData;
import iron.math.Vec4;
class Postprocess {
public static var colorgrading_global_uniforms = [
[6500.0, 1.0, 0.0], //0: Whitebalance, Shadow Max, Highlight Min
[1.0, 1.0, 1.0], //1: Tint
[1.0, 1.0, 1.0], //2: Saturation
[1.0, 1.0, 1.0], //3: Contrast
[1.0, 1.0, 1.0], //4: Gamma
[1.0, 1.0, 1.0], //5: Gain
[1.0, 1.0, 1.0], //6: Offset
[1.0, 1.0, 1.0] //7: LUT Strength
];
public static var colorgrading_shadow_uniforms = [
[1.0, 1.0, 1.0], //0: Saturation
[1.0, 1.0, 1.0], //1: Contrast
[1.0, 1.0, 1.0], //2: Gamma
[1.0, 1.0, 1.0], //3: Gain
[1.0, 1.0, 1.0] //4: Offset
];
public static var colorgrading_midtone_uniforms = [
[1.0, 1.0, 1.0], //0: Saturation
[1.0, 1.0, 1.0], //1: Contrast
[1.0, 1.0, 1.0], //2: Gamma
[1.0, 1.0, 1.0], //3: Gain
[1.0, 1.0, 1.0] //4: Offset
];
public static var colorgrading_highlight_uniforms = [
[1.0, 1.0, 1.0], //0: Saturation
[1.0, 1.0, 1.0], //1: Contrast
[1.0, 1.0, 1.0], //2: Gamma
[1.0, 1.0, 1.0], //3: Gain
[1.0, 1.0, 1.0] //4: Offset
];
public static var camera_uniforms = [
1.0, //0: Camera: F-Number
2.8333, //1: Camera: Shutter time
100.0, //2: Camera: ISO
0.0, //3: Camera: Exposure Compensation
0.01, //4: Fisheye Distortion
1, //5: DoF AutoFocus §§ If true, it ignores the DoF Distance setting
10.0, //6: DoF Distance
160.0, //7: DoF Focal Length mm
128, //8: DoF F-Stop
0, //9: Tonemapping Method
2.0 //10: Film Grain
];
public static var tonemapper_uniforms = [
1.0, //0: Slope
1.0, //1: Toe
1.0, //2: Shoulder
1.0, //3: Black Clip
1.0 //4: White Clip
];
public static var ssr_uniforms = [
0.04, //0: Step
0.05, //1: StepMin
5.0, //2: Search
5.0, //3: Falloff
0.6 //4: Jitter
];
public static var bloom_uniforms = [
1.0, //0: Threshold
3.5, //1: Strength
3.0 //2: Radius
];
public static var ssao_uniforms = [
1.0,
1.0,
8
];
public static var lenstexture_uniforms = [
0.1, //0: Center Min Clip
0.5, //1: Center Max Clip
0.1, //2: Luminance Min
2.5, //3: Luminance Max
2.0 //4: Brightness Exponent
];
public static var chromatic_aberration_uniforms = [
2.0, //0: Strength
32 //1: Samples
];
public static function vec3Link(object:Object, mat:MaterialData, link:String):iron.math.Vec4 {
var v:Vec4 = null;
if (link == "_globalWeight") {
var ppm_index = 0;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_global_uniforms[ppm_index][0];
v.y = colorgrading_global_uniforms[ppm_index][1];
v.z = colorgrading_global_uniforms[ppm_index][2];
}
if (link == "_globalTint") {
var ppm_index = 1;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_global_uniforms[ppm_index][0];
v.y = colorgrading_global_uniforms[ppm_index][1];
v.z = colorgrading_global_uniforms[ppm_index][2];
}
if (link == "_globalSaturation") {
var ppm_index = 2;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_global_uniforms[ppm_index][0];
v.y = colorgrading_global_uniforms[ppm_index][1];
v.z = colorgrading_global_uniforms[ppm_index][2];
}
if (link == "_globalContrast") {
var ppm_index = 3;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_global_uniforms[ppm_index][0];
v.y = colorgrading_global_uniforms[ppm_index][1];
v.z = colorgrading_global_uniforms[ppm_index][2];
}
if (link == "_globalGamma") {
var ppm_index = 4;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_global_uniforms[ppm_index][0];
v.y = colorgrading_global_uniforms[ppm_index][1];
v.z = colorgrading_global_uniforms[ppm_index][2];
}
if (link == "_globalGain") {
var ppm_index = 5;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_global_uniforms[ppm_index][0];
v.y = colorgrading_global_uniforms[ppm_index][1];
v.z = colorgrading_global_uniforms[ppm_index][2];
}
if (link == "_globalOffset") {
var ppm_index = 6;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_global_uniforms[ppm_index][0];
v.y = colorgrading_global_uniforms[ppm_index][1];
v.z = colorgrading_global_uniforms[ppm_index][2];
}
//Shadow ppm
if (link == "_shadowSaturation") {
var ppm_index = 0;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_shadow_uniforms[ppm_index][0];
v.y = colorgrading_shadow_uniforms[ppm_index][1];
v.z = colorgrading_shadow_uniforms[ppm_index][2];
}
if (link == "_shadowContrast") {
var ppm_index = 1;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_shadow_uniforms[ppm_index][0];
v.y = colorgrading_shadow_uniforms[ppm_index][1];
v.z = colorgrading_shadow_uniforms[ppm_index][2];
}
if (link == "_shadowGamma") {
var ppm_index = 2;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_shadow_uniforms[ppm_index][0];
v.y = colorgrading_shadow_uniforms[ppm_index][1];
v.z = colorgrading_shadow_uniforms[ppm_index][2];
}
if (link == "_shadowGain") {
var ppm_index = 3;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_shadow_uniforms[ppm_index][0];
v.y = colorgrading_shadow_uniforms[ppm_index][1];
v.z = colorgrading_shadow_uniforms[ppm_index][2];
}
if (link == "_shadowOffset") {
var ppm_index = 4;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_shadow_uniforms[ppm_index][0];
v.y = colorgrading_shadow_uniforms[ppm_index][1];
v.z = colorgrading_shadow_uniforms[ppm_index][2];
}
//Midtone ppm
if (link == "_midtoneSaturation") {
var ppm_index = 0;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_midtone_uniforms[ppm_index][0];
v.y = colorgrading_midtone_uniforms[ppm_index][1];
v.z = colorgrading_midtone_uniforms[ppm_index][2];
}
if (link == "_midtoneContrast") {
var ppm_index = 1;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_midtone_uniforms[ppm_index][0];
v.y = colorgrading_midtone_uniforms[ppm_index][1];
v.z = colorgrading_midtone_uniforms[ppm_index][2];
}
if (link == "_midtoneGamma") {
var ppm_index = 2;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_midtone_uniforms[ppm_index][0];
v.y = colorgrading_midtone_uniforms[ppm_index][1];
v.z = colorgrading_midtone_uniforms[ppm_index][2];
}
if (link == "_midtoneGain") {
var ppm_index = 3;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_midtone_uniforms[ppm_index][0];
v.y = colorgrading_midtone_uniforms[ppm_index][1];
v.z = colorgrading_midtone_uniforms[ppm_index][2];
}
if (link == "_midtoneOffset") {
var ppm_index = 4;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_midtone_uniforms[ppm_index][0];
v.y = colorgrading_midtone_uniforms[ppm_index][1];
v.z = colorgrading_midtone_uniforms[ppm_index][2];
}
//Highlight ppm
if (link == "_highlightSaturation") {
var ppm_index = 0;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_highlight_uniforms[ppm_index][0];
v.y = colorgrading_highlight_uniforms[ppm_index][1];
v.z = colorgrading_highlight_uniforms[ppm_index][2];
}
if (link == "_highlightContrast") {
var ppm_index = 1;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_highlight_uniforms[ppm_index][0];
v.y = colorgrading_highlight_uniforms[ppm_index][1];
v.z = colorgrading_highlight_uniforms[ppm_index][2];
}
if (link == "_highlightGamma") {
var ppm_index = 2;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_highlight_uniforms[ppm_index][0];
v.y = colorgrading_highlight_uniforms[ppm_index][1];
v.z = colorgrading_highlight_uniforms[ppm_index][2];
}
if (link == "_highlightGain") {
var ppm_index = 3;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_highlight_uniforms[ppm_index][0];
v.y = colorgrading_highlight_uniforms[ppm_index][1];
v.z = colorgrading_highlight_uniforms[ppm_index][2];
}
if (link == "_highlightOffset") {
var ppm_index = 4;
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_highlight_uniforms[ppm_index][0];
v.y = colorgrading_highlight_uniforms[ppm_index][1];
v.z = colorgrading_highlight_uniforms[ppm_index][2];
}
//Postprocess Components
if (link == "_PPComp1") {
v = iron.object.Uniforms.helpVec;
v.x = camera_uniforms[0]; //F-Number
v.y = camera_uniforms[1]; //Shutter
v.z = camera_uniforms[2]; //ISO
}
if (link == "_PPComp2") {
v = iron.object.Uniforms.helpVec;
v.x = camera_uniforms[3]; //EC
v.y = camera_uniforms[4]; //Lens Distortion
v.z = camera_uniforms[5]; //DOF Autofocus
}
if (link == "_PPComp3") {
v = iron.object.Uniforms.helpVec;
v.x = camera_uniforms[6]; //Distance
v.y = camera_uniforms[7]; //Focal Length
v.z = camera_uniforms[8]; //F-Stop
}
if (link == "_PPComp4") {
v = iron.object.Uniforms.helpVec;
v.x = Std.int(camera_uniforms[9]); //Tonemapping
v.y = camera_uniforms[10]; //Film Grain
v.z = tonemapper_uniforms[0]; //Slope
}
if (link == "_PPComp5") {
v = iron.object.Uniforms.helpVec;
v.x = tonemapper_uniforms[1]; //Toe
v.y = tonemapper_uniforms[2]; //Shoulder
v.z = tonemapper_uniforms[3]; //Black Clip
}
if (link == "_PPComp6") {
v = iron.object.Uniforms.helpVec;
v.x = tonemapper_uniforms[4]; //White Clip
v.y = lenstexture_uniforms[0]; //Center Min
v.z = lenstexture_uniforms[1]; //Center Max
}
if (link == "_PPComp7") {
v = iron.object.Uniforms.helpVec;
v.x = lenstexture_uniforms[2]; //Lum min
v.y = lenstexture_uniforms[3]; //Lum max
v.z = lenstexture_uniforms[4]; //Expo
}
if (link == "_PPComp8") {
v = iron.object.Uniforms.helpVec;
v.x = colorgrading_global_uniforms[7][0]; //LUT R
v.y = colorgrading_global_uniforms[7][1]; //LUT G
v.z = colorgrading_global_uniforms[7][2]; //LUT B
}
if (link == "_PPComp9") {
v = iron.object.Uniforms.helpVec;
v.x = ssr_uniforms[0]; //Step
v.y = ssr_uniforms[1]; //StepMin
v.z = ssr_uniforms[2]; //Search
}
if (link == "_PPComp10") {
v = iron.object.Uniforms.helpVec;
v.x = ssr_uniforms[3]; //Falloff
v.y = ssr_uniforms[4]; //Jitter
v.z = bloom_uniforms[0]; //Bloom Threshold
}
if (link == "_PPComp11") {
v = iron.object.Uniforms.helpVec;
v.x = bloom_uniforms[1]; //Bloom Strength
v.y = bloom_uniforms[2]; //Bloom Radius
v.z = ssao_uniforms[0]; //SSAO Strength
}
if (link == "_PPComp12") {
v = iron.object.Uniforms.helpVec;
v.x = ssao_uniforms[1]; //SSAO Radius
v.y = ssao_uniforms[2]; //SSAO Max Steps
v.z = 0;
}
if(link == "_PPComp13") {
v = iron.object.Uniforms.helpVec;
v.x = chromatic_aberration_uniforms[0]; //CA Strength
v.y = chromatic_aberration_uniforms[1]; //CA Samples
v.z = 0;
}
return v;
}
public static function init() {
iron.object.Uniforms.externalVec3Links.push(vec3Link);
}
}

View file

@ -24,6 +24,13 @@ class RenderPathCreator {
public static function get(): RenderPath {
path = new RenderPath();
Inc.init(path);
#if rp_pp
iron.App.notifyOnInit(function() {
Postprocess.init();
});
#end
#if (rp_renderer == "Forward")
RenderPathForward.init(path);
path.commands = RenderPathForward.commands;

View file

@ -9,6 +9,8 @@ class NavAgent extends Trait {
@prop
var speed: Float = 5;
@prop
var turnDuration: Float = 0.4;
var path: Array<Vec4> = null;
var index = 0;
@ -64,7 +66,7 @@ class NavAgent extends Trait {
}});
var q = new Quat();
rotAnim = Tween.to({ target: object.transform, props: { rot: q.fromEuler(0, 0, targetAngle) }, duration: 0.4});
rotAnim = Tween.to({ target: object.transform, props: { rot: q.fromEuler(0, 0, targetAngle) }, duration: turnDuration});
}
function update() {

View file

@ -62,7 +62,7 @@ class PhysicsBreak extends Trait {
var ud = breaker.userDataMap.get(cast o);
var params = [0.04, 0.1, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.04, 0.0, 0.0, 0.0];
o.addTrait(new RigidBody(Shape.ConvexHull, ud.mass, ud.friction, 0, 1, params));
if (cast(o, MeshObject).data.geom.positions.length < 600) {
if (cast(o, MeshObject).data.geom.positions.values.length < 600) {
o.addTrait(new PhysicsBreak());
}
}
@ -115,7 +115,7 @@ class ConvexBreaker {
}
public function initBreakableObject(object: MeshObject, mass: Float, friction: Float, velocity: Vec4, angularVelocity: Vec4, breakable: Bool) {
var ar = object.data.geom.positions;
var ar = object.data.geom.positions.values;
var scalePos = object.data.scalePos;
// Create vertices mark
var sc = object.transform.scale;
@ -550,11 +550,11 @@ class ConvexBreaker {
var inda = new kha.arrays.Uint32Array(ind.length);
for (i in 0...ind.length) inda.set(i, ind[i]);
var pos: TVertexArray = { attrib: "pos", values: paa };
var nor: TVertexArray = { attrib: "nor", values: naa };
var pos: TVertexArray = { attrib: "pos", values: paa, data: "short4norm" };
var nor: TVertexArray = { attrib: "nor", values: naa, data: "short2norm" };
var indices: TIndexArray = { material: 0, values: inda };
var rawmesh: TMeshData = {
var rawmesh: TMeshData = {
name: "TempMesh" + (meshIndex++),
vertex_arrays: [pos, nor],
index_arrays: [indices],

View file

@ -77,17 +77,32 @@ class CanvasScript extends Trait {
onReady = f;
}
// Defines layout
/**
* Returns an element of the canvas.
* @param name The name of the element
* @return TElement
*/
public function getElement(name: String): TElement {
for (e in canvas.elements) if (e.name == name) return e;
return null;
}
// Returns canvas array of elements
/**
* Returns an array of the elements of the canvas.
* @return Array<TElement>
*/
public function getElements(): Array<TElement> {
return canvas.elements;
}
/**
* Returns the canvas object of this trait.
* @return TCanvas
*/
public function getCanvas(): Null<TCanvas> {
return canvas;
}
/**
* Set visibility of canvas
* @param visible Whether canvas should be visible or not

View file

@ -331,7 +331,7 @@ class KinematicCharacterController extends Trait {
}
function addPointsToConvexHull(shape: bullet.Bt.ConvexHullShape, scale: Vec4, margin: Float) {
var positions = cast(object, MeshObject).data.geom.positions;
var positions = cast(object, MeshObject).data.geom.positions.values;
var sx = scale.x * (1.0 - margin);
var sy = scale.y * (1.0 - margin);

View file

@ -97,7 +97,7 @@ class PhysicsHook extends Trait {
#end
var geom = cast(object, MeshObject).data.geom;
var numNodes = Std.int(geom.positions.length / 4);
var numNodes = Std.int(geom.positions.values.length / 4);
for (i in 0...numNodes) {
var node = nodes.at(i);
#if js

View file

@ -486,7 +486,7 @@ class RigidBody extends iron.Trait {
convexHullCache.set(data, shape);
usersCache.set(data, 1);
var positions = data.geom.positions;
var positions = data.geom.positions.values;
var sx: kha.FastFloat = scale.x * (1.0 - margin) * (1 / 32767);
var sy: kha.FastFloat = scale.y * (1.0 - margin) * (1 / 32767);
@ -520,7 +520,7 @@ class RigidBody extends iron.Trait {
triangleMeshCache.set(data, triangleMesh);
usersCache.set(data, 1);
var positions = data.geom.positions;
var positions = data.geom.positions.values;
var indices = data.geom.indices;
var sx: kha.FastFloat = scale.x * (1 / 32767);

View file

@ -92,7 +92,7 @@ class SoftBody extends Trait {
object.transform.buildMatrix();
}
var positions = fromI16(geom.positions, mo.data.scalePos);
var positions = fromI16(geom.positions.values, mo.data.scalePos);
for (i in 0...Std.int(positions.length / 3)) {
v.set(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
v.applyQuat(object.transform.rot);

View file

@ -182,7 +182,9 @@ class ArmoryExporter:
self.export_pose_markers(oanim, action)
if True: #action.arm_cached == False or not os.path.exists(fp):
print('Exporting object action ' + aname)
wrd = bpy.data.worlds['Arm']
if wrd.arm_verbose_output:
print('Exporting object action ' + aname)
actionf = {}
actionf['objects'] = []
actionf['objects'].append(oaction)
@ -285,7 +287,7 @@ class ArmoryExporter:
except KeyError:
if data_path not in target_names:
print(f"Action {action_name}: The data path '{data_path}' is not supported (yet)!")
log.warn(f"Action {action_name}: The data path '{data_path}' is not supported (yet)!")
continue
# Missing target entry for array_index or something else
@ -295,7 +297,9 @@ class ArmoryExporter:
oanim['tracks'].append(data_ttrack)
if True: #action.arm_cached == False or not os.path.exists(fp):
print('Exporting object action ' + action_name)
wrd = bpy.data.worlds['Arm']
if wrd.arm_verbose_output:
print('Exporting object action ' + action_name)
actionf = {}
actionf['objects'] = []
actionf['objects'].append(oaction)
@ -801,22 +805,46 @@ class ArmoryExporter:
aname = arm.utils.safestr(arm.utils.asset_name(action))
o['bone_actions'].append('action_' + armatureid + '_' + aname + ext)
clear_op = set()
skelobj = bobject
baked_actions = []
orig_action = bobject.animation_data.action
if bdata.arm_autobake and bobject.name not in bpy.context.collection.all_objects:
clear_op.add( 'unlink' )
#clone bjobject and put it in the current scene so the bake operator can run
if bobject.library is not None:
skelobj = bobject.copy()
clear_op.add('rem')
bpy.context.collection.objects.link(skelobj)
for action in export_actions:
aname = arm.utils.safestr(arm.utils.asset_name(action))
bobject.animation_data.action = action
skelobj.animation_data.action = action
fp = self.get_meshes_file_path('action_' + armatureid + '_' + aname, compressed=self.is_compress())
assets.add(fp)
if bdata.arm_cached == False or not os.path.exists(fp):
print('Exporting armature action ' + aname)
#handle autobake
if bdata.arm_autobake:
sel = bpy.context.selected_objects[:]
for _o in sel: _o.select_set(False)
skelobj.select_set(True)
bpy.ops.nla.bake(frame_start = action.frame_range[0], frame_end=action.frame_range[1], step=1, only_selected=False, visual_keying=True)
action = skelobj.animation_data.action
skelobj.select_set(False)
for _o in sel: _o.select_set(True)
baked_actions.append(action)
wrd = bpy.data.worlds['Arm']
if wrd.arm_verbose_output:
print('Exporting armature action ' + aname)
bones = []
self.bone_tracks = []
for bone in bdata.bones:
if not bone.parent:
boneo = {}
self.export_bone(bobject, bone, scene, boneo, action)
self.export_bone(skelobj, bone, scene, boneo, action)
bones.append(boneo)
self.write_bone_matrices(scene, action)
self.write_bone_matrices( bpy.context.scene, action)
if len(bones) > 0 and 'anim' in bones[0]:
self.export_pose_markers(bones[0]['anim'], action)
# Save action separately
@ -824,7 +852,13 @@ class ArmoryExporter:
action_obj['name'] = aname
action_obj['objects'] = bones
arm.utils.write_arm(fp, action_obj)
bobject.animation_data.action = orig_action
#restore settings
skelobj.animation_data.action = orig_action
for a in baked_actions: bpy.data.actions.remove( a, do_unlink=True)
if 'unlink' in clear_op: bpy.context.collection.objects.unlink(skelobj)
if 'rem' in clear_op: bpy.data.objects.remove(skelobj, do_unlink=True)
# TODO: cache per action
bdata.arm_cached = True
@ -934,11 +968,12 @@ class ArmoryExporter:
oskin['bone_weight_array'] = bone_weight_array
# Bone constraints
for bone in armature.pose.bones:
if len(bone.constraints) > 0:
if 'constraints' not in oskin:
oskin['constraints'] = []
self.add_constraints(bone, oskin, bone=True)
if not armature.data.arm_autobake:
for bone in armature.pose.bones:
if len(bone.constraints) > 0:
if 'constraints' not in oskin:
oskin['constraints'] = []
self.add_constraints(bone, oskin, bone=True)
def write_mesh(self, bobject, fp, o):
wrd = bpy.data.worlds['Arm']
@ -969,8 +1004,8 @@ class ArmoryExporter:
has_tex = (self.get_export_uvs(bobject.data) and num_uv_layers > 0) or is_baked
has_tex1 = has_tex and num_uv_layers > 1
num_colors = len(exportMesh.vertex_colors)
has_col = self.get_export_vcols(exportMesh) and num_colors > 0
has_tang = self.has_tangents(exportMesh)
has_col = self.get_export_vcols(bobject.data) and num_colors > 0
has_tang = self.has_tangents(bobject.data)
pdata = np.empty(num_verts * 4, dtype='<f4') # p.xyz, n.z
ndata = np.empty(num_verts * 2, dtype='<f4') # n.xy
@ -1134,16 +1169,16 @@ class ArmoryExporter:
# Output
o['vertex_arrays'] = []
o['vertex_arrays'].append({ 'attrib': 'pos', 'values': pdata })
o['vertex_arrays'].append({ 'attrib': 'nor', 'values': ndata })
o['vertex_arrays'].append({ 'attrib': 'pos', 'values': pdata, 'data': 'short4norm' })
o['vertex_arrays'].append({ 'attrib': 'nor', 'values': ndata, 'data': 'short2norm' })
if has_tex:
o['vertex_arrays'].append({ 'attrib': 'tex', 'values': t0data })
o['vertex_arrays'].append({ 'attrib': 'tex', 'values': t0data, 'data': 'short2norm' })
if has_tex1:
o['vertex_arrays'].append({ 'attrib': 'tex1', 'values': t1data })
o['vertex_arrays'].append({ 'attrib': 'tex1', 'values': t1data, 'data': 'short2norm' })
if has_col:
o['vertex_arrays'].append({ 'attrib': 'col', 'values': cdata })
o['vertex_arrays'].append({ 'attrib': 'col', 'values': cdata, 'data': 'short4norm', 'padding': 1 })
if has_tang:
o['vertex_arrays'].append({ 'attrib': 'tang', 'values': tangdata })
o['vertex_arrays'].append({ 'attrib': 'tang', 'values': tangdata, 'data': 'short4norm', 'padding': 1 })
# If there are multiple morph targets, export them here.
# if (shapeKeys):
@ -1217,7 +1252,8 @@ class ArmoryExporter:
log.warn('{0} users {1} and {2} differ in modifier stack - use Make Single User - Object & Data for now'.format(oid, bobject.name, table[i].name))
break
print('Exporting mesh ' + arm.utils.asset_name(bobject.data))
if wrd.arm_verbose_output:
print('Exporting mesh ' + arm.utils.asset_name(bobject.data))
o = {}
o['name'] = oid
@ -1415,13 +1451,32 @@ class ArmoryExporter:
if has_proxy_user:
continue
# Add external linked objects
if bobject.name not in scene_objects and collection.library is not None:
asset_name = arm.utils.asset_name(bobject)
if collection.library is None:
#collection is in the same file, but (likely) on another scene
if asset_name not in scene_objects:
self.process_bobject(bobject)
self.export_object(bobject, self.scene)
else:
# Add external linked objects
# Iron differentiates objects based on their names,
# so errors will happen if two objects with the
# same name exists. This check is only required
# when the object in question is in a library,
# otherwise Blender will not allow duplicate names
if asset_name in scene_objects:
log.warn("skipping export of the object"
f" {bobject.name} (collection"
f" {collection.name}) because it has the same"
" export name as another object in the scene:"
f" {asset_name}")
continue
self.process_bobject(bobject)
self.export_object(bobject, self.scene)
out_collection['object_refs'].append(arm.utils.asset_name(bobject))
else:
out_collection['object_refs'].append(bobject.name)
out_collection['object_refs'].append(asset_name)
self.output['groups'].append(out_collection)

View file

@ -1,12 +1,14 @@
info_text = ''
num_warnings = 0
def clear():
global info_text
def clear(clear_warnings=False):
global info_text, num_warnings
info_text = ''
if clear_warnings:
num_warnings = 0
def format_text(text):
return (text[:80] + '..') if len(text) > 80 else text # Limit str size
return (text[:80] + '..') if len(text) > 80 else text # Limit str size
def print_info(text):
global info_text
@ -14,4 +16,6 @@ def print_info(text):
info_text = format_text(text)
def warn(text):
global num_warnings
num_warnings += 1
print('Armory Warning: ' + text)

View file

@ -0,0 +1,21 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class ColorgradingGetGlobalNode(Node, ArmLogicTreeNode):
'''Colorgrading Get Global node'''
bl_idname = 'LNColorgradingGetGlobalNode'
bl_label = 'Colorgrading Get Global'
bl_icon = 'QUESTION'
def init(self, context):
self.outputs.new('NodeSocketFloat', 'Whitebalance')
self.outputs.new('NodeSocketVector', 'Tint')
self.outputs.new('NodeSocketVector', 'Saturation')
self.outputs.new('NodeSocketVector', 'Contrast')
self.outputs.new('NodeSocketVector', 'Gamma')
self.outputs.new('NodeSocketVector', 'Gain')
self.outputs.new('NodeSocketVector', 'Offset')
add_node(ColorgradingGetGlobalNode, category='Postprocess')

View file

@ -0,0 +1,20 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class ColorgradingGetHighlightNode(Node, ArmLogicTreeNode):
'''Colorgrading Get Highlight node'''
bl_idname = 'LNColorgradingGetHighlightNode'
bl_label = 'Colorgrading Get Highlight'
bl_icon = 'QUESTION'
def init(self, context):
self.outputs.new('NodeSocketFloat', 'HightlightMin')
self.outputs.new('NodeSocketVector', 'Saturation')
self.outputs.new('NodeSocketVector', 'Contrast')
self.outputs.new('NodeSocketVector', 'Gamma')
self.outputs.new('NodeSocketVector', 'Gain')
self.outputs.new('NodeSocketVector', 'Offset')
add_node(ColorgradingGetHighlightNode, category='Postprocess')

View file

@ -0,0 +1,19 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class ColorgradingGetMidtoneNode(Node, ArmLogicTreeNode):
'''Colorgrading Get Midtone node'''
bl_idname = 'LNColorgradingGetMidtoneNode'
bl_label = 'Colorgrading Get Midtone'
bl_icon = 'QUESTION'
def init(self, context):
self.outputs.new('NodeSocketVector', 'Saturation')
self.outputs.new('NodeSocketVector', 'Contrast')
self.outputs.new('NodeSocketVector', 'Gamma')
self.outputs.new('NodeSocketVector', 'Gain')
self.outputs.new('NodeSocketVector', 'Offset')
add_node(ColorgradingGetMidtoneNode, category='Postprocess')

View file

@ -0,0 +1,20 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class ColorgradingGetShadowNode(Node, ArmLogicTreeNode):
'''Colorgrading Get Shadow node'''
bl_idname = 'LNColorgradingGetShadowNode'
bl_label = 'Colorgrading Get Shadow'
bl_icon = 'QUESTION'
def init(self, context):
self.outputs.new('NodeSocketFloat', 'ShadowMax')
self.outputs.new('NodeSocketVector', 'Saturation')
self.outputs.new('NodeSocketVector', 'Contrast')
self.outputs.new('NodeSocketVector', 'Gamma')
self.outputs.new('NodeSocketVector', 'Gain')
self.outputs.new('NodeSocketVector', 'Offset')
add_node(ColorgradingGetShadowNode, category='Postprocess')

View file

@ -0,0 +1,89 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
def update_node(self, context):
#Clean all nodes
while len(self.inputs) > 1:
self.inputs.remove(self.inputs[-1])
if (self.property0 == 'Uniform'):
self.draw_nodes_uniform(context)
elif (self.property0 == 'RGB'):
self.draw_nodes_rgb(context)
else:
self.draw_nodes_colorwheel(context)
def set_data(self, context):
abspath = bpy.path.abspath(self.filepath)
abspath = abspath.replace("\\","\\\\")
with open(abspath, 'r') as myfile:
data = myfile.read().replace('\n', '').replace('"','')
self.property1 = data
class ColorgradingSetGlobalNode(Node, ArmLogicTreeNode):
'''Colorgrading Set Global node'''
bl_idname = 'LNColorgradingSetGlobalNode'
bl_label = 'Colorgrading Set Global'
bl_icon = 'QUESTION'
# TODO: RRESET FILE OPTION FOR THE BELOW
property0 : EnumProperty(
items = [('RGB', 'RGB', 'RGB'),
('Uniform', 'Uniform', 'Uniform')],
name='Mode', default='Uniform', update=update_node)
property1 : StringProperty(name="Loaded Data", description="Loaded data - Just ignore", default="")
filepath : StringProperty(name="Preset File", description="Postprocess colorgrading preset file", default="", subtype="FILE_PATH", update=set_data)
def draw_nodes_uniform(self, context):
self.inputs.new('NodeSocketFloat', 'Whitebalance')
self.inputs[-1].default_value = 6500.0
self.inputs.new('NodeSocketColor', 'Tint')
self.inputs[-1].default_value = [1.0, 1.0, 1.0, 1.0]
self.inputs.new('NodeSocketFloat', 'Saturation')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Contrast')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Gamma')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Gain')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Offset')
self.inputs[-1].default_value = 1
def draw_nodes_rgb(self, context):
self.inputs.new('NodeSocketFloat', 'Whitebalance')
self.inputs[-1].default_value = 6500.0
self.inputs.new('NodeSocketVector', 'Tint')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Saturation')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Contrast')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Gamma')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Gain')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Offset')
self.inputs[-1].default_value = [1,1,1]
def draw_nodes_colorwheel(self, context):
pass
def init(self, context):
self.inputs.new('ArmNodeSocketAction', 'In')
self.outputs.new('ArmNodeSocketAction', 'Out')
self.draw_nodes_uniform(context)
def draw_buttons(self, context, layout):
layout.label(text="Select value mode")
layout.prop(self, 'property0')
if (self.property0 == 'Preset File'):
layout.prop(self, 'filepath')
layout.prop(self, 'property1')
add_node(ColorgradingSetGlobalNode, category='Postprocess')

View file

@ -0,0 +1,85 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
def update_node(self, context):
#Clean all nodes
while len(self.inputs) > 1:
self.inputs.remove(self.inputs[-1])
if (self.property0 == 'Uniform'):
self.draw_nodes_uniform(context)
elif (self.property0 == 'RGB'):
self.draw_nodes_rgb(context)
else:
self.draw_nodes_colorwheel(context)
def set_data(self, context):
abspath = bpy.path.abspath(self.filepath)
abspath = abspath.replace("\\","\\\\")
with open(abspath, 'r') as myfile:
data = myfile.read().replace('\n', '').replace('"','')
self.property1 = data
class ColorgradingSetHighlightNode(Node, ArmLogicTreeNode):
'''Colorgrading Set Highlight node'''
bl_idname = 'LNColorgradingSetHighlightNode'
bl_label = 'Colorgrading Set Highlight'
bl_icon = 'QUESTION'
# TODO: RRESET FILE OPTION FOR THE BELOW
property0 : EnumProperty(
items = [('RGB', 'RGB', 'RGB'),
('Uniform', 'Uniform', 'Uniform')],
name='Mode', default='Uniform', update=update_node)
property1 : StringProperty(name="Loaded Data", description="Loaded data - Just ignore", default="")
filepath : StringProperty(name="Preset File", description="Postprocess colorgrading preset file", default="", subtype="FILE_PATH", update=set_data)
def draw_nodes_uniform(self, context):
self.inputs.new('NodeSocketFloat', 'HighlightMin')
self.inputs[-1].default_value = 0
self.inputs.new('NodeSocketFloat', 'Saturation')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Contrast')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Gamma')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Gain')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Offset')
self.inputs[-1].default_value = 1
def draw_nodes_rgb(self, context):
self.inputs.new('NodeSocketFloat', 'HighlightMin')
self.inputs[-1].default_value = 0
self.inputs.new('NodeSocketVector', 'Saturation')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Contrast')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Gamma')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Gain')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Offset')
self.inputs[-1].default_value = [1,1,1]
def draw_nodes_colorwheel(self, context):
pass
def init(self, context):
self.inputs.new('ArmNodeSocketAction', 'In')
self.outputs.new('ArmNodeSocketAction', 'Out')
self.draw_nodes_uniform(context)
def draw_buttons(self, context, layout):
layout.label(text="Select value mode")
layout.prop(self, 'property0')
if (self.property0 == 'Preset File'):
layout.prop(self, 'filepath')
layout.prop(self, 'property1')
add_node(ColorgradingSetHighlightNode, category='Postprocess')

View file

@ -0,0 +1,83 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
def update_node(self, context):
#Clean all nodes
while len(self.inputs) > 1:
self.inputs.remove(self.inputs[-1])
if (self.property0 == 'Uniform'):
self.draw_nodes_uniform(context)
elif (self.property0 == 'RGB'):
self.draw_nodes_rgb(context)
else:
self.draw_nodes_colorwheel(context)
def set_data(self, context):
abspath = bpy.path.abspath(self.filepath)
abspath = abspath.replace("\\","\\\\")
with open(abspath, 'r') as myfile:
data = myfile.read().replace('\n', '').replace('"','')
self.property1 = data
class ColorgradingSetMidtoneNode(Node, ArmLogicTreeNode):
'''Colorgrading Set Midtone node'''
bl_idname = 'LNColorgradingSetMidtoneNode'
bl_label = 'Colorgrading Set Midtone'
bl_icon = 'QUESTION'
# TODO: RRESET FILE OPTION FOR THE BELOW
property0 : EnumProperty(
items = [('RGB', 'RGB', 'RGB'),
('Uniform', 'Uniform', 'Uniform')],
name='Mode', default='Uniform', update=update_node)
property1 : StringProperty(name="Loaded Data", description="Loaded data - Just ignore", default="")
filepath : StringProperty(name="Preset File", description="Postprocess colorgrading preset file", default="", subtype="FILE_PATH", update=set_data)
def draw_nodes_uniform(self, context):
self.inputs.new('NodeSocketFloat', 'Saturation')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Contrast')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Gamma')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Gain')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Offset')
self.inputs[-1].default_value = 1
def draw_nodes_rgb(self, context):
self.inputs.new('NodeSocketVector', 'Tint')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Saturation')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Contrast')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Gamma')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Gain')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Offset')
self.inputs[-1].default_value = [1,1,1]
def draw_nodes_colorwheel(self, context):
pass
def init(self, context):
self.inputs.new('ArmNodeSocketAction', 'In')
self.outputs.new('ArmNodeSocketAction', 'Out')
self.draw_nodes_uniform(context)
def draw_buttons(self, context, layout):
layout.label(text="Select value mode")
layout.prop(self, 'property0')
if (self.property0 == 'Preset File'):
layout.prop(self, 'filepath')
layout.prop(self, 'property1')
add_node(ColorgradingSetMidtoneNode, category='Postprocess')

View file

@ -0,0 +1,85 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
def update_node(self, context):
#Clean all nodes
while len(self.inputs) > 1:
self.inputs.remove(self.inputs[-1])
if (self.property0 == 'Uniform'):
self.draw_nodes_uniform(context)
elif (self.property0 == 'RGB'):
self.draw_nodes_rgb(context)
else:
self.draw_nodes_colorwheel(context)
def set_data(self, context):
abspath = bpy.path.abspath(self.filepath)
abspath = abspath.replace("\\","\\\\")
with open(abspath, 'r') as myfile:
data = myfile.read().replace('\n', '').replace('"','')
self.property1 = data
class ColorgradingSetShadowNode(Node, ArmLogicTreeNode):
'''Colorgrading Set Shadow node'''
bl_idname = 'LNColorgradingSetShadowNode'
bl_label = 'Colorgrading Set Shadow'
bl_icon = 'QUESTION'
# TODO: RRESET FILE OPTION FOR THE BELOW
property0 : EnumProperty(
items = [('RGB', 'RGB', 'RGB'),
('Uniform', 'Uniform', 'Uniform')],
name='Mode', default='Uniform', update=update_node)
property1 : StringProperty(name="Loaded Data", description="Loaded data - Just ignore", default="")
filepath : StringProperty(name="Preset File", description="Postprocess colorgrading preset file", default="", subtype="FILE_PATH", update=set_data)
def draw_nodes_uniform(self, context):
self.inputs.new('NodeSocketFloat', 'ShadowMax')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Saturation')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Contrast')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Gamma')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Gain')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketFloat', 'Offset')
self.inputs[-1].default_value = 1
def draw_nodes_rgb(self, context):
self.inputs.new('NodeSocketFloat', 'ShadowMax')
self.inputs[-1].default_value = 1
self.inputs.new('NodeSocketVector', 'Saturation')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Contrast')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Gamma')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Gain')
self.inputs[-1].default_value = [1,1,1]
self.inputs.new('NodeSocketVector', 'Offset')
self.inputs[-1].default_value = [1,1,1]
def draw_nodes_colorwheel(self, context):
pass
def init(self, context):
self.inputs.new('ArmNodeSocketAction', 'In')
self.outputs.new('ArmNodeSocketAction', 'Out')
self.draw_nodes_uniform(context)
def draw_buttons(self, context, layout):
layout.label(text="Select value mode")
layout.prop(self, 'property0')
if (self.property0 == 'Preset File'):
layout.prop(self, 'filepath')
layout.prop(self, 'property1')
add_node(ColorgradingSetShadowNode, category='Postprocess')

View file

@ -0,0 +1,17 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class BloomGetNode(Node, ArmLogicTreeNode):
'''Get Bloom Effect'''
bl_idname = 'LNBloomGetNode'
bl_label = 'Get Bloom'
bl_icon = 'QUESTION'
def init(self, context):
self.outputs.new('NodeSocketFloat', 'Threshold')
self.outputs.new('NodeSocketFloat', 'Strength')
self.outputs.new('NodeSocketFloat', 'Radius')
add_node(BloomGetNode, category='Postprocess')

View file

@ -0,0 +1,24 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class CameraGetNode(Node, ArmLogicTreeNode):
'''Get Camera Effect'''
bl_idname = 'LNCameraGetNode'
bl_label = 'Get Camera'
bl_icon = 'QUESTION'
def init(self, context):
self.outputs.new('NodeSocketFloat', 'F-Stop')
self.outputs.new('NodeSocketFloat', 'Shutter Time')
self.outputs.new('NodeSocketFloat', 'ISO')
self.outputs.new('NodeSocketFloat', 'Exposure Compensation')
self.outputs.new('NodeSocketFloat', 'Fisheye Distortion')
self.outputs.new('NodeSocketBool', 'Auto Focus')
self.outputs.new('NodeSocketFloat', 'DOF Distance')
self.outputs.new('NodeSocketFloat', 'DOF Length')
self.outputs.new('NodeSocketFloat', 'DOF F-Stop')
self.outputs.new('NodeSocketFloat', 'Film Grain')
add_node(CameraGetNode, category='Postprocess')

View file

@ -0,0 +1,16 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class ChromaticAberrationGetNode(Node, ArmLogicTreeNode):
'''Get Chromatic Aberration Effect'''
bl_idname = 'LNChromaticAberrationGetNode'
bl_label = 'Get ChromaticAberration'
bl_icon = 'QUESTION'
def init(self, context):
self.outputs.new('NodeSocketFloat', 'Strength')
self.outputs.new('NodeSocketFloat', 'Samples')
add_node(ChromaticAberrationGetNode, category='Postprocess')

View file

@ -0,0 +1,17 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class SSAOGetNode(Node, ArmLogicTreeNode):
'''Get SSAO Effect'''
bl_idname = 'LNSSAOGetNode'
bl_label = 'Get SSAO'
bl_icon = 'QUESTION'
def init(self, context):
self.outputs.new('NodeSocketFloat', 'Radius')
self.outputs.new('NodeSocketFloat', 'Strength')
self.outputs.new('NodeSocketFloat', 'Max Steps')
add_node(SSAOGetNode, category='Postprocess')

View file

@ -0,0 +1,19 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class SSRGetNode(Node, ArmLogicTreeNode):
'''Get SSR Effect'''
bl_idname = 'LNSSRGetNode'
bl_label = 'Get SSR'
bl_icon = 'QUESTION'
def init(self, context):
self.outputs.new('NodeSocketFloat', 'SSR Step')
self.outputs.new('NodeSocketFloat', 'SSR Step Min')
self.outputs.new('NodeSocketFloat', 'SSR Search')
self.outputs.new('NodeSocketFloat', 'SSR Falloff')
self.outputs.new('NodeSocketFloat', 'SSR Jitter')
add_node(SSRGetNode, category='Postprocess')

View file

@ -0,0 +1,19 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class LenstextureGetNode(Node, ArmLogicTreeNode):
'''Get Tonemapper Effect'''
bl_idname = 'LNLenstextureGetNode'
bl_label = 'Get Lenstexture'
bl_icon = 'QUESTION'
def init(self, context):
self.outputs.new('NodeSocketFloat', 'Center Min Clip')
self.outputs.new('NodeSocketFloat', 'Center Max Clip')
self.outputs.new('NodeSocketFloat', 'Luminance Min')
self.outputs.new('NodeSocketFloat', 'Luminance Max')
self.outputs.new('NodeSocketFloat', 'Brightness Exponent')
add_node(LenstextureGetNode, category='Postprocess')

View file

@ -0,0 +1,27 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class LenstextureSetNode(Node, ArmLogicTreeNode):
'''Set Lenstexture Effect'''
bl_idname = 'LNLenstextureSetNode'
bl_label = 'Set Lenstexture'
bl_icon = 'QUESTION'
def init(self, context):
self.inputs.new('ArmNodeSocketAction', 'In')
self.inputs.new('NodeSocketFloat', 'Center Min Clip')
self.inputs[-1].default_value = 0.1
self.inputs.new('NodeSocketFloat', 'Center Max Clip')
self.inputs[-1].default_value = 0.5
self.inputs.new('NodeSocketFloat', 'Luminance Min')
self.inputs[-1].default_value = 0.10
self.inputs.new('NodeSocketFloat', 'Luminance Max')
self.inputs[-1].default_value = 2.50
self.inputs.new('NodeSocketFloat', 'Brightness Exponent')
self.inputs[-1].default_value = 2.0
self.outputs.new('ArmNodeSocketAction', 'Out')
add_node(LenstextureSetNode, category='Postprocess')

View file

@ -0,0 +1,22 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class BloomSetNode(Node, ArmLogicTreeNode):
'''Set Bloom Effect'''
bl_idname = 'LNBloomSetNode'
bl_label = 'Set Bloom'
bl_icon = 'QUESTION'
def init(self, context):
self.inputs.new('ArmNodeSocketAction', 'In')
self.inputs.new('NodeSocketFloat', 'Threshold')
self.inputs[-1].default_value = 1.00
self.inputs.new('NodeSocketFloat', 'Strength')
self.inputs[-1].default_value = 3.50
self.inputs.new('NodeSocketFloat', 'Radius')
self.inputs[-1].default_value = 3.0
self.outputs.new('ArmNodeSocketAction', 'Out')
add_node(BloomSetNode, category='Postprocess')

View file

@ -0,0 +1,38 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class CameraSetNode(Node, ArmLogicTreeNode):
'''Set Camera Effect'''
bl_idname = 'LNCameraSetNode'
bl_label = 'Set Camera'
bl_icon = 'QUESTION'
def init(self, context):
self.inputs.new('ArmNodeSocketAction', 'In')
self.inputs.new('NodeSocketFloat', 'F-stop')
self.inputs[-1].default_value = 2.0
self.inputs.new('NodeSocketFloat', 'Shutter Time')
self.inputs[-1].default_value = 1.0
self.inputs.new('NodeSocketFloat', 'ISO')
self.inputs[-1].default_value = 100.0
self.inputs.new('NodeSocketFloat', 'Exposure Compensation')
self.inputs[-1].default_value = 0.0
self.inputs.new('NodeSocketFloat', 'Fisheye Distortion')
self.inputs[-1].default_value = 0.01
self.inputs.new('NodeSocketBool', 'Auto Focus')
self.inputs[-1].default_value = True
self.inputs.new('NodeSocketFloat', 'DoF Distance')
self.inputs[-1].default_value = 10.0
self.inputs.new('NodeSocketFloat', 'DoF Length')
self.inputs[-1].default_value = 160.0
self.inputs.new('NodeSocketFloat', 'DoF F-Stop')
self.inputs[-1].default_value = 128.0
self.inputs.new('NodeSocketInt', 'Tonemapper')
self.inputs[-1].default_value = 0.0
self.inputs.new('NodeSocketFloat', 'Film Grain')
self.inputs[-1].default_value = 2.0
self.outputs.new('ArmNodeSocketAction', 'Out')
add_node(CameraSetNode, category='Postprocess')

View file

@ -0,0 +1,20 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class ChromaticAberrationSetNode(Node, ArmLogicTreeNode):
'''Set Chromatic Aberration Effect'''
bl_idname = 'LNChromaticAberrationSetNode'
bl_label = 'Set ChromaticAberration'
bl_icon = 'QUESTION'
def init(self, context):
self.inputs.new('ArmNodeSocketAction', 'In')
self.inputs.new('NodeSocketFloat', 'Strength')
self.inputs[-1].default_value = 2.0
self.inputs.new('NodeSocketInt', 'Samples')
self.inputs[-1].default_value = 32
self.outputs.new('ArmNodeSocketAction', 'Out')
add_node(ChromaticAberrationSetNode, category='Postprocess')

View file

@ -0,0 +1,22 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class SSAOSetNode(Node, ArmLogicTreeNode):
'''Set SSAO Effect'''
bl_idname = 'LNSSAOSetNode'
bl_label = 'Set SSAO'
bl_icon = 'QUESTION'
def init(self, context):
self.inputs.new('ArmNodeSocketAction', 'In')
self.inputs.new('NodeSocketFloat', 'Radius')
self.inputs[-1].default_value = 1.0
self.inputs.new('NodeSocketFloat', 'Strength')
self.inputs[-1].default_value = 5.0
self.inputs.new('NodeSocketInt', 'Max Steps')
self.inputs[-1].default_value = 8
self.outputs.new('ArmNodeSocketAction', 'Out')
add_node(SSAOSetNode, category='Postprocess')

View file

@ -0,0 +1,26 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class SSRSetNode(Node, ArmLogicTreeNode):
'''Set SSR Effect'''
bl_idname = 'LNSSRSetNode'
bl_label = 'Set SSR'
bl_icon = 'QUESTION'
def init(self, context):
self.inputs.new('ArmNodeSocketAction', 'In')
self.inputs.new('NodeSocketFloat', 'SSR Step')
self.inputs[-1].default_value = 0.04
self.inputs.new('NodeSocketFloat', 'SSR Step Min')
self.inputs[-1].default_value = 0.05
self.inputs.new('NodeSocketFloat', 'SSR Search')
self.inputs[-1].default_value = 5.0
self.inputs.new('NodeSocketFloat', 'SSR Falloff')
self.inputs[-1].default_value = 5.0
self.inputs.new('NodeSocketFloat', 'SSR Jitter')
self.inputs[-1].default_value = 0.6
self.outputs.new('ArmNodeSocketAction', 'Out')
add_node(SSRSetNode, category='Postprocess')

View file

@ -0,0 +1,25 @@
import bpy
from bpy.props import *
from bpy.types import Node, NodeSocket
from arm.logicnode.arm_nodes import *
class GetWorldNode(Node, ArmLogicTreeNode):
'''Get world node'''
bl_idname = 'LNGetWorldNode'
bl_label = 'Get World'
bl_icon = 'QUESTION'
property0: EnumProperty(
items = [('right', 'right', 'right'),
('look', 'look', 'look'),
('up', 'up', 'up')],
name='', default='right')
def init(self, context):
self.inputs.new('ArmNodeSocketObject', 'Object')
self.outputs.new('NodeSocketVector', 'Vector')
def draw_buttons(self, context, layout):
layout.prop(self, 'property0')
add_node(GetWorldNode, category='Value')

View file

@ -60,12 +60,14 @@ def export_data(fp, sdk_path):
global exporter
wrd = bpy.data.worlds['Arm']
print('\nArmory v{0} ({1})'.format(wrd.arm_version, wrd.arm_commit))
print('OS: ' + arm.utils.get_os() + ', Target: ' + state.target + ', GAPI: ' + arm.utils.get_gapi() + ', Blender: ' + bpy.app.version_string)
print('\n' + '_' * 10 + ' [Armory] Compiling ' + '_' * 10)
if wrd.arm_verbose_output:
print('\nArmory v{0} ({1})'.format(wrd.arm_version, wrd.arm_commit))
print('OS: ' + arm.utils.get_os() + ', Target: ' + state.target + ', GAPI: ' + arm.utils.get_gapi() + ', Blender: ' + bpy.app.version_string)
# Clean compiled variants if cache is disabled
build_dir = arm.utils.get_fp_build()
if wrd.arm_cache_build == False:
if not wrd.arm_cache_build:
if os.path.isdir(build_dir + '/debug/html5-resources'):
shutil.rmtree(build_dir + '/debug/html5-resources', onerror=remove_readonly)
if os.path.isdir(build_dir + '/krom-resources'):
@ -104,15 +106,17 @@ def export_data(fp, sdk_path):
if not os.path.exists(build_dir + '/compiled/Assets'):
os.makedirs(build_dir + '/compiled/Assets')
# have a "zoo" collection in the current scene
export_coll = bpy.data.collections.new("export_coll")
export_coll = bpy.data.collections.new("export_coll")
bpy.context.scene.collection.children.link(export_coll)
for scene in bpy.data.scenes:
if scene == bpy.context.scene: continue
for o in scene.collection.all_objects:
if o.type == "MESH" or o.type == "EMPTY": export_coll.objects.link(o)
if o.type == "MESH" or o.type == "EMPTY":
if o.name not in export_coll.all_objects.keys():
export_coll.objects.link(o)
depsgraph = bpy.context.evaluated_depsgraph_get()
bpy.data.collections.remove(export_coll) # destroy "zoo" collection
for scene in bpy.data.scenes:
if scene.arm_export:
ext = '.lz4' if ArmoryExporter.compress_enabled else '.arm'
@ -147,12 +151,13 @@ def export_data(fp, sdk_path):
modules.append('navigation')
if export_ui:
modules.append('ui')
print('Exported modules: ' + str(modules))
defs = arm.utils.def_strings_to_array(wrd.world_defs)
cdefs = arm.utils.def_strings_to_array(wrd.compo_defs)
print('Shader flags: ' + str(defs))
if wrd.arm_debug_console:
if wrd.arm_verbose_output:
print('Exported modules: ' + str(modules))
print('Shader flags: ' + str(defs))
print('Khafile flags: ' + str(assets.khafile_defs))
# Render path is configurable at runtime
@ -289,8 +294,12 @@ def compile(assets_only=False):
cmd.append('--nohaxe')
cmd.append('--noproject')
print("Running: ", cmd)
print("Using project from " + arm.utils.get_fp())
if not wrd.arm_verbose_output:
cmd.append("--quiet")
else:
print("Using project from " + arm.utils.get_fp())
print("Running: ", cmd)
state.proc_build = run_proc(cmd, assets_done if compilation_server else build_done)
def build(target, is_play=False, is_publish=False, is_export=False):
@ -306,7 +315,7 @@ def build(target, is_play=False, is_publish=False, is_export=False):
if arm.utils.get_save_on_build():
bpy.ops.wm.save_mainfile()
log.clear()
log.clear(clear_warnings=True)
# Set camera in active scene
active_scene = arm.utils.get_active_scene()
@ -400,7 +409,9 @@ def compilation_server_done():
def build_done():
print('Finished in ' + str(time.time() - profile_time))
if state.proc_build == None:
if log.num_warnings > 0:
print(f'{log.num_warnings} warnings occurred during compilation!')
if state.proc_build is None:
return
result = state.proc_build.poll()
state.proc_build = None
@ -467,8 +478,6 @@ def play():
global scripts_mtime
wrd = bpy.data.worlds['Arm']
log.clear()
build(target=runtime_to_target(), is_play=True)
khajs_path = get_khajs_path(state.target)
@ -575,7 +584,7 @@ def build_success():
new_files_path = files_path + '-' + ext
os.rename(files_path, new_files_path)
files_path = new_files_path
if target_name == 'html5':
print('Exported HTML5 package to ' + files_path)
elif target_name.startswith('ios') or target_name.startswith('osx'): # TODO: to macos

View file

@ -46,6 +46,11 @@ def build_node_tree(node_group):
pack_path = arm.utils.safestr(bpy.data.worlds['Arm'].arm_project_package)
path = 'Sources/' + pack_path.replace('.', '/') + '/node/'
group_name = arm.utils.safesrc(node_group.name[0].upper() + node_group.name[1:])
if group_name != node_group.name:
arm.log.warn('Logic node tree and generated trait names differ! Node'
f' tree: "{node_group.name}", trait: "{group_name}"')
file = path + group_name + '.hx'
# Import referenced node group
@ -74,7 +79,7 @@ def build_node_tree(node_group):
for node in root_nodes:
build_node(node, f)
f.write('\t}\n')
# Create node functions
for node_name in function_nodes:
node = function_nodes[node_name]
@ -154,7 +159,7 @@ def build_node(node, f):
else:
prop = str(prop)
f.write('\t\t' + name + '.property' + str(i) + ' = ' + prop + ';\n')
# Create inputs
for inp in node.inputs:
# Is linked - find node
@ -179,7 +184,7 @@ def build_node(node, f):
inp_from = 0
# Add input
f.write('\t\t' + name + '.addInput(' + inp_name + ', ' + str(inp_from) + ');\n')
# Create outputs
for out in node.outputs:
if out.is_linked:
@ -216,7 +221,7 @@ def collect_nodes_from_output(out, f):
for o in reroute.outputs:
outputs = outputs + collect_nodes_from_output(o, f)
return outputs
def get_root_nodes(node_group):
roots = []
for node in node_group.nodes:

View file

@ -195,6 +195,9 @@ def build():
if compo_depth:
wrd.compo_defs += '_CDepth'
assets.add_khafile_def('rp_compositordepth')
if rpdat.rp_pp:
wrd.compo_defs += '_CPostprocess'
assets.add_shader_pass('compositor_pass')
assets.add_khafile_def('rp_antialiasing={0}'.format(rpdat.rp_antialiasing))
@ -329,6 +332,9 @@ def build():
if rpdat.rp_dynres:
assets.add_khafile_def('rp_dynres')
if rpdat.rp_pp:
assets.add_khafile_def('rp_pp')
if rpdat.rp_chromatic_aberration:
assets.add_shader_pass('copy_pass')
assets.add_khafile_def('rp_chromatic_aberration')

View file

@ -383,6 +383,10 @@ def parse_vector(node, socket):
elif node.type == 'GROUP_INPUT':
return parse_group_input(node, socket)
elif node.type == 'VERTEX_COLOR':
con.add_elem('col', 'short4norm') # Vcols only for now
return 'vcolor'
elif node.type == 'ATTRIBUTE':
if socket == node.outputs[0]: # Color
con.add_elem('col', 'short4norm') # Vcols only for now

View file

@ -12,7 +12,7 @@ import arm.proxy
import arm.nodes_logic
# Armory version
arm_version = '2020.2'
arm_version = '2020.3'
arm_commit = '$Id$'
def init_properties():
@ -71,7 +71,8 @@ def init_properties():
items=[('Scene', 'Scene', 'Scene'),
('Viewport', 'Viewport', 'Viewport')],
name="Camera", description="Viewport camera", default='Scene', update=assets.invalidate_compiler_cache)
bpy.types.World.arm_debug_console = BoolProperty(name="Debug Console", description="Show inspector in player and enable debug draw", default=False, update=assets.invalidate_shader_cache)
bpy.types.World.arm_debug_console = BoolProperty(name="Debug Console", description="Show inspector in player and enable debug draw.\nRequires that Zui is not disabled", default=False, update=assets.invalidate_shader_cache)
bpy.types.World.arm_verbose_output = BoolProperty(name="Verbose Output", description="Print additional information to the console during compilation", default=False)
bpy.types.World.arm_runtime = EnumProperty(
items=[('Krom', 'Krom', 'Krom'),
('Browser', 'Browser', 'Browser')],
@ -139,6 +140,7 @@ def init_properties():
bpy.types.MetaBall.arm_dynamic_usage = BoolProperty(name="Dynamic Data Usage", description="Metaball data can change at runtime", default=False)
# For armature
bpy.types.Armature.arm_cached = BoolProperty(name="Armature Cached", description="No need to reexport armature data", default=False)
bpy.types.Armature.arm_autobake = BoolProperty(name="Auto Bake", description="Bake constraints automatically", default=True)
# For camera
bpy.types.Camera.arm_frustum_culling = BoolProperty(name="Frustum Culling", description="Perform frustum culling for this camera", default=True)

View file

@ -41,6 +41,7 @@ def update_preset(self, context):
rpdat.arm_texture_filter = 'Anisotropic'
rpdat.arm_irradiance = True
rpdat.arm_radiance = True
rpdat.rp_pp = False
elif self.rp_preset == 'Mobile':
rpdat.rp_renderer = 'Forward'
rpdat.rp_depthprepass = False
@ -75,6 +76,7 @@ def update_preset(self, context):
rpdat.arm_texture_filter = 'Linear'
rpdat.arm_irradiance = True
rpdat.arm_radiance = False
rpdat.rp_pp = False
elif self.rp_preset == 'Max':
rpdat.rp_renderer = 'Deferred'
rpdat.rp_shadows = True
@ -112,6 +114,7 @@ def update_preset(self, context):
rpdat.arm_texture_filter = 'Anisotropic'
rpdat.arm_irradiance = True
rpdat.arm_radiance = True
rpdat.rp_pp = False
elif self.rp_preset == '2D/Baked':
rpdat.rp_renderer = 'Forward'
rpdat.rp_depthprepass = False
@ -146,6 +149,7 @@ def update_preset(self, context):
rpdat.arm_texture_filter = 'Linear'
rpdat.arm_irradiance = False
rpdat.arm_radiance = False
rpdat.rp_pp = False
update_renderpath(self, context)
def update_renderpath(self, context):
@ -326,6 +330,7 @@ class ArmRPListItem(bpy.types.PropertyGroup):
name='Draw Order', description='Sort objects', default='Auto', update=assets.invalidate_compiled_data)
rp_stereo: BoolProperty(name="VR", description="Stereo rendering", default=False, update=update_renderpath)
rp_water: BoolProperty(name="Water", description="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),

View file

@ -313,6 +313,7 @@ class ArmoryGenerateNavmeshButton(bpy.types.Operator):
'''Generate navmesh from selected meshes'''
bl_idname = 'arm.generate_navmesh'
bl_label = 'Generate Navmesh'
def execute(self, context):
obj = context.active_object
@ -330,7 +331,7 @@ class ArmoryGenerateNavmeshButton(bpy.types.Operator):
apply_modifiers = not armature
obj_eval = obj.evaluated_get(depsgraph) if apply_modifiers else obj
exportMesh = obj_eval.to_mesh()
export_mesh = obj_eval.to_mesh()
# TODO: build tilecache here
print("Started visualization generation")
# For visualization
@ -342,11 +343,11 @@ class ArmoryGenerateNavmeshButton(bpy.types.Operator):
mesh_path = nav_full_path + '/' + nav_mesh_name + '.obj'
with open(mesh_path, 'w') as f:
for v in exportMesh.vertices:
for v in export_mesh.vertices:
f.write("v %.4f " % (v.co[0] * obj_eval.scale.x))
f.write("%.4f " % (v.co[2] * obj_eval.scale.z))
f.write("%.4f\n" % (v.co[1] * obj_eval.scale.y)) # Flipped
for p in exportMesh.polygons:
for p in export_mesh.polygons:
f.write("f")
for i in reversed(p.vertices): # Flipped normals
f.write(" %d" % (i + 1))
@ -356,13 +357,12 @@ class ArmoryGenerateNavmeshButton(bpy.types.Operator):
# append config values
nav_config = {}
for t in obj.arm_traitlist:
for trait in obj.arm_traitlist:
# check if trait is navmesh here
if len(t.arm_traitpropslist) > 0 and t.class_name_prop == 'NavMesh':
for pt in t.arm_traitpropslist: # Append props
prop = pt.name.replace(')', '').split('(')
name = prop[0]
value = float(pt.value)
if trait.arm_traitpropslist and trait.class_name_prop == 'NavMesh':
for prop in trait.arm_traitpropslist: # Append props
name = prop.name
value = prop.get_value()
nav_config[name] = value
nav_config_json = json.dumps(nav_config)
@ -374,8 +374,8 @@ class ArmoryGenerateNavmeshButton(bpy.types.Operator):
navmesh = bpy.context.selected_objects[0]
navmesh.name = nav_mesh_name
navmesh.rotation_euler = (0,0,0)
navmesh.location = (obj.location.x,obj.location.y,obj.location.z)
navmesh.rotation_euler = (0, 0, 0)
navmesh.location = (obj.location.x, obj.location.y, obj.location.z)
navmesh.arm_export = False
bpy.context.view_layer.objects.active = navmesh

View file

@ -82,7 +82,7 @@ class ArmTraitPropListItem(bpy.types.PropertyGroup):
elif self.type == "Float":
self.value_float = float(val)
elif self.type == "Bool":
self.value_bool = bool(val)
self.value_bool = val == "true"
elif self.type in ("Vec2", "Vec3", "Vec4"):
if isinstance(val, str):
dimensions = int(self.type[-1])

View file

@ -142,6 +142,7 @@ class ARM_PT_DataPropsPanel(bpy.types.Panel):
layout.prop(obj.data, 'arm_loop')
layout.prop(obj.data, 'arm_stream')
elif obj.type == 'ARMATURE':
layout.prop(obj.data, 'arm_autobake')
pass
class ARM_PT_ScenePropsPanel(bpy.types.Panel):
@ -264,7 +265,7 @@ class ARM_PT_ArmoryPlayerPanel(bpy.types.Panel):
wrd = bpy.data.worlds['Arm']
row = layout.row(align=True)
row.alignment = 'EXPAND'
if state.proc_play == None and state.proc_build == None:
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")
@ -272,6 +273,14 @@ class ARM_PT_ArmoryPlayerPanel(bpy.types.Panel):
layout.prop(wrd, 'arm_runtime')
layout.prop(wrd, 'arm_play_camera')
if log.num_warnings > 0:
box = layout.box()
# Less spacing between lines
col = box.column(align=True)
col.label(text=f'{log.num_warnings} warnings occurred during compilation!', icon='ERROR')
# Blank icon to achieve the same indentation as the line before
col.label(text='Please open the console to get more information.', icon='BLANK1')
class ARM_PT_ArmoryExporterPanel(bpy.types.Panel):
bl_label = "Armory Exporter"
bl_space_type = "PROPERTIES"
@ -362,7 +371,10 @@ class ARM_PT_ProjectFlagsPanel(bpy.types.Panel):
layout.use_property_split = True
layout.use_property_decorate = False
wrd = bpy.data.worlds['Arm']
layout.prop(wrd, 'arm_debug_console')
row = layout.row()
row.enabled = wrd.arm_ui != 'Disabled'
row.prop(wrd, 'arm_debug_console')
layout.prop(wrd, 'arm_verbose_output')
layout.prop(wrd, 'arm_cache_build')
layout.prop(wrd, 'arm_live_patch')
layout.prop(wrd, 'arm_stream_scene')
@ -608,7 +620,7 @@ class ArmoryCleanProjectButton(bpy.types.Operator):
return{'FINISHED'}
def draw_view3d_header(self, context):
if state.proc_build != None:
if state.proc_build is not None:
self.layout.label(text='Compiling..')
elif log.info_text != '':
self.layout.label(text=log.info_text)
@ -709,6 +721,7 @@ class ARM_PT_RenderPathRendererPanel(bpy.types.Panel):
layout.prop(rpdat, "rp_hdr")
layout.prop(rpdat, "rp_stereo")
layout.prop(rpdat, 'arm_culling')
layout.prop(rpdat, 'rp_pp')
class ARM_PT_RenderPathShadowsPanel(bpy.types.Panel):
bl_label = "Shadows"

View file

@ -479,7 +479,8 @@ def fetch_prop(o):
prop = item.arm_traitpropslist[found_prop.name]
# Default value added and current value is blank (no override)
if (not found_prop.get_value() and defaults[index]):
if (found_prop.get_value() is None
or found_prop.get_value() == "") and defaults[index]:
prop.set_value(defaults[index])
# Type has changed, update displayed name
if (len(found_prop.name) == 1 or (len(found_prop.name) > 1 and found_prop.name[1] != p[1])):
@ -718,11 +719,11 @@ def open_editor(hx_path=None):
def open_folder():
if arm.utils.get_os() == 'win':
subprocess.Popen(['explorer', arm.utils.get_fp()])
subprocess.run(['explorer', arm.utils.get_fp()])
elif arm.utils.get_os() == 'mac':
subprocess.Popen(['open', arm.utils.get_fp()])
subprocess.run(['open', arm.utils.get_fp()])
elif arm.utils.get_os() == 'linux':
subprocess.Popen(['xdg-open', arm.utils.get_fp()])
subprocess.run(['xdg-open', arm.utils.get_fp()])
else:
webbrowser.open('file://' + arm.utils.get_fp())