Я придумал хак, чтобы сделать почти то, что вы хотите. Поскольку матрицы проекций задействованы, это немного сложно. Возможно, кто-то более искушенный в OGL мог бы сделать лучше. Вот мой взлом:
Сначала я хотел экстенты трехмерного объекта, поэтому я изменил метод __init__()
класса ObjFile
:
def __init__(self, filename, swapyz=False):
"""Loads a Wavefront OBJ file. """
self.objects = {}
self.vertices = []
self.normals = []
self.texcoords = []
self.faces = []
maxf = sys.float_info.max
# initialize the minimums and maximums
self.mins = [maxf, maxf, maxf]
self.maxs = [-maxf, -maxf, -maxf]
self._current_object = None
material = None
for line in open(filename, "r"):
if line.startswith('#'):
continue
if line.startswith('s'):
continue
values = line.split()
if not values:
continue
if values[0] == 'o':
self.finish_object()
self._current_object = values[1]
# elif values[0] == 'mtllib':
# self.mtl = MTL(values[1])
# elif values[0] in ('usemtl', 'usemat'):
# material = values[1]
if values[0] == 'v':
v = list(map(float, values[1:4]))
if swapyz:
v = v[0], v[2], v[1]
# keep the vertex minimums and maximums
for i in range(3):
self.mins[i] = min(self.mins[i], v[i])
self.maxs[i] = max(self.maxs[i], v[i])
self.vertices.append(v)
elif values[0] == 'vn':
v = list(map(float, values[1:4]))
if swapyz:
v = v[0], v[2], v[1]
self.normals.append(v)
elif values[0] == 'vt':
self.texcoords.append(map(float, values[1:3]))
elif values[0] == 'f':
face = []
texcoords = []
norms = []
for v in values[1:]:
w = v.split('/')
face.append(int(w[0]))
if len(w) >= 2 and len(w[1]) > 0:
texcoords.append(int(w[1]))
else:
texcoords.append(-1)
if len(w) >= 3 and len(w[2]) > 0:
norms.append(int(w[2]))
else:
norms.append(-1)
self.faces.append((face, norms, texcoords, material))
self.finish_object()
print('max :', self.maxs, ', mins:', self.mins)
И в * Класс 1008 *, я изменил два метода:
def update_glsl(self, delta):
# Calculate new left edge for the clip matrix
old_scene_width = self.scene.maxs[0] - self.scene.mins[0]
app_width = App.get_running_app().root.width
renderer_width = self.width
ratio = app_width / renderer_width
new_scene_width = old_scene_width * ratio
left = self.scene.mins[0] - (new_scene_width - old_scene_width)
# calculate new top and bottom of clip frustum that maintains monkey head aspect ratio
scene_center_vertical = (self.scene.mins[1] + self.scene.maxs[1]) / 2.0
old_scene_height = self.scene.maxs[1] - self.scene.mins[1]
new_scene_height = old_scene_height * ratio
bottom = scene_center_vertical - new_scene_height / 2.0
top = scene_center_vertical + new_scene_height / 2.0
# create new clip matrix
proj = Matrix().view_clip(left, self.scene.maxs[0],
bottom, top,
1, self.scene.maxs[2] - self.scene.mins[2] - self.translate.z,
1)
self.canvas['projection_mat'] = proj
self.canvas['diffuse_light'] = (1.0, 1.0, 0.8)
self.canvas['ambient_light'] = (0.1, 0.1, 0.1)
self.rot.angle += delta * 100
def setup_scene(self):
Color(1, 1, 1, 1)
PushMatrix()
# save a reference to the Translate matrix
self.translate = Translate(0, 0, -3)
self.rot = Rotate(1, 0, 1, 0)
m = list(self.scene.objects.values())[0]
UpdateNormalMatrix()
self.mesh = Mesh(
vertices=m.vertices,
indices=m.indices,
fmt=m.vertex_format,
mode='triangles',
)
PopMatrix()
Идея состоит в том, чтобы отрегулировать матрицу отсечения так, чтобы голова обезьяны центрировалась в Renderer
Widget
. Для этого sh я изменил параметр left
матрицы клипа так, чтобы обезьяна больше не находилась в центре усеченного усеченного конуса. Я также пересчитал параметры top
и bottom
усеченного конуса, чтобы избежать неравномерного масштабирования (искажения).