0% found this document useful (0 votes)
16 views82 pages

CEN 515-New

The document provides a comprehensive introduction to OpenGL and computer graphics, detailing its history, key components, and programming techniques. It covers essential concepts such as 2D and 3D graphics, vertex buffers, user interaction, and visual effects, along with practical programming examples. Additionally, it includes exercises and solutions for implementing basic graphics tasks using modern OpenGL techniques.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views82 pages

CEN 515-New

The document provides a comprehensive introduction to OpenGL and computer graphics, detailing its history, key components, and programming techniques. It covers essential concepts such as 2D and 3D graphics, vertex buffers, user interaction, and visual effects, along with practical programming examples. Additionally, it includes exercises and solutions for implementing basic graphics tasks using modern OpenGL techniques.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 82

CEN 515

COMPUTER
GRAPHICS
Understanding OpenGL
and Computer Graphics
A Comprehensive
Introduction

• What is OpenGL?
• Open Graphics Library (OpenGL)
is a cross-platform API for
rendering 2D and 3D graphics
• Developed by Silicon Graphics Inc.
in 1992
• Industry standard for graphics
programming
• Used in: video games, CAD
software, scientific visualization,
VR applications
Understanding
Computer Graphics:
The Basics
• 2D Graphics
• Like drawing on paper
• Flat images made of pixels
• Examples: icons, buttons, 2D games
• 3D Graphics
• Like sculpting in virtual space
• Objects with depth and volume
• Must be converted to 2D for display
How Screens
Display Graphics
• The Reality of Screens
• Screens are flat surfaces made of
pixels
• Each pixel shows one color at a time
• Arranged in a grid pattern
• Creating the 3D Illusion
1.Perspective (smaller = farther)
2.Shading and shadows
3.Overlapping objects
4.Color and contrast variations
OpenGL
Programming
Devices
• Key Components
1.Graphics Processing Unit (GPU)
1. Specialized processor for graphics
calculations
2. Parallel processing capabilities
3. Optimized for matrix and vector
operations
2.Frame Buffer
1. Temporary storage for rendered
images
2. Like a digital canvas
3. Holds pixel data before display
3.Display Device
1. Monitor or screen
2. Converts digital data to visible pixels
Understanding
Vertex Buffers
What is a Vertex?
• A point in 3D space
• Contains position information
• May include other data (color, texture coordinates)
• Vertex Buffer Example
// Create and bind buffer
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
// Define triangle coordinates
float vertices[] = {
-0.5f, -0.5f, 0.0f, // Bottom left
0.5f, -0.5f, 0.0f, // Bottom right
0.0f, 0.5f, 0.0f // Top
};
Core OpenGL
Concepts
• Vertex Arrays and VBOs
• Efficient storage of geometric data
• Reduces data transfer time
• Optimizes memory usage
• Vertex Array Objects (VAOs)
• Encapsulates vertex array
configuration
• Stores attribute settings
• Simplifies state management
User Interaction
in OpenGL
Mouse Programming

void mouseClick(int button, int state, int x, int y) {


if (button == GLUT_LEFT_BUTTON && state ==
GLUT_DOWN) {
// Handle left click
}
}
glutMouseFunc(mouseClick);

• Menus and Input


• Pop-up menu creation
• Keyboard input handling
• Custom interaction systems
Visual Effects
and
Rendering
• Line Stipples
• Create dashed or dotted
lines
• Customizable patterns
• Used for special effects
• Clipping Planes
• Control visibility of objects
• Create cross-section views
• Additional to standard
view frustum
View Management

Viewports

Define rendering areas

Multiple views possible

Custom screen layouts

Multiple Windows

Separate OpenGL contexts

Independent view management

Complex application interfaces


An OpenGL
Toolbox

• Frequently-used
OpenGL programming
devices
1. Vertex Arrays and Drawing
Commands
• Understanding Vertex Arrays
• A vertex array is a contiguous
block of memory containing
vertex data
• More efficient than immediate
mode rendering
• Reduces function call overhead

• Key Benefits
• Reduced API calls
• Better performance
• More organized code structure

• Implementation Example
// Define vertex data
GLfloat vertices[] = {
// x, y, z coordinates for a triangle
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};

// Enable vertex arrays


glEnableClientState(GL_VERTEX_ARRAY);

// Specify vertex array


glVertexPointer(3, GL_FLOAT, 0, vertices);

// Draw triangle
glDrawArrays(GL_TRIANGLES, 0, 3);

// Disable vertex arrays


glDisableClientState(GL_VERTEX_ARRAY);
2. Vertex Buffer Objects (VBOs)
• What are VBOs?
• Store vertex data in high-performance
graphics memory
• Reduce data transfer between CPU and
GPU
• Optimal for static geometry

• Performance Considerations
• Use GL_STATIC_DRAW for unchanging
data
• GL_DYNAMIC_DRAW for frequently
updated data
• Creating and Using VBOs
// Generate and bind a VBO
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

// Upload data to VBO


GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

// Set up vertex attributes


glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
Visual
Representati
on of Vertex
Buffer
Memory
This diagram shows how vertex data is stored in GPU
memory:
• Each block represents a vertex with its attributes
• Data is stored contiguously for efficient access
• Memory addresses show the linear layout
3. Vertex Array Objects (VAOs)

• Understanding VAOs
• Stores vertex attribute configurations
• Reduces state changes
• Simplifies rendering code
• Implementation
// Create and bind VAO
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);

// Set up vertex buffer and attributes (stored in VAO)


GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

// Specify vertex attributes


glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);

// Later, to draw:
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
4. Display Lists

• Purpose of Display Lists


• Store sequences of OpenGL
commands
• Optimize frequently used rendering
operations
• Reduce CPU overhead
• Creating Display Lists
// Create a display list
GLuint listID = glGenLists(1);
glNewList(listID, GL_COMPILE);

// Add commands to the list


glBegin(GL_TRIANGLES);
glVertex3f(-0.5f, -0.5f, 0.0f);
glVertex3f( 0.5f, -0.5f, 0.0f);
glVertex3f( 0.0f, 0.5f, 0.0f);
glEnd();

glEndList();

// Use the display list


glCallList(listID);
5. Drawing Text

• Text Rendering Methods


1.Bitmap fonts
2.Vector fonts
3.Texture-based fonts

• Example Using GLUT Bitmap Fonts


void renderText(float x, float y, const char *text) {
glRasterPos2f(x, y);

for (const char* c = text; *c != '\0'; c++) {


glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18,
*c);
}
}

// Usage in display function


void display() {
glClear(GL_COLOR_BUFFER_BIT);
renderText(-0.5f, 0.0f, "Hello OpenGL!");
glutSwapBuffers();
}
6. Mouse Programming

• Mouse Event Handling


• Button clicks
• Mouse movement
• Scroll wheel
• Implementation
void mouseButton(int button, int state, int x, int y) {

if (button == GLUT_LEFT_BUTTON) {

if (state == GLUT_DOWN) {

// Handle left click

} else if (button == GLUT_RIGHT_BUTTON) {

if (state == GLUT_DOWN) {

// Handle right click

void mouseMotion(int x, int y) {

// Handle mouse movement

void mouseWheel(int button, int dir, int x, int y) {

if (dir > 0) {

// Scroll up

} else {

// Scroll down

// Register callbacks

glutMouseFunc(mouseButton);

glutMotionFunc(mouseMotion);

glutMouseWheelFunc(mouseWheel);
7. Programming Non-
ASCII Keys

• Special Key Handling


• Function keys
• Arrow keys
• Modifier keys
• Implementation
void specialKeys(int key, int x, int y) {
switch(key) {
case GLUT_KEY_LEFT:
// Handle left arrow
break;
case GLUT_KEY_RIGHT:
// Handle right arrow
break;
case GLUT_KEY_F1:
// Handle F1 key
break;
}
glutPostRedisplay();
}

// Register callback
glutSpecialFunc(specialKeys);
8. Programming Pop-up Menus

• Creating Context Menus


• Menu hierarchy
• Menu callbacks
• Menu attachment
• Implementation
void menuCallback(int value) {
switch(value) {
case 1:
// Handle option 1
break;
case 2:
// Handle option 2
break;
}
glutPostRedisplay();
}
void createMenus() {
// Create submenu
int subMenu = glutCreateMenu(menuCallback);
glutAddMenuEntry("Sub Option 1", 11);
glutAddMenuEntry("Sub Option 2", 12);

// Create main menu


int mainMenu = glutCreateMenu(menuCallback);
glutAddMenuEntry("Option 1", 1);
glutAddMenuEntry("Option 2", 2);
glutAddSubMenu("Sub Menu", subMenu);
// Attach to right mouse button
9. Line Stipples

• Creating Patterned Lines


• Pattern definition
• Repeat factor
• Enable/disable stippling
• Implementation
// Enable line stipple
glEnable(GL_LINE_STIPPLE);

// Set stipple pattern (dashed line)


glLineStipple(1, 0x00FF); // Pattern: 1111 1111 0000 0000

// Draw stippled line


glBegin(GL_LINES);
glVertex2f(-0.5f, 0.0f);
glVertex2f(0.5f, 0.0f);
glEnd();

// Disable line stipple


glDisable(GL_LINE_STIPPLE);
10. FreeGLUT Objects

• Built-in Shapes
• Geometric primitives
• Complex objects
• Utility functions

• Using FreeGLUT
Objects
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Draw a wire cube


glutWireCube(1.0);

// Draw a solid sphere


glutSolidSphere(0.5, 20, 20);

// Draw the famous teapot


glutSolidTeapot(0.6);

glutSwapBuffers();
}
11. Clipping Planes

• Additional Clipping Planes


• Define custom clipping
boundaries
• Multiple simultaneous
planes
• Dynamic updates

• Implementation
// Define clipping plane
GLdouble equation[] = {1.0, 0.0, 0.0, 0.0}; // x = 0
plane

// Enable additional clipping plane


glEnable(GL_CLIP_PLANE0);
glClipPlane(GL_CLIP_PLANE0, equation);

// Draw objects (they will be clipped)


// ...

// Disable clipping plane


glDisable(GL_CLIP_PLANE0);
12. Using gluPerspective

• Intuitive Camera Setup


• Field of view
• Aspect ratio
• Near and far planes

• Implementation
void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

// Set up perspective projection


gluPerspective(
45.0, // Field of view in degrees
(float)w/h, // Aspect ratio
0.1, // Near clipping plane
100.0 // Far clipping plane
);

glMatrixMode(GL_MODELVIEW);
}
Viewing
Frustum
Visualization
• Key elements shown:
• Camera position at
apex
• Near and far clipping
planes
• Field of View (FOV)
angle
• Objects within viewing
volume
13. Viewports

• Multiple Views
• Split screen effects
• Custom view regions
• Mini-maps

• Implementation
void display() {
glClear(GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT);

// Main viewport (full window)


glViewport(0, 0, width, height);
// Draw main scene

// Mini-map viewport (top-right


corner)
glViewport(width-200, height-200,
200, 200);
// Draw mini-map

glutSwapBuffers();
}
Understanding
Viewports and
Windows
The diagram illustrates:
• Main viewport for
primary rendering
• Mini-map viewport in
corner
• Coordinate system
orientation
• Relative positioning of
viewports
14. Multiple Windows

• Managing Multiple Windows


• Independent contexts
• Window management
• Inter-window communication

• Implementation
int window1, window2;
void display1() {
glutSetWindow(window1);
// Draw in window 1
}
void display2() {
glutSetWindow(window2);
// Draw in window 2
}
int main(int argc, char** argv) {
glutInit(&argc, argv);

// Create first window


glutInitWindowPosition(100, 100);
window1 = glutCreateWindow("Window 1");
glutDisplayFunc(display1);

// Create second window


glutInitWindowPosition(500, 100);
window2 = glutCreateWindow("Window 2");
glutDisplayFunc(display2);

glutMainLoop();
Exercises
• Exercise 1: Basic Triangle Rendering
• Create a program that displays a
colored triangle in the center of the
window. The triangle should rotate
continuously.
• Requirements:
• Use modern OpenGL (3.3+)
• Implement vertex and fragment
shaders
• Use VBOs and VAOs
• Implement rotation using
Solution (Setting up our shaders)
• // Vertex Shader
• const char* vertexShaderSource = R"(
• #version 330 core
• layout (location = 0) in vec3 aPos; // Position attribute
• layout (location = 1) in vec3 aColor; // Color attribute
• out vec3 vertexColor; // Output to fragment shader
• uniform mat4 transform; // Transformation matrix

• void main() {
• gl_Position = transform * vec4(aPos, 1.0);
• vertexColor = aColor;
• }
• )";

• // Fragment Shader
• const char* fragmentShaderSource = R"(
• #version 330 core
• in vec3 vertexColor;
• out vec4 FragColor;

• void main() {
• FragColor = vec4(vertexColor, 1.0);
• }
• )";
Main Program
• class RotatingTriangle {

private:
GLuint VBO, VAO;
GLuint shaderProgram;
float rotationAngle = 0.0f;

public:
void init() {
// Define vertex data with positions and colors
float vertices[] = {
// Positions // Colors
-0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // Bottom left - Red
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // Bottom right - Green
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f // Top - Blue
};
// Create and bind Vertex Array Object
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
Main Program – Contd
// Create and bind Vertex Buffer Object
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices,GL_STATIC_DRAW);

// Set vertex position attribute


glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

// Set vertex color attribute


glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float),
(void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);

// Create and compile shaders


shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource);
}
void render() {
glUseProgram(shaderProgram);

// Update rotation
rotationAngle += 0.01f;
// Create rotation matrix
glm::mat4 transform = glm::mat4(1.0f);
transform = glm::rotate(transform, rotationAngle, glm::vec3(0.0f, 0.0f, 1.0f));

// Pass transformation matrix to shader


unsigned int transformLoc = glGetUniformLocation(shaderProgram,
"transform");
glUniformMatrix4fv(transformLoc, 1, GL_FALSE, glm::value_ptr(transform));

// Draw the triangle


glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
void cleanup() {
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram); }
};
Drawing
• Create a program that allows users
to draw different shapes using
keyboard input.
• Requirements:
• Press '1' for triangle
• Press '2' for square
• Press '3' for circle (approximated
with triangle fan)
• Press 'c' to change colors
• Use mouse position to place shapes
• Hints:
• Store shape vertices in separate VBOs
• Implement color as a uniform
variable
Solution
class ShapeDrawer {
private:
GLuint VBO, VAO;
GLuint shaderProgram;
std::vector<Shape> shapes;
glm::vec3 currentColor;
glm::vec2 mousePos;

struct Shape {
std::vector<float> vertices;
GLenum drawMode;
int vertexCount;
};
public:
void init() {
// Initialize shapes
createShapes();
// Create and set up shaders (similar to Exercise 1)
shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource);

// Create buffers
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);

// Set initial color


currentColor = glm::vec3(1.0f, 0.0f, 0.0f);
}
void createShapes() {
// Create triangle
Shape triangle;
triangle.vertices = {
-0.1f, -0.1f, 0.0f,
0.1f, -0.1f, 0.0f,
0.0f, 0.1f, 0.0f
};
triangle.drawMode = GL_TRIANGLES;
triangle.vertexCount = 3;
shapes.push_back(triangle);
// Create square
Shape square;
square.vertices = {
-0.1f, -0.1f, 0.0f,
0.1f, -0.1f, 0.0f,
0.1f, 0.1f, 0.0f,
-0.1f, 0.1f, 0.0f
};
square.drawMode = GL_TRIANGLE_FAN;
square.vertexCount = 4;
shapes.push_back(square);
// Create circle (approximated with triangle fan)
Shape circle;
const int segments = 32;
circle.vertices.push_back(0.0f); // Center point
circle.vertices.push_back(0.0f);
circle.vertices.push_back(0.0f);
for(int i = 0; i <= segments; i++) {
float angle = 2.0f * M_PI * i / segments;
circle.vertices.push_back(0.1f * cos(angle));
circle.vertices.push_back(0.1f * sin(angle));
circle.vertices.push_back(0.0f);
}
circle.drawMode = GL_TRIANGLE_FAN;
circle.vertexCount = segments + 2;
shapes.push_back(circle);
}
void handleInput(char key) {
switch(key) {
case '1': // Triangle
case '2': // Square
case '3': // Circle
int shapeIndex = key - '1’;
if(shapeIndex >= 0 && shapeIndex < shapes.size()) { updateCurrentShape(shapes[shapeIndex]);
}
break;
case 'c’:
randomizeColor();
break;
}
}
void setMousePosition(float x, float y) {
// Convert screen coordinates to OpenGL coordinates
mousePos.x = (2.0f * x) / windowWidth - 1.0f;
mousePos.y = 1.0f - (2.0f * y) / windowHeight;
}

void render() {
glUseProgram(shaderProgram);

// Set color uniform


int colorLoc = glGetUniformLocation(shaderProgram, "color");
glUniform3fv(colorLoc, 1, glm::value_ptr(currentColor));

// Set position uniform


int posLoc = glGetUniformLocation(shaderProgram, "offset");
glUniform2fv(posLoc, 1, glm::value_ptr(mousePos));

// Draw current shape


glBindVertexArray(VAO);
glDrawArrays(currentShape.drawMode, 0, currentShape.vertexCount);
}
};
• Exercise 3: Texture Mapping
• Create a textured cube that
responds to user input for
rotation.

• Requirements:
• Load and apply a texture to
cube faces
• Implement perspective
projection
• Add mouse-controlled
rotation
• Include depth testing
Solution
class TexturedCube {
private:
GLuint VBO, VAO, EBO;
GLuint texture;
GLuint shaderProgram;
glm::mat4 projection;
float rotation = 0.0f;

// Vertex shader source


const char* vertexShaderSource = R"(
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;

out vec2 TexCoord;

uniform mat4 model;


uniform mat4 view;
uniform mat4 projection;

void main() {
gl_Position = projection * view * model * vec4(aPos, 1.0);
TexCoord = aTexCoord;
}
)";
// Fragment shader source
const char* fragmentShaderSource = R"(
#version 330 core
out vec4 FragColor;

in vec2 TexCoord;
uniform sampler2D ourTexture;
void main() {
FragColor = texture(ourTexture, TexCoord);
}
)";
public:
void init() {
// Set up vertex data for a cube with texture coordinates
float vertices[] = {
// positions // texture coords
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
// ... (remaining vertices for all six faces)
};
unsigned int indices[] = {
0, 1, 2, // first triangle
2, 3, 0, // second triangle
// ... (remaining indices for all faces)
};
// Create and bind VAO
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

// Create and bind VBO


glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

// Create and bind EBO


glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

// Set vertex attributes


// Position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);

// Texture coordinate attribute


glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float),
(void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// Load and create texture
loadTexture("texture.jpg");
// Create shader program
shaderProgram createShaderProgram(vertexShaderSource,fragmentShaderSource);
// Set up projection matrix
projection = glm::perspective(glm::radians(45.0f), 800.0f/600.0f, 0.1f, 100.0f);
}
void loadTexture(const char* path) {
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

// Set texture wrapping/filtering options


glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

// Load image data


int width, height, nrChannels;
stbi_set_flip_vertically_on_load(true);
unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,
GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}

stbi_image_free(data);
}
void render() {
glEnable(GL_DEPTH_TEST);
glUseProgram(shaderProgram);

// Create transformations
glm::mat4 model = glm::mat4(1.0f);
model = glm::rotate(model, rotation, glm::vec3(0.5f, 1.0f, 0.0f));
rotation += 0.01f;
glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -3.0f));

// Pass transformation matrices to shader


glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE,
glm::value_ptr(model));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE,
glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE,
glm::value_ptr(projection));

// Bind texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
// Render cube
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
}
};
• Exercise 4: Multiple Viewport
Scene

• Create a program that shows the


same scene from different
viewpoints using multiple
viewports.

• Requirements:
• Main viewport: Perspective view
• Top-right viewport: Top-down
view
• Bottom-right viewport: Side view
• Allow switching active viewport
Solution
class MultiViewportScene {
private:
GLuint VBO, VAO;
GLuint shaderProgram;
std::vector<glm::mat4> viewMatrices;
glm::mat4 projection;

struct ViewportSetup {
int x, y, width, height;
glm::mat4 view;
glm::mat4 projection;
};

std::vector<ViewportSetup> viewports;
public:
void init(int windowWidth, int windowHeight) {
// Initialize viewports
setupViewports(windowWidth, windowHeight);

// Create geometry (e.g., a simple scene with multiple


objects)
setupGeometry();

// Create shader program


shaderProgram =
createShaderProgram(vertexShaderSource,
fragmentShaderSource);
}
void setupViewports(int windowWidth, int windowHeight) {
// Main perspective view
viewports.push_back({
0, 0, // x, y
windowWidth * 0.7f, // width
windowHeight, // height
glm::lookAt(
glm::vec3(0.0f, 0.0f, 3.0f),
glm::vec3(0.0f),
glm::vec3(0.0f, 1.0f, 0.0f)
),
glm::perspective(glm::radians(45.0f),
(float)(windowWidth * 0.7f) / windowHeight,
0.1f, 100.0f)
});
// Top view
viewports.push_back({
windowWidth * 0.7f, // x
windowHeight * 0.5f, // y
windowWidth * 0.3f, // width
windowHeight * 0.5f, // height
glm::lookAt(
glm::vec3(0.0f, 5.0f, 0.0f),
glm::vec3(0.0f),
glm::vec3(0.0f, 0.0f, -1.0f)
),
glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 0.1f, 100.0f)
});
// Side view
viewports.push_back({
windowWidth * 0.7f, // x
0, // y
windowWidth * 0.3f, // width
windowHeight * 0.5f, // height
glm::lookAt(
glm::vec3(5.0f, 0.0f, 0.0f),
glm::vec3(0.0f),
glm::vec3(0.0f, 1.0f, 0.0f)
),
glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 0.1f, 100.0f)
});
}
void render() {
glEnable(GL_DEPTH_TEST);
glUseProgram(shaderProgram);

for(const auto& viewport : viewports) {


// Set viewport
glViewport(viewport.x, viewport.y, viewport.width, viewport.height);

// Set matrices
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"),
1, GL_FALSE, glm::value_ptr(viewport.view));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"),
1, GL_FALSE, glm::value_ptr(viewport.projection));

// Draw scene
renderScene();
}
}
private:
void renderScene() {
// Draw background grid for orientation
drawGrid();

// Draw main scene objects


drawObjects();

// Ensure all drawing commands are executed


glFlush();
}

void drawGrid() {
// Set grid color
glUniform3f(glGetUniformLocation(shaderProgram, "objectColor"), 0.5f, 0.5f, 0.5f);
// Draw horizontal and vertical grid lines
glBegin(GL_LINES);

// Draw horizontal lines


for(float i = -10.0f; i <= 10.0f; i += 1.0f) {
glVertex3f(-10.0f, 0.0f, i);
glVertex3f( 10.0f, 0.0f, i);
}

// Draw vertical lines


for(float i = -10.0f; i <= 10.0f; i += 1.0f) {
glVertex3f(i, 0.0f, -10.0f);
glVertex3f(i, 0.0f, 10.0f);
}

glEnd();
}
void drawObjects() {
// Draw a cube at the origin
drawCube(glm::vec3(0.0f, 0.5f, 0.0f), glm::vec3(1.0f, 0.0f, 0.0f));

// Draw a sphere slightly offset


drawSphere(glm::vec3(2.0f, 0.5f, 2.0f), glm::vec3(0.0f, 1.0f, 0.0f));

// Draw a cylinder at another position


drawCylinder(glm::vec3(-2.0f, 0.5f, -2.0f), glm::vec3(0.0f, 0.0f, 1.0f));
}

void drawCube(const glm::vec3& position, const glm::vec3& color) {


glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, position);

glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"),
1, GL_FALSE, glm::value_ptr(model));
glUniform3fv(glGetUniformLocation(shaderProgram, "objectColor"),
1, glm::value_ptr(color));
// Bind cube VAO and draw
glBindVertexArray(cubeVAO);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT,
0);
}

void drawSphere(const glm::vec3& position, const glm::vec3&


color) {
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, position);

glUniformMatrix4fv(glGetUniformLocation(shaderProgram,
"model"),
1, GL_FALSE, glm::value_ptr(model));
// Use GLUT to draw a sphere
glutSolidSphere(0.5, 32, 32);
}

void drawCylinder(const glm::vec3& position, const glm::vec3& color) {


glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, position);

glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"),
1, GL_FALSE, glm::value_ptr(model));
glUniform3fv(glGetUniformLocation(shaderProgram, "objectColor"),
1, glm::value_ptr(color));

// Use GLUT to draw a cylinder


GLUquadricObj *quadric = gluNewQuadric();
gluCylinder(quadric, 0.5, 0.5, 1.0, 32, 32);
gluDeleteQuadric(quadric);
}
• Exercise 5: Scene Graph Implementation

• Create a solar system simulation using a


scene graph.

• Requirements:
• Implement a hierarchical transformation
system
• Show planets orbiting the sun
• Show moons orbiting planets
• Allow camera movement through the scene
Solution
// First, let's define our Scene Node class which forms the foundation of our scene graph
class SceneNode {
private:
std::string name; // Node identifier
glm::mat4 localTransform; // Local transformation matrix
glm::mat4 worldTransform; // Cached world transformation
SceneNode* parent; // Parent node
std::vector<std::shared_ptr<SceneNode>> children; // Child nodes
std::shared_ptr<Mesh> mesh; // Geometry data
bool transformDirty; // Flag for transform updates

public:
SceneNode(const std::string& nodeName)
: name(nodeName),
localTransform(1.0f),
worldTransform(1.0f),
parent(nullptr),
transformDirty(true) {
}
// Add a child node to this node
void addChild(std::shared_ptr<SceneNode> child) {
children.push_back(child);
child->parent = this;
child->markTransformDirty();
}

// Set the local transformation matrix


void setLocalTransform(const glm::mat4& transform) {
localTransform = transform;
markTransformDirty();
}
// Mark the transform as needing update
void markTransformDirty() {
transformDirty = true;
// Propagate to children
for(auto& child : children) {
child->markTransformDirty();
}
}

// Update the world transform


void updateWorldTransform() {
if(transformDirty) {
if(parent) {
worldTransform = parent->worldTransform * localTransform;
} else {
worldTransform = localTransform;
}
transformDirty = false;
}
}
// Set the mesh for this node
void setMesh(std::shared_ptr<Mesh> newMesh) {
mesh = newMesh;
}

// Recursive render function


void render(GLuint shaderProgram) {
updateWorldTransform();

if(mesh) {
// Set the world transform uniform
GLuint worldMatrixLoc = glGetUniformLocation(shaderProgram, "worldMatrix");
glUniformMatrix4fv(worldMatrixLoc, 1, GL_FALSE, glm::value_ptr(worldTransform));

// Render the mesh


mesh->render();
}

// Render all children


for(auto& child : children) {
child->render(shaderProgram);
}
}
};
// Now let's create a Solar System class that uses our scene graph
class SolarSystem {
private:
std::shared_ptr<SceneNode> rootNode;
std::shared_ptr<SceneNode> sunNode;
std::shared_ptr<SceneNode> earthOrbitNode;
std::shared_ptr<SceneNode> earthNode;
std::shared_ptr<SceneNode> moonOrbitNode;
std::shared_ptr<SceneNode> moonNode;

GLuint shaderProgram;
std::shared_ptr<Mesh> sphereMesh;

float earthRotationSpeed = 1.0f; // Earth rotation speed (radians per


second)
float earthOrbitSpeed = 0.5f; // Earth orbit speed
float moonRotationSpeed = 2.0f; // Moon rotation speed
float moonOrbitSpeed = 2.0f; // Moon orbit speed
public:
void init() {
// Create shader program
shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource);

// Create sphere mesh that will be shared among celestial bodies


sphereMesh = std::make_shared<Mesh>();
sphereMesh->createSphere(1.0f, 32, 32);

// Create scene graph hierarchy


setupSceneGraph();
}

void setupSceneGraph() {
// Create all nodes
rootNode = std::make_shared<SceneNode>("root");
sunNode = std::make_shared<SceneNode>("sun");
earthOrbitNode = std::make_shared<SceneNode>("earthOrbit");
earthNode = std::make_shared<SceneNode>("earth");
moonOrbitNode = std::make_shared<SceneNode>("moonOrbit");
moonNode = std::make_shared<SceneNode>("moon");
// Set up hierarchy
rootNode->addChild(sunNode);
sunNode->addChild(earthOrbitNode);
earthOrbitNode->addChild(earthNode);
earthNode->addChild(moonOrbitNode);
moonOrbitNode->addChild(moonNode);

// Set initial transforms


sunNode->setLocalTransform(glm::scale(glm::mat4(1.0f), glm::vec3(5.0f))); // Sun
is 5 units in diameter

earthNode->setLocalTransform(
glm::translate(glm::mat4(1.0f), glm::vec3(10.0f, 0.0f, 0.0f)) * // Earth is 10
units from sun
glm::scale(glm::mat4(1.0f), glm::vec3(1.0f)) // Earth is 1 unit in
diameter
);

moonNode->setLocalTransform(
glm::translate(glm::mat4(1.0f), glm::vec3(2.0f, 0.0f, 0.0f)) * // Moon is 2 units
from earth
// Assign meshes
sunNode->setMesh(sphereMesh);
earthNode->setMesh(sphereMesh);
moonNode->setMesh(sphereMesh);
}

void update(float deltaTime) {


// Update earth orbit
glm::mat4 earthOrbitTransform = glm::rotate(
glm::mat4(1.0f),
deltaTime * earthOrbitSpeed,
glm::vec3(0.0f, 1.0f, 0.0f)
);
earthOrbitNode->setLocalTransform(earthOrbitTransform);
// Update earth rotation
glm::mat4 earthRotationTransform = glm::rotate(
glm::mat4(1.0f),
deltaTime * earthRotationSpeed,
glm::vec3(0.0f, 1.0f, 0.0f)
);
earthNode->setLocalTransform(earthNode-
>getLocalTransform() * earthRotationTransform);

// Update moon orbit


glm::mat4 moonOrbitTransform = glm::rotate(
glm::mat4(1.0f),
deltaTime * moonOrbitSpeed,
glm::vec3(0.0f, 1.0f, 0.0f)
);
moonOrbitNode->setLocalTransform(moonOrbitTransform);
// Update moon rotation
glm::mat4 moonRotationTransform = glm::rotate(
glm::mat4(1.0f),
deltaTime * moonRotationSpeed,
glm::vec3(0.0f, 1.0f, 0.0f)
);
moonNode->setLocalTransform(moonNode->getLocalTransform() * moonRotationTransform);
}

void render(const glm::mat4& viewProjection) {


glUseProgram(shaderProgram);

// Set view-projection matrix


GLuint viewProjLoc = glGetUniformLocation(shaderProgram, "viewProjection");
glUniformMatrix4fv(viewProjLoc, 1, GL_FALSE, glm::value_ptr(viewProjection));

// Render entire scene graph


rootNode->render(shaderProgram);
}
};

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy