Fix minimap's viewing area outline.
Check for intersection with eight of the frustum's edges, not just four.
This commit is contained in:
parent
c5836353c6
commit
3772d5dfb3
@ -2,6 +2,7 @@
|
|||||||
minimap.py
|
minimap.py
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
from collections import namedtuple
|
||||||
from OpenGL import GL
|
from OpenGL import GL
|
||||||
from PySide import QtCore, QtGui
|
from PySide import QtCore, QtGui
|
||||||
import logging
|
import logging
|
||||||
@ -16,50 +17,93 @@ from mceditlib.geometry import Vector, Ray
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class LineSegment(namedtuple("LineSegment", "p1 p2")):
|
||||||
|
def atHeight(self, y):
|
||||||
|
p1 = self.p1
|
||||||
|
p2 = self.p2
|
||||||
|
if not (p1.y < y < p2.y or p1.y > y > p2.y):
|
||||||
|
return None
|
||||||
|
|
||||||
|
r = Ray.fromPoints(p1, p2)
|
||||||
|
return r.atHeight(y)
|
||||||
|
|
||||||
|
|
||||||
class ViewCornersRenderNode(rendergraph.RenderNode):
|
class ViewCornersRenderNode(rendergraph.RenderNode):
|
||||||
# bottom left, near
|
|
||||||
# bottom left, far
|
#
|
||||||
# top left, near
|
# Renders the intersection of a horizontal plane with the view frustum
|
||||||
# top left, far
|
# We only check the four vertical segments (with respect to the view angle)
|
||||||
# bottom right, near
|
# and the four segments pointing outward from the viewer.
|
||||||
# bottom right, far
|
# The four outward segments are checked first, if all four intersect they are used
|
||||||
# top right, near
|
# as the corners. If only two outwards segments intersect, the two furthest
|
||||||
# top right, far
|
# verticals are intersected and used as the last two corners.
|
||||||
|
# If no outward segments intersect (rare) then all four verticals are used.
|
||||||
|
|
||||||
|
# 0: bottom left, near
|
||||||
|
# 1: bottom left, far
|
||||||
|
# 2: top left, near
|
||||||
|
# 3: top left, far
|
||||||
|
# 4: bottom right, near
|
||||||
|
# 5: bottom right, far
|
||||||
|
# 6: top right, near
|
||||||
|
# 7: top right, far
|
||||||
|
|
||||||
|
verticalIndices = [
|
||||||
|
(1, 3),
|
||||||
|
(5, 7),
|
||||||
|
(0, 2),
|
||||||
|
(4, 6),
|
||||||
|
]
|
||||||
|
outwardIndices = [
|
||||||
|
(0, 1),
|
||||||
|
(2, 3),
|
||||||
|
(4, 5),
|
||||||
|
(6, 7),
|
||||||
|
]
|
||||||
|
|
||||||
def drawSelf(self):
|
def drawSelf(self):
|
||||||
if self.sceneNode.corners is None or self.sceneNode.dimension is None:
|
if self.sceneNode.corners is None or self.sceneNode.dimension is None:
|
||||||
return
|
return
|
||||||
corners = self.sceneNode.corners
|
corners = self.sceneNode.corners
|
||||||
dimension = self.sceneNode.dimension
|
|
||||||
corners = corners[:2], corners[2:4], corners[6:8], corners[4:6]
|
|
||||||
|
|
||||||
def rayCastCorner(near, far):
|
outwardSegments = [LineSegment(corners[i], corners[j]) for i, j in self.outwardIndices]
|
||||||
ray = Ray.fromPoints(near, far)
|
verticalSegments = [LineSegment(corners[i], corners[j]) for i, j in self.verticalIndices]
|
||||||
if not any(ray.vector):
|
points = []
|
||||||
return far
|
|
||||||
try:
|
|
||||||
#point = rayCastInBounds(ray, dimension, 50)[0]
|
|
||||||
#return point or far
|
|
||||||
return near + (near - far) / 4
|
|
||||||
except raycast.MaxDistanceError:
|
|
||||||
return ray.atHeight(0)
|
|
||||||
|
|
||||||
# Average nearby height values or something to suppress jitter??
|
for segment in outwardSegments:
|
||||||
corners = [rayCastCorner(near, far) for near, far in corners]
|
p = segment.atHeight(self.sceneNode.planeHeight)
|
||||||
corners.append(corners[0])
|
if p is not None:
|
||||||
|
points.append(p)
|
||||||
|
|
||||||
|
if len(points) < 4:
|
||||||
|
# only intersected two outward segments. check the far verticals.
|
||||||
|
for segment in verticalSegments[:2]:
|
||||||
|
r = Ray.fromPoints(*segment)
|
||||||
|
points.append(r.atHeight(self.sceneNode.planeHeight))
|
||||||
|
|
||||||
|
if len(points) < 4:
|
||||||
|
# intersected zero outward segments!
|
||||||
|
# rarely occurs, the near verticals are 1/10 of a block tall
|
||||||
|
for segment in verticalSegments[2:]:
|
||||||
|
r = Ray.fromPoints(*segment)
|
||||||
|
points.append(r.atHeight(self.sceneNode.planeHeight))
|
||||||
|
|
||||||
|
if len(points) < 4:
|
||||||
|
return
|
||||||
|
|
||||||
|
p1, p2, p3, p4 = points[:4]
|
||||||
|
points = [p1, p2, p4, p3, p1]
|
||||||
|
|
||||||
with gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT, GL.GL_COLOR_BUFFER_BIT):
|
with gl.glPushAttrib(GL.GL_DEPTH_BUFFER_BIT, GL.GL_COLOR_BUFFER_BIT):
|
||||||
GL.glDepthMask(False)
|
GL.glDepthMask(False)
|
||||||
GL.glEnable(GL.GL_BLEND)
|
GL.glEnable(GL.GL_BLEND)
|
||||||
GL.glVertexPointer(3, GL.GL_FLOAT, 0, numpy.array(corners).ravel())
|
GL.glVertexPointer(3, GL.GL_FLOAT, 0, numpy.array(points).ravel())
|
||||||
|
|
||||||
GL.glLineWidth(3.0)
|
GL.glLineWidth(3.0)
|
||||||
|
|
||||||
GL.glColor(1, 1, .1, 0.5)
|
GL.glColor(1, 1, .1, 0.5)
|
||||||
GL.glDisable(GL.GL_DEPTH_TEST)
|
GL.glDisable(GL.GL_DEPTH_TEST)
|
||||||
GL.glDrawArrays(GL.GL_LINE_STRIP, 0, 5)
|
GL.glDrawArrays(GL.GL_LINE_STRIP, 0, len(points))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ViewCornersNode(scenegraph.Node):
|
class ViewCornersNode(scenegraph.Node):
|
||||||
@ -86,6 +130,17 @@ class ViewCornersNode(scenegraph.Node):
|
|||||||
def dimension(self, value):
|
def dimension(self, value):
|
||||||
self._dimension = value
|
self._dimension = value
|
||||||
self.dirty = True
|
self.dirty = True
|
||||||
|
|
||||||
|
_planeHeight = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def planeHeight(self):
|
||||||
|
return self._planeHeight
|
||||||
|
|
||||||
|
@planeHeight.setter
|
||||||
|
def planeHeight(self, value):
|
||||||
|
self._planeHeight = value
|
||||||
|
self.dirty = True
|
||||||
|
|
||||||
|
|
||||||
class MinimapWorldView(WorldView):
|
class MinimapWorldView(WorldView):
|
||||||
@ -124,7 +179,10 @@ class MinimapWorldView(WorldView):
|
|||||||
self.matrixNode.modelview = modelview
|
self.matrixNode.modelview = modelview
|
||||||
|
|
||||||
def currentViewMatrixChanged(self, currentView):
|
def currentViewMatrixChanged(self, currentView):
|
||||||
self.viewCornersNode.corners = currentView.getViewBounds()
|
self.viewCornersNode.corners = currentView.getViewCorners()
|
||||||
|
planeDistance = 20
|
||||||
|
planeHeight = (currentView.centerPoint + currentView.cameraVector * planeDistance).y
|
||||||
|
self.viewCornersNode.planeHeight = planeHeight
|
||||||
|
|
||||||
def zoom(self, scale, (mx, my)):
|
def zoom(self, scale, (mx, my)):
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ class WorldView(QGLWidget):
|
|||||||
matrix = self.matrixNode.projection * self.matrixNode.modelview
|
matrix = self.matrixNode.projection * self.matrixNode.modelview
|
||||||
matrix, inverted = matrix.inverted()
|
matrix, inverted = matrix.inverted()
|
||||||
worldCorners = [matrix.map(corner) for corner in corners]
|
worldCorners = [matrix.map(corner) for corner in corners]
|
||||||
worldCorners = [(corner / corner.w()).toTuple()[:3] for corner in worldCorners]
|
worldCorners = [Vector(*((corner / corner.w()).toTuple()[:3])) for corner in worldCorners]
|
||||||
return worldCorners
|
return worldCorners
|
||||||
|
|
||||||
def getViewBounds(self):
|
def getViewBounds(self):
|
||||||
|
Reference in New Issue
Block a user