What would be the best way of converting std::vector of Vertices to float*? I have vtx as my original data, which contains two vertices with position, normal and uv and I have std::vector of vertices v with the same position, normal and uv. What I am trying to achieve is getting the same memory layout and data as vtx into vtx2 using std::vector v. I tried copying the memory from v to vtx2 using memcpy but when I print them they are ordered in different way.
#include <iostream>
#include <vector>
using namespace std;
struct Vector3
{
float x;
float y;
float z;
};
struct Vector2
{
float x;
float y;
};
struct Vertex
{
Vector3 position;
Vector3 normal;
Vector2 uv;
};
int main(int argc, char *argv[])
{
const int n = 16;
float* vtx = new float[n];
// Vertex 1
// Position
vtx[0] = 1.0f;
vtx[1] = 2.0f;
vtx[2] = 3.0f;
// Normal
vtx[3] = 0.1f;
vtx[4] = 0.2f;
vtx[5] = 0.3f;
// UV
vtx[6] = 0.0f;
vtx[7] = 1.0f;
vtx += 8;
// Vertex 2
// Position
vtx[0] = 4.0f;
vtx[1] = 5.0f;
vtx[2] = 6.0f;
// Normal
vtx[3] = 0.2f;
vtx[4] = 0.3f;
vtx[5] = 0.4f;
// UV
vtx[6] = 0.0f;
vtx[7] = 1.0f;
vtx += 8;
for (int i = n; i>0; i--)
{
cout << *(vtx + i * -1) << endl;
}
vector<Vertex> v;
Vertex vt;
// Vertex 1
// Position
Vector3 pos1 = {1.0, 2.0, 3.0};
vt.position = pos1;
// Normal
Vector3 normal1 = {0.1, 0.2, 0.3};
vt.position = normal1;
// UV
Vector2 uv1 = {0.0, 1.0};
vt.uv = uv1;
v.push_back(vt);
// Vertex 2
// Position
Vector3 pos2 = {4.0, 5.0, 6.0};
vt.position = pos2;
// Normal
Vector3 normal2 = {0.2, 0.3, 0.4};
vt.position = normal2;
// UV
Vector2 uv2 = {0.0, 1.0};
vt.uv = uv2;
v.push_back(vt);
float* vtx2 = new float[n];
memcpy(vtx2, &v[0], v.size() * sizeof(Vertex));
for (int i = n; i>0; i--)
{
cout << *(vtx2 + i * -1) << endl;
}
delete[] vtx;
delete[] vtx2;
return 0;
}
#include <cstring>
#include <iostream>
#include <vector>
#include <cstddef>
using namespace std;
struct Vector3
{
float x;
float y;
float z;
};
struct Vector2
{
float x;
float y;
};
struct Vertex
{
Vector3 position;
Vector3 normal;
Vector2 uv;
};
int main(int argc, char *argv[])
{
const int n = 16;
float* vtx1 = new float[n];
float* vtx = vtx1;
cout << offsetof(Vertex, normal) << " " << offsetof(Vertex, uv) << " " << sizeof(Vertex) << "\n";
// Vertex 1
// Position
vtx[0] = 1.0f;
vtx[1] = 2.0f;
vtx[2] = 3.0f;
// Normal
vtx[3] = 0.1f;
vtx[4] = 0.2f;
vtx[5] = 0.3f;
// UV
vtx[6] = 0.0f;
vtx[7] = 1.0f;
vtx += 8;
// Vertex 2
// Position
vtx[0] = 4.0f;
vtx[1] = 5.0f;
vtx[2] = 6.0f;
// Normal
vtx[3] = 0.2f;
vtx[4] = 0.3f;
vtx[5] = 0.4f;
// UV
vtx[6] = 0.0f;
vtx[7] = 1.0f;
vtx += 8;
for (int i = n; i>0; i--)
{
cout << *(vtx + i * -1) << endl;
}
cout << "\n";
vector<Vertex> v;
Vertex vt;
// Vertex 1
// Position
Vector3 pos1 = {1.0, 2.0, 3.0};
vt.position = pos1;
// Normal
Vector3 normal1 = {0.1, 0.2, 0.3};
vt.normal = normal1;
// UV
Vector2 uv1 = {0.0, 1.0};
vt.uv = uv1;
v.push_back(vt);
// Vertex 2
// Position
Vector3 pos2 = {4.0, 5.0, 6.0};
vt.position = pos2;
// Normal
Vector3 normal2 = {0.2, 0.3, 0.4};
vt.normal = normal2;
// UV
Vector2 uv2 = {0.0, 1.0};
vt.uv = uv2;
v.push_back(vt);
float* vtx2 = new float[n];
vtx = vtx2;
memcpy(vtx, &v[0], n*sizeof(float));
vtx += n;
for (int i = n; i>0; i--)
{
cout << *(vtx + i * -1) << endl;
}
delete[] vtx1;
delete[] vtx2;
return 0;
}
Here is some corrected code with .normal instead of .position, it doesn't delete random memory by deleting vtx and the second print loop is fixed to show the data in the array instead of the 16 bytes of memory preceding it. It also prints the struct size and offsets in the first line. If you don't get 12 24 32 as the first line, your compiler is padding the structs with empty space which is causing your problems. You can use struct Vertex __attribute__((packed)) to prevent this on GCC or clang. Other compilers have different ways of doing it.
There is a bug in your code:
vt.position = normal1
should read
vt.normal = normal1
And similarly for the second vertex in your vector. Upon fixing that you may find the output matches (it does for me), but it may depend on how your compiler is padding structs.
For example, forcing a different alignment on Vector3 using struct Vector3 {...} __attribute__ ((aligned (16))); will generate "corrupted" output.
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/
So I have this code for graphics pipeline, but I am getting errors for some reason.
#include <GL/glut.h>
#include <stdio.h>
#include <unistd.h>
#define UpperBD 3
#define Xe 200
#define Ye 200
#define Ze 200
#define Rho sqrt(sq(Xe) + sq(Ye) + sq(Ze))
#define PI 3.1415926
#define D_focal 20
typedef struct {
float X[] = {};
float Y[] = {};
float Z[] = {};
} pworld;
typedef struct {
float X[] = {};
float Y[] = {};
float Z[] = {};
} pviewer;
typedef struct{
float X[] = {};
float Y[] = {};
} pperspective;
void mydisplay()
{
float p1x = 0.0f, p1y = 1.0f; //the window coordinates (-1.0, 1.0)
float p2x = 0.0f, p2y = -1.0f;
float p3x = 1.0f, p3y = 0.0f;
float p4x = -1.0f, p4y = 0.0f;
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
/* Line starts */
glBegin(GL_LINES);
glVertex2f(p1x, p1y);
glVertex2f(p2x, p2y);
glVertex2f(p3x, p3y);
glVertex2f(p4x, p4y);
glEnd();
/* Line Ends */
// #define Pheta = PI/4.0;
// #define Phi =
/* World to viewer */
pworld world[3];
pviewer viewer[3];
pperspective perspective[3];
float sPheta = Ye / sqrt(sq(Xe) + sq(Ye));
float cPheta = Xe / sqrt(sq(Xe) + sq(Ye));
float sPhi = sqrt(sq(Xe) + sq(Ye)) / Rho;
float cPhi = Ze / Rho;
for(int i = 0; i <= UpperBD; i++)
{
viewer[i].X = -sPheta * world[i].X; + cPheta * world[i].y;
viewer[i].Y = -cPheta * cPhi * world[i].X
- cPhi * sPheta * world[i].Y
+ sPhi * world[i].Z;
viewer[i].Z = -sPhi * cPheta * world[i].X
- sPhi * cPheta * world[i].Y
-cPheta * world[i].Z + Rho;
perspective[i].X = (D_focal / viewer[i].Z) * viewer[i].X;
perspective[i].Y = (D_focal / viewer[i].Z) * viewer[i].Y;
cout << perspective[i].X << endl;
cout << perspective[i].Y << endl;
}
glFlush();
usleep(50);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutCreateWindow("William");
glutDisplayFunc(mydisplay);
glutMainLoop();
}
The error occurs at viewer[i].X = -sPheta * world[i].X; + cPheta * world[i].y; and for the lines below it in the for loop. I am not sure what's going on. I'm trying to multiply a float by a float[], but it's not working.
typedef struct {
float X[] = {};
float Y[] = {};
float Z[] = {};
} pworld;
It's structure with 3 zero elements(empty) C arrays. -sPheta * world[i].X; is multiplying float(number) with empty arrays - what do you want to achieve? I guess you don't need these [].
However, I thought that zero elements C arrays are forbidden, but it compiles fine.
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 :
I want to draw 2 circles, and here are the necessary bits from three files of my project.
circle.h
#include "main.h"
#ifndef CIRCLE_H
#define CIRCLE_H
class Circle{
public:
Circle(){};
Circle(float x, float y, float radius, float fraction, color_t color);
void set_position(float x, float y);
void draw(glm::mat4 VP);
bounding_box_t bounding_box();
glm::vec3 position;
float rotation;
float radius;
float fraction;
private:
VAO *object;
};
#endif //CIRCLE_H
circle.cpp
#include "circle.h"
#include "main.h"
#include <iostream>
#define PI 3.14159265358979323846
typedef struct {
GLfloat x;
GLfloat y;
GLfloat z;
}point;
point rotate_by(double angle, point inp_point){
point new_point;
new_point.x = inp_point.x*cos(angle) - inp_point.y*sin(angle);
new_point.y = inp_point.x*sin(angle) + inp_point.y*cos(angle);
return new_point;
};
void fill_array(int sides, float radius, int fraction, GLfloat array[]){
double angle = 2 * PI / sides;
point vertex;
vertex.x = 0.0f;
vertex.y = 0.0f;
vertex.z = 0.0f;
point oldpoint;
oldpoint.x = 0.0f;
oldpoint.y = radius;
oldpoint.z = 0.0f;
int iterations = (int)(fraction*sides);
std::cout<< iterations <<std::endl;
//For each triangle
for(int i = 0; i < iterations; i++){
// setting the vertex
array[9*i + 0] = vertex.x;
array[9*i + 1] = vertex.y;
array[9*i + 2] = vertex.z;
// setting the oldpoint
array[9*i + 3] = oldpoint.x;
array[9*i + 4] = oldpoint.y;
array[9*i + 5] = oldpoint.z;
// making the new point
point newpoint = rotate_by(angle, oldpoint);
// setting the new point
array[9*i + 6] = newpoint.x;
array[9*i + 7] = newpoint.y;
array[9*i + 8] = newpoint.z;
// New point is now old
oldpoint = newpoint;
}
};
Circle::Circle(float x, float y, float radius, float fraction, color_t color) {
this->position = glm::vec3(x, y, 0);
this->rotation = 0;
int sides = 50;
this->radius = radius;
this->fraction = fraction;
static GLfloat vertex_buffer_data[1000];
fill_array(sides, radius, fraction, vertex_buffer_data);
int num_vertices = (int)(fraction*sides)*3;
std::cout << num_vertices <<std::endl;
this->object = create3DObject(GL_TRIANGLES, num_vertices, vertex_buffer_data, color, GL_FILL);
}
void Circle::draw(glm::mat4 VP) {
Matrices.model = glm::mat4(1.0f);
glm::mat4 translate = glm::translate (this->position); // glTranslatef
glm::mat4 rotate = glm::rotate((float) (this->rotation * M_PI / 180.0f), glm::vec3(0, 0, 1));
rotate = rotate * glm::translate(glm::vec3(0, -0.6, 0));
Matrices.model *= (translate * rotate);
glm::mat4 MVP = VP * Matrices.model;
glUniformMatrix4fv(Matrices.MatrixID, 1, GL_FALSE, &MVP[0][0]);
draw3DObject(this->object);
}
main.cpp
//-------------------Necessary tools----------------------------------------------
#include <vector>
#include <random>
#include "timer.h"
#include "main.h"
using namespace std;
//------------------Template Imports---------------------------------------------
#include "circle.h"
//---------------Important declarations-------------------------------------------
GLMatrices Matrices;
GLuint programID;
GLFWwindow *window;
float screen_zoom = 1, screen_center_x = 0, screen_center_y = 0;
Timer t60(1.0 / 60);
//--------------Object declarations-----------------------------------------------
Circle c1;
Circle c2;
// -------------Functions----------------------------------------------------------
void draw() {
//---------Don't touch---------------------------------------------------------
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram (programID);
Matrices.view = glm::lookAt(glm::vec3(0, 0, 3), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0)); // Fixed camera for 2D (ortho) in XY plane
glm::mat4 VP = Matrices.projection * Matrices.view;
glm::mat4 MVP;
//---------Scene render--------------------------------------------------------
c1.draw(VP);
c2.draw(VP);
}
void initGL(GLFWwindow *window, int width, int height) {
//-----------Create objects----------------------------------------------
c1 = Circle(1,1,1.0f,1.0f,COLOR_BLACK);
c2 = Circle(2,2,1.0f,1.0f, COLOR_RED);
//-----------Don't touch-------------------------------------------------
programID = LoadShaders("Sample_GL.vert", "Sample_GL.frag");
Matrices.MatrixID = glGetUniformLocation(programID, "MVP");
reshapeWindow (window, width, height);
glClearColor (COLOR_BACKGROUND.r / 256.0, COLOR_BACKGROUND.g / 256.0, COLOR_BACKGROUND.b / 256.0, 0.0f); // R, G, B, A
glClearDepth (1.0f);
glEnable (GL_DEPTH_TEST);
glDepthFunc (GL_LEQUAL);
cout << "VENDOR: " << glGetString(GL_VENDOR) << endl;
cout << "RENDERER: " << glGetString(GL_RENDERER) << endl;
cout << "VERSION: " << glGetString(GL_VERSION) << endl;
cout << "GLSL: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl;
}
int main(int argc, char **argv) {
srand(time(0));
int width = 600;
int height = 600;
window = initGLFW(width, height);
initGL (window, width, height);
/* Draw in loop */
while (!glfwWindowShouldClose(window)) {
// Process timers
if (t60.processTick()) {
// 60 fps
// OpenGL Draw commands
draw();
// Swap Frame Buffer in double buffering
glfwSwapBuffers(window);
tick_elements();
//tick_input(window);
}
// Poll for Keyboard and mouse events
glfwPollEvents();
}
quit(window);
}
void reset_screen() {
float top = screen_center_y + 4 / screen_zoom;
float bottom = screen_center_y - 4 / screen_zoom;
float left = screen_center_x - 4 / screen_zoom;
float right = screen_center_x + 4 / screen_zoom;
Matrices.projection = glm::ortho(left, right, bottom, top, 0.1f, 500.0f);
}
For some reason, sometimes, I get the right output, but sometimes, I get funny outputs.
This is the correct image that I want:
But several times nothing appears at all:
Sometimes really funny outputs appear, like this:
... And this:
Notice that I am not even running make again and again, these variations happen each time I am opening the executable itself.
How can I get the correct output every time?
Do you call reset_screen() function somewhere? Because in this function you are creating your projection matrix. It looks like this matrix is uninitialized (initialized with some trash).
This is a ray tracer code I'm working on. When I tested it out, everything seemed to be working fine until I started changing the camera(view point) position. Here are some of the results:
campos(-60, 100, -30), lightPos(-70, 100, -30)
The light on the floor is cut off somehow.
campos(60, 100, -30), lightPos(-70, 100, -30)
This one shows the same problem.
campos(60, 30, -30), lightPos(-70, 100, -30)
The light in this screenshot seems to have two light sources although there's only one active at the moment.
campos(-70, 100, -30), lightPos(-70, 100, -30)
The final position is the last position I set on the code below. It's at the exact same location as the light sorce.
Why is the light creating shadows like that?
main.cpp
#include <iostream>
#include <algorithm>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <math.h>
#include <vector>
#include "Vector.h"
#include "Ray.h"
#include "Camera.h"
#include "Color.h"
#include "Light.h"
#include "Sphere.h"
#include "Plane.h"
#define PI 3.141592653589793
#define INFINITY 1e6
#define FOV 60
#define KA 0.2
#define KD 0.5
#define KS 5
VECTOR X = { 1,0,0 };
VECTOR Y = { 0,1,0 };
VECTOR Z = { 0,0,1 };
VECTOR O = { 0,0,0 };
Color white(1, 1, 1);
Color black(0, 0, 0);
Color greenC(0.5, 1, 0.5);
Color gray(0.5, 0.5, 0.5);
Color maroon(0.5, 0.25, 0.25);
unsigned int width = 640;
unsigned int height = 480;
using namespace std;
Color trace(Ray &ray, vector<Object*> objects, vector<Light*> lights)
{
float hit = INFINITY;
float closest = INFINITY;
Object* objectHit = NULL;
for (int i = 0; i < objects.size(); i++)
{
if (objects.at(i)->intersect(ray, hit))
{
if (hit < closest)
{
closest = hit;
objectHit = objects.at(i);
}
}
}
if (objectHit)
{
VECTOR hitP = ray.getOrigin() + ray.getDirction() * closest;
VECTOR hitN = objectHit->getNormal(hitP);
Color finalColor = objectHit->getColor() * objectHit->getKa(); //ambient color
for (int i = 0; i < lights.size(); i++)
{
VECTOR lightDir = lights.at(i)->getPos() - hitP;
float lightDist = lightDir.Magnitude();
lightDir.Normalize();
bool shadow = false;
Ray shadowRay(hitP, lightDir);
float angle = max(hitN.DotProduct(lightDir), 0.0f);
for (int j = 0; j < objects.size() && shadow == false; j++)
{
float p;
if (objects.at(j)->intersect(shadowRay, p) && objectHit != objects.at(j))
{
VECTOR objectDist = hitP + lightDir * p;
if (objectDist.Magnitude() <= lightDist)
shadow = true;
}
}
if (!shadow)
{
VECTOR h = ray.getDirction() + lightDir;
h.Normalize();
Color diffuse = lights.at(i)->getCol() * objectHit->getKd() * angle;
Color specular = lights.at(i)->getCol() * angle * pow(max(hitN.DotProduct(h), 0.0f), objectHit->getKs());
finalColor = finalColor + diffuse + specular;
}
}
return finalColor.clip();
}
else return black;
}
void Render(void)
{
glClear(GL_COLOR_BUFFER_BIT);
vector<Object*> objects;
int radius = 20;
Sphere sphere(O, radius, greenC, KA, KD, KS);
Plane plane(Y, VECTOR(0, -radius, 0), maroon, 0.3, 0.5, 0.01);
objects.push_back(&sphere);
objects.push_back(&plane);
float xx, yy;
Color *image = new Color[width*height];
Color *pixel = image;
VECTOR lightPos(-70, 100, -30);
Light light(lightPos, gray);
//Light l2(VECTOR(10, 10, -20), white);
vector<Light*> lights;
lights.push_back(&light);
//lights.push_back(&l2);
VECTOR camPos(-70, 100, -30);
VECTOR lookat(0, 0, 0);
VECTOR diff(camPos.getX() - lookat.getX(), camPos.getY() - lookat.getY(), camPos.getZ() - lookat.getZ());
VECTOR camDir = diff;
camDir.Normalize();
VECTOR camRight = Y.CrossProduct(camDir);
camRight.Normalize();
VECTOR camUp = camRight.CrossProduct(camDir).Negative();
Camera cam(camPos, camDir, camRight, camUp);
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
xx = -(double)(width / 2) + x + 0.5;
yy = -(double)(height / 2) + y + 0.5;
VECTOR ray_d = camRight*xx + camUp*yy + camDir;
VECTOR ray_origin = camPos;
VECTOR ray_dir = ray_d - ray_origin;
ray_dir.Normalize();
Ray ray(ray_origin, ray_dir);
*(pixel++) = trace(ray, objects, lights);
float red = image[x*height + y].getRed();
float green = image[x*height + y].getGreen();
float blue = image[x*height + y].getBlue();
glColor3f(red, green, blue);
glBegin(GL_POINTS);
glVertex2i(x, y);
glEnd();
}
}
glutSwapBuffers();
}
struct RGBtype
{
float r, g, b;
};
int main(int argc, char ** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(width, height);
glutCreateWindow("Ray tracer");
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, width, 0.0, height);
glutDisplayFunc(Render);
glutMainLoop();
return 0;
}
Vector.h
#ifndef _VECTOR_H_
#define _VECTOR_H_
#include <math.h>
class VECTOR
{
private:
float x, y, z;
public:
VECTOR();
~VECTOR();
VECTOR(float, float, float);
float getX() { return x; }
float getY() { return y; }
float getZ() { return z; }
float Magnitude();
VECTOR CrossProduct(VECTOR);
float DotProduct(VECTOR);
VECTOR vecAdd(VECTOR);
VECTOR vecMul(float);
void Normalize();
VECTOR Negative();
VECTOR operator - (VECTOR);
VECTOR operator + (VECTOR);
VECTOR operator * (float);
};
VECTOR VECTOR::operator-(VECTOR v)
{
VECTOR result = (*this);
result.x -= v.getX();
result.y -= v.getY();
result.z -= v.getZ();
return result;
}
VECTOR VECTOR::operator+(VECTOR v)
{
VECTOR result = (*this);
result.x += v.getX();
result.y += v.getY();
result.z += v.getZ();
return result;
}
VECTOR VECTOR::operator*(float f)
{
return VECTOR(x*f, y*f, z*f);
}
VECTOR::VECTOR()
{
x = y = z = 0;
}
VECTOR::~VECTOR(){}
VECTOR::VECTOR(float xPos, float yPos, float zPos)
{
x = xPos;
y = yPos;
z = zPos;
}
float VECTOR::Magnitude()
{
return sqrt(x * x + y * y + z * z);
}
float VECTOR::DotProduct(VECTOR v)
{
return (x * v.getX() + y * v.getY() + z * v.getZ());
}
VECTOR VECTOR::CrossProduct(VECTOR v)
{
VECTOR result;
result.x = y * v.getZ() - z * v.getY();
result.y = z * v.getX() - x * v.getZ();
result.z = x * v.getY() - y * v.getX();
return result;
}
VECTOR VECTOR::vecAdd(VECTOR v)
{
return VECTOR(x + v.getX(), y + v.getY(), +z + v.getZ());
}
VECTOR VECTOR::vecMul(float f)
{
return VECTOR(x*f, y*f, z*f);
}
void VECTOR::Normalize()
{
float w = Magnitude();
if (w < 0.00001) return;
x /= w;
y /= w;
z /= w;
}
VECTOR VECTOR::Negative()
{
return VECTOR( -x,-y,-z );
}
#endif // !_VECTOR_H_#pragma once
Ray.h
#ifndef _RAY_H_
#define _RAY_H_
#include "Vector.h"
class Ray
{
private:
VECTOR origin, direction;
public:
Ray();
~Ray();
Ray(VECTOR, VECTOR);
VECTOR getOrigin() { return origin; }
VECTOR getDirction() { return direction; }
};
Ray::Ray()
{
origin = VECTOR { 0,0,0 };
direction = VECTOR { 1,0,0 };
}
Ray::~Ray() {}
Ray::Ray(VECTOR o, VECTOR d)
{
origin = o;
direction = d;
}
#endif // !_Ray_H_#pragma once
Camera.h
#ifndef _CAMERA_H_
#define _CAMERA_H_
#include "Vector.h"
class Camera
{
private:
VECTOR camPos, camDir, camRight, camUp;
public:
Camera();
~Camera();
Camera(VECTOR, VECTOR, VECTOR, VECTOR);
VECTOR getCamPos() { return camPos; }
VECTOR getCamDir() { return camDir; }
VECTOR getCamRight() { return camRight; }
VECTOR getcamUp() { return camUp; }
};
Camera::Camera()
{
camPos = VECTOR{ 0,0,0 };
camDir = VECTOR{ 0,0,1 };
camRight = VECTOR{ 0,0,0 };
camUp = VECTOR{ 0,0,0 };
}
Camera::~Camera() {}
Camera::Camera(VECTOR pos, VECTOR dir, VECTOR right, VECTOR down)
{
camPos = pos;
camDir = dir;
camRight = right;
camUp = down;
}
#endif // !_CAMERA_H_#pragma once
Color.h
#ifndef _COLOR_H_
#define _COLOR_H_
#include "Vector.h"
class Color
{
private:
double red, green, blue;
public:
Color();
~Color();
Color(double, double, double);
double getRed() { return red; }
double getGreen() { return green; }
double getBlue() { return blue; }
void setRed(double r) { red = r; }
void setGreen(double g) { green = g; }
void setBlue(double b) { blue = b; }
double brightness() { return (red + green + blue) / 3; }
Color average(Color c) { return Color((red + c.getRed()) / 2, (green + c.getGreen()) / 2, (blue + c.getBlue()) / 2); }
Color operator * (double);
Color operator + (Color);
Color operator * (Color);
Color clip()
{
float sum = red + green + blue;
float extra = sum - 3;
if (extra > 0)
{
red = red + extra * (red / sum);
green = red + extra * (green / sum);
blue = red + extra * (blue / sum);
}
if (red > 1) { red = 1; }
if (green > 1) { green = 1; }
if (blue > 1) { blue = 1; }
if (red < 0) { red = 0; }
if (green < 0) { green = 0; }
if (blue < 0) { blue = 0; }
return Color(red, green, blue);
}
};
Color Color::operator * (double c) { return Color(red*c, green*c, blue*c); }
Color Color::operator + (Color c) { return Color(red + c.getRed(), green + c.getGreen(), blue + c.getBlue()); }
Color Color::operator * (Color c) { return Color(red*c.getRed(), green*c.getGreen(), blue*c.getBlue()); }
Color::Color()
{
red = green = blue = 1;
}
Color::~Color() {}
Color::Color(double r, double g, double b)
{
red = r;
green = g;
blue = b;
}
#endif // !_COLOR_H_#pragma once
Light.h
#ifndef _LIGHT_H_
#define _LIGHT_H_
#include "Vector.h"
#include "Color.h"
class Light
{
private:
VECTOR position;
Color color;
public:
Light();
~Light();
Light(VECTOR, Color);
virtual VECTOR getPos() { return position; }
virtual Color getCol() { return color; }
};
Light::Light()
{
position = VECTOR(0, 0, 0);
color = Color(1,1,1);
}
Light::~Light() {}
Light::Light(VECTOR v, Color c)
{
position = v;
color = c;
}
#endif // !_LIGHT_H_#pragma once
Sphere.h
#ifndef _SPHERE_H_
#define _SPHERE_H_
#include <math.h>
#include "Vector.h"
#include "Color.h"
#include "Object.h"
class Sphere : public Object
{
private:
VECTOR center;
float radius;
Color color;
float ka, kd, ks;
public:
Sphere();
~Sphere();
Sphere(VECTOR, float, Color, float, float, float);
float getKa() { return ka; }
float getKd() { return kd; }
float getKs() { return ks; }
VECTOR getCenter() { return center; }
float getRadius() { return radius; }
Color getColor() { return color; }
VECTOR getNormal(VECTOR &v)
{
VECTOR a = v - center;
a.Normalize();
return a;
}
bool intersect(Ray &ray, float &t)
{
float t0, t1;
float radius2 = radius * radius; //radius squared
VECTOR line = center - ray.getOrigin(); //vector from ray origin to sphere center
float ray_t = line.DotProduct(ray.getDirction()); //the current ray vector
if (ray_t < 0)
return false;
float d2 = line.DotProduct(line) - (ray_t * ray_t); //d2 + t2 = line2 by pythagorian theorm
if (d2 > radius2) //if larger than the radius, then the ray doesn't intersect with sphere
return false;
float ray_i = sqrt(radius2 - d2); //part of ray that is going through the sphere
t0 = ray_t - ray_i; //first sphere vertex along the ray
t1 = ray_t + ray_i; //second sphere vertex
if (t0 > t1)
{
float tmp = t0;
t0 = t1;
t1 = t0;
}
if (t0 < 0)
{
t0 = t1;
t = t0;
if (t0 < 0) return false;
}
t = t0;
return true;
}
};
Sphere::Sphere()
{
center = VECTOR(0, 0, 0);
radius = 1;
color = Color(1, 1, 1);
}
Sphere::~Sphere() {}
Sphere::Sphere(VECTOR v, float r, Color c, float a, float d, float s)
{
center = v;
radius = r;
color = c;
ka = a;
kd = d;
ks = s;
}
#endif // !_SPHERE_H_#pragma once
Object.h
#ifndef _OBJECT_H_
#define _OBJECT_H_
#include "Ray.h"
#include "Vector.h"
#include "Color.h"
class Object
{
private:
VECTOR center;
Color color;
float ka, kd, ks;
public:
Object();
~Object();
virtual float getKa() = 0;
virtual float getKd() = 0;
virtual float getKs() = 0;
virtual VECTOR getCenter() = 0;
virtual Color getColor() = 0;
virtual VECTOR getNormal(VECTOR&) = 0;
virtual bool intersect(Ray&, float&) = 0;
};
Object::Object(){}
Object::~Object() {}
#endif // !_OBJECT_H_#pragma once
Plane.h
#ifndef _PLANE_H_
#define _PLANE_H_
#include <math.h>
#include<vector>
#include "Vector.h"
#include "Color.h"
#include "Object.h"
using namespace std;
class Plane : public Object
{
private:
VECTOR normal;
float width, height;
vector<VECTOR> vertice;
VECTOR center; //to be used in equation (p - p0) * n = 0 where p is the point of intersection and p0 is the center
Color color;
float ka, kd, ks;
public:
Plane();
~Plane();
Plane(VECTOR, VECTOR, Color, float, float, float);
float getKa() { return ka; }
float getKd() { return kd; }
float getKs() { return ks; }
VECTOR getNormal(VECTOR &point)
{
VECTOR a = normal;
a.Normalize();
return a;
}
VECTOR getCenter() { return center; }
Color getColor() { return color; }
bool intersect(Ray &ray, float &t)
{
VECTOR rayDir = ray.getDirction();
float ray_f = rayDir.DotProduct(normal);
//ray doesn't intersect or is parallel to the plane - ray-plane intersection
if (fabs(ray_f) < 1e-6)
return false;
else
{
VECTOR tmp = (center - ray.getOrigin());
float plane_f = normal.DotProduct(tmp);
//returns t in parametric equation of ray point = origin + t*direction
t = plane_f / ray_f;
return (t >= 0);
}
}
};
Plane::Plane()
{
normal = VECTOR(0, 1, 0);
center = VECTOR(0, 0, 0);
color = Color(0.5, 0.5, 0.5);
width = 500;
height = 500;
}
Plane::~Plane() {}
Plane::Plane(VECTOR v, VECTOR o, Color c, float a, float d, float s)
{
normal = v;
center = o;
color = c;
ka = a;
kd = d;
ks = s;
}
#endif // !_PLANE_H_#pragma once
This is an awful lot of code, so I can only guess at what the problem is. Since the problem is in the not shadowed part of the image, the problem is in the calculation of either the diffuse or specular colors (or both). You could comment out each one individually to see what gives you the expected coloring, then further diagnose the problem from there.
The problem may be in your normalize method, which does not normalize really short vectors. This would cause the specular color to be off.