Add depth pass for picking a location

This commit is contained in:
fieldOfView 2018-03-13 11:54:32 +01:00
parent f40e9bffa9
commit 0caea24afc
3 changed files with 160 additions and 10 deletions

60
cura/DepthPass.py Normal file
View file

@ -0,0 +1,60 @@
# Copyright (c) 2018 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from UM.Application import Application
from UM.Math.Color import Color
from UM.Resources import Resources
from UM.View.RenderPass import RenderPass
from UM.View.GL.OpenGL import OpenGL
from UM.View.RenderBatch import RenderBatch
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
## A RenderPass subclass that renders a depthmap of selectable objects to a texture.
# It uses the active camera by default, but it can be overridden to use a different camera.
#
# Note that in order to increase precision, the 24 bit depth value is encoded into all three of the R,G & B channels
class DepthPass(RenderPass):
def __init__(self, width: int, height: int):
super().__init__("preview", width, height, 0)
self._renderer = Application.getInstance().getRenderer()
self._shader = None
self._scene = Application.getInstance().getController().getScene()
def render(self) -> None:
if not self._shader:
self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "camera_distance.shader"))
self._gl.glClearColor(0.0, 0.0, 0.0, 0.0)
self._gl.glClear(self._gl.GL_COLOR_BUFFER_BIT | self._gl.GL_DEPTH_BUFFER_BIT)
# Create a new batch to be rendered
batch = RenderBatch(self._shader)
# Fill up the batch with objects that can be sliced. `
for node in DepthFirstIterator(self._scene.getRoot()):
if node.callDecoration("isSliceable") and node.getMeshData() and node.isVisible():
batch.addItem(node.getWorldTransformation(), node.getMeshData())
self.bind()
batch.render(self._scene.getActiveCamera())
self.release()
## Get the distance in mm from the camera to at a certain pixel coordinate.
def getDepthAtPosition(self, x, y):
output = self.getOutput()
window_size = self._renderer.getWindowSize()
px = (0.5 + x / 2.0) * window_size[0]
py = (0.5 + y / 2.0) * window_size[1]
if px < 0 or px > (output.width() - 1) or py < 0 or py > (output.height() - 1):
return None
distance = output.pixel(px, py) # distance in micron, from in r, g & b channels
return distance / 1000.

View file

@ -4,14 +4,16 @@ from UM.Math.Vector import Vector
from UM.Tool import Tool
from PyQt5.QtCore import Qt, QUrl
from UM.Application import Application
from UM.Event import Event
from UM.Event import Event, MouseEvent
from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
from UM.Settings.SettingInstance import SettingInstance
from cura.Scene.CuraSceneNode import CuraSceneNode
from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator
from cura.Scene.BuildPlateDecorator import BuildPlateDecorator
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
from cura.Settings.SettingOverrideDecorator import SettingOverrideDecorator
from cura.DepthPass import DepthPass
import os
import os.path
@ -25,15 +27,22 @@ class SupportEraser(Tool):
def event(self, event):
super().event(event)
if event.type == Event.ToolActivateEvent:
if event.type == Event.MousePressEvent and self._controller.getToolsEnabled():
active_camera = self._controller.getScene().getActiveCamera()
# Load the remover mesh:
self._createEraserMesh()
# Create depth pass for picking
render_width, render_height = active_camera.getWindowSize()
depth_pass = DepthPass(int(render_width), int(render_height))
depth_pass.render()
# After we load the mesh, deactivate the tool again:
self.getController().setActiveTool(None)
distance = depth_pass.getDepthAtPosition(event.x, event.y)
ray = active_camera.getRay(event.x, event.y)
picked_position = ray.getPointAlongRay(distance)
def _createEraserMesh(self):
# Add the anto_overhang_mesh cube:
self._createEraserMesh(picked_position)
def _createEraserMesh(self, position: Vector):
node = CuraSceneNode()
node.setName("Eraser")
@ -41,9 +50,7 @@ class SupportEraser(Tool):
mesh = MeshBuilder()
mesh.addCube(10,10,10)
node.setMeshData(mesh.build())
# Place the cube in the platform. Do it manually so it works if the "automatic drop models" is OFF
move_vector = Vector(0, 5, 0)
node.setPosition(move_vector)
node.setPosition(position)
active_build_plate = Application.getInstance().getMultiBuildPlateModel().activeBuildPlate

View file

@ -0,0 +1,83 @@
[shaders]
vertex =
uniform highp mat4 u_modelMatrix;
uniform highp mat4 u_viewProjectionMatrix;
attribute highp vec4 a_vertex;
varying highp vec3 v_vertex;
void main()
{
vec4 world_space_vert = u_modelMatrix * a_vertex;
gl_Position = u_viewProjectionMatrix * world_space_vert;
v_vertex = world_space_vert.xyz;
}
fragment =
uniform highp vec3 u_viewPosition;
varying highp vec3 v_vertex;
void main()
{
highp float distance_to_camera = distance(v_vertex, u_viewPosition) * 1000.; // distance in micron
vec3 encoded; // encode float into 3 8-bit channels; this gives a precision of a micron at a range of up to ~16 meter
encoded.b = floor(distance_to_camera / 65536.0);
encoded.g = floor((distance_to_camera - encoded.b * 65536.0) / 256.0);
encoded.r = floor(distance_to_camera - encoded.b * 65536.0 - encoded.g * 256.0);
gl_FragColor.rgb = encoded / 255.;
gl_FragColor.a = 1.0;
}
vertex41core =
#version 410
uniform highp mat4 u_modelMatrix;
uniform highp mat4 u_viewProjectionMatrix;
in highp vec4 a_vertex;
out highp vec3 v_vertex;
void main()
{
vec4 world_space_vert = u_modelMatrix * a_vertex;
gl_Position = u_viewProjectionMatrix * world_space_vert;
v_vertex = world_space_vert.xyz;
}
fragment41core =
#version 410
uniform highp vec3 u_viewPosition;
in highp vec3 v_vertex;
out vec4 frag_color;
void main()
{
highp float distance_to_camera = distance(v_vertex, u_viewPosition) * 1000.; // distance in micron
vec3 encoded; // encode float into 3 8-bit channels; this gives a precision of a micron at a range of up to ~16 meter
encoded.b = floor(distance_to_camera / 65536.0);
encoded.g = floor((distance_to_camera - encoded.b * 65536.0) / 256.0);
encoded.r = floor(distance_to_camera - encoded.b * 65536.0 - encoded.g * 256.0);
frag_color.rgb = encoded / 255.;
frag_color.a = 1.0;
}
[defaults]
[bindings]
u_modelMatrix = model_matrix
u_viewProjectionMatrix = view_projection_matrix
u_normalMatrix = normal_matrix
u_viewPosition = view_position
[attributes]
a_vertex = vertex