How to attach a rigidbody to a camera(bullet physics)? - c++

I've been working on a project using OpenGL and Bullet physics, but can't seem to figure out how to move the rigidbody to the camera. I've tried setting the motion state repeatedly and translating it upon key presses and both of these methods do not work. This is my camera movement code.(I have commented out both methods.)
void CameraUpdateLoop()
{
xpos = 0;
ypos = 0;
deltatime = glfwGetTime() - prevtime;
glfwGetCursorPos(window,&xpos,&ypos);
// cout << xpos << " " << ypos << endl;
glfwSetCursorPos(window,800/2,600/2);
hangle += mousesens * deltatime * (400 - xpos);
vangle += mousesens * deltatime * (300 - ypos);
direction = glm::vec3(cos(vangle)* sin(hangle),sin(vangle),cos(vangle)* cos(hangle));
right = glm::vec3(sin(hangle - 3.14f/2.0f),0,cos(hangle - 3.14f/2.0f));
up = glm::vec3(glm::cross(right,direction));
if(glfwGetKey(window,GLFW_KEY_W) == GLFW_PRESS)
{
position += direction * deltatime * speed;
// rigidbody->translate(btVector3(direction.x,direction.y,direction.z) * deltatime * speed);
}
if(glfwGetKey(window,GLFW_KEY_S) == GLFW_PRESS)
{
position -= direction * deltatime * speed;
// rigidbody->translate(-(btVector3(direction.x,direction.y,direction.z) * deltatime * speed));
}
if(glfwGetKey(window,GLFW_KEY_D) == GLFW_PRESS)
{
position += right * deltatime * speed;
//rigidbody->translate(btVector3(right.x,right.y,right.z) * deltatime * speed);
}
if(glfwGetKey(window,GLFW_KEY_A) == GLFW_PRESS)
{
position -= right * deltatime * speed;
//rigidbody->translate(-(btVector3(right.x,right.y,right.z) * deltatime * speed));
}
btTransform output;
//fallMotionState = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(position.x,position.y, position.z)));
//rigidbody->setMotionState(fallMotionState);
rigidbody->getMotionState()->getWorldTransform(output);
cout << output.getOrigin().getZ() << endl;
if(vangle < -90.0f)
{
vangle = -90.0f;
}
if(vangle > 90.0f)
{
vangle = 90.0f;
}
// cout << vangle << endl;
// cout << hangle << endl;
ProjectionMatrix = glm::perspective(initfov,4.0f/3.0f,0.1f,100.0f);
ViewMatrix= (glm::lookAt(position,position+direction,up));
prevtime = glfwGetTime();
}
The issue is that no manifolds are produced with each tick even though getting the origin with motion states usually produces correct output.
static void test (btDynamicsWorld *world, btScalar timeStep)
{
int numManifolds = world->getDispatcher()->getNumManifolds();
if(numManifolds >= 1)
{
cout << "collision" << endl;
glClearColor(0.0,0.7,0.8,1.0);
}
else if(numManifolds < 1)
{
glClearColor(0.0,0.3,0.8,1.0);
}

Related

SFML Movement with mouse event

I'm new to SFML currently I'm trying to make a simple 2D golf ball physics. Right now, I have a class called Ball that contain the attributes of the ball sprite, position, velocity etc. I would call the call class it in main and it working as expected, but the one thing that didn't work is it would just move/teleport the ball to the next position rather than moving the ball like expected.
void Ball::move(sf::Vector2f& velocity)
{
// boundaries
if (ballSprite.getPosition().x < 0 - 49 || ballSprite.getPosition().x > 700 - 70)
{
velocity.x *= (float) -1;
}
if (ballSprite.getPosition().y < 0 - 30 || ballSprite.getPosition().y > 1200 - 70)
{
velocity.y *= (float) -1;
}
if (ballSprite.getPosition().x + 1 == 700 || ballSprite.getPosition().x - 1 == 0)
{
velocity.x *= -1;
}
if (ballSprite.getPosition().y + 1 == 1200 || ballSprite.getPosition().y - 1 == 0)
{
velocity.y *= -1;
}
ballSprite.move(velocity.x, velocity.y);
sf::Texture ballTex;
ballTex.loadFromFile("ball2.png");
Ball gameBall(1, ballTex);
while (window.isOpen())
{
sf::Event event;
bool mouseReleased = false;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
}
if (event.type == sf::Event::MouseButtonPressed)
{
cout << "Mouse Button Pressed\n";
}
mouseReleased = false;
if (event.mouseButton.button == sf::Mouse::Left && event.type == sf::Event::MouseButtonReleased)
{
mouseReleased = true;
cout << "Mouse Button Released\n";
cout << "Ball Position: " << gameBall.getSprite().getPosition().x << "," << gameBall.getSprite().getPosition().y << endl;
sf::Vector2i velo = sf::Mouse::getPosition(window);
cout << "Velocity: " << velo.x - gameBall.getSprite().getPosition().x << ", " << -1 * (velo.y - gameBall.getSprite().getPosition().y) << endl;
sf::Vector2f velocity(-1 *(velo.x - gameBall.getSprite().getPosition().x) , (-1 * (velo.y - gameBall.getSprite().getPosition().y)));
gameBall.move(velocity);
cout << "Ball Position After: " << gameBall.getSprite().getPosition().x << "," << gameBall.getSprite().getPosition().y << endl;
}
}
I'm not sure how to update the ball so it would show the ball move on the screen rather than teleporting to a new position on the screen.
The way you are calculating the change in position is simply a delta of position i.e. movining your ball by the delta will result in teleporting to the destination. The delta itself is really useful.
One way to make it work is to devide the delta into smaller parts (ball speed) and move by these parts.
However, it seems to me that it is easier to calculate the normalized vector (unit vector) and multiply by the ball speed, then fix it (if needed) by multiplying by sqrt of 2 (to prevent faster movement on diagonal).
This method is not very accurate, the ball would only move in 8 directions (it doesn't keep the vector ratio) so if you need it to be more realistic i.e. keep the ratio of x and y delta you can calculate it like that:
sf::Vector2f stretchVector(const sf::Vector2f& vector, const float& radius)
{
sf::Vector2i xySymb(1, 1);//calculation of the symbol(-/+)
xySymb.x = isPositive(vector.x);//isPositive should return -1 or (1 when>=0)
xySymb.y = isPositive(vector.y);
//dealing with [0,...] or [0,0] vectors and the 0 radius.
if (radius == 0.f)
return sf::Vector2f(0.f, 0.f);
if (vector.y == 0.f or vector.x == 0.f) {
if (vector.x == vector.y) {
return sf::Vector2f(0.f, 0.f);
}
if (vector.x != 0.f) {
return sf::Vector2f(radius*xySymb.x, 0.f);
}
return sf::Vector2f(0.f, radius*xySymb.y);
}
//<------------------------------------------------>
else {
float ratio = abs(vector.x / vector.y);
float x, y;
x = sqrt((radius * radius * ratio * ratio) / (1 + ratio * ratio));
y = sqrt(abs(radius * radius - x * x));
return sf::Vector2f(float(x * xySymb.x), float(y * xySymb.y));
}
}
I didn't know how to name the function but it can stretch and shrink to provided radius.
The example stretchVector call:
sf::Vector2f deltaPosition(mousePos.x-ballPos.x,mousePos.y-ballPos.y);
sf::Vector2f desiredMove = stretchVector(deltaPositon, ballSpeed);
ball.move(desiredMove);

How to draw a 45x45 grid with SDL

I am trying to make a grid of 45x45 in SDL but I am not so sure how to do it. Should I use SDL_RenderDrawLine? If so how should I use it inside my void ParticleManager::renderGrid(SDL_Renderer* renderer) function?
#include <iostream>
#include <vector>
#include <string>
#include <cassert>
#include <SDL.h>
#include "Constants.h"
#include "ParticleManager.h"
using namespace std;
Particle::Particle(double _x, double _y) :
x(_x), y(_y),
vx(0.f), vy(0.f),
fx(0.f), fy(0.f),
rho(0.f), p(0.f)
{
}
ParticleManager::ParticleManager()
{
ax = 0;
ay = GRAVITY;
renderMode = "particles";
}
void ParticleManager::init(unsigned long n)
{
cout << "Init with " << n << " particles" << endl;
particles.clear();
particles.reserve(n);
while (particles.size() < n) {
double x = rand() / (double)(RAND_MAX)*SCREEN_WIDTH;
double y = rand() / (double)(RAND_MAX)*SCREEN_HEIGHT;
double centerDist = sqrt(
pow(x - SCREEN_WIDTH / 2.0, 2) +
pow(y - SCREEN_HEIGHT / 2.0, 2));
if (centerDist < fmin(SCREEN_WIDTH, SCREEN_HEIGHT) * 0.25)
particles.push_back(Particle(x, y));
}
}
void ParticleManager::addBlock(double center_x, double center_y)
{
for (int i = 0; i <= 4; i++) {
for (int j = 0; j <= 4; j++) {
double x = center_x + (j - 2) * SCREEN_WIDTH * 0.04f + (rand() / (double)(RAND_MAX)) * H;
double y = center_y + (i - 2) * SCREEN_HEIGHT * 0.04f + (rand() / (double)(RAND_MAX)) * H;
if (x >= 0 && x < SCREEN_WIDTH && y >= 0 && y < SCREEN_HEIGHT)
particles.push_back(Particle(x, y));
}
}
cout << particles.size() << " particles" << endl;
}
void ParticleManager::addOne(double x, double y)
{
particles.push_back(Particle(x, y));
cout << particles.size() << " particles" << endl;
}
void ParticleManager::setGravity(int direction)
{
switch (direction) {
case DOWN:
ax = 0;
ay = +GRAVITY;
break;
case UP:
ax = 0;
ay = -GRAVITY;
break;
case RIGHT:
ax = +GRAVITY;
ay = 0;
break;
default:
ax = -GRAVITY;
ay = 0;
}
}
void ParticleManager::explode() {
for (auto& p : particles) {
p.vx = rand() / (double)RAND_MAX * 10000 - 5000;
p.vy = rand() / (double)RAND_MAX * 10000 - 5000;
}
}
void ParticleManager::integrate(double dt)
{
for (auto& p : particles)
{
// forward Euler integration
if (p.rho != 0 && p.fx == p.fx && p.fy == p.fy) {
p.vx += dt * p.fx / p.rho;
p.vy += dt * p.fy / p.rho;
}
p.x += dt * p.vx;
p.y += dt * p.vy;
// enforce boundary conditions
if (p.x - PARTICLE_RADIUS < 0.0f)
{
p.vx *= BOUND_DAMPING;
p.x = PARTICLE_RADIUS;
}
if (p.x + PARTICLE_RADIUS > SCREEN_WIDTH)
{
p.vx *= BOUND_DAMPING;
p.x = SCREEN_WIDTH - PARTICLE_RADIUS;
}
if (p.y - PARTICLE_RADIUS < 0.0f)
{
p.vy *= BOUND_DAMPING;
p.y = PARTICLE_RADIUS;
}
if (p.y + PARTICLE_RADIUS > SCREEN_HEIGHT)
{
p.vy *= BOUND_DAMPING;
p.y = SCREEN_HEIGHT - PARTICLE_RADIUS;
}
}
}
void ParticleManager::computeDensityPressure()
{
// for each particles
for (auto& pi : particles)
{
pi.rho = 0.f;
// Find all the particles that contribute to the
// pressure / density
for (auto& pj : particles)
{
double distance = sqrt(
pow(pj.x - pi.x, 2) +
pow(pj.y - pi.y, 2));
if (distance < H)
{
// this computation is symmetric
pi.rho += MASS * POLY6 * pow(pow(H, 2) - pow(distance, 2), 3.f);
}
}
pi.p = GAS_CONST * (pi.rho - REST_DENS);
}
}
void ParticleManager::computeForces()
{
// For each particle
for (auto& pi : particles) {
double pressure_x = 0.f;
double pressure_y = 0.f;
double viscosity_x = 0.f;
double viscosity_y = 0.f;
// Calculate the sum of the viscosity and pressure forces
// applied by the other particles
for (auto& pj : particles) {
if (&pi == &pj)
continue;
double r = sqrt(
pow(pj.x - pi.x, 2) +
pow(pj.y - pi.y, 2));
if (r < H) {
// compute pressure force contribution
double fpress = MASS * (pi.p + pj.p) / (2.0 * pj.rho) * SPIKY_GRAD * pow(H - r, 2.0);
pressure_x += (pi.x - pj.x) / r * fpress;
pressure_y += (pi.y - pj.y) / r * fpress;
// compute viscosity force contribution
viscosity_x += VISC * MASS * (pj.vx - pi.vx) / pj.rho * VISC_LAP * (H - r);
viscosity_y += VISC * MASS * (pj.vy - pi.vy) / pj.rho * VISC_LAP * (H - r);
}
}
pi.fx = pressure_x + viscosity_x + ax * pi.rho;
pi.fy = pressure_y + viscosity_y + ay * pi.rho;
}
}
void ParticleManager::update(unsigned long dt)
{
// TODO: calculate the grid here
computeDensityPressure();
computeForces();
integrate(dt / 10000.0f);
}
void ParticleManager::renderParticles(SDL_Renderer* renderer) {
SDL_SetRenderDrawColor(renderer, 230, 120, 0, 100);
SDL_Rect r;
// Draw particles
for (long unsigned int i = 0; i < particles.size(); i++) {
r.x = (int)(particles[i].x - PARTICLE_RADIUS);
r.y = (int)(particles[i].y - PARTICLE_RADIUS);
r.w = (int)(PARTICLE_RADIUS * 2);
r.h = (int)(PARTICLE_RADIUS * 2);
SDL_RenderFillRect(renderer, &r);
}
}
void ParticleManager::renderGrid(SDL_Renderer* renderer) {
// TODO: Draw the lines that form the grid
cout << "Affichage de la grile (TODO)" << endl;
}
void ParticleManager::renderCells(SDL_Renderer* renderer) {
// TODO: Draw the boxes in different colors to
// represent the number of particles in each cell
//
// Use the calculation:
// int alpha = nb_particles * 255/5;
// if (alpha> 255) alpha = 255;
// SDL_SetRenderDrawColor (renderer, 0, 0, 255, alpha);
//
// To assign the color to the cell
cout << "Affichage des cellules (TODO)" << endl;
}
void ParticleManager::render(SDL_Renderer* renderer)
{
if (renderMode.find("particle") != string::npos)
renderParticles(renderer);
if (renderMode.find("grid") != string::npos) {
renderCells(renderer);
renderGrid(renderer);
}
}
The end result should look like this:

SFML. Code is not executed but it 100% should

Im trying to implement jumping mechanics so i have 2 states, falling and jumping. I code it this way that if its not jumping its falling and the other way around, bool switches when player is at the pick of jump and thats when jumpSpedDecrease > 0.299f, in code there u can see that in that if statement theres cout saying "This code should work". When i run program i can see this in code but the values i change there stay same way, but it obviously should change.
if (isJumping)
{
fallingSpeed = 0;
falSpedIncrease = 0;
birdSprite.setPosition(pos.x, pos.y - (jumpStartSped - jumpSpedDecrease) * time.asMilliseconds() * jumpingSpeed);
jumpSpedDecrease += jumpSpedDcrsValue;
std::cout << " jumpStartSped: " << jumpStartSped << " jumpSpedDecrease: " << jumpSpedDecrease << " jumpSpedDcrsValue: " << jumpSpedDcrsValue << " fallingSpeed: " << fallingSpeed << std::endl;
if (jumpSpedDecrease > 0.299f)
{
float fallingSpeed = 1;
float startSped = 0.004f;
float falSpedIcrsValue = 0.001f;
float falSpedIncrease = 0;
float jumpingSpeed = 1;
float jumpStartSped = 0.3f;
float jumpSpedDcrsValue = 0.001f;
float jumpSpedDecrease = 0;
std::cout << "This code should work" << std::endl;
}
if (jumpSpedDecrease > 0.3f) isJumping = false;`
Whole code here:
#include <SFML\Graphics.hpp>
#include <iostream>
using namespace sf;
class Player
{
public:
float fallingSpeed = 1;
float startSped = 0.004f;
float falSpedIcrsValue = 0.001f;
float falSpedIncrease = 0;
float jumpingSpeed = 1;
float jumpStartSped = 0.3f;
float jumpSpedDcrsValue = 0.001f;
float jumpSpedDecrease = 0;
bool isJumping = false;
Vector2u windowSize;
Time time;
Texture birdTex;
Sprite birdSprite;
void loadingSprite()
{
if (!birdTex.loadFromFile("./../Textures/flappyBird.png"))
{
std::cerr << "Cannot load texture" << std::endl;
}
birdSprite.setTexture(birdTex);
Vector2u size = birdTex.getSize();
birdSprite.setOrigin(size.x/2, size.y/2);
birdSprite.setScale(0.1f, 0.1f);
birdSprite.setPosition(windowSize.x/2, windowSize.y/2);
}
void falling()
{
if (!isJumping)
{
Vector2f pos = birdSprite.getPosition();
birdSprite.setPosition(pos.x, pos.y + (startSped +
falSpedIncrease) * time.asMilliseconds() * fallingSpeed);
falSpedIncrease += falSpedIcrsValue;
}
}
void jump()
{
Vector2f pos = birdSprite.getPosition();
if (Keyboard::isKeyPressed(Keyboard::Space)) isJumping = true;
if (isJumping)
{
fallingSpeed = 0;
falSpedIncrease = 0;
birdSprite.setPosition(pos.x, pos.y - (jumpStartSped -
jumpSpedDecrease) * time.asMilliseconds() * jumpingSpeed);
jumpSpedDecrease += jumpSpedDcrsValue;
std::cout << " jumpStartSped: " << jumpStartSped << "
jumpSpedDecrease: " << jumpSpedDecrease << " jumpSpedDcrsValue: " <<
jumpSpedDcrsValue << " fallingSpeed: " << fallingSpeed << std::endl;
if (jumpSpedDecrease > 0.299f)
{
float fallingSpeed = 1;
float startSped = 0.004f;
float falSpedIcrsValue = 0.001f;
float falSpedIncrease = 0;
float jumpingSpeed = 1;
float jumpStartSped = 0.3f;
float jumpSpedDcrsValue = 0.001f;
float jumpSpedDecrease = 0;
std::cout << "This code should work" << std::endl;
}
if (jumpSpedDecrease > 0.3f) isJumping = false;
}
}
};
int main()
{
Clock clock;
RenderWindow window(VideoMode(600, 600), "Dupako");
window.setFramerateLimit(240);
Player player;
player.windowSize = window.getSize();
player.loadingSprite();
// MAIN LOOP //
while (window.isOpen())
{
Event event;
while (window.pollEvent(event)) {
if (event.type == Event::Closed) window.close();
}
Time time = clock.getElapsedTime();
// MOVEMENT FUNCTIONS START //
player.time = time;
player.falling();
player.jump();
// MOVEMENT FUNCTIONS END //
clock.restart().asMilliseconds();
window.clear();
/// DRAW ///
window.draw(player.birdSprite);
/// DRAW END ///
window.display();
// MAIN LOOP END //
}
return 0;
}
Reconsider these lines:
if (jumpSpedDecrease > 0.299f)
{
float fallingSpeed = 1;
float startSped = 0.004f;
float falSpedIcrsValue = 0.001f;
float falSpedIncrease = 0;
float jumpingSpeed = 1;
float jumpStartSped = 0.3f;
float jumpSpedDcrsValue = 0.001f;
float jumpSpedDecrease = 0;
std::cout << "This code should work" << std::endl;
}
if (jumpSpedDecrease > 0.3f) isJumping = false;
Here you just create some local variables (e.g. float jumpSpedDecrease = 0), thereby not modifying the class fields. For example, the fallingSpeed (class field) set to 0 here:
if (isJumping)
{
fallingSpeed = 0;
falSpedIncrease = 0;
is not set back to 1, when the jump ends. And you use this field in the falling() method. I suggest removing float type specifiers first (inside of if (jumpSpedDecrease > 0.299f) {} statement).

OpenGL: Shading/Interpolation not working

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.

Projectile not going downwards on negative angle

I'm building a small Physics engine that fires a projectile on a set of launch parameters by the user (angle, height, time interval and initial velocity), then displays some information such as the total distance or angle at every time interval that it's in the air:
bool heightCheck = false;
double theta;
double initialVelocity, velocity;
double yNew = 0.0, xNew, xOld = 0.0, yOld = 0.0;
const double time = 0.1;
const double gravitiyHalf = 9.8 / 2;
double velocityX = 0.0, velocityY = 0.0;
double angle = 0.0;
double totalT = 0;
double maxHeight = 0.0;
double thetaDegrees = 0;
#define PI 3.14159265l // constant for PI
cout << "Insert a lanuch Angle (theta): ";
cin >> thetaDegrees;
cout << "Insert a launch height: ";
cin >> yOld;
cout << "Insert an initial velocity: ";
cin >> initialVelocity;
cout << "Time (DeltaT) in seconds: ";
cin >> totalT;
for (double deltaTime = 0.0; deltaTime < totalT; deltaTime += 0.1) {
const double squared = deltaTime * deltaTime; // squared constant for deltaTime squared
theta = thetaDegrees * PI / 180; // converts theta to a degrees value
velocityX = initialVelocity * cos(theta); // calculates Vx
velocityY = initialVelocity * sin(theta); // calculates Vy
// apply initialV to velocity
velocity = initialVelocity + 9.8 * time;
xNew = xOld + velocity * time; // works out displacement for X
yNew = yOld + velocity * deltaTime - gravitiyHalf / 0.5 * (squared); // calculates Y
velocityY = velocity - 9.8 * deltaTime; // includes gravity to Y
angle = atan2(yNew, xNew) * 180 / PI; // convert angle to degrees
cout << "\nHeight: " << yNew << endl;
cout << "Distance in Meters: " << xNew << "m" << endl;
cout << "Angle: " << angle << endl;
cout << "Time: " << deltaTime << "s " << endl;
if (heightCheck == false) {
maxHeight = yOld;
// keep maxheight equal to previous height
}
if (yNew < yOld && heightCheck == false) {
heightCheck = true;
// if projectile is going down, trigger maxheight
}
cout << "Maximum height: " << maxHeight << endl;
if ((yNew < 0) || (deltaTime == totalT)) {
getchar(); // stops if delta t = total T or projectile landed
}
yOld = yNew; // refresh x & y
xOld = xNew;
}
If I enter the following values at the start of my program:
theteDegrees = 45
yOld = 0
initialVelocity = 20
totalT = 10
My program displays the expected results that show my projectile going up, then down. However, if I enter the same values expect -40 for thetaDegrees, my projectile should head straight down, instead it just goes up and then down again.
Where have I gone wrong in my code?
As Igor said, during distance calculation over X and Y you've not taken velocityX and velocityY into consideration.
xNew = xOld + velocity * time; // works out displacement for X
yNew = yOld + velocity * deltaTime - gravitiyHalf / 0.5 * (squared); // calculates Y
There is some redundant calculations involved. A more simplistic version could be like this.
theta = thetaDegrees * PI / 180; // converts theta to a degrees value
velocityX = initialVelocity * cos(theta); // calculates Vx
velocityY = initialVelocity * sin(theta); // calculates Vy
//cout<<velocityX<<endl<<velocityY<<endl;
for (double deltaTime = 0.0; deltaTime < totalT; deltaTime += 0.1) {
const double squared = deltaTime * deltaTime; // squared constant for deltaTime squared
xNew = xOld + velocityX * time; // works out displacement for X
yNew = yOld + velocityY * deltaTime - gravitiyHalf / 0.5 * (squared); // calculates Y
velocityY = velocityY - 9.8 * deltaTime; // includes gravity to Y
angle = atan2(yNew, xNew) * 180 / PI; // convert angle to degrees
cout << "\nHeight: " << yNew << endl;
cout << "Distance in Meters: " << xNew << "m" << endl;
cout << "Angle: " << angle << endl;
cout << "Time: " << deltaTime << "s " << endl;
if (heightCheck == false) {
maxHeight = yOld;
// keep maxheight equal to previous height
}
if (yNew < yOld && heightCheck == false) {
heightCheck = true;
// if projectile is going down, trigger maxheight
}
cout << "Maximum height: " << maxHeight << endl;
if ((yNew < 0) || (deltaTime == totalT)) {
getchar(); // stops if delta t = total T or projectile landed
}
yOld = yNew; // refresh x & y
xOld = xNew;
}
You either have to change
xNew = xOld + velocityX * time; // works out displacement for X
to
xNew = xOld + velocityX * deltaTime; // works out displacement for X
or remove
xOld = xNew;
at the end, as leaving both unchanged would give you a quadratically speeding x coordinate, not a linear motion of constant velocity.