Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

glDrawElements not rendering input from obj file

I'm writing an object loader in lisp using cl-opengl, and when trying to render the loaded vertices/elements using glDrawElements, I'm left with a blank screen.

(require :cl-opengl)
(require :sdl2)

(defvar *vertices* nil)
(defvar *elements* nil)

(setf *vertices* (make-array 9 :fill-pointer 0))
(setf *elements* (make-array 9 :fill-pointer 0))

(defvar *vertex-shader* "
#version 330 core 
layout (location = 0) in vec3 aPos;

void main() {
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
")

(defvar *fragment-shader* "
#version 330 core
out vec4 FragColor;

void main() {
    FragColor = vec4(0.95f, 0.98f, 0.65f, 1.0f);
}
")

(defun split-str-1 (string &optional (separator " ") (r nil))
  (let ((n (position separator string
                     :from-end t
                     :test #'(lambda (x y)
                               (find y x :test #'string=)))))
    (if n
        (split-str-1 (subseq string 0 n) separator (cons (subseq string (1+ n)) r))
      (cons string r))))

(defun split-str (string &optional (separator " "))
  (split-str-1 string separator))

(defun parse-float (number)
  (with-input-from-string (in number)
    (read in)))

(defun load-obj (file-name)
   (let ((file (open file-name)))
     (with-open-stream (source file)
       (loop for line = (read-line source nil nil)
          while line do
            (let* ((split-line (split-str line " "))
                   (header (car split-line))
                   (rest (cdr split-line)))
              (cond ((string= header "v")
                     (dolist (vertex rest)
                       (vector-push-extend (parse-float vertex) vertices)))
                    ((string= header "f")
                     (dolist (face rest)
                       (let ((element (parse-integer (car (split-str face "/")))))
                          (vector-push-extend (- element 1) elements))))))))))

(defun main ()
  (load-obj "tortoise.obj")
  (sdl2:with-init (:everything)
  (sdl2:gl-set-attr :context-profile-mask 0)
  (sdl2:gl-set-attr :context-major-version 3)
  (sdl2:gl-set-attr :context-minor-version 3)

  (sdl2:with-window (win :flags `(:shown :opengl))
    (sdl2:with-gl-context (gl-context win)
    (sdl2:gl-make-current win gl-context)
    (gl:viewport 0 0 800 600)
    (gl:clear-color 0.957 0.376 0.286 1.0)

    (let ((glarray (gl:alloc-gl-array :float (length vertices)))
          (glarray-2 (gl:alloc-gl-array :unsigned-short (length elements))))
      (dotimes (i (length elements))
        (setf (gl:glaref glarray-2 i) (aref elements i)))
      (dotimes (i (length vertices))
        (setf (gl:glaref glarray i) (aref vertices i)))

      (let ((vbo (gl:gen-buffer))
            (vao (gl:gen-vertex-array))
            (ebo (gl:gen-buffer)))
        (gl:bind-vertex-array vao)
        (gl:bind-buffer :array-buffer vbo)
        (gl:buffer-data :array-buffer :static-draw glarray)
        (gl:free-gl-array glarray)
        (gl:bind-buffer :element-array-buffer ebo)
        (gl:buffer-data :element-array-buffer :static-draw glarray-2)
        (gl:vertex-attrib-pointer 0 4 :float nil 0 0)
        (gl:enable-vertex-attrib-array 0)

        (let ((vertex-shader (gl:create-shader :vertex-shader))
              (fragment-shader (gl:create-shader :fragment-shader)))
          (gl:shader-source vertex-shader *vertex-shader*)
          (gl:shader-source fragment-shader *fragment-shader*)
          (gl:compile-shader vertex-shader)
          (gl:compile-shader fragment-shader)
          (print (gl:get-shader-info-log vertex-shader))
          (print (gl:get-shader-info-log fragment-shader))

          (let ((program (gl:create-program)))
            (gl:attach-shader program vertex-shader)
            (gl:attach-shader program fragment-shader)
            (gl:link-program program)
            (gl:delete-shader vertex-shader)
            (gl:delete-shader fragment-shader)
            (gl:use-program program)))

        (sdl2:with-event-loop (:method :poll)
          (:idle ()
                 (gl:clear :color-buffer)
                 (gl:bind-vertex-array vao)
                 (gl:draw-elements :triangles glarray-2)
                 (gl:flush)
                 (sdl2:gl-swap-window win))
          (:quit () t))))))))

I've experimented with multiple obj files, and the results are the same; nothing is drawn to the screen. I've looked at some of the other SO posts and haven't found anything particularly helpful and can't really think of anything that would be causing this.

like image 232
PavelF Avatar asked May 26 '18 17:05

PavelF


1 Answers

In your case the vertex array is an array with coordinates of 3 components (x, y, z). So the "size" parameter of gl:vertex-attrib-pointer has to be 3 instead of 4:

(gl:vertex-attrib-pointer 0 3 :float nil 0 0)

Note, by using a size of 4, the specification of the vertex coordinates is misaligned. And at the end the vertex array is accessed out of bounds.


Your assumption about the indices of the obj file may be wrong.

In general a obj file looks like this:

v -1.000000 0.000000 1.000000
v 1.000000 0.000000 1.000000
v -1.000000 0.000000 -1.000000
v 1.000000 0.000000 -1.000000

vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000

vn 0.0000 1.0000 0.0000

f 1/1/1 2/2/1 4/4/1
f 1/1/1 4/4/1 3/3/1

It consists of vertex coordinates (v with 3 components), texture coordinates (vt 2 components) and normal vectors (vn 3 components).
Further there are the faces (f). Each faces specifies a single triangle, with 3 vertex coordinates and its attributes.
Each vertex consists of three indices the 1st one is the index of the vertex coordinate, the 2nd one is the index of the texture coordinate and the 3d one is the index of the normal vector.

This meanse that the following face

f 1/1/1 2/2/1 4/4/1

defines a single triangle (with 3 vertices) where the indices of the vertex coordiantes (1st indices) are

1//   2//   4//

the indices of the coresponding texture coordinates (2nd indices) are

/1/   /2/   /4/

and the indices of the coresponding normal vectors (3rd indices) are

//1   //1   //1

You may try

vertices #(-0.707 -0.5 0.0 
            0.707 -0.5 0.0
            0.0    1.0 0.0)

instead of the orignal vertex array and

elements #(0 1 2)

instead of the orignal indices, to draw a single triangle, for debug reasons.

like image 83
Rabbid76 Avatar answered Oct 26 '22 23:10

Rabbid76