def draw_callback_px(self, context):
font_id = 0
# A4 dimensions at 300 DPI
a4_width = 707
a4_height = 1000
region_width = context.region.width
region_height = context.region.height
x_offset = (region_width - a4_width) / 2
y_offset = (region_height - a4_height) / 2
draw_a4_outline(context, x_offset, y_offset, a4_width, a4_height)
font_size = 14
background_color = (1.0, 1.0, 1.0, 0.8)
rectangle_height = 3.5 * font_size
rectangle_width = a4_width - 20
draw_filled_rectangle(
x_offset + 10, y_offset + a4_height - 20, rectangle_width, rectangle_height, background_color
)
# Rest of drawing code...
class OBJECT_OT_draw_dimensions(Operator):
bl_idname = "view3d.draw_dimensions"
bl_label = "Draw Dimensions"
bl_options = {"REGISTER", "UNDO"}
_handle = None
def modal(self, context, event):
if event.type in {"RIGHTMOUSE", "ESC"} or context.mode != "OBJECT":
if self._handle is not None:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, "WINDOW")
context.area.tag_redraw()
self._handle = None
return {"CANCELLED"}
if event.type in {"TIMER"}:
context.area.tag_redraw()
return {"PASS_THROUGH"}
def invoke(self, context, event):
if context.area.type == "VIEW_3D":
if self._handle is None:
self._handle = bpy.types.SpaceView3D.draw_handler_add(
draw_callback_px, (self, context), "WINDOW", "POST_PIXEL"
)
context.window_manager.modal_handler_add(self)
return {"RUNNING_MODAL"}
else:
self.report({"WARNING"}, "Dimension drawing is already active")
return {"CANCELLED"}
else:
self.report({"WARNING"}, "View3D not found, cannot run operator")
return {"CANCELLED"}
class OBJECT_OT_export_to_image(Operator):
bl_idname = "object.export_to_image"
bl_label = "Export to Image"
bl_options = {"REGISTER", "UNDO"}
fp = fr"my_file_path.JPEG"
def execute(self, context):
global to_draw
to_draw = False
a4_width = 707
a4_height = 1000
framebuffer_image = bpy.data.images.new("buffer_copy", a4_width, a4_height, float_buffer=True, alpha=False, is_data=True)
def draw():
global to_draw
if to_draw:
framebuffer = gpu.state.active_framebuffer_get()
viewport_info = gpu.state.viewport_get()
width = viewport_info[2]
height = viewport_info[3]
framebuffer_image.scale(a4_width, a4_height)
pixelBuffer = framebuffer.read_color(
int((width - a4_width) / 2), int((height - a4_height) / 2), a4_width, a4_height, 4, 0, 'FLOAT'
)
pixelBuffer.dimensions = a4_width * a4_height * 4
framebuffer_image.pixels.foreach_set(pixelBuffer)
framebuffer_image.file_format = 'JPEG'
framebuffer_image.filepath_raw = self.fp
try:
framebuffer_image.save()
self.report({"INFO"}, f"Exported to Image: {self.fp}")
except Exception as e:
self.report({"ERROR"}, f"Failed to save image: {str(e)}")
to_draw = False
def update_draw():
global to_draw
bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
to_draw = True
bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)
# Ensure the active area is the 3D view for capturing
for area in context.screen.areas:
if area.type == "VIEW_3D":
for region in area.regions:
if region.type == "WINDOW":
# Draw handler setup for dimensions
draw_handler = bpy.types.SpaceView3D.draw_handler_add(draw, (), "WINDOW", "POST_PIXEL")
# draw_handler_dimensions = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, (self, context), "WINDOW", "POST_PIXEL")
time.sleep(.1)
update_draw()
# Remove the dimensions draw handler after capturing
bpy.types.SpaceView3D.draw_handler_remove(draw_handler, "WINDOW")
# bpy.types.SpaceView3D.draw_handler_remove(draw_handler_dimensions, "WINDOW")
# Delete the created image from bpy.data.images
bpy.data.images.remove(framebuffer_image)
return {"FINISHED"}
bpy types SpaceView3D draw_handler_add(draw_callback_px, (self, context), "WINDOW", "POST_PIXEL")
产生:
为什么材质和灯光不显示?对“POST_VIEW”执行相同的操作会显示正确的视图(材质、渲染),但没有线条和矩形。文档仅说明:
通常
POST_PIXEL
用于 2D 绘图,POST_VIEW
用于 3D 绘图。在某些情况下,可以使用PRE_VIEW
BACKDROP
可用于节点编辑器中的背景。 (types.py)
如何设置场景(除了闪电)?它应该是什么样子:
你遇到的问题是,你正试图在一个不考虑 3D 场景信息(如材质和灯光)的绘图阶段绘制 2D 元素。
以下是分解发生的事情:
-
POST_PIXEL
绘制处理程序: 当你使用POST_PIXEL
时,你基本上是在所有 3D 渲染发生 之后 在屏幕空间中进行绘制。这意味着你的 2D 图形(线条、矩形)被绘制在渲染图像的顶部,并且不会受到光照或材质的影响。 -
POST_VIEW
绘制处理程序: 另一方面,POST_VIEW
允许你在 3D 空间中进行绘制,这意味着你的绘图 将 受到光照和材质的影响。然而,你遇到的问题是,POST_VIEW
处理程序通常用于 3D 几何图形,而不是 2D 图形。当你尝试在POST_VIEW
处理程序中绘制 2D 形状时,它们可能会以意外的方式进行渲染,或者根本不进行渲染,因为它们没有与之交互的光照或材质信息。
为了实现你想要的结果(在渲染的 3D 场景之上显示材质、灯光和 2D 图形),你需要结合这两种方法:
-
在
POST_VIEW
处理程序中渲染 3D 场景: 这将确保你的场景按预期使用材质和灯光进行渲染。 -
在
POST_PIXEL
处理程序中绘制 2D 图形: 这将允许你在渲染的 3D 场景之上绘制 2D 图形。
以下是你可以如何修改你的代码以实现这一点的示例:
import bpy
import gpu
import time
# ... other code ...
def draw_3d_scene(self, context):
"""在 POST_VIEW 处理程序中渲染 3D 场景"""
# 设置 3D 场景的视图和投影矩阵
# ...
# 渲染 3D 场景
# ...
def draw_2d_graphics(self, context):
"""在 POST_PIXEL 处理程序中绘制 2D 图形"""
# 你现有的 draw_callback_px 函数的内容
# ...
class OBJECT_OT_draw_dimensions(Operator):
# ... (其他代码不变) ...
def invoke(self, context, event):
if context.area.type == "VIEW_3D":
if self._handle is None:
# 添加 POST_VIEW 处理程序以渲染 3D 场景
self._handle_3d = bpy.types.SpaceView3D.draw_handler_add(
draw_3d_scene, (self, context), "WINDOW", "POST_VIEW"
)
# 添加 POST_PIXEL 处理程序以绘制 2D 图形
self._handle_2d = bpy.types.SpaceView3D.draw_handler_add(
draw_2d_graphics, (self, context), "WINDOW", "POST_PIXEL"
)
context.window_manager.modal_handler_add(self)
return {"RUNNING_MODAL"}
else:
self.report({"WARNING"}, "Dimension drawing is already active")
return {"CANCELLED"}
else:
self.report({"WARNING"}, "View3D not found, cannot run operator")
return {"CANCELLED"}
def modal(self, context, event):
# ... (其他代码不变) ...
if event.type in {"RIGHTMOUSE", "ESC"} or context.mode != "OBJECT":
if self._handle_3d is not None:
bpy.types.SpaceView3D.draw_handler_remove(self._handle_3d, "WINDOW")
self._handle_3d = None
if self._handle_2d is not None:
bpy.types.SpaceView3D.draw_handler_remove(self._handle_2d, "WINDOW")
self._handle_2d = None
context.area.tag_redraw()
return {"CANCELLED"}
# ... (其他代码不变) ...
# ... (其他代码不变) ...
通过分别处理 3D 和 2D 绘制,你应该能够在最终渲染中同时获得材质、灯光和 2D 图形。
标签:python,3d,blender From: 78794697