glViewport 错误地将法线坐标映射到 window 坐标?

glViewport incorrectly mapping normal coordinates to window coordinates?

我想我可以通过这些调用使 opengl 将坐标 (-1, -1) 和 (1, 1) 映射到像素 (0,0) 和 (width,height):

(gl-viewport 0 0 width height)

(gl-ortho -1 1 -1 1 -1 1)

然而,从 (-1,-1) 到 (1,1) 绘制的矩形仅跨越 window 左边缘和下边缘的三分之二。我可以使用

来解决这个问题
(gl-viewport 0 0 (* 3/2 width) (* 3/2 height))

但这对我来说似乎不正确。我做错了什么?

这是 DrRacket 的片段

#lang racket/base

(require racket/class)
(require racket/gui/base)
(require sgl)
(require sgl/gl-vectors)

(define game-canvas%
  (class canvas%
    (inherit refresh with-gl-context swap-gl-buffers)

    (super-new)

    (define (next x)
      (modulo (+ 1 x) 100))

    (define x-factor 0)

    (define/override (on-paint)
      (with-gl-context
       (lambda ()
         (gl-clear-color 0.0 0.0 0.0 0.0)
         (gl-clear 'color-buffer-bit 'depth-buffer-bit)
         (gl-color 1 1 0) (gl-rect -1 -1 (+ -1 (* 2 x-factor 1/100)) 1)
         (swap-gl-buffers)
         (gl-flush))))

    (define/public (STEP)
      (set! x-factor (next x-factor))
      (refresh)
      (sleep/yield 1/60)
      (queue-callback (lambda _ (send this STEP) #f)))

    (define/override (on-event e)
      (when (is-a? e mouse-event%)
        (when (eq? (send e get-event-type) 'left-down)
          (exit 0))))

    (define/override (on-size width height)
      (with-gl-context
       (lambda ()
         (let ((aspect (/ width height)))
           ;(gl-viewport 0 0 width height)
           (gl-viewport 0 0 (* 3/2 width) (* 3/2 height))
           (gl-matrix-mode 'projection)
           (gl-load-identity)
           (gl-ortho (* aspect -1) (* aspect 1) -1 1 -1 1)
           (gl-enable 'depth-test))))
      (refresh))))

(module+ main
  (define-values (W H) (get-display-size #t))
  (define f (new frame%
                 [style '(no-resize-border
                          no-caption
                          no-system-menu
                          hide-menu-bar)]
                 [label "glui"]
                 [width (/ W 2)]
                 [height (/ H 2)]))
  (define c (new game-canvas%
                 [parent f]
                 [style '(gl)]))
  (send f show #t)
  (send f center 'both)

  (send c STEP))

看来您没有直接使用(gl-ortho -1 1 -1 1 -1 1),而是在(gl-ortho (* aspect -1) (* aspect 1) -1 1 -1 1)中将左右值分别乘以aspect。这是错误的,因为 -1 和 1 将始终指向左右边框(如果指定了其他值),而与您的纵横比无关。所以我会完全删除 aspect 并使用 -1 和 1。这是适用于我的 16/9 显示器的代码:

#lang racket/base

(require racket/class)
(require racket/gui/base)
(require sgl)
(require sgl/gl-vectors)

(define game-canvas%
  (class canvas%
    (inherit refresh with-gl-context swap-gl-buffers)

    (super-new)

    (define (next x)
      (modulo (+ 1 x) 100))

    (define x-factor 0)

    (define/override (on-paint)
      (with-gl-context
       (lambda ()
         (gl-clear-color 0.0 0.0 0.0 0.0)
         (gl-clear 'color-buffer-bit 'depth-buffer-bit)
         (gl-color 1 1 0) (gl-rect -1 -1 (+ -1 (* 2 x-factor 1/100)) 1)
         (swap-gl-buffers)
         (gl-flush))))

    (define/public (STEP)
      (set! x-factor (next x-factor))
      (refresh)
      (sleep/yield 1/60)
      (queue-callback (lambda _ (send this STEP) #f)))

    (define/override (on-event e)
      (when (is-a? e mouse-event%)
        (when (eq? (send e get-event-type) 'left-down)
          (exit 0))))

    (define/override (on-size width height)
      (with-gl-context
       (lambda ()
         ;; Changes here
         (gl-viewport 0 0 width height)
         (gl-matrix-mode 'projection)
         (gl-load-identity)
         (gl-ortho  -1  1 -1 1 -1 1)
         (gl-enable 'depth-test)))
         ;; End of changes
      (refresh))))

(module+ main
  (define-values (W H) (get-display-size #t))
  (define f (new frame%
                 [style '(no-resize-border
                          no-caption
                          no-system-menu
                          hide-menu-bar)]
                 [label "glui"]
                 [width (/ W 2)]
                 [height (/ H 2)]))
  (define c (new game-canvas%
                 [parent f]
                 [style '(gl)]))
  (send f show #t)
  (send f center 'both)

  (send c STEP))

您的 Windows 系统似乎将显示缩放设置为 150%。 OpenGL 并不知道,您需要手动缩放。

(define/override (on-size width height)
  ...
  (let ([scale (get-display-backing-scale)]
        [scaled-width (exact-truncate (* width scale))]
        [scaled-height (exact-truncate (* height scale))])
    ...
    (gl-viewport 0 0 scaled-width scaled-height)