Render capture for Krom

This commit is contained in:
Lubos Lenco 2017-06-26 15:37:10 +02:00
parent 07ea79b376
commit b1f4c27567
13 changed files with 92 additions and 78 deletions

View file

@ -34,9 +34,9 @@ void main() {
float weight = 0.5 * clamp(1.0 - sqrt(delta) * SMAA_REPROJECTION_WEIGHT_SCALE, 0.0, 1.0);
// Blend the pixels according to the calculated weight:
fragColor.rgb = mix(current.rgb, previous.rgb, weight);
fragColor = vec4(mix(current.rgb, previous.rgb, weight), 1.0);
#else
vec4 previous = texture(tex2, texCoord);
fragColor = mix(current.rgb, previous.rgb, 0.5);
fragColor = vec4(mix(current.rgb, previous.rgb, 0.5), 1.0);
#endif
}

View file

@ -21,12 +21,6 @@ class SpaceArmory extends Trait {
static var first = true;
#if js
static var patchTime = 0.0;
static var lastMtime:Dynamic = null;
static var lastSize:Dynamic;
#end
public function new() {
super();
@ -43,8 +37,8 @@ class SpaceArmory extends Trait {
if (first) {
first = false;
#if (js && kha_webgl)
electronRenderCapture();
#if (kha_krom && arm_render)
renderCapture();
#end
}
}
@ -112,9 +106,10 @@ class SpaceArmory extends Trait {
}
#end
}
var time = 0.0;
#if (js && kha_webgl)
static var time = 0.0;
static var lastMtime:Dynamic = null;
function reloadOnUpdate() {
// Reload page on kha.js rewrite
var khaPath = "kha.js";
@ -131,58 +126,33 @@ class SpaceArmory extends Trait {
}
xhr.send();
}
#end
public static function getRenderResult():js.html.Uint8Array {
var gl = kha.SystemImpl.gl;
var w = gl.drawingBufferWidth;
var h = gl.drawingBufferHeight;
var pixels = new js.html.Uint8Array(w * h * 4);
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, js.html.webgl.GL.RGBA, js.html.webgl.GL.UNSIGNED_BYTE, pixels);
return pixels;
// var bytes = haxe.io.Bytes.ofData(pixels.buffer);
// var pngdata = armory.trait.internal.png.Tools.buildRGB(w, h, bytes);
// var output = new haxe.io.BytesOutput();
// var writer = new armory.trait.internal.png.Writer(output);
// writer.write(pngdata);
// return output.getBytes();
}
function electronRenderCapture() {
var electron = untyped __js__('window && window.process && window.process.versions["electron"]');
if (electron) {
untyped __js__('var fs = require("fs");');
App.notifyOnUpdate(function() {
patchTime += iron.system.Time.delta;
if (patchTime > 0.2) {
patchTime = 0;
var repatch = false;
untyped __js__('
if (fs.existsSync(__dirname + "/" + "render.msg")) {
{0} = true;
fs.unlinkSync(__dirname + "/" + "render.msg");
}'
, repatch);
if (repatch) {
var pixels = getRenderResult();
untyped __js__('
fs.writeFileSync(__dirname + "/render.bin", new Buffer({0}));
', pixels);
var w = kha.SystemImpl.gl.drawingBufferWidth;
var h = kha.SystemImpl.gl.drawingBufferHeight;
trace("__arm|render" + "|" + w + "|" + h);
}
// Compare mtime and size of file
// untyped __js__('fs.stat(__dirname + "/" + {0} + ".arm", function(err, stats) {', Scene.active.raw.name);
// untyped __js__(' if ({0} > stats.mtime || {0} < stats.mtime || {1} !== stats.size) { if ({0} !== undefined) { {2} = true; } {0} = stats.mtime; {1} = stats.size; }', lastMtime, lastSize, repatch);
// if (repatch) {
#if (kha_krom && arm_render)
static var frame = 0;
function renderCapture() {
App.notifyOnRender(function(g:kha.graphics4.Graphics) {
frame++;
if (frame >= 3) {
var pd = iron.Scene.active.cameras[0].data.pathdata;
var tex = pd.renderTargets.get("capture").image;
if (tex != null) {
var pixels = tex.getPixels();
Krom.fileSaveBytes("render.bin", pixels.getData());
// var bo = new haxe.io.BytesOutput();
// var rgb = haxe.io.Bytes.alloc(tex.width * tex.height * 3);
// for (i in 0...tex.width * tex.height) {
// rgb.set(i * 3 + 0, pixels.get(i * 4 + 2));
// rgb.set(i * 3 + 1, pixels.get(i * 4 + 1));
// rgb.set(i * 3 + 2, pixels.get(i * 4 + 0));
// }
// untyped __js__('});');
// var pngwriter = new armory.format.png.Writer(bo);
// pngwriter.write(armory.format.png.Tools.buildRGB(tex.width, tex.height, rgb));
// Krom.fileSaveBytes("render.png", bo.getBytes().getData());
}
});
}
kha.System.requestShutdown();
}
});
}
#end
}

View file

@ -21,14 +21,6 @@ def parse_operator(text):
bpy.context.object.select = False
bpy.context.scene.objects[cmd[2]].select = True
bpy.context.scene.objects.active = bpy.context.scene.objects[cmd[2]]
elif cmd[1] == 'render':
import numpy
data = numpy.fromfile(arm.utils.get_fp_build() + '/html5/render.bin', dtype=numpy.uint8)
data = data.astype(float)
data = numpy.divide(data, 255)
image = bpy.data.images.new("Render Result", width=int(cmd[2]), height=int(cmd[3]))
image.pixels = data
return
def send_operator(op):
# Try to translate operator directly to armory

View file

@ -62,6 +62,23 @@ def on_scene_update_post(context):
# op_changed(last_operator, bpy.context.object)
# last_operator = None
if state.is_render:
fp = arm.utils.get_fp_build()
resx, resy = arm.utils.get_render_resolution(arm.utils.get_active_scene())
if os.path.isfile(fp + '/render.bin') and os.path.getsize(fp + '/render.bin') == resx * resy * 4:
import numpy
data = numpy.fromfile(fp + '/render.bin', dtype=numpy.uint8)
# data = data.astype(float)
data = numpy.divide(data, 255)
n = "Render Result"
if n in bpy.data.images and bpy.data.images[n].size[0] == resx and bpy.data.images[n].size[1] == resy:
bpy.data.images[n].pixels = data
else:
image = bpy.data.images.new("Render Result", width=resx, height=resy)
image.pixels = data
state.is_render = False
os.remove(fp + '/render.bin')
# Player running
state.krom_running = False
if not state.is_paused and bpy.context.screen != None:

View file

@ -217,9 +217,11 @@ def compile_project(target_name=None, is_publish=False, watch=False, patch=False
else:
return subprocess.Popen(cmd)
def build_project(is_play=False, is_publish=False, in_viewport=False, target=None):
def build_project(is_play=False, is_publish=False, is_render=False, in_viewport=False, target=None):
wrd = bpy.data.worlds['Arm']
state.is_render = is_render
# Set target
if target == None:
state.target = wrd.arm_project_target.lower()
@ -357,7 +359,7 @@ def get_khajs_path(in_viewport, target):
else: # Browser
return arm.utils.build_dir() + '/html5/kha.js'
def play_project(in_viewport):
def play_project(in_viewport, is_render=False):
global scripts_mtime
wrd = bpy.data.worlds['Arm']
@ -370,7 +372,7 @@ def play_project(in_viewport):
state.target = runtime_to_target(in_viewport)
# Build data
build_project(is_play=True, in_viewport=in_viewport, target=state.target)
build_project(is_play=True, is_render=is_render, in_viewport=in_viewport, target=state.target)
state.in_viewport = in_viewport
khajs_path = get_khajs_path(in_viewport, state.target)
@ -450,8 +452,12 @@ def on_compiled(mode): # build, play, play_viewport, publish
webbrowser.open(html5_app_path)
elif wrd.arm_play_runtime == 'Krom':
krom_location, krom_path = arm.utils.krom_paths()
os.chdir(krom_location)
state.playproc = subprocess.Popen([krom_path, arm.utils.get_fp_build() + '/window/krom', arm.utils.get_fp_build() + '/window/krom-resources', '--nosound'], stderr=subprocess.PIPE)
# os.chdir(krom_location)
os.chdir(arm.utils.get_fp_build())
args = [krom_path, arm.utils.get_fp_build() + '/window/krom', arm.utils.get_fp_build() + '/window/krom-resources', '--nosound']
# if state.is_render:
# args.append('--nowindow')
state.playproc = subprocess.Popen(args, stderr=subprocess.PIPE)
watch_play()
def clean_cache():
@ -516,5 +522,4 @@ def publish_project():
assets.invalidate_enabled = True
def get_render_result():
with open(arm.utils.get_fp_build() + '/html5/render.msg', 'w') as f:
pass
play_project(False, is_render=True)

View file

@ -196,6 +196,7 @@ def make_deferred(cam):
if cam.rp_supersampling == '4':
links.new(nodes[last_node].outputs[0], nodes['SS Resolve'].inputs[0])
last_node = 'SS Resolve'
if cam.rp_antialiasing == 'SMAA':
links.new(nodes['Reroute.014'].outputs[0], nodes['SMAA'].inputs[1])
links.new(nodes['Reroute.014'].outputs[0], nodes['SS Resolve'].inputs[2])
@ -209,6 +210,15 @@ def make_deferred(cam):
links.new(nodes['Reroute.008'].outputs[0], nodes['Draw Compositor'].inputs[1])
links.new(nodes['Reroute.008'].outputs[0], nodes['SS Resolve'].inputs[2])
if cam.rp_rendercapture:
# links.new(nodes[last_node].outputs[0], nodes['CopyCapture'].inputs[0])
fb = nodes['Framebuffer']
cc = nodes['CopyCapture']
cn = nodes['Capture']
for l in fb.outputs[0].links:
if l.to_node != cc:
links.new(cn.outputs[0], l.to_socket)
def make_deferred_plus(cam):
pass

View file

@ -13,3 +13,4 @@ compileproc_success = False
play_area = None
krom_running = False
is_paused = False
is_render = False

View file

@ -364,6 +364,7 @@ def init_properties():
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_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_motionblur = EnumProperty(
items=[('None', 'None', 'None'),
('Basic', 'Basic', 'Basic'),

View file

@ -43,6 +43,7 @@ def set_preset(self, context, preset):
cam.rp_dfrs = False
cam.rp_dfao = False
cam.rp_bloom = False
cam.rp_rendercapture = False
cam.rp_motionblur = 'None'
elif preset == 'Forward':
cam.rp_renderer = 'Forward'
@ -69,6 +70,7 @@ def set_preset(self, context, preset):
cam.rp_dfrs = False
cam.rp_dfao = False
cam.rp_bloom = False
cam.rp_rendercapture = False
cam.rp_motionblur = 'None'
elif preset == 'Deferred':
cam.rp_renderer = 'Deferred'
@ -94,6 +96,7 @@ def set_preset(self, context, preset):
cam.rp_dfrs = False
cam.rp_dfao = False
cam.rp_bloom = False
cam.rp_rendercapture = False
cam.rp_motionblur = 'None'
elif preset == 'Max':
cam.rp_renderer = 'Deferred'
@ -119,6 +122,7 @@ def set_preset(self, context, preset):
cam.rp_dfrs = False
cam.rp_dfao = False
cam.rp_bloom = False
cam.rp_rendercapture = False
cam.rp_motionblur = 'None'
elif preset == 'Render Capture':
cam.rp_renderer = 'Deferred'
@ -147,6 +151,7 @@ def set_preset(self, context, preset):
cam.rp_dfrs = False
cam.rp_dfao = False
cam.rp_bloom = False
cam.rp_rendercapture = True
cam.rp_motionblur = 'None'
wrd.lighting_model = 'Cycles'
wrd.generate_pcss_state = 'On'
@ -174,6 +179,7 @@ def set_preset(self, context, preset):
cam.rp_dfrs = False
cam.rp_dfao = False
cam.rp_bloom = False
cam.rp_rendercapture = False
cam.rp_motionblur = 'None'
elif preset == 'VR Low':
cam.rp_renderer = 'Forward'
@ -200,6 +206,7 @@ def set_preset(self, context, preset):
cam.rp_dfrs = False
cam.rp_dfao = False
cam.rp_bloom = False
cam.rp_rendercapture = False
cam.rp_motionblur = 'None'
elif preset == 'Mobile Low':
cam.rp_renderer = 'Forward'
@ -226,6 +233,7 @@ def set_preset(self, context, preset):
cam.rp_dfrs = False
cam.rp_dfao = False
cam.rp_bloom = False
cam.rp_rendercapture = False
cam.rp_motionblur = 'None'
elif preset == 'Grease Pencil':
cam.rp_renderer = 'Forward'
@ -251,6 +259,7 @@ def set_preset(self, context, preset):
cam.rp_dfrs = False
cam.rp_dfao = False
cam.rp_bloom = False
cam.rp_rendercapture = False
cam.rp_motionblur = 'None'
updating_preset = False
@ -335,6 +344,7 @@ class GenRPDataPropsPanel(bpy.types.Panel):
layout.prop(dat, "rp_dfrs")
layout.prop(dat, "rp_bloom")
layout.prop(dat, "rp_motionblur")
layout.prop(dat, "rp_rendercapture")
class PropsRPDataPropsPanel(bpy.types.Panel):
bl_label = "Armory Render Props"

View file

@ -740,10 +740,15 @@ class ArmoryRenderButton(bpy.types.Operator):
bl_label = 'Render'
def execute(self, context):
if state.playproc == None:
self.report({"ERROR"}, "Run Armory player in electron window first")
return {"CANCELLED"}
if state.playproc != None:
make.stop_project()
if bpy.data.worlds['Arm'].arm_play_runtime != 'Krom':
bpy.data.worlds['Arm'].arm_play_runtime = 'Krom'
if bpy.data.cameras[0].rp_preset != 'Render Capture':
bpy.data.cameras[0].rp_preset = 'Render Capture'
assets.invalidate_enabled = False
make.get_render_result()
assets.invalidate_enabled = True
return{'FINISHED'}
# Play button in 3D View panel

View file

@ -89,6 +89,9 @@ project.addSources('Sources');
if enable_dce:
f.write("project.addParameter('-dce full');")
if state.is_render:
assets.add_khafile_def('arm_render')
shaderload = state.target == 'krom' or state.target == 'html5'
if wrd.arm_cache_compiler and shaderload and not is_publish:
# Load shaders manually

Binary file not shown.

Binary file not shown.