I'm making a script allowing me to apply fragment shaders to the 3D Viewport real-time. However, I don't know how to get view and perspective matrices of the current point of view. I know how to get view and perspective matrices of the currently active camera using
view_matrix = scene.camera.matrix_world.inverted()
projection_matrix = scene.camera.calc_matrix_camera(context.evaluated_depsgraph_get(), x=WIDTH, y=HEIGHT)
but that's not what I want. I want to get these matrices, but for the current point of view (I mean the view you see when you hold and drag Middle Mouse Button in 3D Viewport).
I tried to use:
bpy.context.region_data.perspective_matrix
bpy.context.region_data.view_matrix
but it doesn't work as I would expect.
EDIT: My whole code:
import bpy
import gpu
import bgl
from mathutils import Matrix
from gpu_extras.batch import batch_for_shader
def get_viewport_width_height():
'gets the current height and width of the viewport'
for a in bpy.context.screen.areas:
if a.type == 'VIEW_3D':
for r in a.regions:
if r.type == 'WINDOW':
return r.width, r.height
vertex_shader = '''
// uniform mat4 modelMatrix;
// uniform mat4 viewProjectionMatrix;
in vec2 position;
in vec2 uv;
out vec2 uvInterp;
void main()
{
uvInterp = uv;
gl_Position = vec4(position, 0.0, 1.0); //viewProjectionMatrix * modelMatrix *
}
'''
fragment_shader = '''
uniform sampler2D image;
in vec2 uvInterp;
out vec4 out_color;
void main()
{
vec2 uv = uvInterp;
//float pixelation = 500.;
//uv = ceil(uv*pixelation)/pixelation;
vec3 tex = texture(image, uv).rgb;
out_color = vec4(tex,1.);
}
'''
WIDTH, HEIGHT = get_viewport_width_height()
offscreen = gpu.types.GPUOffScreen(WIDTH, HEIGHT)
shader = gpu.types.GPUShader(vertex_shader, fragment_shader)
batch = batch_for_shader(
shader, 'TRI_FAN',
{
"position": ((-1, -1), (1, -1), (1, 1), (-1, 1)),
"uv": ((0, 0), (1, 0), (1, 1), (0, 1)),
},
)
def draw():
'draw loop'
WIDTH, HEIGHT = get_viewport_width_height()
context = bpy.context
scene = context.scene
#################
# That doesn't work (give some weird point of view)
##################
# for area in bpy.context.screen.areas:
# if area.type == 'VIEW_3D':
# area.spaces.active.region_3d.view_matrix
# view_matrix = area.spaces.active.region_3d.view_matrix
# projection_matrix = area.spaces.active.region_3d.perspective_matrix
#################
# That give the camera's view
##################
view_matrix = scene.camera.matrix_world.inverted()
projection_matrix = scene.camera.calc_matrix_camera(
context.evaluated_depsgraph_get(), x=WIDTH, y=HEIGHT)
offscreen.draw_view3d(
scene,
context.view_layer,
context.space_data,
context.region,
view_matrix,
projection_matrix)
bgl.glClearColor(1., 1., 0., 1.)
bgl.glClear(bgl.GL_COLOR_BUFFER_BIT)
bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, offscreen.color_texture)
bgl.glDisable(bgl.GL_DEPTH_TEST)
shader.bind()
shader.uniform_float("image", 0)
batch.draw(shader)
draw_texture_2d(offscreen.color_texture, (0, 0), WIDTH, HEIGHT)
#registering and unregistering a handler
h = bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_PIXEL')
def rm_handler():
global h
print("Handler removed")
bpy.types.SpaceView3D.draw_handler_remove(h, 'WINDOW')
bpy.app.timers.register(rm_handler, first_interval=5)