I have a rotation problems.
I have the camera set up so that up vector is Z, -X is forward and right is Y. I have models that are exported in another coordinate system where Y is up, -Z is forward, X is right.
My challenge/problem is with rotation. How to do correct rotation in this case without changing the coordinate system of objects that I import. Scale and transform are working as they should.
So far I have tried swapping Y and Z axis in the rotation matrix manual, doing the rotation matrix separately, doing the rotation as we read control file, flipping Z and Y rotation axis, changing the matrix to
| 1 0 0 |
| 0 0 1 |
| 0 1 0 |
etc.
PS. I dont want to change the coordinate system of the object files that I import now and when I write in the control file rotateY it will rotate the object in my Y axis not the object Y axis.
This is the part of code I am trying the transformations
// control file is where i store transform, rotate and scale in a text file and objects that i want to read.
for(int i = 0; i< controls.size(); i++) {
meshStruct tempMesh;
int isMeshLoaded = loadObjFile((char*)controls[i].path, &tempMesh.objectInfo_, &tempMesh.numObjects_);
if(isMeshLoaded)
{
cout<< "Mesh " << controls[i].path << " loaded sucesfully." << endl;
} else {
cout<< "Mesh " << controls[i].path << " loaded failed." << endl;
}
tempModelMatrix = mat4(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
//mat4 tempModelMatrixFlip = mat4(1.0f, 0.0f, 0.0f, 0.0f,
// 0.0f, 0.0f, 1.0f, 0.0f,
// 0.0f, 1.0f, 0.0f, 0.0f,
// 0.0f, 0.0f, 0.0f, 1.0f);
//tempModelMatrix *= tempModelMatrixFlip;
tempModelMatrix = glm::translate(tempModelMatrix, controls[i].translate);
tempModelMatrix = glm::rotate(tempModelMatrix, radians(controls[i].rotation.x), vec3(1.0, 0.0, 0.0));
// I dont want to flip here Y and Z because some objects are in the correct coordinate system
tempModelMatrix = glm::rotate(tempModelMatrix, radians(controls[i].rotation.y), vec3(0.0, 1.0, 0.0));
tempModelMatrix = glm::rotate(tempModelMatrix, radians(controls[i].rotation.z), vec3(0.0, 0.0, 1.0));
/*
mat4 r = mat4(1.0f);
mat4 rx = mat4(1.0f);
mat4 ry = mat4(1.0f);
mat4 rz = mat4(1.0f);
rx = rotate(radians(controls[i].rotation.x), vec3(1.0, 0.0, 0.0));
ry = rotate(radians(controls[i].rotation.y), vec3(0.0, 1.0, 0.0));
rz = rotate(radians(controls[i].rotation.z), vec3(0.0, 0.0, 1.0));
r = rx * ry * rz;
vec4 temp;
temp = column(r, 1);
cout << to_string(temp) << endl;
r = column(r,1, column(r, 2));
r = column(r,2, temp);
temp = row(r,1);
r = row(r, 1,row(r,2));
r = row(r, 2, temp);
//cout << to_string(column(tempModelMatrix, 1)) << endl;
//tempModelMatrix *= r;
float tempModelMatrix2[16];// = mat4(1.0f);
tempModelMatrix2[0] = controls[i].scale.x * column(r, 0).x;//controls[i].scale.x * controls[i].rotation.x;
tempModelMatrix2[1] = controls[i].scale.x * column(r, 0).y;//controls[i].scale.x * controls[i].rotation.x;
tempModelMatrix2[2] = controls[i].scale.x * column(r, 0).z;//controls[i].scale.x * controls[i].rotation.x;
tempModelMatrix2[3] = 0.0f;
tempModelMatrix2[4] = controls[i].scale.y * column(r, 2).x;//controls[i].scale.y * controls[i].rotation.y;
tempModelMatrix2[5] = controls[i].scale.y * column(r, 2).y;//controls[i].scale.y * controls[i].rotation.y;
tempModelMatrix2[6] = controls[i].scale.y * column(r, 2).z;//controls[i].scale.y * controls[i].rotation.y;
tempModelMatrix2[7] = 0.0f;
tempModelMatrix2[8] = controls[i].scale.z * column(r, 1).x;//controls[i].scale.z * controls[i].rotation.z;
tempModelMatrix2[9] = controls[i].scale.z * column(r, 1).y;//controls[i].scale.z * controls[i].rotation.z;
tempModelMatrix2[10] = controls[i].scale.z * column(r, 1).z;//controls[i].scale.z * controls[i].rotation.z;
tempModelMatrix2[11] = 0.0f;
tempModelMatrix2[12] = controls[i].translate.x;
tempModelMatrix2[13] = controls[i].translate.y;
tempModelMatrix2[14] = controls[i].translate.z;
tempModelMatrix2[15] = 1.0f;*/
tempModelMatrix = glm::scale(tempModelMatrix, controls[i].scale);
//cout << controls[i].path << " controls[i].translate " << to_string(controls[i].translate) << endl;
//cout << controls[i].path << " controls[i].rotation.X " << controls[i].rotation.x << endl;
//cout << controls[i].path << " controls[i].rotation.y " << controls[i].rotation.y << endl;
//cout << controls[i].path << " controls[i].rotation.Z " << controls[i].rotation.z << endl;
//cout << controls[i].path << " controls[i].scale " << to_string(controls[i].scale) << endl;
string basedir = dirname(controls[i].path);
for(int j = 0; j < tempMesh.numObjects_; j++){
//tempMesh.objectInfo_[j].modelMatrix = controls[i].modelMatrix;
tempMesh.objectInfo_[j].modelMatrix = tempModelMatrix;
//tempMesh.objectInfo_[j].modelMatrix = make_mat4(tempModelMatrix2);
Since I cannot determine how you're storing the vertex data from the object I will define something simple:
struct Vertex {
glm::vec3 position;
};
struct Mesh {
std::vector<Vertex> vertices;
};
Now walk through all of the vertex positions and convert them to your world coordinates:
Mesh originalMesh = loadObjectFromFile("object.file");
Mesh convertedMesh = Mesh();
for (Vertex v : originalMesh.vertices) {
convertedMesh.push_back(glm::vec3(v.y, v.z, v.x));
}
The key thing to notice here is that we're doing the following mapping:
x = v.y
y = v.z
z = v.x
If you've got other vertex data (e.g. normals, texcoords) make sure those are converted also.
Fixed the problem after going through some emails with the professor and had a small error when calculating rotation matrix. I was doing it in the reverse way
tempModelMatrix = glm::rotate(tempModelMatrix, radians(controls[i].rotation.x), vec3(1.0, 0.0, 0.0));
tempModelMatrix = glm::rotate(tempModelMatrix, radians(controls[i].rotation.y), vec3(0.0, 1.0, 0.0));
tempModelMatrix = glm::rotate(tempModelMatrix, radians(controls[i].rotation.z), vec3(0.0, 0.0, 1.0));
instead of
tempModelMatrix = glm::rotate(tempModelMatrix, radians(controls[i].rotation.z), vec3(0.0, 0.0, 1.0));
tempModelMatrix = glm::rotate(tempModelMatrix, radians(controls[i].rotation.y), vec3(0.0, 1.0, 0.0));
tempModelMatrix = glm::rotate(tempModelMatrix, radians(controls[i].rotation.x), vec3(1.0, 0.0, 0.0));
Thanks for suggestions #Exide
Related
Edit: Code is now runnable
So I am trying to update the position of objects in a struct and I have tested the code within the Update and Rule function both execute and the local variables in the Rule class change as expected. What doesn't change are the member variables of the struct objects of type Object.
Here is the relevant code in my cpp file:
struct Object
{
float x;
float y;
float vx;
float vy;
glm::vec4 v_Color;
unsigned int id;
Object(float _x, float _y,
float _vx, float _vy,
glm::vec4 _v_Color, unsigned int _id)
{
x = _x;
y = _y;
vx = _vx;
vy = _vy;
v_Color = _v_Color;
id = _id;
}
}
std::vector<Object> red;
std::vector<Object> green;
std::vector<Object> blue;
std::vector<Object> yellow;
void Rule(std::vector<Object>* group1, std::vector<Object>* group2, float G)
{
float g = G;
for (int i = 0; i < group1->size(); i++) {
Object p1 = (*group1)[i];
float fx = 0;
float fy = 0;
for (int j = 0; j < group2->size(); j++) {
Object p2 = (*group2)[j];
float dx = p1.position.x - p2.position.x;
float dy = p1.position.y - p2.position.y;
float r = std::sqrt(dx * dx + dy * dy);
if (r < 80 && r > 0) {
fx += (dx / r);
fy += (dy / r);
}
}
p1.velocity.x = (p1.velocity.x + fx) * 0.5;
p1.velocity.y = (p1.velocity.y + fx) * 0.5;
p1.position.x += p1.velocity.x;
p1.position.y += p1.velocity.y;
if ((p1.position.x >= 800) || (p1.position.x <= 0)) { p1.velocity.x *= -1; }
if ((p1.position.y >= 700) || (p1.position.y <= 0)) { p1.velocity.y *= -1; }
std::cout << "Calculated velocity: " << fx << ", " << fy << std::endl; // these numbers will change
(*group1)[i] = p1;
std::cout << "ID: " << p1.id << ", " << "Velocity " << p1.velocity.x << ", " << p1.velocity.y << "Position: " << p1.position.x << ", " << p1.position.y << std::endl; // you will see these values do not change
}
}
std::vector<Object> CreateObjects(unsigned int number, glm::vec4 color)
{
std::vector<Object> group;
for (int i = 0; i < 10; i++) {
float x = rand() % 750 + 50;
float y = rand() % 550 + 50;
Object o(x, y, 0, 0, color, objects.size());
group.push_back(o);
objects.push_back(o);
}
return group;
}
void main()
{
yellow = CreateObjects(10, glm::vec4(1.0f, 1.0f, 0.0f, 1.0f));
blue = CreateObjects(10, glm::vec4(0.0f, 0.0f, 1.0f, 1.0f));
green = CreateObjects(10, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
red = CreateObjects(10, glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
Rule(&green, &green, -0.32);
Rule(&green, &red, -0.17);
Rule(&green, &yellow, 0.34);
Rule(&red, &red, -0.1);
Rule(&red, &green, -0.34);
Rule(&yellow, &yellow, 0.15);
Rule(&yellow, &green, -0.2);
Rule(&blue, &green, -0.2);
}
Edit: Code should now be runnable
You should debug your program to see in which exact step the program behaves as not expected
pointer to std::vector actually modifies your object.
you should see it if you add another field - int counter in your Object struct
struct Object
{
glm::vec3 position;
glm::vec3 velocity;
glm::vec4 v_Color;
unsigned int id;
int counter; // dont forget to initialise it in Object constructor
and here
void Rule(std::vector<Object>* group1, std::vector<Object>* group2, float G)
simply add
p1.counter += 1;
Either you actually modify values but presicion is small to notice it. Or there is some kind of mistake on your side. May be glm::vec3 fields x and y should be modified another way than glm::vec3::x += val
P.S
some sources from the internet says that you can access vec3 cooridates but cant change them. Seems like your case
https://www.reddit.com/r/cpp_questions/comments/60nsl5/accessing_the_x_y_and_z_values_of_a_vec3_position/
I want to have an enum which contains glm::vec3 "constants".
Currently I have an enum called "Axis", which contains X, Y and Z. and every time I use them I have to map them with a switch case into a glm::vec3 with corresponding values.
This is my Axis enum:
enum Axis
{
X,
Y,
Z
};
This is how I currently convert it to glm::vec3:
glm::vec3 angleVector;
switch (axis)
{
case X:
angleVector = glm::vec3(1.0f, 0.0f, 0.0f);
break;
case Y:
angleVector = glm::vec3(0.0f, 1.0f, 0.0f);
break;
case Z:
angleVector = glm::vec3(0.0f, 0.0f, 1.0f);
break;
}
And this is how I want to use it instead:
enum Axis
{
X = glm::vec3(1.0f, 0.0f, 0.0f),
Y = glm::vec3(0.0f, 1.0f, 0.0f),
Z = glm::vec3(0.0f, 0.0f, 1.0f)
};
I tried much things to get the glm::vec3(1.0f, 0.0f, 0.0f) as a constant which my enum does accept, but nothing worked.
(
like this:
static const glm::vec3 vec3x = glm::vec3(1.0f, 0.0f, 0.0f);
and then:
enum Axis
{
X = vec3x
};
)
You could use a namespace with static variables instead. Then you'll be able to use it roughly as you would with an enum.
namespace Axis
{
static const glm::vec3 X = glm::vec3(1.0f, 0.0f, 0.0f);
static const glm::vec3 Y = glm::vec3(0.0f, 1.0f, 0.0f);
static const glm::vec3 Z = glm::vec3(0.0f, 0.0f, 1.0f);
};
If you want to pass it to a function, you could create a class. However, then you'd have to instantiate an object when passing it in.
class Axis
{
public:
glm::vec3 X = glm::vec3(1.0f, 0.0f, 0.0f);
glm::vec3 Y = glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 Z = glm::vec3(0.0f, 0.0f, 1.0f);
};
static const Axis euclidean_space_axis;
void DoStuff(Axis axis)
{
std::cout << "X-axis: " << axis.X.x << ", " << axis.X.y << ", " << axis.X.z << "\n" <<
std::cout << "Y-axis: " << axis.Y.x << ", " << axis.Y.y << ", " << axis.Y.z << "\n" <<
std::cout << "Z-axis: " << axis.Z.x << ", " << axis.Z.y << ", " << axis.Z.z << std::endl;
}
int main()
{
DoStuff(euclidean_space_axis);
}
You can use a table instead of switching:
enum Axis { X, Y, Z };
const glm::vec3 axes[] = { glm::vec3(1.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f)};
and then
Axis axis = ... whatever ...;
glm::vec3 angleVector = axes[axis];
The purpose of this code is to generate a 'surface' with random Y variation, and then have a light source shine on it and generate areas of brightness and perform shading on darker areas. The problem is, this isn't really happening. The light either illuminates one side or the other, and those sides are all uniformly bright or dark. What am I missing with this? Keep in mind there is a good bit of code that has yet to be removed, but it is not my priority, I'm just trying to get shading functional at this point.
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#ifdef MAC
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
//Camera variables
int xangle = -270;
int yangle = 0;
//Control Mode (Rotate mode by default)
int mode = 0;
//Player Position (Y offset so it would not be straddling the grid)
float cubeX = 0;
float cubeY = 0.5;
float cubeZ = 0;
//Vertex arrays for surface
float surfaceX [11][11];
float surfaceY [11][11];
float surfaceZ [11][11];
//Surface Normal arrays
float Nx[11][11];
float Ny[11][11];
float Nz[11][11];
//Color arrays
float R[11][11];
float G[11][11];
float B[11][11];
// Material properties
float Ka = 0.2;
float Kd = 0.4;
float Ks = 0.4;
float Kp = 0.5;
//Random number generator
float RandomNumber(float Min, float Max)
{
return ((float(rand()) / float(RAND_MAX)) * (Max - Min)) + Min;
}
//---------------------------------------
// Initialize material properties
//---------------------------------------
void init_material(float Ka, float Kd, float Ks, float Kp,
float Mr, float Mg, float Mb)
{
// Material variables
float ambient[] = { Ka * Mr, Ka * Mg, Ka * Mb, 1.0 };
float diffuse[] = { Kd * Mr, Kd * Mg, Kd * Mb, 1.0 };
float specular[] = { Ks * Mr, Ks * Mg, Ks * Mb, 1.0 };
// Initialize material
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, Kp);
}
//---------------------------------------
// Initialize light source
//---------------------------------------
void init_light(int light_source, float Lx, float Ly, float Lz,
float Lr, float Lg, float Lb)
{
// Light variables
float light_position[] = { Lx, Ly, Lz, 0.0 };
float light_color[] = { Lr, Lg, Lb, 1.0 };
// Initialize light source
glEnable(GL_LIGHTING);
glEnable(light_source);
glLightfv(light_source, GL_POSITION, light_position);
glLightfv(light_source, GL_AMBIENT, light_color);
glLightfv(light_source, GL_DIFFUSE, light_color);
glLightfv(light_source, GL_SPECULAR, light_color);
glLightf(light_source, GL_CONSTANT_ATTENUATION, 1.0);
glLightf(light_source, GL_LINEAR_ATTENUATION, 0.0);
glLightf(light_source, GL_QUADRATIC_ATTENUATION, 0.0);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
}
//---------------------------------------
// Initialize surface
//---------------------------------------
void init_surface()
{
//Initialize X, select column
for (int i = 0; i < 11; i++)
{
//Select row
for (int j = 0; j < 11; j++)
{
surfaceX[i][j] = i-5;
surfaceY[i][j] = RandomNumber(5, 7) - 5;
surfaceZ[i][j] = j-5;
//std::cout << "Coordinate "<< i << "," << j << std::endl;
}
//std::cout << "Hello world "<< std::endl;
}
//std::cout << "Coordinate -5,-5" << surfaceX[-5][-5] << std::endl;
}
void define_normals()
{
//Define surface normals
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
//Get two tangent vectors
float Ix = surfaceX[i+1][j] - surfaceX[i][j];
float Iy = surfaceY[i+1][j] - surfaceY[i][j];
float Iz = surfaceZ[i+1][j] - surfaceZ[i][j];
float Jx = surfaceX[i][j+1] - surfaceX[i][j];
float Jy = surfaceY[i][j+1] - surfaceY[i][j];
float Jz = surfaceZ[i][j+1] - surfaceZ[i][j];
//Get two tangent vectors
//float Ix = Px[i+1][j] - Px[i][j];
//float Iy = Py[i+1][j] - Py[i][j];
//float Iz = Pz[i+1][j] - Pz[i][j];
//float Jx = Px[i][j+1] - Px[i][j];
//float Jy = Py[i][j+1] - Py[i][j];
//float Jz = Pz[i][j+1] - Pz[i][j];
//Do cross product
Nx[i][j] = Iy * Jz - Iz * Jy;
Ny[i][j] = Iz * Jx - Ix * Jz;
Nz[i][j] = Ix * Jy - Iy * Jx;
//Nx[i][j] = Nx[i][j] * -1;
//Ny[i][j] = Ny[i][j] * -1;
//Nz[i][j] = Nz[i][j] * -1;
float length = sqrt(
Nx[i][j] * Nx[i][j] +
Ny[i][j] * Ny[i][j] +
Nz[i][j] * Nz[i][j]);
if (length > 0)
{
Nx[i][j] /= length;
Ny[j][j] /= length;
Nz[i][j] /= length;
}
}
}
//std::cout << "Surface normal for 0,0: "<< Nx[0][0] << "," << Ny[0][0] << "," << Nz[0][0] << std::endl;
}
void calc_color()
{
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
//Calculate light vector
//Light position, hardcoded for now 0,1,1
float Lx = -1 - surfaceX[i][j];
float Ly = -1 - surfaceY[i][j];
float Lz = -1 - surfaceZ[i][j];
std::cout << "Lx: " << Lx << std::endl;
std::cout << "Ly: " << Ly << std::endl;
std::cout << "Lz: " << Lz << std::endl;
//Grab surface normals
//These are Nx,Ny,Nz due to compiler issues
float Na = Nx[i][j];
float Nb = Ny[i][j];
float Nc = Nz[i][j];
std::cout << "Na: " << Na << std::endl;
std::cout << "Nb: " << Nb << std::endl;
std::cout << "Nc: " << Nc << std::endl;
//Do cross product
float Color = (Na * Lx) + (Nb * Ly) + (Nc * Lz);
std::cout << "Color: " << Color << std::endl;
//Color = Color * -1;
R[i][j] = Color;
G[i][j] = Color;
B[i][j] = Color;
//std::cout << "Color Value: " << std::endl;
////std::cout << "R: " << R[i][j] << std::endl;
//std::cout << "G: " << G[i][j] << std::endl;
//std::cout << "B: " << B[i][j] << std::endl;
}
}
}
//---------------------------------------
// Init function for OpenGL
//---------------------------------------
void init()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//Viewing Window Modified
glOrtho(-7.0, 7.0, -7.0, 7.0, -7.0, 7.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Rotates camera
//glRotatef(30.0, 1.0, 1.0, 1.0);
glEnable(GL_DEPTH_TEST);
//Project 3 code
init_surface();
define_normals();
//Shading code
glShadeModel(GL_SMOOTH);
glEnable(GL_NORMALIZE);
init_light(GL_LIGHT0, 0, 1, 1, 0.5, 0.5, 0.5);
//init_light(GL_LIGHT1, 0, 0, 1, 0.5, 0.5, 0.5);
//init_light(GL_LIGHT2, 0, 1, 0, 0.5, 0.5, 0.5);
}
void keyboard(unsigned char key, int x, int y)
{
//Controls
//Toggle Mode
if (key == 'q')
{
if(mode == 0)
{
mode = 1;
std::cout << "Switched to Move mode (" << mode << ")" << std::endl;
}
else if(mode == 1)
{
mode = 0;
std::cout << "Switched to Rotate mode (" << mode << ")" << std::endl;
}
}
////Rotate Camera (mode 0)
//Up & Down
else if (key == 's' && mode == 0)
xangle += 5;
else if (key == 'w' && mode == 0)
xangle -= 5;
//Left & Right
else if (key == 'a' && mode == 0)
yangle -= 5;
else if (key == 'd' && mode == 0)
yangle += 5;
////Move Cube (mode 1)
//Forward & Back
else if (key == 'w' && mode == 1)
{
if (cubeZ > -5)
cubeZ = cubeZ - 1;
else
std::cout << "You have struck an invisible wall! (Min Z bounds)" << std::endl;
}
else if (key == 's' && mode == 1)
{
if (cubeZ < 5)
cubeZ = cubeZ + 1;
else
std::cout << "You have struck an invisible wall! (Max Z bounds)" << std::endl;
}
//Strafe
else if (key == 'd' && mode == 1)
{
if (cubeX < 5)
cubeX = cubeX + 1;
else
std::cout << "You have struck an invisible wall! (Max X bounds)" << std::endl;
}
else if (key == 'a' && mode == 1)
{
if (cubeX > -5)
cubeX = cubeX - 1;
else
std::cout << "You have struck an invisible wall! (Min X bounds)" << std::endl;
}
//Up & Down (Cube offset by +0.5 in Y)
else if (key == 'z' && mode == 1)
{
if (cubeY < 5)
cubeY = cubeY + 1;
else
std::cout << "You've gone too high! Come back! (Max Y bounds)" << std::endl;
}
else if (key == 'x' && mode == 1)
{
if (cubeY > 0.5)
cubeY = cubeY - 1;
else
std::cout << "You've reached bedrock! (Min Y bounds)" << std::endl;
}
//Place/Remove block
else if (key == 'e' && mode == 1)
{
//Occupied(cubeX,cubeY,cubeZ);
}
//Redraw objects
glutPostRedisplay();
}
//---------------------------------------
// Display callback for OpenGL
//---------------------------------------
void display()
{
// Clear the screen
//std::cout << "xangle: " << xangle << std::endl;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Rotation Code
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(xangle, 1.0, 0.0, 0.0);
glRotatef(yangle, 0.0, 1.0, 0.0);
//Light Code
init_material(Ka, Kd, Ks, 100 * Kp, 0.8, 0.6, 0.4);
calc_color();
//Draw the squares, select column
for (int i = 0; i <= 9; i++)
{
//Select row
for (int j = 0; j <= 9; j++)
{
glBegin(GL_POLYGON);
//Surface starts at top left
//Counter clockwise
// CALCULATE COLOR HERE
// - calculate direction from surface to light
// - calculate dot product of normal and light direction vector
// - call glColor function
//Calculate light vector
//Light position, hardcoded for now 0,1,1
///float Lx = 0 - surfaceX[i][j];
//float Ly = 1 - surfaceY[i][j];
//float Lz = 1 - surfaceZ[i][j];
//Grab surface normals
//These are Nx,Ny,Nz due to compiler issues
//float Na = Nx[i][j];
//float Nb = Ny[i][j];
//float Nc = Nz[i][j];
//Do cross product
//float Color = (Na * Lx) + (Nb * Ly) + (Nc * Lz);
//???
//glColor3fv(Color);
//glColor3f(0.5*Color,0.5*Color,0.5*Color);
glColor3f(R[i][j], G[i][j], B[i][j]);
glVertex3f(surfaceX[i][j], surfaceY[i][j], surfaceZ[i][j]);
glColor3f(R[i][j+1], G[i][j+1], B[i][j+1]);
glVertex3f(surfaceX[i][j+1], surfaceY[i][j+1], surfaceZ[i][j+1]);
glColor3f(R[i+1][j+1], G[i+1][j+1], B[i+1][j+1]);
glVertex3f(surfaceX[i+1][j+1], surfaceY[i+1][j+1], surfaceZ[i+1][j+1]);
glColor3f(R[i+1][j], G[i+1][j], B[i+1][j]);
glVertex3f(surfaceX[i+1][j], surfaceY[i+1][j], surfaceZ[i+1][j]);
glEnd();
}
}
//Draw the normals
for (int i = 0; i <= 10; i++)
{
for (int j = 0; j <= 10; j++)
{
glBegin(GL_LINES);
//glColor3f(0.0, 1.0, 1.0);
float length = 1;
glVertex3f(surfaceX[i][j], surfaceY[i][j], surfaceZ[i][j]);
glVertex3f(surfaceX[i][j]+length*Nx[i][j],
surfaceY[i][j]+length*Ny[i][j],
surfaceZ[i][j]+length*Nz[i][j]);
glEnd();
}
}
glEnd();
glFlush();
//Player Cube
//Cube: midx, midy, midz, size
//+Z = Moving TOWARD camera in opengl
//Origin point for reference
glPointSize(10);
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POINTS);
glVertex3f(0, 0, 0);
glEnd();
//Assign Color of Lines
float R = 1;
float G = 1;
float B = 1;
glBegin(GL_LINES);
glColor3f(R, G, B);
////Drawing the grid
//Vertical lines
for (int i = 0; i < 11; i++)
{
int b = -5 + i;
glVertex3f(b, 0, -5);
glVertex3f(b, 0, 5);
}
//Horizontal lines
for (int i = 0; i < 11; i++)
{
int b = -5 + i;
glVertex3f(-5,0,b);
glVertex3f(5,0,b);
}
glEnd();
glEnd();
glFlush();
}
//---------------------------------------
// Main program
//---------------------------------------
int main(int argc, char *argv[])
{
srand(time(NULL));
//Print Instructions
std::cout << "Project 3 Controls: " << std::endl;
std::cout << "q switches control mode" << std::endl;
std::cout << "w,a,s,d for camera rotation" << std::endl;
//Required
glutInit(&argc, argv);
//Window will default to a different size without
glutInitWindowSize(500, 500);
//Window will default to a different position without
glutInitWindowPosition(250, 250);
//
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);
//Required
glutCreateWindow("Project 3");
//Required, calls display function
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
//Required
init();
glutMainLoop();
return 0;
}
Both the surface and normals are being generated as well as the color for the given vertex, I'm just not understanding why it isn't working.
The light or brightness of the surface is a function of the incident light vector the view direction and the normal vector of the surface.
You missed to set the normal vector attributes when you render the plane. Set the normal vector attribute by glNormal, before the vertex coordinate is specified:
for (int i = 0; i <= 9; i++)
{
for (int j = 0; j <= 9; j++)
{
glBegin(GL_POLYGON);
glColor3f(R[i][j], G[i][j], B[i][j]);
glNormal3f(Nx[i][j], Ny[i][j], Nz[i][j]);
glVertex3f(surfaceX[i][j], surfaceY[i][j], surfaceZ[i][j]);
glColor3f(R[i][j+1], G[i][j+1], B[i][j+1]);
glNormal3f(Nx[i][j+1], Ny[i][j+1], Nz[i][j+1]);
glVertex3f(surfaceX[i][j+1], surfaceY[i][j+1], surfaceZ[i][j+1]);
glColor3f(R[i+1][j+1], G[i+1][j+1], B[i+1][j+1]);
glNormal3f(Nx[i+1][j+1], Ny[i+1][j+1], Nz[i+1][j+1]);
glVertex3f(surfaceX[i+1][j+1], surfaceY[i+1][j+1], surfaceZ[i+1][j+1]);
glColor3f(R[i+1][j], G[i+1][j], B[i+1][j]);
glNormal3f(Nx[i+1][j], Ny[i+1][j], Nz[i+1][j]);
glVertex3f(surfaceX[i+1][j], surfaceY[i+1][j], surfaceZ[i+1][j]);
glEnd();
}
}
But note, that the quality of the light will be low, because of the Gouraud shading of the Legacy OpenGL standard light model.
See also OpenGL Lighting on texture plane is not working.
Further, the normal vectors are inverted. You can change the direction by swapping the vectors in the cross product:
Nx[i][j] = Iz * Jy - Iy * Jz;
Ny[i][j] = Ix * Jz - Iz * Jx;
Nz[i][j] = Iy * Jx - Ix * Jy;
Side note:
Note, that drawing by glBegin/glEnd sequences, the fixed function matrix stack and fixed function, per vertex light model, is deprecated since decades. See Fixed Function Pipeline and Legacy OpenGL.
Read about Vertex Specification and Shader for a state of the art way of rendering.
so I got an image as a texture for a square, but the problem is that whenever I run the code I get this:
But when I take this line out:
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
Then I get this output (the white space is where I want to put the image as a texture):
Or if I change the third parameter to 5, then I get this output. But I know that the texture does display correctly when I run the code below, but the output is still like the first image at the top. How would I go about fixing the output so that it looks like the second image with the texture showing? Note that the texture DOES display fine with my code, you just cant see it becuase it's hidden becuase the whole output wont display properly.
#include <GL/glut.h>
#include <iostream>
#include <unistd.h>
#include <math.h>
#include <GL/gl.h>
#include <opencv2/opencv.hpp> //for OpenCV 3.x
#include <opencv/highgui.h> //for OpenCV 3.x
#include <cstdio>
#include <stdlib.h>
#include <string.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <stdio.h>
#include <math.h>
#define UpperBD 80
#define PI 3.1415926
#define Num_pts 10
using namespace std;
float Xe = 200.0f;//100
float Ye = 300.0f;
float Ze = 450.0f;
float Rho = sqrt(pow(Xe,2) + pow(Ye,2) + pow(Ze,2));
float D_focal = 100.0f;
GLuint texture[2];
struct Image {
unsigned long sizeX;
unsigned long sizeY;
char *data;
};
typedef struct Image Image;
#define checkImageWidth 64
#define checkImageHeight 64
GLubyte checkImage[checkImageWidth][checkImageHeight][3];
void makeCheckImage(void){
int i, j, c;
for (i = 0; i < checkImageWidth; i++) {
for (j = 0; j < checkImageHeight; j++) {
c = ((((i&0x8)==0)^((j&0x8)==0)))*255;
checkImage[i][j][0] = (GLubyte) c;
checkImage[i][j][1] = (GLubyte) c;
checkImage[i][j][2] = (GLubyte) c;
}
}
}
int ImageLoad(char *filename, Image *image) {
FILE *file;
unsigned long size; // size of the image in bytes.
unsigned long i; // standard counter.
unsigned short int planes; // number of planes in image (must be 1)
unsigned short int bpp; // number of bits per pixel (must be 24)
char temp; // temporary color storage for bgr-rgb conversion.
// make sure the file is there.
if ((file = fopen(filename, "rb"))==NULL){
printf("File Not Found : %s\n",filename);
return 0;
}
// seek through the bmp header, up to the width/height:
fseek(file, 18, SEEK_CUR);
// read the width
if ((i = fread(&image->sizeX, 4, 1, file)) != 1) {
printf("Error reading width from %s.\n", filename);
return 0;
}
if ((i = fread(&image->sizeY, 4, 1, file)) != 1) {
printf("Error reading height from %s.\n", filename);
return 0;
}
size = image->sizeX * image->sizeY * 3;
// read the planes
if ((fread(&planes, 2, 1, file)) != 1) {
printf("Error reading planes from %s.\n", filename);
return 0;
}
if (planes != 1) {
printf("Planes from %s is not 1: %u\n", filename, planes);
return 0;
}
// read the bitsperpixel
if ((i = fread(&bpp, 2, 1, file)) != 1) {
printf("Error reading bpp from %s.\n", filename);
return 0;
}
if (bpp != 24) {
printf("Bpp from %s is not 24: %u\n", filename, bpp);
return 0;
}
// seek past the rest of the bitmap header.
fseek(file, 24, SEEK_CUR);
// read the data.
image->data = (char *) malloc(size);
if (image->data == NULL) {
printf("Error allocating memory for color-corrected image data");
return 0;
}
if ((i = fread(image->data, size, 1, file)) != 1) {
printf("Error reading image data from %s.\n", filename);
return 0;
}
for (i=0;i<size;i+=3) { // reverse all of the colors. (bgr -> rgb)
temp = image->data[i];
image->data[i] = image->data[i+2];
image->data[i+2] = temp;
}
// we're done.
return 1;
}
Image * loadTexture(){
Image *image1;
// allocate space for texture
image1 = (Image *) malloc(sizeof(Image));
if (image1 == NULL) {
printf("Error allocating space for image");
exit(0);
}
if (!ImageLoad("g.bmp", image1)) {
exit(1);
}
return image1;
}
void myinit(void)
//something in this function is making it not appear properly
{
// glClearColor (0.5, 0.5, 0.5, 0.0);
// glEnable(GL_DEPTH_TEST);
// glDepthFunc(GL_LESS);
Image *image1 = loadTexture();
// makeCheckImage();
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Create Texture
glGenTextures(2, texture);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); //scale linearly when image bigger than texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); //scale linearly when image smalled than texture
glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->data);
//above line causing problem
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glBindTexture(GL_TEXTURE_2D, texture[1]);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
// glTexImage2D(GL_TEXTURE_2D, 0, 3, checkImageWidth, checkImageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE,&checkImage[0][0][0]);
glEnable(GL_TEXTURE_2D);
// glShadeModel(GL_FLAT);
}
typedef struct {
float X[UpperBD];
float Y[UpperBD];
float Z[UpperBD];
} pworld;
typedef struct {
float X[UpperBD];
float Y[UpperBD];
float Z[UpperBD];
} pviewer;
typedef struct{
float X[UpperBD];
float Y[UpperBD];
} pperspective;
typedef struct{
float X[UpperBD];
float Y[UpperBD];
} pattern2DL;
typedef struct{
float X[UpperBD];
float Y[UpperBD];
} arrowpoint;
typedef struct {
float r[UpperBD], g[UpperBD], b[UpperBD];
} pt_diffuse;
void mydisplay()
{
// define x-y coordinate
float p1x=-1.0f, p1y= 0.0f;
float p2x= 1.0f, p2y= 0.0f;
float p3x= 0.0f, p3y= 1.0f;
float p4x= 0.0f, p4y=-1.0f;
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
pworld world;
pviewer viewer;
pperspective perspective;
pattern2DL letterL;
arrowpoint arrow;
//define the x-y-z world coordinate
world.X[0] = 0.0; world.Y[0] = 0.0; world.Z[0] = 0.0; // origin
world.X[1] = 50.0; world.Y[1] = 0.0; world.Z[1] = 0.0; // x-axis
world.X[2] = 0.0; world.Y[2] = 50.0; world.Z[2] = 0.0; // y-axis
world.X[3] = 0.0; world.Y[3] = 0.0; world.Z[3] = 50.0; // y-axis
//define projection plane world coordinate , THIS IS THE SQUARE AROUND THE LETTERS
world.X[4] = 60.0; world.Y[4] = -50.0; world.Z[4] = 0.0;
world.X[5] = 60.0; world.Y[5] = 50.0; world.Z[5] = 0.0; // base line
world.X[7] = 60.0; world.Y[7] = -50.0; world.Z[7] = 100.0; // side bar
world.X[6] = 60.0; world.Y[6] = 50.0; world.Z[6] = 100.0; // side bar
//define 2D pattern letter A
letterL.X[0] = -10.0; letterL.Y[0] = 10.0;
letterL.X[1] = -15.0; letterL.Y[1] = 10.0;
letterL.X[2] = -20.0; letterL.Y[2] = 30.0;
letterL.X[3] = -40.0; letterL.Y[3] = 30.0;
letterL.X[4] = -45.0; letterL.Y[4] = 10.0;
letterL.X[5] = -50.0; letterL.Y[5] = 10.0;
letterL.X[6] = -37.0; letterL.Y[6] = 70.0;
letterL.X[7] = -23.0; letterL.Y[7] = 70.0;
letterL.X[8] = -25.0; letterL.Y[8] = 40.0;
letterL.X[9] = -35.0; letterL.Y[9] = 40.0;
letterL.X[10] = -30.0; letterL.Y[10] = 60.0;
//letter B
letterL.X[11] = 10.0; letterL.Y[11] = 10.0;
letterL.X[12] = 10.0; letterL.Y[12] = 70.0;
letterL.X[13] = 20.0; letterL.Y[13] = 10.0;
letterL.X[14] = 20.0; letterL.Y[14] = 70.0;
letterL.X[15] = 20.0; letterL.Y[15] = 60.0;
letterL.X[16] = 20.0; letterL.Y[16] = 45.0;
letterL.X[17] = 20.0; letterL.Y[17] = 35.0;
letterL.X[18] = 20.0; letterL.Y[18] = 20.0;
letterL.X[19] = 25.0; letterL.Y[19] = 58.0;
letterL.X[20] = 27.0; letterL.Y[20] = 56.0;
letterL.X[21] = 28.0; letterL.Y[21] = 52.0;
letterL.X[22] = 27.0; letterL.Y[22] = 49.0;
letterL.X[23] = 25.0; letterL.Y[23] = 47.0;
letterL.X[24] = 25.0; letterL.Y[24] = 33.0;
letterL.X[25] = 27.0; letterL.Y[25] = 31.0;
letterL.X[26] = 28.0; letterL.Y[26] = 27.0;
letterL.X[27] = 27.0; letterL.Y[27] = 24.0;
letterL.X[28] = 25.0; letterL.Y[28] = 22.0;
letterL.X[29] = 30.0; letterL.Y[29] = 65.0;
letterL.X[30] = 34.0; letterL.Y[30] = 60.0;
letterL.X[31] = 34.0; letterL.Y[31] = 50.0;
letterL.X[32] = 30.0; letterL.Y[32] = 45.0;
letterL.X[33] = 25.0; letterL.Y[33] = 40.0;
letterL.X[34] = 30.0; letterL.Y[34] = 38.0;
letterL.X[35] = 34.0; letterL.Y[35] = 30.0;
letterL.X[36] = 34.0; letterL.Y[36] = 20.0;
letterL.X[37] = 30.0; letterL.Y[37] = 15.0;
arrow.X[0] = 0.0; arrow.Y[0] = 25.0;
arrow.X[1] = 0.0; arrow.Y[1] = 75.0;
arrow.X[2] = 60.0; arrow.Y[2] = 75.0;
arrow.X[3] = 60.0; arrow.Y[3] = 85.0;
arrow.X[4] = 90.0; arrow.Y[4] = 50.0;
arrow.X[5] = 60.0; arrow.Y[5] = 15.0;
arrow.X[6] = 60.0; arrow.Y[6] = 25.0;
arrow.X[7] = 0.0; arrow.Y[7] = 25.0;
arrow.X[8] = 0.0; arrow.Y[8] = 75.0;
arrow.X[9] = 60.0; arrow.Y[9] = 75.0;
arrow.X[10] = 60.0; arrow.Y[10] = 85.0;
arrow.X[11] = 90.0; arrow.Y[11] = 50.0;
arrow.X[12] = 60.0; arrow.Y[12] = 15.0;
arrow.X[13] = 60.0; arrow.Y[13] = 25.0;
//decoration
for(int i = 0; i <= 37; i++)
{
world.X[8+i] = 60.0;
world.Y[8+i] = letterL.X[i];
world.Z[8+i] = letterL.Y[i];
}
//arrow
for(int j = 0; j <= 6; j++)
{
world.X[46+j] = arrow.X[j]-50;//-50
world.Y[46+j] = arrow.Y[j];
world.Z[46+j] = 100.0;//CHANGE TO 150?
}
for(int k = 0; k <= 6; k++)
{
world.X[53+k] = arrow.X[k]-50;
world.Y[53+k] = arrow.Y[k];
world.Z[53+k] = 110.0;//CHANGE TO 150?
}
float sPheta = Ye / sqrt(pow(Xe,2) + pow(Ye,2));
float cPheta = Xe / sqrt(pow(Xe,2) + pow(Ye,2));
float sPhi = sqrt(pow(Xe,2) + pow(Ye,2)) / Rho;
float cPhi = Ze / Rho;
float xMin = 1000.0, xMax = -1000.0;
float yMin = 1000.0, yMax = -1000.0;
//47 is normal vector 46 is a, 45 is ps, 7 is top left box vertex
//COMUTER SHADE OF FLOATING ARROW DUE NEXT WEEK
world.X[60] = -200.0; world.Y[60]=50.0; world.Z[60]=200.0;//ps
world.X[61] = 0.0; world.Y[61]=0.0; world.Z[61]=0.0;//vector a
world.X[62] = 0.0; world.Y[62]=0.0; world.Z[62]=1.0;//VECTOR N
float tmp = (world.X[62]*(world.X[61]-world.X[60]))
+(world.Y[62]*(world.Y[61]-world.Y[60]))
+(world.Z[62]*(world.Z[61]-world.Z[60]));
cout << tmp;
float lambda = tmp/((world.X[62]*(world.X[60]-world.X[7]))
+(world.Y[62]*(world.Y[60]-world.Y[7]))
+(world.Z[62]*(world.Z[60]-world.Z[7])));
cout << lambda;
float lambda_2 = tmp/((world.X[62]*(world.X[60]-world.X[6]))//MAKE ARROW HIGHER, ABOVE PROJECTION PLANE SQUARE
+(world.Y[62]*(world.Y[60]-world.Y[6]))
+(world.Z[62]*(world.Z[60]-world.Z[6])));
cout << lambda_2;
world.X[63] = world.X[60]+lambda*(world.X[60]-world.X[7]);//interseciton point for p7, X COMP
world.Y[63] = world.Y[60]+lambda*(world.Y[60]-world.Y[7]);//Y COMP
world.Z[63] = 0.0;
world.X[64] = world.X[60]+lambda_2*(world.X[60]-world.X[6]);//interseciton point for p7, X COMP
world.Y[64] = world.Y[60]+lambda_2*(world.Y[60]-world.Y[6]);//Y COMP
world.Z[64] = 0.0;
//for arrow's shade, 46-52
float lambda_arrow1 = tmp/((world.X[62]*(world.X[60]-world.X[46]))
+(world.Y[62]*(world.Y[60]-world.Y[46]))
+(world.Z[62]*(world.Z[60]-world.Z[46])));
float lambda_arrow2 = tmp/((world.X[62]*(world.X[60]-world.X[47]))//MAKE ARROW HIGHER, ABOVE PROJECTION PLANE SQUARE
+(world.Y[62]*(world.Y[60]-world.Y[47]))
+(world.Z[62]*(world.Z[60]-world.Z[47])));
float lambda_arrow3 = tmp/((world.X[62]*(world.X[60]-world.X[48]))
+(world.Y[62]*(world.Y[60]-world.Y[48]))
+(world.Z[62]*(world.Z[60]-world.Z[48])));
float lambda_arrow4 = tmp/((world.X[62]*(world.X[60]-world.X[49]))
+(world.Y[62]*(world.Y[60]-world.Y[49]))
+(world.Z[62]*(world.Z[60]-world.Z[49])));
float lambda_arrow5 = tmp/((world.X[62]*(world.X[60]-world.X[50]))
+(world.Y[62]*(world.Y[60]-world.Y[50]))
+(world.Z[62]*(world.Z[60]-world.Z[50])));
float lambda_arrow6 = tmp/((world.X[62]*(world.X[60]-world.X[51]))
+(world.Y[62]*(world.Y[60]-world.Y[51]))
+(world.Z[62]*(world.Z[60]-world.Z[51])));
float lambda_arrow7 = tmp/((world.X[62]*(world.X[60]-world.X[52]))
+(world.Y[62]*(world.Y[60]-world.Y[52]))
+(world.Z[62]*(world.Z[60]-world.Z[52])));
world.X[65] = world.X[60]+lambda_arrow1*(world.X[60]-world.X[46]);//interseciton point for p7, X COMP
world.Y[65] = world.Y[60]+lambda_arrow1*(world.Y[60]-world.Y[46]);//Y COMP
world.Z[65] = 0.0;
world.X[66] = world.X[60]+lambda_arrow2*(world.X[60]-world.X[47]);//interseciton point for p7, X COMP
world.Y[66] = world.Y[60]+lambda_arrow2*(world.Y[60]-world.Y[47]);//Y COMP
world.Z[66] = 0.0;
world.X[67] = world.X[60]+lambda_arrow3*(world.X[60]-world.X[48]);//interseciton point for p7, X COMP
world.Y[67] = world.Y[60]+lambda_arrow3*(world.Y[60]-world.Y[48]);//Y COMP
world.Z[67] = 0.0;
world.X[68] = world.X[60]+lambda_arrow4*(world.X[60]-world.X[49]);//interseciton point for p7, X COMP
world.Y[68] = world.Y[60]+lambda_arrow4*(world.Y[60]-world.Y[49]);//Y COMP
world.Z[68] = 0.0;
world.X[69] = world.X[60]+lambda_arrow5*(world.X[60]-world.X[50]);//interseciton point for p7, X COMP
world.Y[69] = world.Y[60]+lambda_arrow5*(world.Y[60]-world.Y[50]);//Y COMP
world.Z[69] = 0.0;
world.X[70] = world.X[60]+lambda_arrow6*(world.X[60]-world.X[51]);//interseciton point for p7, X COMP
world.Y[70] = world.Y[60]+lambda_arrow6*(world.Y[60]-world.Y[51]);//Y COMP
world.Z[70] = 0.0;
world.X[71] = world.X[60]+lambda_arrow7*(world.X[60]-world.X[52]);//interseciton point for p7, X COMP
world.Y[71] = world.Y[60]+lambda_arrow7*(world.Y[60]-world.Y[52]);//Y COMP
world.Z[71] = 0.0;
// -----------diffuse reflection-----------*
pt_diffuse diffuse; //diffuse.r[3]
//-------reflectivity coefficient-----------*
#define Kdr 0.8
#define Kdg 0.0
#define Kdb 0.0
// define additional pts to find diffuse reflection
//world.X[49] = world.X[45] + lambda_2*(world.X[45] - world.X[6]);
//--------compute distance------------------*//change 45 to 60!!!!!!
float distance[UpperBD];
for (int i=63; i<=71; i++) {
distance[i] = sqrt(pow((world.X[i]-world.X[60]),2)+ //intersect pt p7
pow((world.Y[i]-world.Y[60]),2)+
pow((world.X[i]-world.X[60]),2) );
//std::cout << "distance[i] " << distance[i] << std::endl;
}
// for (int i=4; i<=5; i++){
// distance[i] = sqrt(pow((world.X[i]-world.X[60]),2)+ //pt p4 of projection plane
// pow((world.Y[i]-world.Y[60]),2)+
// pow((world.X[i]-world.X[60]),2) );
// //std::cout << "distance[i] " << distance[i] << std::endl;
// }
//--------compute angle---------------------*
float angle[UpperBD], tmp_dotProd[UpperBD], tmp_mag_dotProd[UpperBD];
for (int i=63; i<=71; i++){
tmp_dotProd[i] = world.Z[i]-world.X[60];
std::cout << " tmp_dotProd[i] " << tmp_dotProd[i] << std::endl;
tmp_mag_dotProd[i] = sqrt(pow((world.X[i]-world.X[60]),2)+ //[45] pt light source
pow((world.Y[i]-world.Y[60]),2)+
pow((world.Z[i]-world.Z[60]),2) );
std::cout << " tmp_mag_dotProd[i] 1 " << tmp_mag_dotProd[i] << std::endl;
angle[i] = tmp_dotProd[i]/ tmp_mag_dotProd[i];
std::cout << "angle[i] " << angle[i] << std::endl;
//compute color intensity
diffuse.r[i] = Kdr * angle[i] / pow(distance[i],2) ;
diffuse.g[i] = Kdg * angle[i] / pow(distance[i],2) ;
diffuse.b[i] = Kdb * angle[i] / pow(distance[i],2) ;
}
// for (int i=4; i<=5; i++){
//
// tmp_dotProd[i] = world.Z[i]-world.X[45];
// std::cout << " tmp_dotProd[i] " << tmp_dotProd[i] << std::endl;
//
// tmp_mag_dotProd[i] = sqrt(pow((world.X[i]-world.X[45]),2)+ //[45] pt light source
// pow((world.Y[i]-world.Y[45]),2)+
// pow((world.Z[i]-world.Z[45]),2) );
// std::cout << " tmp_mag_dotProd[i] 1 " << tmp_mag_dotProd[i] << std::endl;
//
// angle[i] = tmp_dotProd[i]/ tmp_mag_dotProd[i];
// std::cout << "angle[i] " << angle[i] << std::endl;
//
// //compute color intensity
// diffuse.r[i] = Kdr * angle[i] / pow(distance[i],2) ;
// diffuse.g[i] = Kdg * angle[i] / pow(distance[i],2) ;
// diffuse.b[i] = Kdb * angle[i] / pow(distance[i],2) ;
//
// //std::cout << "diffuse.r[i] " << diffuse.r[i] << std::endl;
// //std::cout << "diffuse.g[i] " << diffuse.g[i] << std::endl;
// }
//
for(int i = 0; i < UpperBD; i++)
{
viewer.X[i] = -sPheta * world.X[i] + cPheta * world.Y[i];
viewer.Y[i] = -cPheta * cPhi * world.X[i]
- cPhi * sPheta * world.Y[i]
+ sPhi * world.Z[i];
viewer.Z[i] = -sPhi * cPheta * world.X[i]
- sPhi * cPheta * world.Y[i]
-cPheta * world.Z[i] + Rho;
// cout << i;
}
for(int i = 0; i <= UpperBD; i++)
{
perspective.X[i] = D_focal * viewer.X[i] / viewer.Z[i] ;
perspective.Y[i] = D_focal * viewer.Y[i] / viewer.Z[i] ;
if (perspective.X[i] > xMax) xMax = perspective.X[i];
if (perspective.X[i] < xMin) xMin = perspective.X[i];
if (perspective.Y[i] > yMax) yMax = perspective.Y[i];
if (perspective.Y[i] < yMin) yMin = perspective.Y[i];
/////*
//std::cout << "xMin " << xMin << std::endl;
// std::cout << "xMax " << xMax << std::endl;
// std::cout << "yMin " << yMin << std::endl;
// std::cout << "yMax " << yMax << std::endl;
//*/
}
for(int i = 0; i <= UpperBD; i++)
{
if ((xMax-xMin) != 0) perspective.X[i] = perspective.X[i]/(xMax-xMin);
if ((yMax-yMin) != 0) perspective.Y[i] = perspective.Y[i]/(yMax-yMin);
std::cout << i << perspective.X[i] << perspective.Y[i] << std::endl;
}
glViewport(0,0,1550,1250);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glBegin(GL_LINES);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 0.0, 0.0);
glVertex2f(perspective.X[0],perspective.Y[0]);
glVertex2f(perspective.X[1],perspective.Y[1]);
glColor3f(0.0, 1.0, 0.0);
glVertex2f(perspective.X[0],perspective.Y[0]);
glVertex2f(perspective.X[2],perspective.Y[2]);
glColor3f(0.0, 0.0, 1.0);
glVertex2f(perspective.X[0],perspective.Y[0]);
glVertex2f(perspective.X[3],perspective.Y[3]);
glColor3f(1.0, 1.0, 0.0); // projection plane , square
glVertex2f(perspective.X[4],perspective.Y[4]);
glVertex2f(perspective.X[5],perspective.Y[5]);
glVertex2f(perspective.X[4],perspective.Y[4]);
glVertex2f(perspective.X[7],perspective.Y[7]);
glVertex2f(perspective.X[5],perspective.Y[5]);
glVertex2f(perspective.X[6],perspective.Y[6]);
glVertex2f(perspective.X[6],perspective.Y[6]);
glVertex2f(perspective.X[7],perspective.Y[7]);
glEnd();
glColor3f(0.0, 1.0, 0.0); // LETTER A STARTS HERE
glBegin(GL_POLYGON);
glVertex2f(perspective.X[13],perspective.Y[13]);
glVertex2f(perspective.X[12],perspective.Y[12]);
glVertex2f(perspective.X[11],perspective.Y[11]);
glVertex2f(perspective.X[12],perspective.Y[12]);
glVertex2f(perspective.X[14],perspective.Y[14]);
glVertex2f(perspective.X[13],perspective.Y[13]);
glVertex2f(perspective.X[18],perspective.Y[18]);
glVertex2f(perspective.X[17],perspective.Y[17]);
glVertex2f(perspective.X[11],perspective.Y[11]);
glVertex2f(perspective.X[17],perspective.Y[17]);
glVertex2f(perspective.X[18],perspective.Y[18]);
glVertex2f(perspective.X[14],perspective.Y[14]);
glEnd();
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(perspective.X[8],perspective.Y[8]);
glVertex2f(perspective.X[15],perspective.Y[15]);
glVertex2f(perspective.X[14],perspective.Y[14]);
glVertex2f(perspective.X[15],perspective.Y[15]);
glVertex2f(perspective.X[14],perspective.Y[14]);
glVertex2f(perspective.X[18],perspective.Y[18]);
glVertex2f(perspective.X[16],perspective.Y[16]);
glVertex2f(perspective.X[18],perspective.Y[18]);
glVertex2f(perspective.X[16],perspective.Y[16]);
glVertex2f(perspective.X[10],perspective.Y[10]);
glVertex2f(perspective.X[9],perspective.Y[9]);
glVertex2f(perspective.X[10],perspective.Y[10]);
glVertex2f(perspective.X[8],perspective.Y[8]);
glVertex2f(perspective.X[9],perspective.Y[9]);
glEnd();
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(perspective.X[16],perspective.Y[16]);
glVertex2f(perspective.X[17],perspective.Y[17]);
//etc...
glEnd();
glColor3f(0.0, 1.0, 0.0); //LETTER B STARTS HERE
glBegin(GL_POLYGON);
glVertex2f(perspective.X[19],perspective.Y[19]);
glVertex2f(perspective.X[20],perspective.Y[20]);
//etc...
glEnd();
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINES);
//
glVertex2f(perspective.X[23],perspective.Y[23]);
glVertex2f(perspective.X[24],perspective.Y[24]);
glVertex2f(perspective.X[25],perspective.Y[25]);
glVertex2f(perspective.X[26],perspective.Y[26]);
glEnd();
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(perspective.X[27],perspective.Y[27]);
glVertex2f(perspective.X[28],perspective.Y[28]);
//etc...
glEnd();
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(perspective.X[29],perspective.Y[29]);
glVertex2f(perspective.X[30],perspective.Y[30]);
//etc...
glEnd();
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_POLYGON);
glVertex2f(perspective.X[24],perspective.Y[24]);
glVertex2f(perspective.X[41],perspective.Y[41]);
//etc...
glEnd();
glColor3f(0.0, 1.0, 0.0);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_LINES);//3D arrow starts here
glVertex2f(perspective.X[46],perspective.Y[46]);
glVertex2f(perspective.X[47],perspective.Y[47]);
//etc...
glEnd(); //end arrow
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_LINES);
glVertex2f(perspective.X[63],perspective.Y[63]);
glVertex2f(perspective.X[64],perspective.Y[64]);
//etc...
glEnd(); //end arrow
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_LINES);
//arrow shadow
glVertex2f(perspective.X[65],perspective.Y[65]);
glVertex2f(perspective.X[66],perspective.Y[66]);
//etc...
glEnd();
glBindTexture(GL_TEXTURE_2D, texture[1]);
// glutSolidTeapot(0.1);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glEnable( GL_TEXTURE_2D );
glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
glBegin(GL_QUADS);
glVertex2f(perspective.X[4],perspective.Y[4]);
glTexCoord2f(0.0, 0.0);
glVertex2f(perspective.X[5],perspective.Y[5]);
glTexCoord2f(0.1, 0.0);
glVertex2f(perspective.X[4],perspective.Y[4]);
glTexCoord2f(0.1, 0.1);
glVertex2f(perspective.X[7],perspective.Y[7]);
glTexCoord2f(0.0, 0.1);
glVertex2f(perspective.X[5],perspective.Y[5]);
glVertex2f(perspective.X[6],perspective.Y[6]);
glVertex2f(perspective.X[6],perspective.Y[6]);
glVertex2f(perspective.X[7],perspective.Y[7]);
glEnd();
glDisable( GL_TEXTURE_2D );
//glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
#define display_scaling 200000.0
#define display_shifting 0.2
for (int i=63; i<=71; i++) {
float r, g, b;
r = display_scaling*diffuse.r[i]+display_shifting;
//r = display_scaling*diffuse.r[i];
g = diffuse.g[i]; b = diffuse.b[i] ;
glColor3f(r, g, b);
std::cout << "display_scaling*diffuse.r[i] " << r << std::endl;
glBegin(GL_POLYGON);
glVertex2f(perspective.X[i],perspective.Y[i]);
glVertex2f(perspective.X[i]+0.1,perspective.Y[i]);
glVertex2f(perspective.X[i]+0.1,perspective.Y[i]+0.1);
glVertex2f(perspective.X[i],perspective.Y[i]+0.1);
glEnd();
}
gluPerspective(45.0,0.5,1.0,60.0);
gluOrtho2D(5, 10, 0.0, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glutSwapBuffers();
glFlush();
//sleep(5);
}
int main(int argc, char** argv)
{
cv::Mat image = cv::imread("b.jpg", CV_LOAD_IMAGE_COLOR);
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB );
glutInitWindowSize(900, 1000);
glutCreateWindow("lab");
//imshow( "lab", image );
glutDisplayFunc(mydisplay);
myinit();
glutMainLoop();
}
glEnable(GL_TEXTURE_2D) has to be removed from myinit, because it is done immediately before the object with the texture is drawn.
Further use the STB library, which can be found at GitHub - nothings/stb to load the bitmap:
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
void myinit(void)
{
glGenTextures(2, texture);
int cx, cy, ch;
stbi_uc *img = stbi_load("g.bmp", &cx, &cy, &ch, 3);
if (!img)
return;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, cx, cy, 0, GL_RGB, GL_UNSIGNED_BYTE, img);
stbi_image_free( img );
// ....
}
The number of vertex coordinates is UpperBD, so the maximum index is UpperBD-1 or < UpperBD, but not <= UpperBD.
Change (2 times):
for(int i = 0; i <= UpperBD; i++)
for(int i = 0; i < UpperBD; i++)
gluPerspective and gluOrtho2D at once makes no sense at all.
Init the projection matrix and the model view matrix at the begin of each frame in mydisplay:
void mydisplay()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0,0.5,1.0,60.0);
//gluOrtho2D(5, 10, 0.0, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
.....
}
When the vertex coordinate is set by glVertex the current texture coordinates, and is associated with the vertex coordinate. This means glTexCoord has to be dine before glVertex. A GL_QUAD primitive consitis of 4 vertices and each vertex coordinate needs its own texture coordinate:
glBindTexture(GL_TEXTURE_2D, texture[0]);
glEnable( GL_TEXTURE_2D );
glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex2f(perspective.X[4],perspective.Y[4]);
glTexCoord2f(1.0, 0.0);
glVertex2f(perspective.X[5],perspective.Y[5]);
glTexCoord2f(1.0, 1.0);
glVertex2f(perspective.X[6],perspective.Y[6]);
glTexCoord2f(0.0, 1.0);
glVertex2f(perspective.X[7],perspective.Y[7]);
glEnd();
I generated a 3d shape using a perlin noise.
I am trying to smooth shade it, to do so I calculated the face normal for each of my triangles and then I calculated the normal of each triangle vertex by averaging the normals of the faces they belong to and normalizing the final result.
The final result looks a lot like flat shading (see attached screenshots)
The normals looks correct to me.
I cannot use shaders and have to use the old deprecated way of rendering.
The shape generator :
void Island::generateTopTriangles() {
float xStep = 2 * _xmax / _tess;
float zStep = 2 * _zmax / _tess;
PointMap top;
for (int i = 0; i <= _tess; i++) {
float z = -_zmax + i * zStep;
std::vector<Vector3f> rowTop;
for (int j = 0; j <= _tess; j++) {
float x = -_xmax + j * xStep;
rowTop.emplace_back(x, islandPerlin(x, z), z);
}
top.emplace_back(rowTop);
}
for (int i = 0; i < top.size() - 1; i++) {
const std::vector<Vector3f> &pointRow = top[i];
const std::vector<Vector3f> &pointUpRow = top[i + 1];
std::vector<Triangle> newRow;
for (int j = 0; j < pointRow.size() - 1; j++) {
const Vector3f &p1 = pointRow.at(j);
const Vector3f &p2 = pointRow.at(j + 1);
const Vector3f &p3 = pointUpRow.at(j);
const Vector3f &p4 = pointUpRow.at(j + 1);
Vertex::Ptr v1, v2, v3, v4, v5;
if (j == 0) {
v1 = std::make_shared<Vertex>(Vertex(p1, p3, Vector3f()));
} else { //Retrieve existing Vertex
v1 = newRow[newRow.size() - 1].v2;
}
v2 = std::make_shared<Vertex>(Vertex(p3, p2, Vector3f()));
if (i == 0) {
v3 = std::make_shared<Vertex>(Vertex(p2, p1, Vector3f()));
} else { //Retrieve existing Vertex
v3 = _triangles[_triangles.size() - 1][j == 0 ? 1 : newRow.size() + 1].v3;
}
v4 = std::make_shared<Vertex>(Vertex(p2, p4, Vector3f()));
v5 = std::make_shared<Vertex>(Vertex(p4, p3, Vector3f()));
//Create triangles
newRow.emplace_back(v1, v2, v3, computeNormal(v1->p, v2->p, v3->p));
newRow.emplace_back(v2, v4, v5, computeNormal(v2->p, v4->p, v5->p).invert());
}
_triangles.emplace_back(newRow);
}
}
I compute face normals with a simple cross product between two vectors :
Vector3f Island::computeNormal(const Vector3f &p1, const Vector3f &p2, const Vector3f &p3) {
Vector3f u = {p2.x - p1.x,
p2.y - p1.y,
p2.z - p1.z};
Vector3f v = {p3.x - p1.x,
p3.y - p1.y,
p3.z - p1.z};
Vector3f n = {u.y * v.z - u.z * v.y,
u.z * v.x - u.x * v.z,
u.x * v.y - u.y * v.x};
return n.normalize();
}
The per vertex normals (initialized to 0) :
void Island::computePerVertexNormal() {
for (auto row : _triangles) {
for (auto t : row) {
t.v1->n.x += t.n.x;
t.v1->n.y += t.n.y;
t.v1->n.z += t.n.z;
t.v2->n.x += t.n.x;
t.v2->n.y += t.n.y;
t.v2->n.z += t.n.z;
t.v3->n.x += t.n.x;
t.v3->n.y += t.n.y;
t.v3->n.z += t.n.z;
}
}
for (auto row : _triangles) {
for (auto t : row) {
t.v1->n.normalize();
t.v2->n.normalize();
t.v3->n.normalize();
}
}
}
And finally the drawing part :
void Island::draw() const {
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_BLEND);
glEnable(GL_COLOR_MATERIAL);
GLfloat specular[] = {0.1f, 0.1f, 0.1f, 0.0f};
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
GLfloat diffuse[] = {0.5f, 0.5f, 0.5f, 1.0f};
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse);
GLfloat emission[] = {0.0f, 0.0f, 0.0f, 1.0f};
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emission);
GLfloat shininess = 128.0f;
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
glShadeModel(GL_SMOOTH);
glColor4f(1.0f, 0.5f, 0.0f, 1.0f);
glBegin(GL_TRIANGLES);
for (auto &row : _triangles) {
for (auto &t : row) {
glNormal3f(t.v1->n.x, t.v1->n.y, t.v1->n.z);
glVertex3f(t.v1->p.x, t.v1->p.y, t.v1->p.z);
glNormal3f(t.v2->n.x, t.v2->n.y, t.v2->n.z);
glVertex3f(t.v2->p.x, t.v2->p.y, t.v2->p.z);
glNormal3f(t.v3->n.x, t.v3->n.y, t.v3->n.z);
glVertex3f(t.v3->p.x, t.v3->p.y, t.v3->p.z);
}
}
glEnd();
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_BLEND);
glDisable(GL_LIGHT0);
glDisable(GL_LIGHTING);
}
The solution was simple. I got confused and thought my edges were the vertices. Once corrected, since the new vertices share the correct points this time, the new normals are now calculated from the 6 adjacent triangle faces and are now correct. the generation code is now much simpler as well.
void Island::generateTopTriangles() {
float xStep = 2 * _xmax / _tess;
float zStep = 2 * _zmax / _tess;
float z;
for (int i = 0; i <= _tess; i++) {
z = -_zmax + i * zStep;
std::vector<Vertex::Ptr> row;
for (int j = 0; j <= _tess; j++) {
float x = -_xmax + j * xStep;
row.emplace_back(std::make_shared<Vertex>(Vector3f(x, islandPerlin(x, z), z)));
}
_vertices.emplace_back(row);
}
for (int i = 0; i < _vertices.size() - 1; i++) {
const std::vector<Vertex::Ptr> &pointRow = _vertices[i];
const std::vector<Vertex::Ptr> &pointUpRow = _vertices[i + 1];
std::vector<Triangle::Ptr> newRow;
for (int j = 0; j < pointRow.size() - 1; j++) {
const Vertex::Ptr p1 = pointRow.at(j);
const Vertex::Ptr p2 = pointRow.at(j + 1);
const Vertex::Ptr p3 = pointUpRow.at(j);
const Vertex::Ptr p4 = pointUpRow.at(j + 1);
newRow.emplace_back(std::make_shared<Triangle>(p1, p2, p3, computeNormal(p3->p, p2->p, p1->p)));
newRow.emplace_back(std::make_shared<Triangle>(p3, p2, p4, computeNormal(p4->p, p2->p, p3->p)));
}
_triangles.emplace_back(newRow);
}
}
The rest of the code was actually correct. Here are the results :