Dynamic resolution scaling.

This commit is contained in:
Lubos Lenco 2016-10-19 17:46:13 +02:00
parent cf43d567f8
commit 202ad3d7cf
9 changed files with 106 additions and 12 deletions

View file

@ -32,6 +32,10 @@ uniform vec2 texStep;
uniform float time;
#endif
#ifdef _DynRes
uniform float dynamicScale;
#endif
in vec2 texCoord;
#ifdef _CompoPos
in vec3 viewRay;
@ -125,10 +129,13 @@ vec3 lensflare(vec2 uv, vec2 pos) {
void main() {
vec2 texCo = texCoord;
#ifdef _DynRes
texCo *= dynamicScale;
#endif
#ifdef _CompoFishEye
const float fishEyeStrength = -0.01;
const vec2 m = vec2(0.5, 0.5);
vec2 d = texCoord - m;
vec2 d = texCo - m;
float r = sqrt(dot(d, d));
float power = (2.0 * PI / (2.0 * sqrt(dot(m, m)))) * fishEyeStrength;
float bind;

View file

@ -40,6 +40,11 @@
"name": "texStep",
"link": "_screenSizeInv",
"ifdef": ["_CompoFXAA"]
},
{
"name": "dynamicScale",
"link": "_dynamicScale",
"ifdef": ["_DynRes"]
}
],
"texture_params": [],

View file

@ -9,6 +9,7 @@ class Uniforms {
public static function register() {
iron.object.Uniforms.externalTextureLink = externalTextureLink;
iron.object.Uniforms.externalVec3Link = externalVec3Link;
iron.object.Uniforms.externalFloatLink = externalFloatLink;
}
public static function externalTextureLink(tulink:String):kha.Image {
@ -123,4 +124,11 @@ class Uniforms {
}
return v;
}
public static function externalFloatLink(clink:String):Float {
if (clink == "_dynamicScale") {
return armory.renderpath.DynamicResolutionScale.dynamicScale;
}
return 0.0;
}
}

View file

@ -0,0 +1,51 @@
package armory.renderpath;
import iron.data.RenderPath;
class DynamicResolutionScale {
public static var dynamicScale = 1.0;
static var firstFrame = true;
static inline var startScaleMs = 30;
static inline var scaleRangeMs = 10;
static inline var maxScale = 0.6;
public static function run(path:RenderPath) {
if (firstFrame) {
App.notifyOnRender(render);
firstFrame = false;
return;
}
// TODO: execute once per frame max
if (frameTimeAvg > startScaleMs && frameTimeAvg < 100) {
var overTime = Math.min(scaleRangeMs, frameTimeAvg - startScaleMs);
var scale = 1.0 - (overTime / scaleRangeMs) * (1.0 - maxScale);
var w = Std.int(App.w() * scale);
var h = Std.int(App.h() * scale);
path.setCurrentViewport(w, h);
path.setCurrentScissor(w, h);
dynamicScale = scale;
}
else dynamicScale = 1.0;
}
static var frameTime:Float;
static var lastTime:Float = 0;
static var totalTime:Float = 0;
static var frames = 0;
static var frameTimeAvg = 0.0;
public static function render(g:kha.graphics4.Graphics) {
frameTime = kha.Scheduler.realTime() - lastTime;
lastTime = kha.Scheduler.realTime();
totalTime += frameTime;
frames++;
if (totalTime >= 1) {
frameTimeAvg = Std.int(totalTime / frames * 10000) / 10;
totalTime = 0;
frames = 0;
}
}
}

View file

@ -24,10 +24,11 @@ def on_scene_update_post(context):
# Tag redraw if playing in space_armory
state.last_chromium_running = state.chromium_running
state.chromium_running = False
for area in bpy.context.screen.areas:
if area.type == 'VIEW_ARMORY':
state.chromium_running = True
barmory.draw()
if not state.is_paused:
for area in bpy.context.screen.areas:
if area.type == 'VIEW_ARMORY':
state.chromium_running = True
barmory.draw()
# Have to update chromium one more time before exit, to prevent 'AudioSyncReader::Read timed out' warnings
if state.chromium_running == False:

View file

@ -94,6 +94,11 @@ def make_set_target(stage, node_group, node, currentNode=None, target_index=1, v
targetId = ''
stage['params'].append(targetId)
def make_set_viewport(stage, node_group, node):
stage['command'] = 'set_viewport'
stage['params'].append(node.inputs[1].default_value) # W
stage['params'].append(node.inputs[2].default_value) # H
def make_clear_target(stage, color_val=None, depth_val=None, stencil_val=None):
stage['command'] = 'clear_target'
if color_val != None:
@ -258,7 +263,8 @@ def make_draw_grease_pencil(stage, node_group, node):
def make_call_function(stage, node_group, node):
stage['command'] = 'call_function'
stage['params'].append(node.inputs[1].default_value)
fstr = node.inputs[1].default_value
stage['params'].append(fstr)
def make_branch_function(stage, node_group, node):
make_call_function(stage, node_group, node)
@ -446,6 +452,9 @@ def buildNode(stages, node, node_group):
buildNode.last_bind_target = None
make_set_target(stage, node_group, node)
elif node.bl_idname == 'SetViewportNodeType':
make_set_viewport(stage, node_group, node)
elif node.bl_idname == 'ClearTargetNodeType':
color_val = None
depth_val = None
@ -665,7 +674,10 @@ def get_root_node(node_group):
break
return rn
dynRes_added = False
def preprocess_renderpath(root_node, node_group):
global dynRes_added
dynRes_added = False
render_targets = []
render_targets3D = []
depth_buffers = []
@ -701,6 +713,13 @@ def traverse_renderpath(node, node_group, render_targets, depth_buffers):
assets.add_khafile_def('arm_vr')
bpy.data.worlds['Arm'].world_defs += '_VR'
elif node.bl_idname == 'CallFunctionNodeType':
global dynRes_added
fstr = node.inputs[1].default_value
if not dynRes_added and fstr.startswith('armory.renderpath.DynamicResolutionScale'):
bpy.data.worlds['Arm'].world_defs += '_DynRes'
dynRes_added = True
# Collect render targets
if node.bl_idname == 'SetTargetNodeType' or node.bl_idname == 'BindTargetNodeType' or node.bl_idname == 'QuadPassNodeType' or node.bl_idname == 'DrawCompositorNodeType' or node.bl_idname == 'DrawCompositorWithFXAANodeType':
if node.inputs[1].is_linked:

View file

@ -8,3 +8,4 @@ compileproc_success = False
play_area = None
chromium_running = False
last_chromium_running = False
is_paused = False

View file

@ -10,6 +10,7 @@ import make
import make_utils
import make_state as state
import assets
import log
# Menu in object region
class ObjectPropsPanel(bpy.types.Panel):
@ -489,6 +490,7 @@ class ArmoryPlayInViewportButton(bpy.types.Operator):
def execute(self, context):
assets.invalidate_enabled = False
if state.playproc == None:
log.clear()
# Cancel viewport render
for space in context.area.spaces:
if space.type == 'VIEW_3D':

View file

@ -5,11 +5,11 @@ from bpy.app.translations import contexts as i18n_contexts
import utils
import make
import make_state as state
import log
class ArmorySpaceHeader(Header):
bl_space_type = 'VIEW_ARMORY'
info_text = ''
is_paused = False
def draw(self, context):
layout = self.layout
@ -20,7 +20,7 @@ class ArmorySpaceHeader(Header):
row = layout.row(align=True)
# row.template_header()
row.operator('arm.space_stop', icon='MESH_PLANE')
if ArmorySpaceHeader.is_paused:
if state.is_paused:
row.operator('arm.space_resume', icon="PLAY")
else:
row.operator('arm.space_pause', icon="PAUSE")
@ -37,8 +37,8 @@ class ArmorySpaceStopButton(bpy.types.Operator):
if area == None:
area = state.play_area
area.type = 'VIEW_3D'
ArmorySpaceHeader.is_paused = False
ArmorySpaceHeader.info_text = ''
state.is_paused = False
log.clear()
return{'FINISHED'}
class ArmorySpacePauseButton(bpy.types.Operator):
@ -47,7 +47,7 @@ class ArmorySpacePauseButton(bpy.types.Operator):
bl_label = 'Pause'
def execute(self, context):
ArmorySpaceHeader.is_paused = True
state.is_paused = True
return{'FINISHED'}
class ArmorySpaceResumeButton(bpy.types.Operator):
@ -56,7 +56,7 @@ class ArmorySpaceResumeButton(bpy.types.Operator):
bl_label = 'Resume'
def execute(self, context):
ArmorySpaceHeader.is_paused = False
state.is_paused = False
return{'FINISHED'}
def register():