diff --git a/Libraries/paint/blender.py b/Libraries/paint/blender.py index dc290440..9b9447a4 100644 --- a/Libraries/paint/blender.py +++ b/Libraries/paint/blender.py @@ -3,6 +3,11 @@ import arm.material.make_mesh def register(): arm.material.make_mesh.write_material_attribs = write_material_attribs + arm.material.mat_utils.add_mesh_contexts.append('voxel') # Defaults to make_ao + arm.write_data.add_compiledglsl = """ + const ivec3 voxelgiResolution = ivec3(256, 256, 256); + const vec3 voxelgiHalfExtents = vec3(2.0, 2.0, 2.0); + """ def write_material_attribs(con, frag): diff --git a/Sources/arm/FlyCamera.hx b/Sources/arm/FlyCamera.hx index 9bb1fa6e..d0559bbb 100644 --- a/Sources/arm/FlyCamera.hx +++ b/Sources/arm/FlyCamera.hx @@ -41,8 +41,12 @@ class FlyCamera extends Trait { function update() { if (Input.occupied) return; - + if (!UITrait.uienabled) return; + if (UITrait.isScrolling) return; + if (UITrait.isDragging) return; if (UITrait.cameraType != 1) return; + + if (mouse.x > iron.App.w()) return; var moveForward = keyboard.down("w") || keyboard.down("up"); var moveBackward = keyboard.down("s") || keyboard.down("down"); diff --git a/Sources/arm/UINodes.hx b/Sources/arm/UINodes.hx index 8ba06f1c..b97e9f5a 100644 --- a/Sources/arm/UINodes.hx +++ b/Sources/arm/UINodes.hx @@ -337,19 +337,22 @@ class UINodes extends armory.Trait { alpha_blend_operation: 'add', vertex_structure: [{"name": "pos", "size": 3},{"name": "nor", "size": 3},{"name": "tex", "size": 2}] }); + if (UITrait.brushType == 2) { + con_paint.data.color_write_green = false; // R + con_paint.data.color_write_blue = false; // M + } + var vert = con_paint.make_vert(); var frag = con_paint.make_frag(); vert.add_out('vec3 sp'); - // vert.add_out('vec3 wnormal'); frag.ins = vert.outs; - // vert.add_uniform('mat4 N', '_normalMatrix'); vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix'); - vert.write('vec2 tpos = vec2(tex.x * 2.0 - 1.0, tex.y * 2.0 - 1.0);'); // TODO: Fix seams at uv borders vert.add_uniform('vec2 sub', '_sub'); + vert.add_uniform('float paintDepthBias', '_paintDepthBias'); vert.write('tpos += sub;'); vert.write('gl_Position = vec4(tpos, 0.0, 1.0);'); @@ -359,6 +362,7 @@ class UINodes extends armory.Trait { vert.write('sp.xyz = ndc.xyz * 0.5 + 0.5;'); vert.write('sp.y = 1.0 - sp.y;'); vert.write('sp.z -= 0.0001;'); // Bias + vert.write('sp.z -= paintDepthBias;'); // paintVisible vert.add_out('vec3 mposition'); if (UITrait.brushPaint == 0 && con_paint.is_elem('tex')) { @@ -368,13 +372,20 @@ class UINodes extends armory.Trait { vert.write('mposition = ndc.xyz;'); } + if (UITrait.brushType == 2) { + vert.add_out('vec3 wposition'); + vert.add_uniform('mat4 W', '_worldMatrix'); + vert.write('wposition = vec4(W * vec4(pos.xyz, 1.0)).xyz;'); + + vert.add_out('vec3 wnormal'); + vert.add_uniform('mat3 N', '_normalMatrix'); + vert.write('wnormal = N * nor;'); + frag.write('vec3 n = normalize(wnormal);'); + } + frag.add_out('vec4 fragColor[3]'); frag.add_uniform('vec4 inp', '_inputBrush'); - // frag.add_uniform('vec3 v', '_cameraLook'); - // frag.write('vec3 n = normalize(wnormal);'); - // frag.write('if (dot(n, v) > 0.0) discard;'); - frag.add_uniform('float aspectRatio', '_aspectRatioWindowF'); frag.write('vec2 bsp = sp.xy * 2.0 - 1.0;'); frag.write('bsp.x *= aspectRatio;'); @@ -427,13 +438,28 @@ class UINodes extends armory.Trait { frag.write(' str = clamp(str, 0.0, 1.0);'); frag.write(' fragColor[0] = vec4(basecol, str);'); - frag.write(' fragColor[1] = vec4(nortan, 1.0);'); // Encode normal, height, opacity, matid,.. + frag.write(' fragColor[1] = vec4(nortan, 1.0);'); frag.write(' fragColor[2] = vec4(occlusion, roughness, metallic, str);'); if (!UITrait.paintBase) frag.write('fragColor[0].a = 0.0;'); if (!UITrait.paintNor) frag.write('fragColor[1].a = 0.0;'); if (!UITrait.paintRough) frag.write('fragColor[2].a = 0.0;'); + if (UITrait.brushType == 2) { // Bake AO + frag.write('fragColor[0].a = 0.0;'); + frag.write('fragColor[1].a = 0.0;'); + + // frag.write('mat3 TBN = cotangentFrame(n, -vVec, texCoord);') + // frag.write('n = nortan * 2.0 - 1.0;') + // frag.write('n = normalize(TBN * normalize(n));') + + frag.write('const vec3 voxelgiHalfExtents = vec3(2.0);'); + frag.write('vec3 voxpos = wposition / voxelgiHalfExtents;'); + frag.add_uniform('sampler3D voxels'); + frag.add_function(armory.system.CyclesFunctions.str_traceAO); + frag.write('fragColor[2].r = 1.0 - traceAO(voxpos, wnormal, voxels);'); + } + con_paint.data.shader_from_source = true; con_paint.data.vertex_shader = vert.get(); con_paint.data.fragment_shader = frag.get(); diff --git a/Sources/arm/UITrait.hx b/Sources/arm/UITrait.hx index 7357566b..f6f40e08 100644 --- a/Sources/arm/UITrait.hx +++ b/Sources/arm/UITrait.hx @@ -93,8 +93,10 @@ class UITrait extends armory.Trait { // if (UINodes.show && paintVec.y > UINodes.wy) return false; // Prevent painting the same spot - save perf & reduce projection paint jittering caused by _sub offset - if (paintVec.x == lastPaintX && paintVec.y == lastPaintY) painted++; + var mouse = iron.system.Input.getMouse(); + if (mouse.down() && paintVec.x == lastPaintX && paintVec.y == lastPaintY) painted++; else painted = 0; + if (painted > 8) return false; lastPaintX = paintVec.x; lastPaintY = paintVec.y; @@ -122,6 +124,8 @@ class UITrait extends armory.Trait { public static var paintRough = true; public static var paintMet = true; public static var paintNor = true; + + public static var paintVisible = true; function linkFloat(link:String):Null { @@ -138,6 +142,9 @@ class UITrait extends armory.Trait { var f = brushStrength * brushNodesStrength; return f * f * 100; } + else if (link == '_paintDepthBias') { + return paintVisible ? 0.0 : 1.0; + } return null; } @@ -484,6 +491,18 @@ class UITrait extends armory.Trait { return 0; } + function showMaterialNodes() { + if (UINodes.show && !UINodes.isBrush) UINodes.show = false; + else { UINodes.show = true; UINodes.isBrush = false; } + resize(); + } + + function showBrushNodes() { + if (UINodes.show && UINodes.isBrush) UINodes.show = false; + else { UINodes.show = true; UINodes.isBrush = true; } + resize(); + } + var outputType = 0; var isBase = true; var isOpac = true; @@ -496,6 +515,7 @@ class UITrait extends armory.Trait { public static var selected:MaterialSlot; var brushes:Array = null; public static var selectedBrush:BrushSlot; + var selectTime = 0.0; function renderUI(g:kha.graphics2.Graphics) { if (!show) return; @@ -690,16 +710,22 @@ class UITrait extends armory.Trait { } if (ui.panel(Id.handle({selected: false}), "Camera")) { - + var scene = iron.Scene.active; + var cam = scene.cameras[0]; ui.row([1/2,1/2]); cameraType = ui.combo(Id.handle({position: cameraType}), ["Orbit", "Fly"], "Camera"); + var fovHandle = Id.handle({value: Std.int(cam.data.raw.fov * 100) / 100}); + cam.data.raw.fov = ui.slider(fovHandle, "FoV", 0.3, 2.0, true); + if (ui.changed) { + cam.buildProjection(); + } if (ui.button("Reset")) { - var scene = iron.Scene.active; - var cam = scene.cameras[0]; for (o in scene.raw.objects) { if (o.type == 'camera_object') { cam.transform.local.setF32(o.transform.values); cam.transform.decompose(); + fovHandle.value = 0.92; + cam.buildProjection(); currentObject.transform.reset(); break; } @@ -753,9 +779,7 @@ class UITrait extends armory.Trait { brushes.push(new BrushSlot()); } if (ui.button("Nodes")) { - if (UINodes.show && UINodes.isBrush) UINodes.show = false; - else { UINodes.show = true; UINodes.isBrush = true; } - resize(); + showBrushNodes(); } var img = bundled.get("brush"); @@ -772,15 +796,21 @@ class UITrait extends armory.Trait { } if (ui.image(im) == State.Started && im == img) { - selectedBrush = brushes[i]; - UINodes.inst.updateCanvasBrushMap(); - UINodes.inst.parseBrush(); + if (selectedBrush != brushes[i]) { + selectedBrush = brushes[i]; + UINodes.inst.updateCanvasBrushMap(); + UINodes.inst.parseBrush(); + } + if (iron.system.Time.time() - selectTime < 0.3) { + showBrushNodes(); + } + selectTime = iron.system.Time.time(); } } ui.row([1/2, 1/2]); var typeHandle = Id.handle(); - brushType = ui.combo(typeHandle, ["Draw", "Fill"], "Type"); + brushType = ui.combo(typeHandle, ["Draw", "Fill", "Bake AO"], "Type"); if (typeHandle.changed) { UINodes.inst.parseMaterial(); } @@ -816,11 +846,14 @@ class UITrait extends armory.Trait { } var roughHandle = Id.handle({selected: paintRough}); + // TODO: Use glColorMaski() to disable specific channel paintRough = ui.check(roughHandle, "ORM"); if (roughHandle.changed) { UINodes.inst.updateCanvasMap(); UINodes.inst.parseMaterial(); } + + paintVisible = ui.check(Id.handle({selected: paintVisible}), "Visible Only"); } if (ui.panel(Id.handle({selected: true}), "Materials")) { @@ -830,9 +863,7 @@ class UITrait extends armory.Trait { materials.push(new MaterialSlot()); } if (ui.button("Nodes")) { - if (UINodes.show && !UINodes.isBrush) UINodes.show = false; - else { UINodes.show = true; UINodes.isBrush = false; } - resize(); + showMaterialNodes(); } var img = bundled.get("mat"); @@ -849,9 +880,15 @@ class UITrait extends armory.Trait { } if (ui.image(im) == State.Started && im == img) { - selected = materials[i]; - UINodes.inst.updateCanvasMap(); - UINodes.inst.parseMaterial(); + if (selected != materials[i]) { + selected = materials[i]; + UINodes.inst.updateCanvasMap(); + UINodes.inst.parseMaterial(); + } + if (iron.system.Time.time() - selectTime < 0.3) { + showMaterialNodes(); + } + selectTime = iron.system.Time.time(); } } } @@ -859,7 +896,7 @@ class UITrait extends armory.Trait { // if (ui.panel(Id.handle({selected: true}), "Layers")) { // } - ui.text("v0.2", zui.Zui.Align.Right); + ui.text("v0.2a", zui.Zui.Align.Right); } if (ui.tab(htab, "Assets")) { diff --git a/Sources/arm/renderpath/RenderPathCreator.hx b/Sources/arm/renderpath/RenderPathCreator.hx index ea14675f..5f82d673 100644 --- a/Sources/arm/renderpath/RenderPathCreator.hx +++ b/Sources/arm/renderpath/RenderPathCreator.hx @@ -890,6 +890,7 @@ class RenderPathCreator { #end } + static var initVoxels = true; static function commands() { // Paint @@ -900,8 +901,31 @@ class RenderPathCreator { } if (arm.UITrait.paintDirty()) { + if (UITrait.brushType == 2) { // Bake AO + if (initVoxels) { + initVoxels = false; + var t = new RenderTargetRaw(); + t.name = "voxels"; + t.format = "R8"; + t.width = 256; + t.height = 256; + t.depth = 256; + t.is_image = true; + t.mipmaps = true; + path.createRenderTarget(t); + } + path.clearImage("voxels", 0x00000000); + path.setTarget(""); + path.setViewport(256, 256); + path.bindTarget("voxels", "voxels"); + path.drawMeshes("voxel"); + path.generateMipmaps("voxels"); + } path.setTarget("texpaint", ["texpaint_nor", "texpaint_pack"]); path.bindTarget("_paintdb", "paintdb"); + if (UITrait.brushType == 2) { // Bake AO + path.bindTarget("voxels", "voxels"); + } path.drawMeshes("paint"); } // diff --git a/armorpaint.blend b/armorpaint.blend index 640153ea..fcf1f902 100644 Binary files a/armorpaint.blend and b/armorpaint.blend differ