Animation capture

This commit is contained in:
Lubos Lenco 2017-10-03 20:27:21 +02:00
parent e4275aac53
commit 424665c70a
7 changed files with 102 additions and 19 deletions

View file

@ -129,8 +129,63 @@ class SpaceArmory extends Trait {
#if (kha_krom && arm_render)
static var frame = 0;
static var captured = false;
#if arm_render_anim
static var current = 0.0;
static var framesCaptured = 0;
@:access(kha.Scheduler)
function renderCapture() {
App.pauseUpdates = true;
App.notifyOnRender(function(g:kha.graphics4.Graphics) {
if (captured) return;
kha.Scheduler.current = current;
frame++;
if (frame >= 2) { // Init TAA
App.pauseUpdates = false;
if (frame % 2 == 0) { // Alternate TAA
current += iron.system.Time.delta;
return;
}
var info = iron.Scene.active.raw.capture_info;
var pd = iron.Scene.active.cameras[0].data.pathdata;
var tex = pd.renderTargets.get("capture").image;
if (tex != null) {
var pixels = tex.getPixels();
var bd = pixels.getData();
var bo = new haxe.io.BytesOutput();
var rgb = haxe.io.Bytes.alloc(tex.width * tex.height * 3);
for (j in 0...tex.height) {
for (i in 0...tex.width) {
var k = j * tex.width + i;
var l = (tex.height - j) * tex.width + i; // Reverse Y
rgb.set(k * 3 + 0, pixels.get(l * 4 + 2));
rgb.set(k * 3 + 1, pixels.get(l * 4 + 1));
rgb.set(k * 3 + 2, pixels.get(l * 4 + 0));
}
}
var pngwriter = new iron.format.png.Writer(bo);
pngwriter.write(iron.format.png.Tools.buildRGB(tex.width, tex.height, rgb));
var fname = framesCaptured + "";
while (fname.length < 4) fname = "0" + fname;
Krom.fileSaveBytes(info.path + "/" + fname + ".png", bo.getBytes().getData());
}
if (framesCaptured++ == info.frame_end) {
captured = true;
kha.System.requestShutdown();
}
}
});
}
#else
function renderCapture() {
App.notifyOnRender(function(g:kha.graphics4.Graphics) {
if (captured) return;
frame++;
if (frame >= 3) {
var pd = iron.Scene.active.cameras[0].data.pathdata;
@ -138,20 +193,12 @@ class SpaceArmory extends Trait {
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));
// }
// 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());
}
captured = true;
kha.System.requestShutdown();
}
});
}
#end
#end
}

View file

@ -2508,7 +2508,7 @@ class ArmoryExporter:
self.output['mesh_datas'] = [];
self.do_export_mesh(objectRef, scene)
def execute(self, context, filepath, scene=None):
def execute(self, context, filepath, scene=None, write_capture_info=False):
profile_time = time.time()
self.output = {}
@ -2523,6 +2523,12 @@ class ArmoryExporter:
self.endFrame = self.scene.frame_end
self.output['frame_time'] = 1.0 / (self.scene.render.fps / self.scene.render.fps_base)
if write_capture_info:
self.output['capture_info'] = {}
self.output['capture_info']['path'] = self.scene.render.filepath
self.output['capture_info']['frame_start'] = self.scene.frame_start
self.output['capture_info']['frame_end'] = self.scene.frame_end
self.bobjectArray = {}
self.meshArray = {}
self.lampArray = {}

View file

@ -62,7 +62,9 @@ def on_scene_update_post(context):
# op_changed(last_operator, bpy.context.object)
# last_operator = None
if state.is_render:
if state.is_render_anim:
pass
elif state.is_render:
import numpy
# fp = arm.utils.get_fp_build()
krom_location, krom_path = arm.utils.krom_paths()

View file

@ -96,7 +96,7 @@ def export_data(fp, sdk_path, is_play=False, is_publish=False, in_viewport=False
if scene.arm_export:
ext = '.zip' if (scene.arm_compress and is_publish) else '.arm'
asset_path = arm.utils.build_dir() + '/compiled/Assets/' + arm.utils.safestr(scene.name) + ext
exporter.execute(bpy.context, asset_path, scene=scene)
exporter.execute(bpy.context, asset_path, scene=scene, write_capture_info=state.is_render_anim)
if ArmoryExporter.export_physics:
physics_found = True
if ArmoryExporter.export_navigation:
@ -232,10 +232,11 @@ def compile_project(target_name=None, watch=False, patch=False):
else:
return subprocess.Popen(cmd)
def build_project(is_play=False, is_publish=False, is_render=False, in_viewport=False):
def build_project(is_play=False, is_publish=False, is_render=False, is_render_anim=False, in_viewport=False):
wrd = bpy.data.worlds['Arm']
state.is_render = is_render
state.is_render_anim = is_render_anim
# Clear flag
state.in_viewport = False
@ -366,7 +367,7 @@ def get_khajs_path(in_viewport, target):
else: # Browser
return arm.utils.build_dir() + '/html5/kha.js'
def play_project(in_viewport, is_render=False):
def play_project(in_viewport, is_render=False, is_render_anim=False):
global scripts_mtime
global code_parsed
wrd = bpy.data.worlds['Arm']
@ -380,7 +381,7 @@ def play_project(in_viewport, is_render=False):
state.target = runtime_to_target(in_viewport)
# Build data
build_project(is_play=True, is_render=is_render, in_viewport=in_viewport)
build_project(is_play=True, is_render=is_render, is_render_anim=is_render_anim, in_viewport=in_viewport)
state.in_viewport = in_viewport
khajs_path = get_khajs_path(in_viewport, state.target)
@ -521,3 +522,8 @@ def clean_project():
def get_render_result():
play_project(False, is_render=True)
def get_render_anim_result():
if bpy.context.scene != None:
print('Capturing animation frames into ' + bpy.context.scene.render.filepath)
play_project(False, is_render=True, is_render_anim=True)

View file

@ -15,5 +15,6 @@ play_area = None
krom_running = False
is_paused = False
is_render = False
is_render_anim = False
recompiled = False
mod_scripts = []

View file

@ -838,13 +838,30 @@ class ArmoryRenderAnimButton(bpy.types.Operator):
bl_label = 'Animation'
def execute(self, context):
if not arm.utils.check_saved(self):
return {"CANCELLED"}
if not arm.utils.check_sdkpath(self):
return {"CANCELLED"}
if not arm.utils.check_engine(self):
return {"CANCELLED"}
make_renderer.check_default()
if state.playproc != None:
make.stop_project()
if bpy.data.worlds['Arm'].arm_play_runtime != 'Krom':
bpy.data.worlds['Arm'].arm_play_runtime = 'Krom'
self.report({"ERROR"}, "Animation capture not yet supported")
return {"CANCELLED"}
# return{'FINISHED'}
rpdat = arm.utils.get_rp()
if rpdat.rp_rendercapture == False:
rpdat.rp_rendercapture = True
if rpdat.rp_antialiasing != 'TAA':
rpdat.rp_antialiasing = 'TAA'
assets.invalidate_enabled = False
make.get_render_anim_result()
assets.invalidate_enabled = True
return{'FINISHED'}
# Play button in 3D View panel
def draw_view3d_header(self, context):

View file

@ -125,6 +125,10 @@ project.addSources('Sources');
if state.is_render:
assets.add_khafile_def('arm_render')
if state.is_render_anim:
assets.add_khafile_def('arm_render_anim')
if not os.path.exists('Libraries/iron_format'):
f.write(add_armory_library(sdk_path + '/lib/', 'iron_format'))
shaderload = state.target == 'krom' or state.target == 'html5'
if wrd.arm_cache_compiler and shaderload and not is_publish: