DFGI test
This commit is contained in:
parent
bb7ec8ecf8
commit
9f62011ffc
|
@ -45,7 +45,7 @@ uniform float envmapStrength;
|
|||
uniform vec3 eyeLook;
|
||||
#endif
|
||||
#ifdef _DFAO
|
||||
//!uniform sampler2D sdftex;
|
||||
//!uniform sampler3D sdftex;
|
||||
#endif
|
||||
|
||||
in vec2 texCoord;
|
||||
|
@ -103,7 +103,7 @@ void main() {
|
|||
|
||||
// return;
|
||||
#endif
|
||||
|
||||
|
||||
// Envmap
|
||||
#ifdef _Irr
|
||||
vec3 envl = shIrradiance(n, 2.2) / PI;
|
||||
|
@ -136,6 +136,10 @@ void main() {
|
|||
envl.rgb *= envmapStrength * g1.a; // Occlusion
|
||||
#endif
|
||||
|
||||
#ifdef _DFGI
|
||||
envl.rgb = dfgi(p, n) * albedo;
|
||||
#endif
|
||||
|
||||
#ifdef _SSAO
|
||||
envl.rgb *= texture(ssaotex, texCoord).r;
|
||||
#endif
|
||||
|
|
|
@ -49,7 +49,7 @@ uniform sampler2D gbuffer1;
|
|||
#endif
|
||||
#endif
|
||||
#ifdef _DFRS
|
||||
//!uniform sampler2D sdftex;
|
||||
//!uniform sampler3D sdftex;
|
||||
#endif
|
||||
|
||||
uniform mat4 invVP;
|
||||
|
@ -152,69 +152,7 @@ void main() {
|
|||
#endif
|
||||
|
||||
#ifdef _DFRS
|
||||
|
||||
const float distmax = 40.0;
|
||||
const float eps = 0.02;
|
||||
const int maxSteps = 30;
|
||||
float dist = 0.2;
|
||||
|
||||
// float test = mapsdf2(p);
|
||||
// if (test < 0.1) {
|
||||
// fragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
// return;
|
||||
// }
|
||||
|
||||
float lastd = distmax;
|
||||
for (int i = 0; i < maxSteps; i++) {
|
||||
vec3 rd = l * dist;
|
||||
float d = sdBox(p + rd, vec3(1.0));
|
||||
|
||||
// Going out of volume box
|
||||
// if (d > 0.0 && lastd < d) {
|
||||
// break;
|
||||
// }
|
||||
// lastd = d;
|
||||
|
||||
if (d <= 0.0) { // In volume
|
||||
d = mapsdf(p, rd);
|
||||
|
||||
if (d < eps) {
|
||||
visibility = 0.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { // To volume
|
||||
// d += mapsdf(p, rd);
|
||||
|
||||
vec3 sampleBorder = clamp(p + rd, vec3(-1.0), vec3(1.0));
|
||||
float phi = mapsdf2(sampleBorder, rd);
|
||||
float dd = 0.1;
|
||||
float grad_x = mapsdf2(sampleBorder + vec3(dd, 0, 0), rd) - phi;
|
||||
float grad_y = mapsdf2(sampleBorder + vec3(0, dd, 0), rd) - phi;
|
||||
vec3 grad = vec3(grad_x, grad_y, 1.0);
|
||||
vec3 endpoint = sampleBorder - normalize(grad) * phi;
|
||||
d = distance(endpoint, p + rd);
|
||||
|
||||
// float dd = 0.1;
|
||||
// vec3 p0 = clamp(p, vec3(-1.0), vec3(1.0));
|
||||
// vec3 p1 = clamp(p, vec3(-0.99), vec3(0.99));
|
||||
// float r0 = mapsdf2(p0, rd);
|
||||
// float r1 = mapsdf2(p1, rd);
|
||||
// float h0 = 0.5 + (r0 * r0 - r1 * r1) / (2.0 * dd * dd);
|
||||
// float ri = sqrt(abs(r0 * r0 - h0 * h0 * dd * dd));
|
||||
// vec3 p2 = p0 + (p1 - p0) * h0;
|
||||
// vec3 p3 = p2 + vec3(p1.z - p0.z, p1.y - p0.y, p1.x - p0.x) * ri;
|
||||
// d = length((p + rd) - p3);
|
||||
}
|
||||
|
||||
const float k = 1.0;
|
||||
visibility = min(visibility, (k * d / dist));
|
||||
dist += d;
|
||||
|
||||
if (dist > distmax) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
visibility = dfrs(p, l, lightPos);
|
||||
#endif
|
||||
|
||||
// Per-light
|
||||
|
|
|
@ -1,44 +1,29 @@
|
|||
const float res = 50.0; // sdftex res
|
||||
|
||||
uniform sampler2D sdftex;
|
||||
uniform sampler3D sdftex;
|
||||
|
||||
float mapsdf(vec3 ro, vec3 rd) {
|
||||
vec3 p = ro + rd;
|
||||
float mapsdf(vec3 p) {
|
||||
p = clamp(p, vec3(-1.0), vec3(1.0));
|
||||
p = p * 0.5 + 0.5;
|
||||
float s1 = (p.z * res);
|
||||
float s2 = int(s1);
|
||||
float s = s2 - s1;
|
||||
|
||||
float m = sign(rd.z) > 0.0 ? s : (1.0 - s);
|
||||
vec2 co = vec2(p.x / res + s2 / res, p.y);
|
||||
float dist = (texture(sdftex, co).r) * m;
|
||||
|
||||
co.x += 1 / res * sign(rd.z);
|
||||
dist += (texture(sdftex, co).r) * (1.0 - m);
|
||||
|
||||
return dist;
|
||||
return texture(sdftex, p).a;
|
||||
}
|
||||
|
||||
float mapsdf2(vec3 p, vec3 rd) {
|
||||
// p = p * 0.5 + 0.5;
|
||||
// float s = int(p.z * res);
|
||||
// vec2 co = vec2(p.x / res + s / res, p.y);
|
||||
// return texture(sdftex, co).r;
|
||||
|
||||
vec4 mapsdf2(vec3 p) {
|
||||
p = clamp(p, vec3(-1.0), vec3(1.0));
|
||||
p = p * 0.5 + 0.5;
|
||||
float s1 = (p.z * res);
|
||||
float s2 = int(s1);
|
||||
float s = s2 - s1;
|
||||
return texture(sdftex, p);
|
||||
}
|
||||
|
||||
float m = sign(rd.z) > 0.0 ? s : (1.0 - s);
|
||||
vec2 co = vec2(p.x / res + s2 / res, p.y);
|
||||
float dist = texture(sdftex, co).r * m;
|
||||
vec3 calcNormal(const vec3 pos, const float eps) {
|
||||
const vec3 v1 = vec3( 1.0,-1.0,-1.0);
|
||||
const vec3 v2 = vec3(-1.0,-1.0, 1.0);
|
||||
const vec3 v3 = vec3(-1.0, 1.0,-1.0);
|
||||
const vec3 v4 = vec3( 1.0, 1.0, 1.0);
|
||||
|
||||
co.x += 1 / res * sign(rd.z);
|
||||
dist += (texture(sdftex, co).r) * (1.0 - m);
|
||||
|
||||
return dist;
|
||||
return normalize(v1 * mapsdf(pos + v1 * eps) +
|
||||
v2 * mapsdf(pos + v2 * eps) +
|
||||
v3 * mapsdf(pos + v3 * eps) +
|
||||
v4 * mapsdf(pos + v4 * eps));
|
||||
}
|
||||
|
||||
float sdBox(vec3 p, vec3 b) {
|
||||
|
@ -47,6 +32,7 @@ float sdBox(vec3 p, vec3 b) {
|
|||
}
|
||||
|
||||
float dfao(const vec3 p, const vec3 n) {
|
||||
const float eps = 0.02;
|
||||
float occ = 0.0;
|
||||
float sca = 1.0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
|
@ -55,14 +41,15 @@ float dfao(const vec3 p, const vec3 n) {
|
|||
vec3 sp = rd + p;
|
||||
float d;
|
||||
if (sdBox(sp, vec3(1.0)) <= 0.0) {
|
||||
d = mapsdf(sp, rd);
|
||||
d = mapsdf(sp + rd);
|
||||
// if (d < eps) break;
|
||||
}
|
||||
else {
|
||||
vec3 sampleBorder = clamp(sp, vec3(-1.0), vec3(1.0));
|
||||
float phi = mapsdf2(sampleBorder, rd);
|
||||
float phi = mapsdf(sampleBorder);
|
||||
float dd = 0.1;
|
||||
float grad_x = mapsdf2(sampleBorder + vec3(dd, 0, 0), rd) - phi;
|
||||
float grad_y = mapsdf2(sampleBorder + vec3(0, dd, 0), rd) - phi;
|
||||
float grad_x = mapsdf(sampleBorder + vec3(dd, 0, 0)) - phi;
|
||||
float grad_y = mapsdf(sampleBorder + vec3(0, dd, 0)) - phi;
|
||||
vec3 grad = vec3(grad_x, grad_y, 1.0);
|
||||
vec3 endpoint = sampleBorder - normalize(grad) * phi;
|
||||
d = distance(endpoint, sp);
|
||||
|
@ -70,5 +57,151 @@ float dfao(const vec3 p, const vec3 n) {
|
|||
occ += (r - d) * sca;
|
||||
sca *= 0.85;
|
||||
}
|
||||
return clamp(1.0 - occ / (3.14), 0.0, 1.0);
|
||||
return clamp(1.0 - occ / (2.14), 0.0, 1.0);
|
||||
}
|
||||
|
||||
// float dfrs(const vec3 p, const vec3 l) {
|
||||
float dfrs(const vec3 p, const vec3 l, const vec3 lp) {
|
||||
float visibility = 1.0;
|
||||
|
||||
const float distmax = 10.0;
|
||||
const float eps = 0.01;
|
||||
float dist = 0.05;
|
||||
|
||||
// float test = mapsdf(p);
|
||||
// if (test < 0.1) {
|
||||
// fragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// float lastd = distmax;
|
||||
for (int i = 0; i < 50; i++) {
|
||||
vec3 rd = l * dist;
|
||||
float d = sdBox(p + rd, vec3(1.0));
|
||||
|
||||
// Going out of volume box
|
||||
// if (d > 0.0 && lastd < d) {
|
||||
// visibility = 1.0;
|
||||
// break;
|
||||
// }
|
||||
// lastd = d;
|
||||
|
||||
if (d <= 0.0) { // In volume
|
||||
d = mapsdf(p + rd);
|
||||
|
||||
// if (distance(p + rd, lp) < 0.05) { // Hits light pos
|
||||
if (dist + d > distance(p, lp) - 0.05) {
|
||||
// visibility = 1.0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (d < eps) {
|
||||
visibility = 0.0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { // To volume
|
||||
// d += mapsdf(p + rd);
|
||||
|
||||
vec3 sampleBorder = clamp(p + rd, vec3(-1.0), vec3(1.0));
|
||||
float phi = mapsdf(sampleBorder);
|
||||
float dd = 0.1;
|
||||
float grad_x = mapsdf(sampleBorder + vec3(dd, 0, 0)) - phi;
|
||||
float grad_y = mapsdf(sampleBorder + vec3(0, dd, 0)) - phi;
|
||||
vec3 grad = vec3(grad_x, grad_y, 1.0);
|
||||
vec3 endpoint = sampleBorder - normalize(grad) * phi;
|
||||
d = distance(endpoint, p + rd);
|
||||
|
||||
// float dd = 0.1;
|
||||
// vec3 p0 = clamp(p, vec3(-1.0), vec3(1.0));
|
||||
// vec3 p1 = clamp(p, vec3(-0.99), vec3(0.99));
|
||||
// float r0 = mapsdf(p0);
|
||||
// float r1 = mapsdf(p1);
|
||||
// float h0 = 0.5 + (r0 * r0 - r1 * r1) / (2.0 * dd * dd);
|
||||
// float ri = sqrt(abs(r0 * r0 - h0 * h0 * dd * dd));
|
||||
// vec3 p2 = p0 + (p1 - p0) * h0;
|
||||
// vec3 p3 = p2 + vec3(p1.z - p0.z, p1.y - p0.y, p1.x - p0.x) * ri;
|
||||
// d = length((p + rd) - p3);
|
||||
}
|
||||
|
||||
const float k = 4.0;
|
||||
visibility = min(visibility, k * d / dist);
|
||||
dist += d;
|
||||
|
||||
if (dist > distmax) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return visibility;
|
||||
}
|
||||
|
||||
vec3 orthogonal(const vec3 u) {
|
||||
// Pass normalized u
|
||||
const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector
|
||||
return abs(dot(u, v)) > 0.99999 ? cross(u, vec3(0.0, 1.0, 0.0)) : cross(u, v);
|
||||
}
|
||||
|
||||
vec3 traceCone(const vec3 p, const vec3 n) {
|
||||
vec3 col = vec3(0.0);
|
||||
|
||||
const float eps = 0.02;
|
||||
float dist = 0.05;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
vec3 rd = n * dist;
|
||||
float d = sdBox(p + rd, vec3(1.0));
|
||||
if (d <= 0.0) {
|
||||
vec4 res = mapsdf2(p + rd);
|
||||
d = res.a;
|
||||
if (d < eps) {
|
||||
// float vis = dfrs(p + rd, l, lp);
|
||||
// vec3 hitn = calcNormal(p + rd, 0.002);
|
||||
// float diffuse = max(0.0, dot(hitn, l));// / dot(l,l);
|
||||
col = res.rgb * max(1.0 - dist, 0.0);// * diffuse;// * vis;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dist += d;
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
vec3 dfgi(const vec3 p, const vec3 n) {
|
||||
|
||||
const float ANGLE_MIX = 0.5; // Angle mix (1.0f -> orthogonal direction, 0.0f -> direction of normal)
|
||||
const float w[3] = { 1.0, 1.0, 1.0 }; // Cone weights
|
||||
// Find a base for the side cones with the normal as one of its base vectors
|
||||
const vec3 ortho = normalize(orthogonal(n));
|
||||
const vec3 ortho2 = normalize(cross(ortho, n));
|
||||
// Find base vectors for the corner cones
|
||||
const vec3 corner = 0.5 * (ortho + ortho2);
|
||||
const vec3 corner2 = 0.5 * (ortho - ortho2);
|
||||
// Find start position of trace (start with a bit of offset)
|
||||
const vec3 offset = 0.0 * n;
|
||||
const vec3 origin = p + offset;
|
||||
|
||||
vec3 col = vec3(0.0);
|
||||
|
||||
const float CONE_OFFSET = 0.0;//-0.01;
|
||||
col += w[0] * traceCone(origin + CONE_OFFSET * n, n);
|
||||
|
||||
const vec3 s1 = mix(n, ortho, ANGLE_MIX);
|
||||
const vec3 s2 = mix(n, -ortho, ANGLE_MIX);
|
||||
const vec3 s3 = mix(n, ortho2, ANGLE_MIX);
|
||||
const vec3 s4 = mix(n, -ortho2, ANGLE_MIX);
|
||||
col += w[1] * traceCone(origin + CONE_OFFSET * ortho, s1);
|
||||
col += w[1] * traceCone(origin - CONE_OFFSET * ortho, s2);
|
||||
col += w[1] * traceCone(origin + CONE_OFFSET * ortho2, s3);
|
||||
col += w[1] * traceCone(origin - CONE_OFFSET * ortho2, s4);
|
||||
|
||||
const vec3 c1 = mix(n, corner, ANGLE_MIX);
|
||||
const vec3 c2 = mix(n, -corner, ANGLE_MIX);
|
||||
const vec3 c3 = mix(n, corner2, ANGLE_MIX);
|
||||
const vec3 c4 = mix(n, -corner2, ANGLE_MIX);
|
||||
col += w[2] * traceCone(origin + CONE_OFFSET * corner, c1);
|
||||
col += w[2] * traceCone(origin - CONE_OFFSET * corner, c2);
|
||||
col += w[2] * traceCone(origin + CONE_OFFSET * corner2, c3);
|
||||
col += w[2] * traceCone(origin - CONE_OFFSET * corner2, c4);
|
||||
|
||||
return col / 9.0;
|
||||
}
|
||||
|
|
|
@ -1931,6 +1931,15 @@ class ArmoryExporter:
|
|||
sdk_path = arm.utils.get_sdk_path()
|
||||
sdfgen_path = sdk_path + '/armory/tools/sdfgen'
|
||||
shutil.copy(fp, sdfgen_path + '/krom/mesh.arm')
|
||||
# Extract basecolor
|
||||
# Assume Armpry PBR with linked texture for now
|
||||
# mat = bobject.material_slots[0].material
|
||||
# img = None
|
||||
# for n in mat.node_tree.nodes:
|
||||
# if n.type == 'GROUP' and n.node_tree.name.startswith('Armory PBR') and n.inputs[0].is_linked:
|
||||
# img = n.inputs[0].links[0].from_node.image
|
||||
# fp_img = bpy.path.abspath(img.filepath)
|
||||
# shutil.copy(fp_img, sdfgen_path + '/krom/mesh.png')
|
||||
# Run
|
||||
krom_location, krom_path = arm.utils.krom_paths()
|
||||
krom_dir = sdfgen_path + '/krom'
|
||||
|
@ -1942,6 +1951,8 @@ class ArmoryExporter:
|
|||
assets.add(sdf_path)
|
||||
os.remove('out.bin')
|
||||
os.remove(sdfgen_path + '/krom/mesh.arm')
|
||||
# if img != None:
|
||||
# os.remove(sdfgen_path + '/krom/mesh.png')
|
||||
|
||||
def export_mesh_quality(self, exportMesh, bobject, fp, o):
|
||||
# Triangulate mesh and remap vertices to eliminate duplicates
|
||||
|
|
|
@ -101,6 +101,11 @@ def build_node_tree(world):
|
|||
if cam.rp_dfao:
|
||||
wrd.world_defs += '_DFAO'
|
||||
assets.add_khafile_def('arm_sdf')
|
||||
if cam.rp_dfgi:
|
||||
wrd.world_defs += '_DFGI'
|
||||
assets.add_khafile_def('arm_sdf')
|
||||
wrd.world_defs += '_Rad' # Always do radiance for gi
|
||||
wrd.world_defs += '_Irr'
|
||||
|
||||
if voxelgi:
|
||||
assets.add_khafile_def('arm_voxelgi')
|
||||
|
|
|
@ -371,6 +371,7 @@ def init_properties():
|
|||
bpy.types.Camera.rp_ssr = bpy.props.BoolProperty(name="SSR", description="Screen space reflections", default=False, update=update_renderpath)
|
||||
bpy.types.Camera.rp_dfao = bpy.props.BoolProperty(name="DFAO", description="Distance field ambient occlusion", default=False)
|
||||
bpy.types.Camera.rp_dfrs = bpy.props.BoolProperty(name="DFRS", description="Distance field ray-traced shadows", default=False)
|
||||
bpy.types.Camera.rp_dfgi = bpy.props.BoolProperty(name="DFGI", description="Distance field global illumination", default=False)
|
||||
bpy.types.Camera.rp_bloom = bpy.props.BoolProperty(name="Bloom", description="Bloom processing", default=False, update=update_renderpath)
|
||||
bpy.types.Camera.rp_rendercapture = bpy.props.BoolProperty(name="Render Capture", description="Save output as render result", default=False, update=update_renderpath)
|
||||
bpy.types.Camera.rp_rendercapture_format = EnumProperty(
|
||||
|
|
|
@ -42,6 +42,7 @@ def set_preset(self, context, preset):
|
|||
cam.rp_ssr = False
|
||||
cam.rp_dfrs = False
|
||||
cam.rp_dfao = False
|
||||
cam.rp_dfgi = False
|
||||
cam.rp_bloom = False
|
||||
cam.rp_rendercapture = False
|
||||
cam.rp_motionblur = 'None'
|
||||
|
@ -69,6 +70,7 @@ def set_preset(self, context, preset):
|
|||
cam.rp_ssr = True
|
||||
cam.rp_dfrs = False
|
||||
cam.rp_dfao = False
|
||||
cam.rp_dfgi = False
|
||||
cam.rp_bloom = False
|
||||
cam.rp_rendercapture = False
|
||||
cam.rp_motionblur = 'None'
|
||||
|
@ -95,6 +97,7 @@ def set_preset(self, context, preset):
|
|||
cam.rp_ssr = False
|
||||
cam.rp_dfrs = False
|
||||
cam.rp_dfao = False
|
||||
cam.rp_dfgi = False
|
||||
cam.rp_bloom = False
|
||||
cam.rp_rendercapture = False
|
||||
cam.rp_motionblur = 'None'
|
||||
|
@ -121,6 +124,7 @@ def set_preset(self, context, preset):
|
|||
cam.rp_ssr = True
|
||||
cam.rp_dfrs = False
|
||||
cam.rp_dfao = False
|
||||
cam.rp_dfgi = False
|
||||
cam.rp_bloom = False
|
||||
cam.rp_rendercapture = False
|
||||
cam.rp_motionblur = 'None'
|
||||
|
@ -150,6 +154,7 @@ def set_preset(self, context, preset):
|
|||
cam.rp_ssr = True
|
||||
cam.rp_dfrs = False
|
||||
cam.rp_dfao = False
|
||||
cam.rp_dfgi = False
|
||||
cam.rp_bloom = False
|
||||
cam.rp_rendercapture = True
|
||||
cam.rp_rendercapture_format = '8bit'
|
||||
|
@ -179,6 +184,7 @@ def set_preset(self, context, preset):
|
|||
cam.rp_ssr = True
|
||||
cam.rp_dfrs = False
|
||||
cam.rp_dfao = False
|
||||
cam.rp_dfgi = False
|
||||
cam.rp_bloom = False
|
||||
cam.rp_rendercapture = False
|
||||
cam.rp_motionblur = 'None'
|
||||
|
@ -206,6 +212,7 @@ def set_preset(self, context, preset):
|
|||
cam.rp_ssr = False
|
||||
cam.rp_dfrs = False
|
||||
cam.rp_dfao = False
|
||||
cam.rp_dfgi = False
|
||||
cam.rp_bloom = False
|
||||
cam.rp_rendercapture = False
|
||||
cam.rp_motionblur = 'None'
|
||||
|
@ -233,6 +240,7 @@ def set_preset(self, context, preset):
|
|||
cam.rp_ssr = False
|
||||
cam.rp_dfrs = False
|
||||
cam.rp_dfao = False
|
||||
cam.rp_dfgi = False
|
||||
cam.rp_bloom = False
|
||||
cam.rp_rendercapture = False
|
||||
cam.rp_motionblur = 'None'
|
||||
|
@ -259,6 +267,7 @@ def set_preset(self, context, preset):
|
|||
cam.rp_ssr = False
|
||||
cam.rp_dfrs = False
|
||||
cam.rp_dfao = False
|
||||
cam.rp_dfgi = False
|
||||
cam.rp_bloom = False
|
||||
cam.rp_rendercapture = False
|
||||
cam.rp_motionblur = 'None'
|
||||
|
@ -341,8 +350,9 @@ class GenRPDataPropsPanel(bpy.types.Panel):
|
|||
layout.prop(dat, "rp_volumetriclight")
|
||||
layout.prop(dat, "rp_ssao")
|
||||
layout.prop(dat, "rp_ssr")
|
||||
layout.prop(dat, "rp_dfao")
|
||||
layout.prop(dat, "rp_dfrs")
|
||||
# layout.prop(dat, "rp_dfao")
|
||||
# layout.prop(dat, "rp_dfrs")
|
||||
# layout.prop(dat, "rp_dfgi")
|
||||
layout.prop(dat, "rp_bloom")
|
||||
layout.prop(dat, "rp_motionblur")
|
||||
layout.prop(dat, "rp_rendercapture")
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
"render_targets": [
|
||||
{
|
||||
"name": "sdf",
|
||||
"width": 2500,
|
||||
"height": 50,
|
||||
"width": 50,
|
||||
"height": 2500,
|
||||
"format": "A32"
|
||||
}
|
||||
],
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue