Answered step by step
Verified Expert Solution
Link Copied!

Question

1 Approved Answer

i have a scene and i have to implement a reflective surface and shadow into the scene using openGL I have the Main cpp, frag

i have a scene and i have to implement a reflective surface and shadow into the scene using openGL

I have the Main cpp, frag shader and vertex shader below

Main CPP

#include

#include "GL/glew.h"

#include "GL/3dgl.h"

#include "GL/glut.h"

#include "GL/freeglut_ext.h"

#pragma comment (lib, "glew32.lib")

using namespace std;

using namespace _3dgl;

// 3D models

C3dglModel table;

C3dglModel vase;

C3dglModel chicken;

C3dglModel lamp;

unsigned nPyramidBuf = 0;

// texture ids

GLuint idTexWood;

GLuint idTexCloth;

GLuint idTexNone;

// GLSL Program

C3dglProgram Program;

// camera position (for first person type camera navigation)

float matrixView[16]; // The View Matrix

float angleTilt = 0; // Tilt Angle

float angleRot = 0.1f; // Camera orbiting angle

float deltaX = 0, deltaY = 0, deltaZ = 0; // Camera movement values

// light switches

int nAmbient = 1, nDir = 1, nPoint1 = 1, nPoint2 = 1;

bool init()

{

// rendering states

glEnable(GL_DEPTH_TEST); // depth test is necessary for most 3D scenes

glEnable(GL_NORMALIZE); // normalization is needed by AssImp library models

glShadeModel(GL_SMOOTH); // smooth shading mode is the default one; try GL_FLAT here!

glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // this is the default one; try GL_LINE!

// Initialise Shaders

C3dglShader VertexShader;

C3dglShader FragmentShader;

if (!VertexShader.Create(GL_VERTEX_SHADER)) return false;

if (!VertexShader.LoadFromFile("shaders/basic.vert")) return false;

if (!VertexShader.Compile()) return false;

if (!FragmentShader.Create(GL_FRAGMENT_SHADER)) return false;

if (!FragmentShader.LoadFromFile("shaders/basic.frag")) return false;

if (!FragmentShader.Compile()) return false;

if (!Program.Create()) return false;

if (!Program.Attach(VertexShader)) return false;

if (!Program.Attach(FragmentShader)) return false;

if (!Program.Link()) return false;

if (!Program.Use(true)) return false;

// glut additional setup

glutSetVertexAttribCoord3(Program.GetAttribLocation("aVertex"));

glutSetVertexAttribNormal(Program.GetAttribLocation("aNormal"));

// load your 3D models here!

if (!table.load("models\\table.obj")) return false;

if (!vase.load("models\\vase.obj")) return false;

if (!chicken.load("models\\chicken.obj")) return false;

if (!lamp.load("models\\lamp.obj")) return false;

// Initialise the View Matrix (initial position of the camera)

glMatrixMode(GL_MODELVIEW);

angleTilt = 15;

glLoadIdentity();

glRotatef(angleTilt, 1, 0, 0);

gluLookAt(0.0, 5.0, 6.0,

0.0, 5.0, 0.0,

0.0, 1.0, 0.0);

glGetFloatv(GL_MODELVIEW_MATRIX, matrixView);

// create pyramid

float vermals[] = {

-4, 0,-4, 0, 4,-7, 4, 0,-4, 0, 4,-7, 0, 7, 0, 0, 4,-7,

-4, 0, 4, 0, 4, 7, 4, 0, 4, 0, 4, 7, 0, 7, 0, 0, 4, 7,

-4, 0,-4,-7, 4, 0,-4, 0, 4,-7, 4, 0, 0, 7, 0,-7, 4, 0,

4, 0,-4, 7, 4, 0, 4, 0, 4, 7, 4, 0, 0, 7, 0, 7, 4, 0,

-4, 0,-4, 0,-1, 0,-4, 0, 4, 0,-1, 0, 4, 0,-4, 0,-1, 0,

4, 0, 4, 0,-1, 0,-4, 0, 4, 0,-1, 0, 4, 0,-4, 0,-1, 0 };

// Generate 1 buffer name

glGenBuffers(1, &nPyramidBuf);

// Bind (activate) the buffer

glBindBuffer(GL_ARRAY_BUFFER, nPyramidBuf);

// Send data to the buffer

glBufferData(GL_ARRAY_BUFFER, sizeof(vermals), vermals, GL_STATIC_DRAW);

// Setup Lights

Program.SendUniform("lightAmbient.on", nAmbient);

Program.SendUniform("lightAmbient.color", 0.025, 0.025, 0.025);

Program.SendUniform("lightEmissive.on", 0);

Program.SendUniform("lightEmissive.color", 1.0, 1.0, 1.0);

Program.SendUniform("materialAmbient", 1.0, 1.0, 1.0);

Program.SendUniform("lightDir.on", nDir);

Program.SendUniform("lightDir.direction", 1.0, 0.5, 1.0);

Program.SendUniform("lightDir.diffuse", 0.3, 0.3, 0.3); // dimmed white light

Program.SendUniform("lightPoint1.on", nPoint1);

Program.SendUniform("lightPoint1.position", -2.95, 4.24, -1.0);

Program.SendUniform("lightPoint1.diffuse", 0.5, 0.5, 0.5);

Program.SendUniform("lightPoint1.specular", 1.0, 1.0, 1.0);

Program.SendUniform("lightPoint2.on", nPoint2);

Program.SendUniform("lightPoint2.position", 1.05, 4.24, 1.0);

Program.SendUniform("lightPoint2.diffuse", 0.5, 0.5, 0.5);

Program.SendUniform("lightPoint2.specular", 1.0, 1.0, 1.0);

Program.SendUniform("materialSpecular", 0.0, 0.0, 0.0);

Program.SendUniform("shininess", 3.0);

// create & load textures

C3dglBitmap bm;

glActiveTexture(GL_TEXTURE0);

// cloth texture

bm.Load("models/cloth.png", GL_RGBA);

if (!bm.GetBits()) return false;

glGenTextures(1, &idTexCloth);

glBindTexture(GL_TEXTURE_2D, idTexCloth);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bm.GetWidth(), bm.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, bm.GetBits());

// wood texture

bm.Load("models/oak.png", GL_RGBA);

if (!bm.GetBits()) return false;

glGenTextures(1, &idTexWood);

glBindTexture(GL_TEXTURE_2D, idTexWood);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bm.GetWidth(), bm.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, bm.GetBits());

// none (simple-white) texture

glGenTextures(1, &idTexNone);

glBindTexture(GL_TEXTURE_2D, idTexNone);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

BYTE bytes[] = { 255, 255, 255 };

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_BGR, GL_UNSIGNED_BYTE, &bytes);

// Send the texture info to the shaders

Program.SendUniform("texture0", 0);

cout << endl;

cout << "Use:" << endl;

cout << " WASD or arrow key to navigate" << endl;

cout << " QE or PgUp/Dn to move the camera up and down" << endl;

cout << " Shift+AD or arrow key to auto-orbit" << endl;

cout << " Drag the mouse to look around" << endl;

cout << endl;

cout << " 1 to switch the lamp #1 on/off" << endl;

cout << " 2 to switch the lamp #2 on/off" << endl;

cout << " 9 to switch directional light on/off" << endl;

cout << " 0 to switch ambient light on/off" << endl;

cout << endl;

return true;

}

void done()

{

}

void render()

{

// this global variable controls the animation

static float theta = 0.0f;

// clear screen and buffers

glClearColor(0.18f, 0.25f, 0.22f, 1.0f); // deep grey background

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// setup the View Matrix (camera)

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

glRotatef(angleTilt, 1, 0, 0); // switch tilt off

glTranslatef(deltaX, deltaY, deltaZ); // animate camera motion (controlled by WASD keys)

glRotatef(-angleTilt, 1, 0, 0); // switch tilt on

glMultMatrixf(matrixView);

glRotatef(angleRot, 0.0, 1.0, 0.0); // animate camera orbiting

glGetFloatv(GL_MODELVIEW_MATRIX, matrixView);

// setup View Matrix

float matrix[16];

glGetFloatv(GL_MODELVIEW_MATRIX, matrix);

Program.SendUniform("matrixView", matrix);

// setup materials

Program.SendUniform("materialSpecular", 0.0, 0.0, 0.0);

// table & chairs

glPushMatrix();

glScalef(0.004f, 0.004f, 0.004f);

Program.SendUniform("materialDiffuse", 1.0, 1.0, 1.0);

Program.SendUniform("materialAmbient", 1.0, 1.0, 1.0);

glBindTexture(GL_TEXTURE_2D, idTexWood);

table.render(1);

glBindTexture(GL_TEXTURE_2D, idTexCloth);

table.render(0);

glRotatef(180, 0, 1, 0);

table.render(0);

glTranslatef(250, 0, 0);

glRotatef(90, 0, 1, 0);

table.render(0);

glTranslatef(0, 0, -500);

glRotatef(180, 0, 1, 0);

table.render(0);

glPopMatrix();

// vase

glPushMatrix();

Program.SendUniform("materialDiffuse", 0.2, 0.4, 0.8);

Program.SendUniform("materialAmbient", 0.2, 0.4, 0.8);

Program.SendUniform("materialSpecular", 1.0, 1.0, 1.0);

glBindTexture(GL_TEXTURE_2D, idTexNone);

glTranslatef(0, 3, 0);

glScalef(0.12f, 0.12f, 0.12f);

vase.render();

glPopMatrix();

// teapot

glPushMatrix();

Program.SendUniform("materialDiffuse", 0.1, 0.8, 0.3);

Program.SendUniform("materialAmbient", 0.1, 0.8, 0.3);

Program.SendUniform("materialSpecular", 1.0, 1.0, 1.0);

glTranslatef(1.8f, 3.4f, 0.0f);

glGetFloatv(GL_MODELVIEW_MATRIX, matrix);

Program.SendUniform("matrixModelView", matrix);

glutSolidTeapot(0.5);

glPopMatrix();

// pyramid

glPushMatrix();

Program.SendUniform("materialDiffuse", 1.0, 0.2, 0.2);

Program.SendUniform("materialAmbient", 1.0, 0.2, 0.2);

Program.SendUniform("materialSpecular", 0.0, 0.0, 0.0);

glTranslatef(-0.9f, 3.7f, -1.2f);

glRotatef(180, 1, 0, 0);

glRotatef(-4*theta, 0, 1, 0);

glScalef(0.1f, 0.1f, 0.1f);

glGetFloatv(GL_MODELVIEW_MATRIX, matrix);

Program.SendUniform("matrixModelView", matrix);

GLuint attribVertex = Program.GetAttribLocation("aVertex");

GLuint attribNormal = Program.GetAttribLocation("aNormal");

glBindBuffer(GL_ARRAY_BUFFER, nPyramidBuf);

glEnableVertexAttribArray(attribVertex);

glEnableVertexAttribArray(attribNormal);

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

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

glDrawArrays(GL_TRIANGLES, 0, 18);

glDisableVertexAttribArray(GL_VERTEX_ARRAY);

glDisableVertexAttribArray(GL_NORMAL_ARRAY);

// chicken

Program.SendUniform("materialDiffuse", 0.8, 0.8, 0.2);

Program.SendUniform("materialAmbient", 0.8, 0.8, 0.2);

Program.SendUniform("materialSpecular", 0.6, 0.6, 1.0);

glTranslatef(0, -5, 0);

glScalef(0.2f, 0.2f, 0.2f);

glRotatef(180, 1, 0, 0);

chicken.render();

glPopMatrix();

// lamp 1

glPushMatrix();

glTranslatef(-2.2f, 3.075f, -1.0f);

glScalef(0.02f, 0.02f, 0.02f);

lamp.render();

glPopMatrix();

// lamp 2

Program.SendUniform("materialDiffuse", 0.8, 0.8, 0.2);

Program.SendUniform("materialAmbient", 0.8, 0.8, 0.2);

Program.SendUniform("materialSpecular", 0.0, 0.0, 0.0);

glPushMatrix();

glTranslatef(1.8f, 3.075f, 1.0f);

glScalef(0.02f, 0.02f, 0.02f);

lamp.render();

glPopMatrix();

// light bulb 1

Program.SendUniform("materialDiffuse", 0.8, 0.8, 0.8);

Program.SendUniform("materialAmbient", 0.8, 0.8, 0.8);

Program.SendUniform("lightEmissive.on", nPoint1);

glPushMatrix();

glTranslatef(-2.95f, 4.24f, -1.0f);

glScalef(0.1f, 0.1f, 0.1f);

glGetFloatv(GL_MODELVIEW_MATRIX, matrix);

Program.SendUniform("matrixModelView", matrix);

glutSolidSphere(1, 32, 32);

glPopMatrix();

// light bulb 2

Program.SendUniform("materialDiffuse", 0.8, 0.8, 0.8);

Program.SendUniform("materialAmbient", 0.8, 0.8, 0.8);

Program.SendUniform("lightEmissive.on", nPoint2);

glPushMatrix();

glTranslatef(1.05f, 4.24f, 1.0f);

glScalef(0.1f, 0.1f, 0.1f);

glGetFloatv(GL_MODELVIEW_MATRIX, matrix);

Program.SendUniform("matrixModelView", matrix);

glutSolidSphere(1, 32, 32);

Program.SendUniform("lightEmissive.on", 0);

glPopMatrix();

// essential for double-buffering technique

glutSwapBuffers();

// proceed the animation

static GLint prev_time = 0;

int time = glutGet(GLUT_ELAPSED_TIME);

theta += (time - prev_time) * 0.01f;

prev_time = time;

glutPostRedisplay();

}

// called before window opened or resized - to setup the Projection Matrix

void reshape(int w, int h)

{

// find screen aspect ratio

float ratio = w * 1.0f / h; // we hope that h is not zero

// setup the projection matrix

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

glViewport(0, 0, w, h);

gluPerspective(60.0, ratio, 0.02, 1000.0);

float matrix[16];

glGetFloatv(GL_PROJECTION_MATRIX, matrix);

Program.SendUniform("matrixProjection", matrix);

}

// Handle WASDQE keys

void onKeyDown(unsigned char key, int x, int y)

{

switch (tolower(key))

{

case 'w': deltaZ = max(deltaZ * 1.05f, 0.01f); break;

case 's': deltaZ = min(deltaZ * 1.05f, -0.01f); break;

case 'a': deltaX = max(deltaX * 1.05f, 0.01f); angleRot = 0.1f; break;

case 'd': deltaX = min(deltaX * 1.05f, -0.01f); angleRot = -0.1f; break;

case 'e': deltaY = max(deltaY * 1.05f, 0.01f); break;

case 'q': deltaY = min(deltaY * 1.05f, -0.01f); break;

case '1': nPoint1 = 1 - nPoint1; Program.SendUniform("lightPoint1.on", nPoint1); return;

case '2': nPoint2 = 1 - nPoint2; Program.SendUniform("lightPoint2.on", nPoint2); return;

case '9': nDir = 1 - nDir; Program.SendUniform("lightDir.on", nDir); return;

case '0': nAmbient = 1 - nAmbient; Program.SendUniform("lightAmbient.on", nAmbient); return;

}

// speed limit

deltaX = max(-0.15f, min(0.15f, deltaX));

deltaY = max(-0.15f, min(0.15f, deltaY));

deltaZ = max(-0.15f, min(0.15f, deltaZ));

// stop orbiting

if ((glutGetModifiers() & GLUT_ACTIVE_SHIFT) == 0) angleRot = 0;

}

// Handle WASDQE keys (key up)

void onKeyUp(unsigned char key, int x, int y)

{

switch (tolower(key))

{

case 'w':

case 's': deltaZ = 0; break;

case 'a':

case 'd': deltaX = 0; break;

case 'q':

case 'e': deltaY = 0; break;

case ' ': deltaY = 0; break;

}

}

// Handle arrow keys and Alt+F4

void onSpecDown(int key, int x, int y)

{

switch (key)

{

case GLUT_KEY_F4: if ((glutGetModifiers() & GLUT_ACTIVE_ALT) != 0) exit(0); break;

case GLUT_KEY_UP: onKeyDown('w', x, y); break;

case GLUT_KEY_DOWN: onKeyDown('s', x, y); break;

case GLUT_KEY_LEFT: onKeyDown('a', x, y); break;

case GLUT_KEY_RIGHT: onKeyDown('d', x, y); break;

case GLUT_KEY_PAGE_UP: onKeyDown('q', x, y); break;

case GLUT_KEY_PAGE_DOWN:onKeyDown('e', x, y); break;

case GLUT_KEY_F11: glutFullScreenToggle();

}

}

// Handle arrow keys (key up)

void onSpecUp(int key, int x, int y)

{

switch (key)

{

case GLUT_KEY_UP: onKeyUp('w', x, y); break;

case GLUT_KEY_DOWN: onKeyUp('s', x, y); break;

case GLUT_KEY_LEFT: onKeyUp('a', x, y); break;

case GLUT_KEY_RIGHT: onKeyUp('d', x, y); break;

case GLUT_KEY_PAGE_UP: onKeyUp('q', x, y); break;

case GLUT_KEY_PAGE_DOWN:onKeyUp('e', x, y); break;

}

}

// Handle mouse click

void onMouse(int button, int state, int x, int y)

{

int cx = glutGet(GLUT_WINDOW_WIDTH) / 2;

int cy = glutGet(GLUT_WINDOW_HEIGHT) / 2;

if (state == GLUT_DOWN)

{

glutSetCursor(GLUT_CURSOR_CROSSHAIR);

glutWarpPointer(cx, cy);

}

else

glutSetCursor(GLUT_CURSOR_INHERIT);

}

// handle mouse move

void onMotion(int x, int y)

{

int cx = glutGet(GLUT_WINDOW_WIDTH) / 2;

int cy = glutGet(GLUT_WINDOW_HEIGHT) / 2;

if (x == cx && y == cy)

return; // caused by glutWarpPointer

float amp = 0.25;

float deltaTilt = amp * (y - cy);

float deltaPan = amp * (x - cx);

glutWarpPointer(cx, cy);

// handle camera tilt (mouse move up & down)

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

glRotatef(deltaTilt, 1, 0, 0);

glMultMatrixf(matrixView);

glGetFloatv(GL_MODELVIEW_MATRIX, matrixView);

angleTilt += deltaTilt;

// handle camera pan (mouse move left & right)

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

glRotatef(angleTilt, 1, 0, 0);

glRotatef(deltaPan, 0, 1, 0);

glRotatef(-angleTilt, 1, 0, 0);

glMultMatrixf(matrixView);

glGetFloatv(GL_MODELVIEW_MATRIX, matrixView);

}

int main(int argc, char **argv)

{

// init GLUT and create Window

glutInit(&argc, argv);

glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);

glutInitWindowPosition(100, 100);

glutInitWindowSize(800, 600);

glutCreateWindow("CI5520 3D Graphics Programming");

// init glew

GLenum err = glewInit();

if (GLEW_OK != err)

{

cerr << "GLEW Error: " << glewGetErrorString(err) << endl;

return 0;

}

cout << "Using GLEW " << glewGetString(GLEW_VERSION) << endl;

// register callbacks

glutDisplayFunc(render);

glutReshapeFunc(reshape);

glutKeyboardFunc(onKeyDown);

glutSpecialFunc(onSpecDown);

glutKeyboardUpFunc(onKeyUp);

glutSpecialUpFunc(onSpecUp);

glutMouseFunc(onMouse);

glutMotionFunc(onMotion);

cout << "Vendor: " << glGetString(GL_VENDOR) << endl;

cout << "Renderer: " << glGetString(GL_RENDERER) << endl;

cout << "Version: " << glGetString(GL_VERSION) << endl;

// init light and everything not a GLUT or callback function!

if (!init())

{

cerr << "Application failed to initialise" << endl;

return 0;

}

// enter GLUT event processing cycle

glutMainLoop();

done();

return 1;

}

FRAGMENT SHADER

// FRAGMENT SHADER

#version 330

in vec4 color;

in vec4 position;

in vec3 normal;

in vec2 texCoord0;

out vec4 outColor;

// Materials

uniform vec3 materialAmbient;

uniform vec3 materialDiffuse;

uniform vec3 materialSpecular;

uniform float shininess;

// View Matrix

uniform mat4 matrixView;

// Texture

uniform sampler2D texture0;

struct POINT

{

int on;

vec3 position;

vec3 diffuse;

vec3 specular;

};

uniform POINT lightPoint1, lightPoint2;

vec4 PointLight(POINT light)

{

// Calculate Directional Light

vec4 color = vec4(0, 0, 0, 0);

// diffuse light

vec3 L = normalize(matrixView * vec4(light.position, 1) - position).xyz;

float NdotL = dot(normal, L);

if (NdotL > 0)

color += vec4(materialDiffuse * light.diffuse, 1) * NdotL;

// specular light

vec3 V = normalize(-position.xyz);

vec3 R = reflect(-L, normal);

float RdotV = dot(R, V);

if (NdotL > 0 && RdotV > 0)

color += vec4(materialSpecular * light.specular * pow(RdotV, shininess), 1);

return color;

}

void main(void)

{

outColor = color;

if (lightPoint1.on == 1)

outColor += PointLight(lightPoint1);

if (lightPoint2.on == 1)

outColor += PointLight(lightPoint2);

outColor *= texture(texture0, texCoord0);

}

Vertex shader

// VERTEX SHADER

#version 330

// Matrices

uniform mat4 matrixProjection;

uniform mat4 matrixView;

uniform mat4 matrixModelView;

// Materials

uniform vec3 materialAmbient;

uniform vec3 materialDiffuse;

uniform vec3 materialSpecular;

uniform float shininess;

layout (location = 0) in vec3 aVertex;

layout (location = 2) in vec3 aNormal;

layout (location = 3) in vec2 aTexCoord;

out vec4 color;

out vec4 position;

out vec3 normal;

out vec2 texCoord0;

// Light declarations

struct AMBIENT

{

int on;

vec3 color;

};

uniform AMBIENT lightAmbient, lightEmissive;

struct DIRECTIONAL

{

int on;

vec3 direction;

vec3 diffuse;

};

uniform DIRECTIONAL lightDir;

vec4 AmbientLight(AMBIENT light)

{

// Calculate Ambient Light

return vec4(materialAmbient * light.color, 1);

}

vec4 DirectionalLight(DIRECTIONAL light)

{

// Calculate Directional Light

vec4 color = vec4(0, 0, 0, 0);

vec3 L = normalize(mat3(matrixView) * light.direction);

float NdotL = dot(normal, L);

if (NdotL > 0)

color += vec4(materialDiffuse * light.diffuse, 1) * NdotL;

return color;

}

void main(void)

{

// calculate position

position = matrixModelView * vec4(aVertex, 1.0);

gl_Position = matrixProjection * position;

// calculate normal

normal = normalize(mat3(matrixModelView) * aNormal);

// calculate texture coordinate

texCoord0 = aTexCoord;

// calculate light

color = vec4(0, 0, 0, 1);

if (lightAmbient.on == 1)

color += AmbientLight(lightAmbient);

if (lightEmissive.on == 1)

color += AmbientLight(lightEmissive);

if (lightDir.on == 1)

color += DirectionalLight(lightDir);

//if (lightPoint1.on == 1)

// color += PointLight(lightPoint1);

//if (lightPoint2.on == 1)

// color += PointLight(lightPoint2);

}

Step by Step Solution

There are 3 Steps involved in it

Step: 1

blur-text-image

Get Instant Access to Expert-Tailored Solutions

See step-by-step solutions with expert insights and AI powered tools for academic success

Step: 2

blur-text-image

Step: 3

blur-text-image

Ace Your Homework with AI

Get the answers you need in no time with our AI-driven, step-by-step assistance

Get Started

Recommended Textbook for

Essentials of Database Management

Authors: Jeffrey A. Hoffer, Heikki Topi, Ramesh Venkataraman

1st edition

133405680, 9780133547702 , 978-0133405682

More Books

Students also viewed these Databases questions

Question

I would have had to wait a long time for a reply.

Answered: 1 week ago

Question

Id already thrown away the receipt.

Answered: 1 week ago