29,99 €
This book is designed for computer science undergraduates and professionals interested in mastering 3D graphics using OpenGL in Java with JOGL. It follows a “teach-yourself” format with numerous examples that can be run as presented. Unique in its approach, it covers OpenGL 4.0+ shader programming using Java, providing all the necessary materials to install JOGL and execute every example.
The course starts with an introduction to OpenGL and the graphics pipeline, followed by mathematical foundations essential for 3D graphics. It then delves into managing 3D graphics data, texture mapping, and creating 3D models. Lighting, shadows, and enhancing surface detail are covered, along with advanced techniques like parametric surfaces, tessellation, and geometry shaders.
The final chapters explore simulating water, ray tracing, and stereoscopy for 3D glasses and VR headsets. This book equips readers with comprehensive skills in OpenGL programming and 3D graphics, making it an invaluable resource for developing sophisticated graphics applications. The practical approach ensures thorough learning, bridging the gap between theory and application.
Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:
Seitenzahl: 549
Veröffentlichungsjahr: 2024
COMPUTER GRAPHICSPROGRAMMING IN OPENGLWITH JAVA
THIRD EDITION
LICENSE, DISCLAIMER OF LIABILITY, AND LIMITED WARRANTY
By purchasing or using this book and its companion files (the “Work”), you agree that this license grants permission to use the contents contained herein, but does not give you the right of ownership to any of the textual content in the book or ownership to any of the information or products contained in it. This license does not permit uploading of the Work onto the Internet or on a network (of any kind) without the written consent of the Publisher. Duplication or dissemination of any text, code, simulations, images, etc. contained herein is limited to and subject to licensing terms for the respective products, and permission must be obtained from the Publisher or the owner of the content, etc., in order to reproduce or network any portion of the textual material (in any media) that is contained in the Work.
MERCURY LEARNING AND INFORMATION (“MLI” or “THE PUBLISHER”) and anyone involved in the creation, writing, or production of the companion disc, accompanying algorithms, code, or computer programs (“the software”), and any accompanying Web site or software of the Work, cannot and do not warrant the performance or results that might be obtained by using the contents of the Work. The author, developers, and the Publisher have used their best efforts to ensure the accuracy and functionality of the textual material and/or programs contained in this package; we, however, make no warranty of any kind, express or implied, regarding the performance of these contents or programs. The Work is sold “as is” without warranty (except for defective materials used in manufacturing the book or due to faulty workmanship).
The author, developers, and the publisher of any accompanying content, and anyone involved in the composition, production, and manufacturing of this work will not be liable for damages of any kind arising out of the use of (or the inability to use) the algorithms, source code, computer programs, or textual material contained in this publication. This includes, but is not limited to, loss of revenue or profit, or other incidental, physical, or consequential damages arising out of the use of this Work.
The sole remedy in the event of a claim of any kind is expressly limited to replacement of the book and disc and only at the discretion of the Publisher. The use of “implied warranty” and certain “exclusions” vary from state to state, and might not apply to the purchaser of this product.
Companion files are available for download from the publisher by writing to info@merclearning.com.
COMPUTER GRAPHICSPROGRAMMING IN OPENGLWITH JAVA
THIRD EDITION
V. Scott Gordon, PhD
California State University, Sacramento
John Clevenger, PhD
California State University, Sacramento
MERCURY LEARNING AND INFORMATIONDulles, VirginiaBoston, MassachusettsNew Delhi
Copyright ©2021 by MERCURY LEARNING AND INFORMATION LLC. All rights reserved.
This publication, portions of it, or any accompanying software may not be reproduced in any way, stored in a retrieval system of any type, or transmitted by any means, media, electronic display or mechanical display, including, but not limited to, photocopy, recording, Internet postings, or scanning, without prior permission in writing from the publisher.
Publisher: David Pallai
MERCURY LEARNING AND INFORMATION22841 Quicksilver DriveDulles, VA 20166info@merclearning.comwww.merclearning.com(800) 232-0223
V. Scott Gordon & John Clevenger.Computer Graphics Programming in OpenGL with Java, Third EditionISBN: 978-1-68392-736-5
The publisher recognizes and respects all marks used by companies, manufacturers, and developers as a means to distinguish their products. All brand names and product names mentioned in this book are trademarks or service marks of their respective companies. Any omission or misuse (of any kind) of service marks or trademarks, etc. is not an attempt to infringe on the property of others.
Library of Congress Control Number: 2021942460
212223 321 Printed on acid-free paper in the United States of America.
Our titles are available for adoption, license, or bulk purchase by institutions, corporations, etc. For additional information, please contact the Customer Service Dept. at 800-232-0223 (toll free). Digital versions of our titles are available at: www.academiccourseware.com and other e-vendors. All companion files are available by writing to the publisher at info@merclearning.com.
The sole obligation of MERCURY LEARNING AND INFORMATION to the purchaser is to replace the book and/or disc, based on defective materials or faulty workmanship, but not based on the operation or functionality of the product.
Contents
Preface
What’s New in This Edition
Intended Audience
How to Use This Book
Acknowledgments
About the Authors
Chapter 1 Getting Started
1.1 Languages and Libraries
1.1.1Java
1.1.2OpenGL / GLSL
1.1.3JOGL
1.1.4JOML
1.2Installation and Configuration
Chapter 2 The OpenGL Graphics Pipeline
2.1The OpenGL Pipeline
2.1.1Java/JOGL Application
2.1.2Vertex and Fragment Shaders
2.1.3Tessellation
2.1.4Geometry Shader
2.1.5Rasterization
2.1.6Fragment Shader
2.1.7Pixel Operations
2.2Detecting OpenGL and GLSL Errors
2.3Reading GLSL Source Code from Files
2.4Building Objects from Vertices
2.5Animating a Scene
2.6Organizing the Java Code Files
Chapter 3 Mathematical Foundations
3.13D Coordinate Systems
3.2Points
3.3Matrices
3.4Transformation Matrices
3.4.1Translation
3.4.2Scaling
3.4.3Rotation
3.5Vectors
3.5.1Uses for Dot Product
3.5.2Uses for Cross Product
3.6Local and World Space
3.7Eye Space and the Synthetic Camera
3.8Projection Matrices
3.8.1The Perspective Projection Matrix
3.8.2The Orthographic Projection Matrix
3.9Look-At Matrix
3.10GLSL Functions for Building Matrix Transforms
Chapter 4 Managing 3D Graphics Data
4.1Buffers and Vertex Attributes
4.2Uniform Variables
4.3Interpolation of Vertex Attributes
4.4Model-View and Perspective Matrices
4.5Our First 3D Program—A 3D Cube
4.6Rendering Multiple Copies of an Object
4.6.1Instancing
4.7Rendering Multiple Different Models in a Scene
4.8Matrix Stacks
4.9Combating “Z-Fighting” Artifacts
4.10Other Options for Primitives
4.11Coding for Performance
4.11.1Minimizing Dynamic Memory Allocation
4.11.2Pre-Computing the Perspective Matrix
4.11.3Back-Face Culling
Chapter 5 Texture Mapping
5.1Loading Texture Image Files
5.2Texture Coordinates
5.3Creating a Texture Object
5.4Constructing Texture Coordinates
5.5Loading Texture Coordinates into Buffers
5.6Using the Texture in a Shader: Sampler Variables and Texture Units
5.7Texture Mapping: Example Program
5.8Mipmapping
5.9Anisotropic Filtering
5.10Wrapping and Tiling
5.11Perspective Distortion
5.12Loading Texture Image Files using Java AWT Classes
Chapter 6 3D Models
6.1Procedural Models—Building a Sphere
6.2OpenGL Indexing—Building a Torus
6.2.1The Torus
6.2.2Indexing in OpenGL
6.3Loading Externally Produced Models
Chapter 7 Lighting
7.1Lighting Models
7.2Lights
7.3Materials
7.4ADS Lighting Computations
7.5Implementing ADS Lighting
7.5.1Gouraud Shading
7.5.2Phong Shading
7.6Combining Lighting and Textures
Chapter 8 Shadows
8.1The Importance of Shadows
8.2Projective Shadows
8.3Shadow Volumes
8.4Shadow Mapping
8.4.1Shadow Mapping (Pass One)—“Draw” Objects from Light Position
8.4.2Shadow Mapping (Intermediate Step)—Copying the Z-Buffer to a Texture
8.4.3Shadow Mapping (Pass Two)—Rendering the Scene with Shadows
8.5A Shadow Mapping Example
8.6Shadow Mapping Artifacts
8.7Soft Shadows
8.7.1Soft Shadows in the Real World
8.7.2Generating Soft Shadows—Percentage Closer Filtering (PCF)
8.7.3A Soft Shadow/PCF Program
Chapter 9 Sky and Backgrounds
9.1Skyboxes
9.2Skydomes
9.3Implementing a Skybox
9.3.1Building a Skybox from Scratch
9.3.2Using OpenGL Cube Maps
9.4Environment Mapping
Chapter 10 Enhancing Surface Detail
10.1Bump Mapping
10.2Normal Mapping
10.3Height Mapping
Chapter 11 Parametric Surfaces
11.1Quadratic Bézier Curves
11.2Cubic Bézier Curves
11.3Quadratic Bézier Surfaces
11.4Cubic Bézier Surfaces
Chapter 12 Tessellation
12.1Tessellation in OpenGL
12.2Tessellation for Bézier Surfaces
12.3Tessellation for Terrain/Height Maps
12.4Controlling Level of Detail (LOD)
Chapter 13 Geometry Shaders
13.1Per-Primitive Processing in OpenGL
13.2Altering Primitives
13.3Deleting Primitives
13.4Adding Primitives
13.5Changing Primitive Types
Chapter 14 Other Techniques
14.1Fog
14.2Compositing/Blending/Transparency
14.3User-Defined Clipping Planes
14.43D Textures
14.5Noise
14.6Noise Application - Marble
14.7Noise Application - Wood
14.8Noise Application - Clouds
14.9Noise Application - Special Effects
Chapter 15 Simulating Water
15.1Pool Surface and Floor Geometry Setup
15.2Adding Surface Reflection and Refraction
15.3Adding Surface Waves
15.4Additional Corrections
15.5Animating the Water Movement
15.6Underwater Caustics
Chapter 16 Ray Tracing and Compute Shaders
16.1Compute Shaders
16.1.1Compiling and Using Compute Shaders
16.1.2Parallel Computing in Compute Shaders
16.1.3Work Groups
16.1.4Work Group Details
16.1.5Work Group Limitations
16.2Ray Casting
16.2.1Defining the 2D Texture Image
16.2.2Building and Displaying the Ray Cast Image
16.2.3Ray-Sphere Intersection
16.2.4Axis-Aligned Ray-Box Intersection
16.2.5Output of Simple Ray Casting Without Lighting
16.2.6Adding ADS Lighting
16.2.7Adding Shadows
16.2.8Non-Axis-Aligned Ray-Box Intersection
16.2.9Determining Texture Coordinates
16.2.10Plane Intersection and Procedural Textures
16.3Ray Tracing
16.3.1Reflection
16.3.2Refraction
16.3.3Combining Reflection, Refraction, and Textures
16.3.4Increasing the Number of Rays
16.3.5Generalizing the Solution
16.3.6Additional Examples
16.3.7Blending Colors for Transparent Objects
Chapter 17 Stereoscopy for 3D Glasses and VR Headsets
17.1View and Projection Matrices for Two Eyes
17.2Anaglyph Rendering
17.3Side-by-Side Rendering
17.4Correcting Lens Distortion in Headsets
17.5A Simple Testing Hardware Configuration
Appendix A Installation and Setup for PC (Windows)
Appendix B Installation and Setup for Macintosh
Appendix C Using the Nsight Graphics Debugger
Index
Preface
This book is designed primarily as a textbook for a typical computer science undergraduate course in modern shader-based, OpenGL 3D graphics programming. However, we have also endeavored to create a text that could be used to teach oneself, without an accompanying course. With both of those aims in mind, we have tried to explain things as clearly and as simply as we can. All of the programming examples are stripped down and simplified as much as possible, but they are still complete, so the reader may run them all as presented.
One of the things we hope is unique about this book is that we have strived to make it accessible to a beginner – that is, someone new to 3D graphics programming. While there is by no means a lack of information available on the topic—quite the contrary—many students are initially overwhelmed. This text is our attempt to write the book we wish we had had when we were starting out, with step-by-step explanations of the basics, progressing in an organized manner up through advanced topics. We considered titling the book “shader programming made easy”; however, we don’t think that there really is any way of making shader programming “easy.” We hope that we have come close.
This book teaches OpenGL programming in Java, using JOGL—a Java “wrapper” for OpenGL’s native C calls [JO21]. There are several advantages to learning graphics programming in Java rather than in C:
•It is more convenient for students at schools that conduct most of their curriculum in Java
•Installation and setup is easier in Java than for C or C++
•Java’s I/O, window, and event handling are arguably cleaner than in C
•Java’s excellent support for object-oriented design patterns can foster good design
•JOGL includes some very nice tools, such as for loading textures, animation loops, etc.
It is worth mentioning that there do exist other Java bindings for OpenGL. One that has become very popular is Lightweight Java Game Library, or LWJGL [LW21]. Like JOGL, LWJGL also offers bindings for OpenAL and OpenCL. This textbook focuses only on JOGL.
Another thing that makes this book unique is that it has a “sister” textbook: Computer Graphics Programming in OpenGL with C++, Second Edition. The two books are organized in lockstep, with the same chapter and section numbers and topics, figures, exercises, and theoretical descriptions. Wherever possible, the code is organized similarly. Of course, the use of Java versus C++ leads to considerable programming differences (although all of the shader code is identical). Still, we believe that we have provided virtually identical learning paths, even allowing a student to choose either option within a single classroom.
An important point of clarification is that there exist both different versions of OpenGL (briefly discussed later) and different variants of OpenGL. For example, in addition to “standard OpenGL” (sometimes called “desktop OpenGL”), there exists a variant called “OpenGL ES,” which is tailored for development of embedded systems (hence the “ES”). “Embedded systems” include devices such as mobile phones, game consoles, automobiles, and industrial control systems. OpenGL ES is mostly a subset of standard OpenGL, eliminating a large number of operations that are typically not needed for embedded systems. OpenGL ES also adds some additional functionality, typically application-specific operations for particular target environments. The JOGL suite of Java bindings includes interfaces for different versions of OpenGL ES, although we do not use them in this book.
Yet another variant of OpenGL is called “WebGL.” Based on OpenGL ES, WebGL is designed to support the use of OpenGL in web browsers. WebGL allows an application to use JavaScript1 to invoke OpenGL ES operations, which makes it easy to embed OpenGL graphics into standard HTML (web) documents. Most modern web browsers support WebGL, including Apple Safari, Google Chrome, Microsoft Edge, Microsoft Internet Explorer, Mozilla Firefox, and Opera. Since web programming is outside the scope of this book, we will not cover any WebGL specifics. Note however, that because WebGL is based on OpenGL ES, which in turn is based on standard OpenGL, much of what is covered in this book can be transferred directly to learning about these OpenGL variants.
The very topic of 3D graphics lends itself to impressive, even beautiful images. Indeed, many popular textbooks on the topic are filled with breathtaking scenes, and it is enticing to leaf through their galleries. While we acknowledge the motivational utility of such examples, our aim is to teach, not to impress. The images in this book are simply the outputs of the example programs, and because this is an introductory text, the resulting scenes are unlikely to impress an expert. However, the techniques presented do constitute the foundational elements for producing today’s stunning 3D effects.
We also haven’t tried to create an OpenGL or JOGL “reference.” Our coverage of OpenGL and JOGL represents only a tiny fraction of their capabilities. Rather, our aim is to use OpenGL and JOGL as vehicles for teaching the fundamentals of modern shader-based 3D graphics programming, and provide the reader with a sufficiently deep understanding for further study. If along the way this text helps to expand awareness of JOGL and other JogAmp technologies, that would be nice, too.
What’s New in This Edition
We have added three new chapters in this 3rd edition of Computer Graphics Programming in OpenGL with Java:
•Chapter 15 – Simulating Water
•Chapter 16 – Ray Tracing
•Chapter 17 – Stereoscopy
Ray tracing in particular has become “hot” recently, so we are especially excited that it is now included in our book. It is also a huge topic, so even though our coverage is just a basic introduction, Chapter 16 is now the longest chapter in the book. Chapter 16 also includes an introduction to compute shaders, which were introduced in OpenGL 4.3, and an introduction to additive and subtractive color blending, which expands on a topic that was introduced in Section 14.2.
For years our own students have repeatedly expressed an interest in simulating water. However, water takes so many forms that writing an introductory section on the topic is challenging. Ultimately, we decided to present water in a way that would complement related topics in the book such as terrain, sky, etc., and so in Chapter 15 we focus on utilizing our noise maps from Chapter 14 to generate water surfaces such as are seen in lakes and oceans.
The new chapter on stereoscopy is motivated by the increased popularity of virtual reality. However, it is also applicable to the development of animation for “3D movies,” and we have tried to provide introductory coverage of both uses equally.
As a result of these additions, this 3rd edition is larger than the previous edition.
Besides the new material, there are important revisions throughout the book. For example, we fixed bugs in our Torus class in Chapter 6, and made significant improvements to our noise map functions in Chapter 14. Another small, but important, modification was to change all of our lighting computations so that they are done in world space rather than in camera space – this makes it easier to develop applications that require being able to move the camera around. We also expanded our Utils.java utility class to handle the loading of compute shaders.
There are dozens of small changes in every chapter that the reader might not even notice: fixing typos, cleaning up code inconsistencies, updating the installation instructions, making slight wording changes, sprucing up figures, updating references, etc. Completely eliminating typos is virtually impossible in a book that covers an ever-changing technology-rich topic, but we have attempted it.
Intended Audience
This book is targeted at students of computer science. This could mean undergraduates pursuing a BS degree, but it could also mean anyone who studies computer science. As such, we are assuming that the reader has at least a solid background in object-oriented programming, at the level of someone who is, say, a computer science major at the junior or senior level.
There are also some specific things that we use in this book, but that we don’t cover, because we assume the reader already has sufficient background. In particular:
•Java and its Abstract Window Toolkit (AWT) or Swing library, especially for GUI-building
•Java configuration details, such as manipulating the CLASSPATH
•basic data structures and algorithms, such as linked lists, stacks and queues, etc.
•recursion
•event-driven programming concepts
•basic matrix algebra and trigonometry
•basic analytic geometry, such as for defining points, lines, vectors, planes, and circles
•awareness of color models, such as RGB, RGBA, etc.
•basic familiarity with C or C++ (some shader syntax is based on C)
The audience for this new 3rd edition is also hoped to be expanded by the similar updates made for the 2nd edition of its “sister” textbook, Computer Graphics Programming in OpenGL withC++. In particular, we envision a learning environment where students are free to utilize either Java or C++ in the same classroom, selecting one or the other book. The two texts cover the material sufficiently in lockstep that we have been conducting our graphics programming course successfully in this manner.
How to Use This Book
This book is designed to be read from front to back. That is, material in later chapters frequently relies on information learned in earlier chapters. So, it probably won’t work to jump back and forth in the chapters; rather, work your way forward through the material.
This is also intended mostly as a practical, hands-on guide. While there is plenty of theoretical material included, the reader should treat this text as a sort of “workbook,” in which you learn basic concepts by actually programming them yourself. We have provided code for all of the examples, but to really learn the concepts you will want to “play” with those examples—extend them to build your own 3D scenes.
At the end of each chapter are a few exercises to solve. Some are very simple, involving merely making simple modifications to the provided code. The problems that are marked “(PROJECT),” however, are expected to take some time to solve, and require writing a significant amount of code, or combining techniques from various examples. There are also a few marked “(RESEARCH)”—those are problems that encourage independent study because this textbook doesn’t provide sufficient detail to solve them.
OpenGL calls, whether made in C or in Java through JOGL, often involve long lists of parameters. While writing this book, the authors debated whether or not to, in each case, describe all of the parameters. We decided that in the early chapters we would describe every detail. But as the topics progress, we decided to avoid getting bogged down in every piece of minutiae in the OpenGL calls (and there are many), for fear of the reader losing sight of the big picture. For this reason, it is essential when working through the examples to have ready access to reference material for Java, OpenGL, and JOGL.
For this, there are a number of excellent reference sources that we recommend using in conjunction with this book. The javadocs for Java and JOGL are absolutely essential, and can be accessed online or downloaded. The reader should bookmark them for easy access in a browser, and expect to access them continuously for looking up items such as parameter and constructor details. The URLs for the Java and JOGL javadocs are:
https://docs.oracle.com/en/java/javase/11/docs/api
https://jogamp.org/deployment/jogamp-next/javadoc/jogl/javadoc
Many of the entries in the JOGL javadoc are simply pointers to the corresponding entry in the OpenGL documentation, available here:
https://www.khronos.org/registry/OpenGL-Refpages/gl4/
Our examples utilize a mathematics library called JOML. This is a Java library that also has its own set of javadocs. After installing JOML (described in the appendices), the reader should locate the accompanying javadoc link and bookmark it. At press time, the current link is:
https://joml-ci.github.io/JOML/apidocs
There are many other books on 3D graphics programming that we recommend reading in parallel with this book (such as for solving the “research” problems). Here are five that we often refer to:
•(Sellers et al.) OpenGL SuperBible [SW15]
•(Kessenich et al.) OpenGL ProgrammingGuide [KS16] (the “red book”)
•(Wolff) OpenGL 4 Shading LanguageCookbook [WO18]
•(Angel and Shreiner) Interactive Computer Graphics [AS20]
•(Luna) Introduction to 3D Game Programming with DirectX 12 [LU16]
Companion Files
This book is accompanied by a companion disc that contains the following items:
•All of the Java/OpenGL programs and related utility class files and GLSL shader code presented in the book
•The models and texture files used in the various programs and examples
•The cubemap and skydome image files used to make the skies and horizons
•Normal maps and height maps for lighting and surface detail effects
•All of the figures in the book, as image files
Readers who have purchased the electronic version of this book may obtain these files by contacting the publisher at info@merclearning.com.
Instructor Ancillaries
Instructors in a college or university setting are encouraged to obtain the instructor ancillary package that is available for this book, which contains the following additional items:
•A complete set of PowerPoint slides covering all topics in the book
•Solutions to most of the exercises at the ends of the chapters, including code where applicable
•Sample syllabus for a course based on the book
•Additional hints for presenting the material, chapter-by-chapter
This instructor ancillary package is available by contacting the publisher at info@merclearning.com.
Acknowledgments
Early drafts of this book (prior to the 1st edition) were developed in 2016 for the CSc-155 (Advanced Computer Graphics Programming) course at CSU Sacramento. Many CSc-155 students actively contributed suggestions and bug fixes during that year, including Mitchell Brannan, Tiffany Chiapuzio-Wong, Samson Chua, Anthony Doan, Kian Faroughi, Cody Jackson, John Johnston, Zeeshan Khaliq, Raymond Rivera, Oscar Solorzano, Darren Takemoto, Jon Tinney, James Womack, and Victor Zepeda. The following year our colleague Dr. Pinar Muyan-Ozcelik used the book while teaching CSc-155 for her first time, and kept a running log of questions and corrections for each chapter, which led to many improvements for subsequent editions.
In Spring 2020 we tested our idea of allowing students (in our CSc-155 course) to select either Java or C++, using the respective edition of this textbook. It was a sort of acid test of our “sister” textbook idea, and we were pleased with how things went. We have been teaching the course in this manner ever since.
Much of the code in Chapters 15 and 16 was developed by two of our best students, Chris Swenson and Luis Gutierrez, respectively. Both did an excellent job of distilling these complex topics into nicely coherent solutions, and their contributions helped to make these two new chapters possible.
We continue to receive a steady stream of great feedback from instructors around the world who adopt our books for their courses, and from professionals and enthusiasts – Dr. Mauricio Papa (University of Tulsa), Dan Asimov (NASA Ames), Sean McCrory, Michael Hiatt, Scott Anderson, Reydalto Hernandez, and Bill Crupi, just to name a few.
Dr. Alan Mills, over the course of several months starting in early 2020, sent us over two hundred suggestions and corrections from his notes as he worked through our 2nd edition. Among his many finds was a significant correction to the texture coordinates in the torus model. Alan’s attention to detail is amazing and we greatly appreciate the positive impact of his efforts on our books (many of his suggestions were also applicable to the C++ edition).
Jay Turberville of Studio 522 Productions in Scottsdale (Arizona) built the dolphin model shown on the cover and used throughout all of our books. Our students love it. Studio 522 Productions does incredibly high-quality 3D animation and video production, as well as custom 3D modeling. We are thrilled that Mr. Turberville kindly offered to build such a wonderful model just for these books.
We are extremely grateful for the ongoing assistance provided to us by Julien Gouesse, engine support maintainer at Jogamp. Mr. Gouesse has provided technical information on JOGL textures, cube maps, buffer handling, animation, proper loading of shader source files, and a variety of other topics. His help has led to significant improvements in each edition.
Kai Burjack, lead developer of the JOML math library, has been extraordinarily generous with his time and assistance since we migrated to using JOML in our 2nd edition. He reviewed key segments of our book and has helped guide us to (hopefully!) using JOML correctly.
We wish to thank a few other artists and researchers who were gracious enough to allow us to utilize their models and textures. James Hastings-Trew of Planet Pixel Emporium provided many of the planetary surface textures. We thank Jochum Skoglund of Crackshell for permitting us to use his beautiful “MIRAMAR” skybox, and for allowing us to include it in the accompanying ancillary files. Paul Bourke allowed us to use his wonderful star field. Dr. Marc Levoy of Stanford University granted us permission to use the famous “Stanford Dragon” model. Paul Baker’s bump-mapping tutorial formed the basis of the “torus” model we used in many examples. We also thank Mercury Learning for allowing us to use some of the textures from [LU16].
The late Dr. Danny Kopec connected us with Mercury Learning and introduced us to its publisher, David Pallai. Being a chess enthusiast, Dr. Gordon (one of the authors) was originally familiar with Dr. Kopec as a well-known international chess master and prolific chess book author. He was also a computer science professor, and his textbook, Artificial Intelligence in the 21st Century, inspired us to consider Mercury Learning for our book project. We had several telephone conversations with Dr. Kopec which were extremely informative. We were deeply saddened by Dr. Kopec’s untimely passing in 2016, and regret that he didn’t have the chance to see our books, which he had helped jump start, come to fruition.
Finally, we wish to thank David Pallai and Jennifer Blaney of Mercury Learning for their continued enthusiasm and support for this project and for guiding us through the textbook publishing process.
Errata
If you find any errors in our book, please let us know! Despite our best efforts, this book almost certainly contains mistakes. We will do our best to post corrections as soon as errors are reported to us. We have established a webpage for collecting errata and posting corrections:
http://ecs.csus.edu/~gordonvs/textJ3E.html
The publisher, Mercury Learning, also maintains a link to our errata page. So, if the URL for our errata page should ever change, check the Mercury Learning website for the latest link.
About the Authors
Dr. V. Scott Gordon has been a professor in the California State University system for over twenty-five years, and currently teaches advanced graphics and game engineering courses at CSU Sacramento. He has authored or coauthored over thirty publications in a variety of areas including artificial intelligence, neural networks, evolutionary computation, computer graphics, software engineering, video and strategy game programming, and computer science education. Dr. Gordon obtained his PhD at Colorado State University. He is also a jazz drummer and a competitive table tennis player.
Dr. John Clevenger has over forty years of experience teaching a wide variety of courses including advanced graphics, game architecture, operating systems, VLSI chip design, system simulation, and other topics. He is the developer of several software frameworks and tools for teaching graphics and game architecture, including the graphicslib3D library used in the first edition of our Java-based textbook. He is the technical director of the International Collegiate Programming Contest (ICPC), and oversees the ongoing development of PC^2, the most widely used programming contest support system in the world. Dr. Clevenger obtained his PhD at the University of California, Davis. He is also a performing jazz musician, and spends summer vacations in his mountain cabin.
References
[AS20]E. Angel and D. Shreiner, Interactive Computer Graphics: A Top-Down Approach with WebGL, 8th ed. (Pearson, 2020).
[JO21]JogAmp, accessed March 2021, http://jogamp.org
[KS16]J. Kessenich, G. Sellers, and D. Shreiner, OpenGL Programming Guide: The Official Guide to Learning OpenGL, Version 4.5 with SPIR-V, 9th ed. (Addison-Wesley, 2016).
[LU16]F. Luna, Introduction to 3D Game Programming with DirectX 12, 2nd ed. (Mercury Learning, 2016).
[LW21]Lightweight Java Game Library (LWJGL), accessed March 2021, https://www.lwjgl.org
[SW15]G. Sellers, R. Wright Jr., and N. Haemel, OpenGL SuperBible: Comprehensive Tutorialand Reference, 7th ed. (Addison-Wesley, 2015).
[WO18]D. Wolff, OpenGL 4 Shading Language Cookbook, 3rd ed. (Packt Publishing, 2018).
1 JavaScript is a scripting language that can be used to embed code in web pages. It has strong similarities to Java, but also many important differences.
CHAPTER1
GETTING STARTED
1.1Languages and Libraries
1.2Installation and Configuration
Graphics programming has a reputation for being among the most challenging computer science topics to learn. These days, graphics programming is shader based—that is, some of the program is written in a standard language such as Java or C++ for running on the CPU and some is written in a special-purpose shader language for running directly on the graphics card (GPU). Shader programming has a steep learning curve, so that even drawing something simple requires a convoluted set of steps to pass graphics data down a “pipeline.” Modern graphics cards are able to process this data in parallel, and so the graphics programmer must understand the parallel architecture of the GPU, even when drawing simple shapes.
The payoff, however, is extraordinary power. The blossoming of stunning virtual reality in videogames and increasingly realistic effects in Hollywood movies can be greatly attributed to advances in shader programming. If reading this book is your entrée into 3D graphics, you are taking on a personal challenge that will reward you not only with pretty pictures but with a level of control over your machine that you never imagined was possible. Welcome to the exciting world of computer graphics programming!
1.1LANGUAGES AND LIBRARIES
Modern graphics programming is done using a graphics library. That is, the programmer writes code which invokes functions in a predefined library (or set of libraries) that provide support for lower-level graphical operations. There are many graphics libraries in use today, but the most common library for platform-independent graphics programming is called OpenGL (OpenGraphicsLibrary). This book describes how to use OpenGL for 3D graphics programming in Java.
Using OpenGL with Java requires configuring several libraries. In this section, we describe which libraries are needed, some common options for each, and the option(s) that we will use throughout the book. Details on how to install and configure these libraries for your specific platform can be found in the appendices.
Running the programs in this book requires the following languages and libraries:
•Java
•OpenGL / GLSL
•JOGL
•JOML
It is likely that the reader will need to do a few preparatory steps to ensure that each of these are installed and properly accessible on his or her system. In the following subsections we briefly describe each of them; see the appendices for details on how to install and/or configure them for use.
1.1.1Java
Java was developed at Sun Microsystems in the early 1990s, and the first stable release of a development kit (JDK) occurred in 1995. In 2010, Oracle Corporation acquired Sun and has maintained Java since that time [OR21]. This book assumes Java version 11, which was released in 2018.
1.1.2OpenGL / GLSL
Version 1.0 of OpenGL appeared in 1992 as an “open” alternative to vendor-specific application programming interfaces (APIs) for computer graphics. Its specification and development was managed and controlled by the OpenGL Architecture Review Board (ARB), a then newly formed group of industry participants. In 2006 the ARB transferred control of the OpenGL specification to the Khronos Group, a nonprofit consortium which manages not only the OpenGL specification but a wide variety of other open industry standards.
Since its beginning OpenGL has been revised and extended regularly. In 2004, version 2.0 introduced the OpenGL Shading Language (GLSL), allowing “shader programs” to be installed and run directly in graphics pipeline stages.
In 2009, version 3.1 removed a large number of features that had been deprecated, to enforce the use of shader programming as opposed to earlier approaches (referred to as “immediate mode”).1 Among the more recent features, version 4.0 (in 2010) added a tessellation stage to the programmable pipeline.
This textbook assumes that the user is using a machine with a graphics card that supports at least version 4.3 of OpenGL. If you are not sure which version of OpenGL your GPU supports, there are free applications available on the web that can be used to find out. One such application is GLView, by a company named “realtech VR” [GV21].
1.1.3JOGL
JOGL (and the associated tool GlueGen) is a set of OpenGL bindings (sometimes called a “wrapper”) which provides a mechanism for invoking C-based OpenGL functions from Java code. JOGL first appeared in 2003, published on the website Java.net. Since 2010 it has been an independent open source project, part of a suite of Java bindings maintained by JogAmp [JO21], an online community of developers. As new versions of OpenGL and/or Java are released, new versions of JOGL are developed to support continued compatibility. This book assumes at least version 2.4 of JOGL.
1.1.4JOML
3D graphics programming makes heavy use of vector and matrix algebra. For this reason, use of OpenGL is greatly facilitated by an accompanying function library or class package to support common mathematical tasks. For example, the popular OpenGL SuperBible [SW15] utilizes a C library called “vmath”; in this book, we use a Java library called Java OpenGL Math Library, or JOML.
JOML provides classes and basic math functions related to graphics concepts, such as vector, matrix, and quaternion. It also contains a variety of utility classes for creating and using common 3D graphics structures, such as a stack for building hierarchical structures, perspective and look-at matrices, and a few basic shapes such as a rectangle and a sphere.
JOML was conceived in mid-2015 by Richard Greenlees and is an open source project currently being developed and maintained by Kai Burjack, who took over the project shortly after its inception. JOML has enjoyed widespread adoption because of its high-performance characteristics. JOML is specifically designed to maximize performance in an OpenGL render loop (animation).
The first edition of this book utilized our own in-house Java mathematics library called graphicslib3D. We hope that users of our first edition appreciate the better support and performance of JOML.
1.2INSTALLATION AND CONFIGURATION
We opted to separate installation and configuration information into individual platform-specific appendices. We hope that this will provide each reader with a single relevant place to look for information regarding his or her specific system, while at the same time avoiding bogging down the rest of the text with platform-specific details which may not be relevant to every reader. In this edition, we provide detailed configuration instructions for Microsoft Windows in Appendix A and for the Macintosh in Appendix B.
Continually updated library installation instructions will be maintained on this textbook’s website, available at: http://ecs.csus.edu/~gordonvs/textJ3E.html.
References
[GV21] GLView, accessed March 2021, https://www.realtech-vr.com/home/glview
[JO21] JogAmp, accessed March 2021, http://jogamp.org/
[OR21] Java Software, Oracle Corp., accessed March 2021, https://www.oracle.com/java/
[SW15] G. Sellers, R. Wright Jr., and N. Haemel, OpenGL SuperBible: ComprehensiveTutorial and Reference, 7th ed. (Addison-Wesley, 2015).
1 Despite this, many graphics card manufacturers (notably NVIDIA) continue to support deprecated functionality.
CHAPTER2
THE OPENGL GRAPHICS PIPELINE
2.1The OpenGL Pipeline
2.2Detecting OpenGL and GLSL Errors
2.3Reading GLSL Source Code from Files
2.4Building Objects from Vertices
2.5Animating a Scene
2.6Organizing the Java Code Files
Supplemental Notes
OpenGL (Open Graphics Library) is a multiplatform 2D and 3D graphics API that incorporates both hardware and software. Using OpenGL requires a graphics card (GPU) that supports a sufficiently up-to-date version of OpenGL (as described in Chapter 1).
On the hardware side, OpenGL provides a multistage graphics pipeline that is partially programmable using a language called GLSL (OpenGL Shading Language).
On the software side, OpenGL’s API is written in C, and thus the calls are directly compatible with C and C++. However, stable language bindings (or “wrappers”) are available for more than a dozen other popular languages (Java, Perl, Python, Visual Basic, Delphi, Haskell, Lisp, Ruby, etc.) with virtually equivalent performance. This textbook uses the popular Java wrapper JOGL (Java OpenGL). When using JOGL, the programmer writes a Java program that runs on the CPU (more specifically, on the Java Virtual Machine, or JVM) and includes JOGL (and thus, OpenGL) calls. We will refer to a Java program that contains JOGL calls as a Java/JOGLapplication. One important task of a Java/JOGL application is to install the programmer’s GLSL code onto the GPU.
An overview of a JOGL-based graphics application is shown in Figure 2.1, with the software components highlighted in pink.
Figure 2.1
Overview of a JOGL-based graphics application.
Some of the code we will write will be in Java, with JOGL calls, and some will be written in GLSL. Our Java/JOGL application will work together with our GLSL modules and the hardware to create our 3D graphics output. Once our application is complete, the end user will interact with the Java application.
GLSL is an example of a shader language. Shader languages are intended to run on a GPU in the context of a graphics pipeline. There are other shader languages, such as HLSL, which works with Microsoft’s 3D framework DirectX. GLSL is the specific shader language that is compatible with OpenGL, and thus we will write shader code in GLSL, in addition to our Java/JOGL application code.
For the rest of this chapter, we will take a brief “tour” of the OpenGL pipeline. The reader is not expected to understand every detail thoroughly, but just to get a feel for how the stages work together.
2.1THE OPENGL PIPELINE
Modern 3D graphics programming utilizes a pipeline, in which the process of converting a 3D scene to a 2D image is broken down into a series of steps. OpenGL and DirectX both utilize similar pipelines.
A simplified overview of the OpenGL graphics pipeline is shown in Figure 2.2 (not every stage is shown, just the major ones we will study). The Java/JOGL application sends graphics data into the vertex shader, processing proceeds through the pipeline, and pixels emerge for display on the monitor.
The stages shaded in blue (vertex, tessellation, geometry, and fragment) are programmable in GLSL. It is one of the responsibilities of the Java/JOGL application to load GLSL programs into these shader stages, as follows:
1.It uses Java to obtain the GLSL shader code, either from text files or hardcoded as strings.
2.It then creates OpenGL shader objects, and loads the GLSL shader code into them.
3.Finally, it uses OpenGL commands to compile and link objects and install them on the GPU.
In practice, it is usually necessary to provide GLSL code for at least the vertex and fragment stages, whereas the tessellation and geometry stages are optional. Let’s walk through the entire process and see what takes place at each step.
Figure 2.2
Overview of the OpenGL pipeline.
2.1.1Java/JOGL Application
The bulk of our graphics application is written in Java. Depending on the purpose of the program, it may interact with the end user using standard Java libraries such as AWT or Swing. For tasks related to 3D rendering, it uses the JOGL library. Other windowing libraries exist that interface with JOGL, such as SWT and NEWT, that have some performance advantages; in this book, however, we use AWT and Swing because of the likelihood the reader already has familiarity with them.
JOGL includes a class called GLCanvas that is compatible with the standard Java JFrame, and on which we can draw 3D scenes. As already mentioned, JOGL also gives us commands for installing GLSL programs onto the programmable shader stages and compiling them. Finally, JOGL uses buffers for sending 3D models and other related graphics data down the pipeline.
Before we try writing shaders, let’s write a simple Java/JOGL application that instantiates a GLCanvas and sets its background color. Doing that won’t require any shaders at all! The code is shown in Program 2.1. It extends JFrame and instantiates a GLCanvas, adding it to the JFrame. It also implements GLEventListener, required to utilize OpenGL—this necessitates implementing some methods, specifically display(), init(), reshape(), and dispose(). The display() method is where we place code that draws to the GLCanvas. In this example, we use the glClearColor() command to specify the color value to be applied when clearing the background—in this case (1,0,0,1), corresponding to the RGB values of the color red, plus a “1” for the opacity component. We then use the OpenGL call glClear(GL_COLOR_BUFFER_BIT) to actually fill the color buffer with that color.
Program 2.1 First Java/JOGL Application
When running a Java/JOGL application (such as Program 2.1) on a Microsoft Windows machine, it is advisable to add command-line options to disable the use of Direct3D acceleration and to disable UI scaling, as follows:
java -Dsun.java2d.d3d=false-Dsun.java2d.uiScale=1 Code
The mechanism by which these functions are deployed is as follows: When a GLCanvas is made “visible” (by our calling “setVisible(true)” on the JFrame that contains it), it initializes OpenGL, which in turn creates a “GL4” object that our application can use for making OpenGL function calls. OpenGL then does a “callback,” calling init(), and passes it a “drawable” object (in this case the drawable object is the GLCanvas, although that isn’t obvious from the code). In this particular example, init() doesn’t do anything—in most applications it is where we would read in GLSL code, load 3D models, and so on. OpenGL (actually, JOGL) next calls display(), also sending it the drawable object. It is typical to immediately obtain the GL4 object and put it in a variable called “gl” (actually, GL4 is an interface—in practice we don’t need to know the actual GL object class).
Figure 2.3
Output of Program 2.1.
Later we will see that if we want our scene to be animated, our Java/JOGL application will need to tell JOGL to make additional calls to display().
Now is an appropriate time to take a closer look at JOGL calls in Program 2.1. Consider this one:
gl.glClear(GL_COLOR_BUFFER_BIT);
Since JOGL is a Java binding for OpenGL, that means that calls to JOGL in turn generate calls to OpenGL’s library of C functions. In this case, the C function being called, as described in the OpenGL reference documentation (available on the web at https://www.khronos.org/registry/OpenGL-Refpages/gl4/) is:
void glClear(GLbitfield mask);
The first thing to notice is that the name of the JOGL function is the same as that of the original OpenGL C function, except it is preceded by “gl.”—which is the name of the GL4 object. The period “.” after the “gl” is significant because “gl” is the object on which we are invoking the OpenGL function.
To reiterate, GL4 is a Java interface to the OpenGL functions. We can obtain it in one of two ways: (a) by calling drawable.getGL(), utilizing the “GLAutoDrawable” object provided automatically when the various GLEventListener functions are invoked (called back) by OpenGL, or (b) by calling GLContext.getCurrentGL() as done in Program 2.1. Obtaining the current GL4 object is important because, in general, any OpenGL function described in the OpenGL documentation can be called from JOGL by preceding it with the name of the appropriate GL4 object (such as “gl.” here).
The parameter references a “GLbitfield” called “GL_COLOR_BUFFER_BIT”; OpenGL has many predefined constants (some of them are called enums), and this one references the color buffer that contains the pixels as they are rendered. OpenGL has several color buffers, and this command clears all of them—that is, it fills them with a predefined color called the “clear color.” Note that “clear” in this context doesn’t mean “a color that is clear”; rather, it refers to the color that is applied when a color buffer is reset (cleared).
Immediately before the call to glClear() is the call to glClearColor(). Again, this specifies the value placed in the elements of a color buffer when it is cleared. Here we have specified (1,0,0,1), which corresponds to the RGBA color red. If a “clear color” isn’t specified, the default value is black.
Finally, besides display() and init(), we also must implement reshape() and dispose(). The reshape() function is called when a GLCanvas is resized, and dispose() is called when the application exits. In Program 2.1 we left them both empty.
2.1.2Vertex and Fragment Shaders
Our first JOGL program didn’t actually draw anything—it simply filled the color buffer with a single color. To actually draw something, we need to include a vertex shader and a fragment shader.
You may be surprised to learn that OpenGL is capable of drawing only a few kinds of very simple things, such as points, lines, or triangles. These simple things are called primitives, and for this reason, most 3D models are made up of lots and lots of primitives, usually triangles.
Primitives are made up of vertices—for example, a triangle consists of three vertices. The vertices can come from a variety of sources—they can be read from files and then loaded into buffers by the Java/JOGL application, or they can be hardcoded in the Java code or even in the GLSL code.
Before any of this can happen, the Java/JOGL application must compile and link appropriate GLSL vertex and fragment shader programs, and then load them into the pipeline. We will see the commands for doing this shortly.
The application also is responsible for telling OpenGL to construct triangles. We do this by using JOGL to call the following OpenGL function:
glDrawArrays(GLenum mode, GLint first, GLsizei count);
The mode is the type of primitive—for triangles we use GL_TRIANGLES. The parameter “first” indicates which vertex to start with (generally vertex number 0, the first one), and count specifies the total number of vertices to be drawn.
When glDrawArrays() is called, the GLSL code in the pipeline starts executing. Let’s now add some GLSL code to that pipeline.
Regardless of where they originate, all of the vertices pass through the vertex shader. They do so one-by-one; that is, the shader is executed once per vertex. For a large and complex model with a lot of vertices, the vertex shader may execute hundreds, thousands, or even millions of times, often in parallel.
Let’s write a simple program with only one vertex, hardcoded in the vertex shader. That’s not enough to draw a triangle, but it is enough to draw a point. For it to display, we also need to provide a fragment shader. For simplicity we will declare the two shader programs as arrays of strings.
Program 2.2 Shaders, Drawing a POINT
Figure 2.4
Output of Program 2.2.
The program appears to have output a blank canvas. But close examination reveals a tiny blue dot in the center of the window (assuming that this printed page is of sufficient resolution). The default size of a point in OpenGL is one pixel.
There are many important details in Program 2.2 (color-coded in the program, for convenience) for us to discuss. First, note that init() is no longer empty—it now calls another function named “createShaderProgram()” (that we wrote). This function starts by declaring two shaders as arrays of strings called vshaderSource and fshaderSource. It then calls glCreateShader(), which generates the desired type of shader (note the predefined value GL_VERTEX_SHADER, and then later GL_FRAGMENT_SHADER). OpenGL creates the shader object (initially empty), and returns an integer ID that is an index for referencing it later—the code stores this ID in the variable vShader (and fShader). It then calls glShaderSource(), which loads the GLSL code from the string array into the empty shader object. glShaderSource() has five parameters: (a) the shader object in which to store the shader, (b) the number of strings in the shader source code, (c) the array of strings containing the source code, and two additional parameters we aren’t using (they will be explained later, in the supplementary chapter notes). Note also that the two commented lines of code in the blue section, highlighting the parameter values 3 and 4, refer to the number of lines of code in each shader (the \n’s delineate each line in the shader source code). The shaders are then each compiled using glCompileShader().
The application then creates a program object named vfprogram and saves the integer ID that points to it. An OpenGL “program” object contains a series of compiled shaders, and here we see the commands glCreateProgram() to create the program object, glAttachShader() to attach each of the shaders to it, and then glLinkProgram() to request that the GLSL compiler ensure that they are compatible.
After init() finishes, display() is called automatically (recall this is also a JOGL callback). One of the first things that display() does is call glUseProgram(), which loads the program containing the two compiled shaders into the OpenGL pipeline stages (onto the GPU!). Note that glUseProgram()doesn’t run the shaders; it just loads them onto the hardware.
As we will see later in Chapter 4, ordinarily at this point the Java/JOGL program would prepare the vertices of the model being drawn for sending down the pipeline. But not in this case, because for our first shader program we simply hardcoded a single vertex in the vertex shader. Therefore in this example the display() function next proceeds to the glDrawArrays() call, which initiates pipeline processing. The primitive type is GL_POINTS, and there is just one point to display.
Now let’s look at the shaders themselves, shown in green earlier (and duplicated ahead). As we saw, they have been declared in the Java/JOGL program as arrays of strings. This is a clumsy way to code, but it is sufficient in this very simple case. The vertex shader is:
#version 430
void main(void)
The first line indicates the OpenGL version, in this case 4.30. There follows a “main” function (as we will see, GLSL is somewhat Java-like in syntax). The primary purpose of any vertex shader is to send a vertex down the pipeline (which, as mentioned before, it does for every vertex). The built-in variable gl_Position is used to set a vertex’s coordinate position in 3D space and is sent to the next stage in the pipeline. The GLSL datatype vec4 is used to hold a 4-tuple, suitable for such coordinates, with the associated four values representing X, Y, Z, and a fourth value set here to 1.0 (we will learn the purpose of this fourth value in Chapter 3). In this case, the vertex is hardcoded to the origin location (0,0,0).
The vertices move through the pipeline to the rasterizer, where they are transformed into pixel locations (or more accurately, fragments—described later). Eventually, these pixels (fragments) reach the fragment shader:
#version 430
out vec4 color;
void main(void)
The purpose of any fragment shader is to set the RGB color of a pixel to be displayed. In this case the specified output color (0, 0, 1) is blue (the fourth value 1.0 specifies the level of opacity). Note the “out” tag indicating that the variable color is an output. (It wasn’t necessary to specify an “out” tag for gl_Position in the vertex shader, because gl_Position is a predefined output variable.)
There is one detail in the code that we haven’t discussed, in the last two lines in the init() function (shown in red). They probably appear a bit cryptic. As we will see in Chapter 4, when sets of data are prepared for sending down the pipeline, they are organized into buffers. Those buffers are in turn organized into Vertex Array Objects (VAOs). In our example, we hardcoded a single point in the vertex shader, so we didn’t need any buffers. However, OpenGL still requires at least one VAO to be created whenever shaders are being used, even if the application isn’t using any buffers. So the two lines create the required VAO.
Finally, there is the issue of how the vertex that came out of the vertex shader became a pixel in the fragment shader. Recall from Figure 2.2 that between vertex processing and pixel processing is the rasterization stage. It is there that primitives (such as points or triangles) are converted into sets of pixels. The default size of an OpenGL “point” is one pixel, so that is why our single point was rendered as a single pixel.
Figure 2.5
Changing glPointSize.
Let’s add the following command in display(), right before the glDrawArrays() call:
gl.glPointSize(30.0f);
Now, when the rasterizer receives the vertex from the vertex shader, it will set pixel color values that form a point having a size of 30 pixels. The resulting output is shown in Figure 2.5.
Let’s now continue examining the remainder of the OpenGL pipeline.
2.1.3Tessellation
We cover tessellation in Chapter 12. The programmable tessellation stage is one of the most recent additions to OpenGL (in version 4.0). It provides a tessellator that can generate a large number of triangles, typically as a grid, and also some tools to manipulate those triangles in a variety of ways. For example, the programmer might manipulate a tessellated grid of triangles as shown in Figure 2.6.
Tessellation is useful when a lot of vertices are needed on what is otherwise a simple shape, such as on a square area or curved surface. It is also very useful for generating complex terrain, as we will see later. In such instances, it is sometimes much more efficient to have the tessellator in the GPU generate the triangle mesh in hardware, rather than doing it in Java.
Figure 2.6
Grid produced by tessellator.
2.1.4Geometry Shader
We cover the geometry shader stage in Chapter 13. Whereas the vertex shader gives the programmer the ability to manipulate one vertex at a time (i.e., “per-vertex” processing), and the fragment shader (as we will see) allows manipulating one pixel at a time (“per-fragment” processing), the geometry shader provides the capability to manipulate one primitive at a time—“per-primitive” processing.
Recalling that the most common primitive is the triangle, by the time we have reached the geometry stage, the pipeline must have completed grouping the vertices into triangles (a process called primitive assembly). The geometry shader then makes all three vertices in each triangle accessible to the programmer simultaneously.
There are a number of uses for per-primitive processing. The primitives could be altered, such as by stretching or shrinking them. Some of the primitives could be deleted, thus putting “holes” in the object being rendered—this is one way of turning a simple model into a more complex one.
The geometry shader also provides a mechanism for generating additional primitives. Here, too, this opens the door to many possibilities for turning simple models into more complex ones.
An interesting use for the geometry shader is adding surface texture such as bumps or scales—even “hair” or “fur”—to an object. Consider for example, the simple torus shown in Figure 2.7 (we will see how to generate this later in the book). The surface of this torus is built out of many hundreds of triangles. If at each triangle, we use a geometry shader to add additional triangles that face outward, we get the result shown in Figure 2.8. This “scaly torus” would be computationally expensive to try and model from scratch in the Java/JOGL application side.
Figure 2.7
Torus model.
Figure 2.8
Torus modified in geometry shader.
It might seem redundant to provide a per-primitive shader stage, when the tessellation stage(s) give the programmer access to all of the vertices in an entire model simultaneously. The difference is that tessellation only offers this capability in very limited circumstances—specifically when the model is a grid of triangles generated by the tessellator. It does not provide such simultaneous access to all the vertices of, say, an arbitrary model being sent in from Java through a buffer.
2.1.5Rasterization
Ultimately, our 3D world of vertices, triangles, colors, and so on needs to be displayed on a 2D monitor. That 2D monitor screen is made up of a raster—a rectangular array of pixels.
When a 3D object is rasterized, OpenGL converts the primitives in the object (usually triangles) into fragments. A fragment holds the information associated with a pixel. Rasterization determines the locations of pixels that need to be drawn in order to produce the triangle specified by its three vertices.
Figure 2.9
Rasterization (step 1).
Rasterization starts by interpolating, pairwise, between the three vertices of the triangle. There are some options for doing this interpolation; for now it is sufficient to consider simple linear interpolation as shown in Figure 2.9. The original three vertices are shown in red.
If rasterization were to stop here, the resulting image would appear as wireframe. This is an option in OpenGL, by adding the following command in the display() function, before the call to glDrawArrays():
gl.glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
If the torus shown previously in Section 2.1.4 is rendered with the addition of this line of code, it appears as shown in Figure 2.10.
Figure 2.10
Torus with wireframe rendering.
If we didn’t insert the preceding line of code (or if GL_FILL had been specified instead of GL_LINE), interpolation would continue along raster lines and fill the interior of the triangle, as shown in Figure 2.11. When applied to the torus, this results in the fully rasterized or “solid” torus shown in Figure 2.12 (on the left). Note that in this case the overall shape and curvature of the torus is not evident—that is because we haven’t included any texturing or lighting techniques, so it appears “flat.” At the right, the same “flat” torus is shown with the wireframe rendering superimposed. The torus shown earlier in Figure 2.7 included lighting effects, and thus revealed the shape of the torus much more clearly. We will study lighting in Chapter 7.
Figure 2.11
Fully rasterized triangle.
As we will see in later chapters, the rasterizer can interpolate more than just pixels. Any variable that is output by the vertex shader and input by the fragment shader will be interpolated based on the corresponding pixel position. We will use this capability to generate smooth color gradations, realistic lighting, and many more effects.
Figure 2.12
Torus with fully rasterized primitives (left) and with wireframe grid superimposed (right).
2.1.6Fragment Shader
Tausende von E-Books und Hörbücher
Ihre Zahl wächst ständig und Sie haben eine Fixpreisgarantie.
Sie haben über uns geschrieben: