For example, can I define a Render Region, but render it at the resolution I've specified in Output Properties?
You can simply use another camera.
- Duplicate your camera, and keep it in the same place
- Lower the Sensor size to "crop" the image
- Use Shift X and Y to "move around"
Because you're not changing focal length, the lens distortion doesn't change.
It's as if you cropped the image in photoshop.
You can use a Python script that calculates and changes resolution accordingly, renders, and restores old resolution.
A simplified version
Most people will actually want this: you don't have to specify the output resolution with the same aspect ratio as the region's dimensions to avoid stretching - the script makes sure your image has at least as many pixels as you specified for both dimensions. If one of the dimensions is too big, it will have accordingly more pixels in order to keep aspect ratio:
import bpy render = bpy.context.scene.render width_original = render.resolution_x height_original = render.resolution_y horizontal_ratio = render.border_max_x - render.border_min_x vertical_ratio = render.border_max_y - render.border_min_y # to keep aspect ratio: # simply take the axis which is more empty and so has to be scaled more # the other axis will end up having more resolution, than specified ratio = min(horizontal_ratio, vertical_ratio) render.resolution_x = round(width_original / ratio) render.resolution_y = round(height_original / ratio) bpy.ops.render.render() render.resolution_x = width_original render.resolution_y = height_original
A correct version
This produces the exact region, as visible in the viewport, in the exact resolution specified in the output settings. It's equivalent to using the first version and then scaling it in 2D software to target resolution with "Keep aspect ratio" disabled.
import bpy render = bpy.context.scene.render width_original = render.resolution_x height_original = render.resolution_y asp_x = render.pixel_aspect_x asp_y = render.pixel_aspect_y horizontal_ratio = render.border_max_x - render.border_min_x vertical_ratio = render.border_max_y - render.border_min_y render.resolution_x = round(width_original / horizontal_ratio) render.resolution_y = round(height_original / vertical_ratio) if horizontal_ratio < vertical_ratio: render.pixel_aspect_y *= vertical_ratio / horizontal_ratio else: render.pixel_aspect_x *= horizontal_ratio / vertical_ratio bpy.ops.render.render() render.resolution_x = width_original render.resolution_y = height_original render.pixel_aspect_x = asp_x render.pixel_aspect_y = asp_y
You can use pre/post render handlers to apply/restore those settings automatically for each render: