Wrong normal for triangles - c++
I am making a 3D game using SFML. I want to use normals to check if the triangle need to be draw in a terrain (triangle) mesh.Here is my code:
vec3d line1, line2, normal;
line1.x = terrain.tris[i].p[0].x - terrain.tris[i].p[1].x;
line1.y = terrain.tris[i].p[0].y - terrain.tris[i].p[1].y;
line1.z = terrain.tris[i].p[0].z - terrain.tris[i].p[1].z;
line2.x = terrain.tris[i].p[1].x - terrain.tris[i].p[2].x;
line2.y = terrain.tris[i].p[1].y - terrain.tris[i].p[2].y;
line2.z = terrain.tris[i].p[1].z - terrain.tris[i].p[2].z;
normal.x = line1.y * line2.z - line1.z * line2.y;
normal.y = line1.z * line2.x - line1.x * line2.z;
normal.z = line1.x * line2.y - line1.y * line2.x;
vec3d vCameraRay = Vector_Sub(terrain.tris[i].p[0], cam.pos);
if (Vector_DotProduct(normal, vCameraRay) < 0.0f){
do_something();
}
Vector_DotProduct:
float Vector_DotProduct(vec3d& v1, vec3d& v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
Vector_sub:
vec3d Vector_Sub(vec3d& v1, vec3d& v2) {
return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
}
And the vec3d is just a struct that contains
float x, y, z;
But whenever I run the program, I always get this
problem
The triangles that should be displayed was considered "Not visable" by my program(The normal of it is wrong), but the calculation seems right to me!
The code for producing triangle grid:
for (int i = 0; i < 2; i++) {
for (int y = 0; y < wds; y++) {
for (int x = 0; x < wds; x++) {
if (x + 1 < wds && y + 1 < wds) {
vec3d point[3];
switch (i) {
case 0:
point[0] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x + 1], (float)(x + 1) * scl + p.z };
point[1] = { (float)y * scl + p.x, height * h[y][x], (float)x * scl + p.z };
point[2] = { (float)y * scl + p.x, height * h[y][x + 1], (float)(x + 1) * scl + p.z };
break;
case 1:
point[0] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x + 1], (float)(x + 1) * scl + p.z };
point[2] = { (float)y * scl + p.x, height * h[y][x], (float)x * scl + p.z };
point[1] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x], (float)x * scl + p.z };
break;
};
triangle out = { point[0], point[1], point[2] };
tris.push_back(out);
}
}
}
}
The wds is for the size of the grid(side length), the scl is the size of per grid, the h is the height map(two dimentions), and p is the position of the upper left corner.
My 3D point to camera point code:
float mx = p.x - pos.x;
float my = p.y - pos.y;
float mz = p.z - pos.z;
float dx = cos(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx) - sin(rot.y) * mz;
float dy = sin(rot.x) * (cos(rot.y) * mz + sin(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx)) + cos(rot.x) * (cos(rot.z) * my + sin(rot.z) * mx);
float dz = cos(rot.x) * (cos(rot.y) * mz + sin(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx)) - sin(rot.x) * (cos(rot.z) * my + sin(rot.z) * mx);
return { dx, dy, dz };
The rot is the rotation of the camera, p is the position of the camera, and the pos is the 3D point I want to transfer to camera point.
I have been working on this problem for almost a week, but nothing seems to work.It will be a lot of help if you guys can find the problem. Thanks in advance!
Full Code
Init.h:
#ifndef _INIT_H_
#define _INIT_H_
#define WIDTH 1200
#define HEIGHT 800
#endif
Noise.h: noice function
#pragma once
#ifndef _NOISE_H_
#define _NOISE_H_
extern int primeIndex;
extern int numOctaves;
extern double persistence;
extern int primes[10][3];
#endif
#include <math.h>
float Noise(int i, int x, int y);
float SmoothedNoise(int i, int x, int y);
float Interpolate(float a, float b, float x);
float InterpolatedNoise(int i, float x, float y);
float noise(float x, float y);
Noise.cpp:
#include "Noise.h"
int primeIndex = 0;
int numOctaves = 7;
double persistence = 0.5;
int primes[10][3] = {
{ 995615039, 600173719, 701464987 },
{ 831731269, 162318869, 136250887 },
{ 174329291, 946737083, 245679977 },
{ 362489573, 795918041, 350777237 },
{ 457025711, 880830799, 909678923 },
{ 787070341, 177340217, 593320781 },
{ 405493717, 291031019, 391950901 },
{ 458904767, 676625681, 424452397 },
{ 531736441, 939683957, 810651871 },
{ 997169939, 842027887, 423882827 }
};
float Noise(int i, int x, int y) {
int n = x + y * 57;
n = (n << 13) ^ n;
int a = primes[i][0], b = primes[i][1], c = primes[i][2];
int t = (n * (n * n * a + b) + c) & 0x7fffffff;
return 1.0 - (float)(t) / 1073741824.0;
}
float SmoothedNoise(int i, int x, int y) {
float corners = (Noise(i, x - 1, y - 1) + Noise(i, x + 1, y - 1) +
Noise(i, x - 1, y + 1) + Noise(i, x + 1, y + 1)) / 16,
sides = (Noise(i, x - 1, y) + Noise(i, x + 1, y) + Noise(i, x, y - 1) +
Noise(i, x, y + 1)) / 8,
center = Noise(i, x, y) / 4;
return corners + sides + center;
}
float Interpolate(float a, float b, float x) {
float ft = x * 3.1415927,
f = (1 - cos(ft)) * 0.5;
return a * (1 - f) + b * f;
}
float InterpolatedNoise(int i, float x, float y) {
int integer_X = x;
float fractional_X = x - integer_X;
int integer_Y = y;
float fractional_Y = y - integer_Y;
float v1 = SmoothedNoise(i, integer_X, integer_Y),
v2 = SmoothedNoise(i, integer_X + 1, integer_Y),
v3 = SmoothedNoise(i, integer_X, integer_Y + 1),
v4 = SmoothedNoise(i, integer_X + 1, integer_Y + 1),
i1 = Interpolate(v1, v2, fractional_X),
i2 = Interpolate(v3, v4, fractional_X);
return Interpolate(i1, i2, fractional_Y);
}
float noise(float x, float y) {
float total = 0,
frequency = pow(2, numOctaves),
amplitude = 1;
for (int i = 0; i < numOctaves; ++i) {
frequency /= 2;
amplitude *= persistence;
total += InterpolatedNoise((primeIndex + i) % 10,
x / frequency, y / frequency) * amplitude;
}
return total / frequency;
}
Struct.h:
#pragma once
#ifndef _STRUCT_H_
#define _STRUCT_H_
#endif
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <list>
#include "Init.h"
struct vec3d {
float x = 0;
float y = 0;
float z = 0;
};
struct vec2d {
float x = 0;
float y = 0;
};
struct triangle {
vec3d p[3];
int color[3] = { 255, 255, 255 };
vec3d normal;
};
Terrain.h: terrain generation
#pragma once
#ifndef _TERRAIN_H_
#define _TERRAIN_H_
#endif
#include <vector>
#include "Struct.h"
#include "Noise.h"
#define wds 50
#define scl 20
#define width 1000
#define height 120
struct Terrain {
public:
std::vector<triangle> tris;
vec3d p = { -width / 2, 0.0f, -width / 2 };
float h[wds][wds];
void triangle_Strip();
};
Terrain.cpp:
#include "Terrain.h"
void Terrain::make_value() {
for (int y = 0; y < wds; y++) {
for (int x = 0; x < wds; x++) {
int a = abs(p.z / scl + x), b = abs(p.x / scl + y);
h[y][x] = noise(a, b) * 30;
}
}
}
void Terrain::triangle_Strip() {
tris.clear();
for (int i = 0; i < 2; i++) {
for (int y = 0; y < wds; y++) {
for (int x = 0; x < wds; x++) {
if (x + 1 < wds && y + 1 < wds) {
vec3d point[3];
switch (i) {
case 0:
point[0] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x + 1], (float)(x + 1) * scl + p.z };
point[1] = { (float)y * scl + p.x, height * h[y][x], (float)x * scl + p.z };
point[2] = { (float)y * scl + p.x, height * h[y][x + 1], (float)(x + 1) * scl + p.z };
break;
case 1:
point[0] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x + 1], (float)(x + 1) * scl + p.z };
point[2] = { (float)y * scl + p.x, height * h[y][x], (float)x * scl + p.z };
point[1] = { (float)(y + 1) * scl + p.x, height * h[y + 1][x], (float)x * scl + p.z };
break;
};
triangle out = { point[0], point[1], point[2] };
tris.push_back(out);
}
}
}
}
}
Camera.h: camera class, get3dcoord which is get camera point, get2dcoord which is get screen point
#pragma once
#ifndef _CAMERA_H_
#define _CAMERA_H_
#endif
#include "Mat.h"
#include "Init.h"
#include "Struct.h"
class Cam {
public:
vec3d pos;
vec3d rot;
float fov;
float speed;
Cam(vec3d p, vec3d r, float f, float s);
vec3d get3dcoord(vec3d p);
vec3d get2dcoord(vec3d p);
};
Camera.cpp:
#include "Camera.h"
Cam::Cam(vec3d p, vec3d r, float f, float s) {
pos = p;
rot = r;
fov = f;
speed = s;
}
vec3d Cam::get3dcoord(vec3d p) {
float mx = p.x - pos.x;
float my = p.y - pos.y;
float mz = p.z - pos.z;
float dx = cos(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx) - sin(rot.y) * mz;
float dy = sin(rot.x) * (cos(rot.y) * mz + sin(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx)) + cos(rot.x) * (cos(rot.z) * my + sin(rot.z) * mx);
float dz = cos(rot.x) * (cos(rot.y) * mz + sin(rot.y) * (sin(rot.z) * my + cos(rot.z) * mx)) - sin(rot.x) * (cos(rot.z) * my + sin(rot.z) * mx);
return { dx, dy, dz };
}
vec3d Cam::get2dcoord(vec3d p) {
float e = (float)tan(fov / 2) * (float)(WIDTH / 2);
float x = (WIDTH / 2) + (e * p.x) / p.z;
float y = (HEIGHT / 2) + (e * p.y) / p.z;
return { x, y, 0 };
}
3D engine.h: main
#pragma once
#ifndef _3D_ENGINE_H_
#define _3D_ENGINE_H_
#endif
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <iostream>
#include <stdlib.h>
#include <sstream>
#include <list>
#include "Struct.h"
#include "Camera.h"
#include "Init.h"
#include "Noise.h"
#include "Terrain.h"
#define endl "\n"
void draw_triangle(vec3d p1, vec3d p2, vec3d p3, int color[]);
vec3d Vector_Sub(vec3d& v1, vec3d& v2);
float Vector_DotProduct(vec3d& v1, vec3d& v2);
3D engine.cpp:
#include "3D engine.h"
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "3D game in progress");
const sf::Vector2i windowCenter(WIDTH / 2, HEIGHT / 2);
Cam cam({ 0.0f, -40.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, 90, 2.0f);
Terrain terrain;
sf::VertexArray TriangleToDraw(sf::Triangles);
void draw_triangle(vec3d p1, vec3d p2, vec3d p3, int color[]) {
sf::VertexArray tri(sf::Triangles, 3);
tri[0].position = sf::Vector2f(p1.x, p1.y);
tri[1].position = sf::Vector2f(p2.x, p2.y);
tri[2].position = sf::Vector2f(p3.x, p3.y);
tri[0].color = sf::Color((int)color[0], (int)color[1], (int)color[2]);
tri[1].color = sf::Color((int)color[0], (int)color[1], (int)color[2]);
tri[2].color = sf::Color((int)color[0], (int)color[1], (int)color[2]);
TriangleToDraw.append(tri[0]);
TriangleToDraw.append(tri[1]);
TriangleToDraw.append(tri[2]);
}
vec3d Vector_Sub(vec3d& v1, vec3d& v2) {
return { v1.x - v2.x, v1.y - v2.y, v1.z - v2.z };
}
float Vector_DotProduct(vec3d& v1, vec3d& v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
int main() {
window.setMouseCursorVisible(false);
sf::Mouse::setPosition(windowCenter, window);
terrain.make_value();
terrain.triangle_Strip();
while (window.isOpen()) {
TriangleToDraw.clear();
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
}
if ((event.type == sf::Event::MouseLeft || event.type == sf::Event::MouseMoved) && sf::Mouse::getPosition(window) != windowCenter) {
sf::Vector2i pos = sf::Mouse::getPosition(window);
int x_a = pos.x;
int y_a = pos.y;
float movex = (float)(x_a - windowCenter.x) / 500.0f;
float movey = (float)(y_a - windowCenter.y) / 500.0f;
cam.rot.x -= movey;
cam.rot.y += movex;
sf::Mouse::setPosition(windowCenter, window);
}
}
float x = sin(cam.rot.y) * cam.speed; float z = cos(cam.rot.y) * cam.speed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) { cam.pos.x -= x; cam.pos.z -= z; /*terrain.p.x -= x; terrain.p.z -= z;*/ }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) { cam.pos.x += x; cam.pos.z += z; /*terrain.p.x += x; terrain.p.z += z;*/ }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) { cam.pos.x += z; cam.pos.z -= x; /*terrain.p.x += z; terrain.p.z -= x;*/ }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) { cam.pos.x -= z; cam.pos.z += x; /*terrain.p.x -= z; terrain.p.z += x;*/ }
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) cam.pos.y += cam.speed;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::LSHIFT)) cam.pos.y -= cam.speed;
window.clear(sf::Color(0, 0, 0));
std::vector<triangle> triangles;
for (int i = 0, len = terrain.tris.size(); i < len; i++) {
std::vector<vec3d> projected(3);
for (int r = 0; r < 3; r++) projected[r] = cam.get3dcoord(terrain.tris[i].p[r]);
vec3d line1, line2, normal;
line1.x = projected[0].x - projected[1].x;
line1.y = projected[0].y - projected[1].y;
line1.z = projected[0].z - projected[1].z;
line2.x = projected[1].x - projected[2].x;
line2.y = projected[1].y - projected[2].y;
line2.z = projected[1].z - projected[2].z;
normal.x = line1.y * line2.z - line1.z * line2.y;
normal.y = line1.z * line2.x - line1.x * line2.z;
normal.z = line1.x * line2.y - line1.y * line2.x;
float l = sqrtf(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z);
normal.x /= l; normal.y /= l; normal.z /= l;
vec3d vCameraRay1 = Vector_Sub(projected[0], cam.pos);
if (Vector_DotProduct(normal, vCameraRay1) < 0.0f && projected[0].z < 0.0f && projected[1].z < 0.0f && projected[2].z < 0.0f/*avoid points behind the camera to be projected*/) {
vec3d light = { 0.0f, 0.0f, 1.0f };
float lNormal = sqrtf(powf(light.x, 2) + powf(light.y, 2) + powf(light.z, 2));
light.x /= lNormal; light.y /= lNormal; light.z /= lNormal;
float dp = std::max(0.3f, Vector_DotProduct(light, normal));
int c = 255 * dp;
triangles.push_back({projected[0], projected[1], projected[2], {c, c, c}});
}
}
std::sort(triangles.begin(), triangles.end(), [](triangle& t1, triangle& t2)
{
float z1 = (t1.p[0].z + t1.p[1].z + t1.p[2].z) / 3.0f;
float z2 = (t2.p[0].z + t2.p[1].z + t2.p[2].z) / 3.0f;
return z1 < z2;
});
for (triangle tri : triangles) {
draw_triangle(cam.get2dcoord(tri.p[0]), cam.get2dcoord(tri.p[1]), cam.get2dcoord(tri.p[2]), tri.color);
}
window.draw(TriangleToDraw);
window.display();
}
return 0;
}
One of the triangle that had the wrong normal:
Normal: -0.08
vCameraRay: -588.2, 19.0, -662.5
Vector Dotproduct: -74.7
Triangle Point1: 19.03, -35.10, -75.69
Triangle Point2: -1.28, -27.57, -92.94
Triangle Point3: -0.96, -25.79, -71.35
Camera position: 2.20, 627.26, 0.03
One of the triangle that had the wrong Dot Product:
Normal: 0.59
vCameraRay: 468.41, 13.59, -634.75
Vector DotProduct: -55.05
Triangle Point1: 13.59, -7.29, -55.05
Triangle Point2: 19.19, 7.04, -37.72
Trianlge Point3: 0.00, 9.75, -28.36
Camera pos: 0.00, 627.45, 0.00
Related
How do I add a wave to a curved surface composed of triangle primatives in C++?
I want to preface this post: This is perhaps more of a math question than a coding question. I am developing a plant (lettuce) model which involves somewhat complex geometry. At this stage I have a surface curved in 2 dimensions but now I want to add waviness to this curved surface but am having a hard time envisioning how to do so. The surface is made of triangle primatives, the primatives take xyz vectors to encode location of vertices. I am using an API termed HELIOS to develop this procedural model of lettuce. I essentially created the surface with for loops and the sine function. Disclaimer: I do not have a strong background in geometry, computer graphics, or C++. Here is the relevant code: #include "Context.h" #include "Visualizer.h" using namespace helios; using namespace std; vector<uint> addLeaf(float leaf_length, float leaf_width, float leaf_bend_x, float leaf_bend_y, float rotation_z, float rotation_x, float displacement, float radius, Context* context ) { std::vector<uint> UUIDs; // float leaf_length = 10; float Nz = 10; // params.s1_leaf_subdivisions ; number of times to split the dimension float dz = leaf_length / Nz; // length of each subdivision // float leaf_width = 10; float Ny = 10; // params.s1_leaf_subdivisions ; number of times to split the dimension float dy = leaf_width / Ny; // length of each subdivision // leaf wave // float A_3 = leaf_length * float(0.5); // Half waves on the leaf 10 // float A_2 = leaf_length * float(0.1); // amplitude 0.25 float A_3 = 1; // Half waves on the leaf 10 float A_2 = 1; // amplitude 0.25 float leaf_amplitude = leaf_length / float(10); // the 2 * dx extends the sine wave a bit beyond 1/2 wavelength so base of leaves come together for (int i = 0; i < Nz + (2 * dz); i++) { for (float j = 0; j < Ny; j++) { float z = i * dz; //for each subdivision in z define Z coord float y = j * dy; //for each subdivision in y define y coord float x = 0; // we will also need an x coord float sz = dz; // the next step in z will be equal to a subdivision in z float sy = dy; // the next step in y will be equal to a subdivision in y float z_i = z * M_PI / (Nz * dz); // the second coord for z is z_i needed to define a triangle primitive float sz_i = (z + sz) * M_PI / (Nz * dz); // // this would be y_1 in sorghum model float y_i = (y * M_PI / (Ny * dy)) / (A_3); // the second coord for y is y_i needed to define a triangle primitive float sy_i = ((y + sy) * M_PI / (Ny * dy)) / (A_3); //waviness of leaf float leaf_wave_1; float leaf_wave_2; float leaf_wave_3; float leaf_wave_4; if (j == 0) { leaf_wave_1 = A_2 * sin(z_i); leaf_wave_2 = A_2 * sin(sz_i); } else { leaf_wave_1 = A_2 * sin(z_i); leaf_wave_2 = A_2 * sin(sz_i); } // Now define x based on z,y and add leaf bend in x and y x = leaf_bend_x * sin(z_i); x = ((x*radius + displacement + (leaf_bend_y * sin(y_i))) / 2) + leaf_wave_1; vec3 v0(x*radius + displacement, y, z); x = leaf_bend_x * sin(sz_i); x = ((x*radius + displacement + (leaf_bend_y * sin(y_i))) / 2) + leaf_wave_2; vec3 v1(x*radius + displacement, y, z + sz); if (j == Nz - 1) { leaf_wave_3 = sin(sz_i) * A_2; leaf_wave_4 = sin(z_i) * A_2; } else { leaf_wave_3 = sin(sz_i) * A_2; leaf_wave_4 = sin(z_i) * A_2; } x = leaf_bend_x * sin(sz_i); x = ((x*radius + displacement + (leaf_bend_y * sin(sy_i))) / 2) + leaf_wave_3 ; vec3 v2(x*radius + displacement, y + sy, z + sz); x = leaf_bend_x * sin(z_i); x = ((x*radius + displacement + (leaf_bend_y * sin(sy_i))) / 2) + leaf_wave_4 ; vec3 v3(x*radius + displacement, y + sy, z); // set of two triangles which form a rectangle or square as subunits of leaf UUIDs.push_back(context->addTriangle(v0, v1, v2, RGB::cyan)); UUIDs.push_back(context->addTriangle(v0, v2, v3, RGB::magenta)); } } return UUIDs; } // call to functions and build lettuce geometries int main( void ){ Context context; float leaf_length = 10; float leaf_width = 10; float radius = 1; // additional control leaf curvature // add leaves one by one; 'i' here is # of leaves external to whorl for (int i = 0; i < 6; i++) { if (i == 0)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, 0, i/5, radius, &context); // if (i == 1)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, -M_PI/ 20, i/5, radius, &context); // if (i == 2)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, -M_PI/ 10, i/5, radius, &context); // if (i == 3)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, -M_PI/ 9, i/5, radius, &context); // if (i == 4)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, -M_PI/ 7, i/5, radius, &context); // if (i == 5)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, -M_PI/ 5, i/5, radius, &context); } Visualizer visualizer(800); visualizer.buildContextGeometry(&context); visualizer.setLightingModel(Visualizer::LIGHTING_PHONG); visualizer.plotInteractive(); } I tried to use a sine function and an additional for loop to create a series of values to add to the X coordinate of the triangles but did not obtain the result I was looking for.
This is how you can create a Wave Geometry. you can keep updating the m_fTime values to animate the wave. // m_iWaveFlowOut -> value to be either 0 or 1 //m_fFrequency -> Number of waves //m_fAmplitude -> Amplitude of wave void Generate() { const int n8 = m_iNSegments * 8; // size of VBO gfx data const int sz0 = m_iMSegments * n8; // size of VBO gfx data const int sz1 = (m_iMSegments - 1) * (m_iNSegments - 1) * 6;// size of indices verticesRect.clear(); indicesRect.clear(); int a,i, j, k, b; float x, y, z, dx, dy, l; glm::vec3 u, v, nor; dx = 2.0 * ( m_fWidth / float(m_iNSegments - 1)); dy = 2.0 * ( m_fHeight / float(m_iMSegments - 1)); for (a = 0, y = -m_fHeight, j = 0; j < m_iMSegments; j++, y += dy) for (x = -m_fWidth, i = 0; i < m_iNSegments; i++, x += dx) { float dist = glm::length(glm::vec2(x + m_fxOffset, y + m_fyOffset)); float attenuation, kc, kq; kc = 1.0; kq = 0.0; attenuation = 1.0f; if (m_bUseAttenuation) { attenuation = 1.0 / (kc + (this->m_fKl * dist) + (kq * pow(dist, 2))); if (attenuation > 1.0) attenuation = 1.0; } switch (m_WAVETYPE) { case Sum_Wave2::WAVE2_TYPE::COS: z = (-m_fAmplitude * attenuation) * cos(((x + m_fxOffset) / m_fFrequency) + m_fTime * m_iWaveFlowOut); break; case Sum_Wave2::WAVE2_TYPE::SIN: z = (-m_fAmplitude * attenuation) * sin(((y + m_fyOffset) / m_fFrequency) + m_fTime * m_iWaveFlowOut); break; case Sum_Wave2::WAVE2_TYPE::RING: z = (-m_fAmplitude * attenuation) * sin((glm::length(glm::vec2(x + m_fxOffset, y + m_fyOffset)) + m_fTime * m_iWaveFlowOut) / m_fFrequency); break; default: z = 0.0; break; } verticesRect.push_back(x); a++; verticesRect.push_back(y); a++; verticesRect.push_back(z); a++; // Normal ( will be recomputed later) verticesRect.push_back(0.0); a++; verticesRect.push_back(0.0); a++; verticesRect.push_back(1.0); a++; // TexCoord verticesRect.push_back((x + m_fWidth) / (m_fWidth + m_fWidth)); a++; verticesRect.push_back((y + m_fHeight) / (m_fHeight + m_fHeight)); a++; } // triangulation indices for(a = 0, j = 1; j < m_iMSegments; j++ ) for (i = 1; i < m_iNSegments; i++) { b = ((m_iNSegments * j) + i) * 8; // First triangle per quad indicesRect.push_back(b - 8); a++; indicesRect.push_back(b - 8 - n8); a++; indicesRect.push_back(b); a++; // Second triangle per quad indicesRect.push_back(b - 8 - n8); a++; indicesRect.push_back(b - n8); a++; indicesRect.push_back(b); a++; // recompute inner normals for (k = 0; k < 3; k++) { u[k] = verticesRect[indicesRect[a - 6] + k] - verticesRect[indicesRect[a - 4] + k]; v[k] = verticesRect[indicesRect[a - 5] + k] - verticesRect[indicesRect[a - 4] + k]; } glm::vec3 cross1 = crossProduct(u, v); cross1 = glm::normalize(cross1); for (k = 0; k < 3; k++) { u[k] = verticesRect[indicesRect[a - 3] + k] - verticesRect[indicesRect[a - 1] + k]; v[k] = verticesRect[indicesRect[a - 2] + k] - verticesRect[indicesRect[a - 1] + k]; } glm::vec3 cross2 = crossProduct(u, v); cross2 = glm::normalize(cross2); for (k = 0; k < 3; k++) { verticesRect[indicesRect[a - 1] + 3 + k] = 0.5 * (cross1[k] + cross2[k]); } } for (i = 0; i < sz1; i++) { indicesRect[i] = indicesRect[i] /= 8; } }
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:
"rotation algorithm" in opngl not working
I'm trying "rotation algorithm" in opngl but it's not working I'm getting a blank page when I run my program . should I put POINT* verts or Point verts[6] is there something wrong with my code? void rotate(POINT* verts, GLint nverts, POINT fixedv, GLdouble theta) { POINT newverts[6]; //POINT fixedv GLint k; for (k = 0; k < nverts; k++) { newverts[k].x = fixedv.x + (verts[k].x - fixedv.x) * cos(theta) - (verts[k].y - fixedv.y) * sin(theta); newverts[k].y = fixedv.y + (verts[k].x - fixedv.x) * sin(theta) + (verts[k].y - fixedv.y) * cos(theta); newverts[k].x = (verts[k].x) * cos(theta) - (verts[k].y) * sin(theta); newverts[k].y = (verts[k].x) * sin(theta) + (verts[k].y) * cos(theta); } glBegin(GL_TRIANGLE_FAN); for (k = 0; k < nverts; k++) glVertex2f(newverts[k].x, newverts[k].y); glEnd(); glFlush(); } display code: void display() { glColor3f(r, g, b); if (check == 3) { double theta = 3.14 * 0.5; POINT verts[6],fixedpivot; fixedpivot.x = x; fixedpivot.y = y; verts[0].x = x + 25; verts[0].y = y + 50; verts[1].x = x; verts[1].y = y; verts[2].x = x+50; verts[2].y = y; verts[3].x = x + 25; verts[3].y = y + 50; verts[4].x = x + 50; verts[4].y = y + 100; verts[5].x = x; verts[5].y = y + 100; glClear(GL_COLOR_BUFFER_BIT); glColor3f(r, g, b); rotate(verts, 6, fixedpivot, theta); glFlush();
Translate Assimp 3D Models also rotates
I have a 3D Model in an OpenGL (C++) loaded using Assimp. I need to move this model around the screen (translate) like it is always facing the camera in the X and Y axis (no Z axis). It would be like moving this model like it is 2D only (but of course if I rotate it, it would show the Z axis as well). my render function is : camX = CamY = 0; camZ = 5; lookatX = lookatY = lookatZ = 0; void C3DModel::render(void) { static float step = 0.0f; setCamera(camX, camY, camZ, lookatX, lookatY, lookatZ); translate(-3, 1, 0); // here is the issue . scale(scaleFactor, scaleFactor, scaleFactor); rotate(step, 0.0f, 1.0f, 0.0f); } void C3DModel::translate(float x, float y, float z) { float aux[16]; setTranslationMatrix(aux, x, y, z); multMatrix(modelMatrix, aux); setModelMatrix(); } void C3DModel::setTranslationMatrix(float *mat, float x, float y, float z) { setIdentityMatrix(mat, 4); mat[12] = x; mat[13] = y; mat[14] = z; } void C3DModel::setScaleMatrix(float *mat, float sx, float sy, float sz) { setIdentityMatrix(mat, 4); mat[0] = sx; mat[5] = sy; mat[10] = sz; } void C3DModel::setRotationMatrix(float *mat, float angle, float x, float y, float z) { float radAngle = DegToRad(angle); float co = cos(radAngle); float si = sin(radAngle); float x2 = x * x; float y2 = y * y; float z2 = z * z; mat[0] = x2 + (y2 + z2) * co; mat[4] = x * y * (1 - co) - z * si; mat[8] = x * z * (1 - co) + y * si; mat[12] = 0.0f; mat[1] = x * y * (1 - co) + z * si; mat[5] = y2 + (x2 + z2) * co; mat[9] = y * z * (1 - co) - x * si; mat[13] = 0.0f; mat[2] = x * z * (1 - co) - y * si; mat[6] = y * z * (1 - co) + x * si; mat[10] = z2 + (x2 + y2) * co; mat[14] = 0.0f; mat[3] = 0.0f; mat[7] = 0.0f; mat[11] = 0.0f; mat[15] = 1.0f; } void C3DModel::rotate(float angle, float x, float y, float z) { float aux[16]; setRotationMatrix(aux, angle, x, y, z); multMatrix(modelMatrix, aux); setModelMatrix(); } void C3DModel::scale(float x, float y, float z) { float aux[16]; setScaleMatrix(aux, x, y, z); multMatrix(modelMatrix, aux); setModelMatrix(); } void C3DModel::setIdentityMatrix(float *mat, int size) { // fill matrix with 0s for (int i = 0; i < size * size; ++i) mat[i] = 0.0f; // fill diagonal with 1s for (int i = 0; i < size; ++i) mat[i + i * size] = 1.0f; } void C3DModel::multMatrix(float *a, float *b) { float res[16]; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { res[j * 4 + i] = 0.0f; for (int k = 0; k < 4; ++k) { res[j * 4 + i] += a[k * 4 + i] * b[j * 4 + k]; } } } memcpy(a, res, 16 * sizeof(float)); } void C3DModel::setModelMatrix() { glBindBuffer(GL_UNIFORM_BUFFER, matricesUniBuffer); glBufferSubData(GL_UNIFORM_BUFFER, ModelMatrixOffset, MatrixSize, modelMatrix); glBindBuffer(GL_UNIFORM_BUFFER, 0); } void C3DModel::crossProduct(float *a, float *b, float *res) { res[0] = a[1] * b[2] - b[1] * a[2]; res[1] = a[2] * b[0] - b[2] * a[0]; res[2] = a[0] * b[1] - b[0] * a[1]; } // Normalize a vec3 void C3DModel::normalize(float *a) { float mag = sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); a[0] /= mag; a[1] /= mag; a[2] /= mag; } void C3DModel::setCamera(float posX, float posY, float posZ, float lookAtX, float lookAtY, float lookAtZ) { float dir[3], right[3], up[3]; up[0] = 0.0f; up[1] = 1.0f; up[2] = 0.0f; dir[0] = (lookAtX - posX); dir[1] = (lookAtY - posY); dir[2] = (lookAtZ - posZ); normalize(dir); crossProduct(dir, up, right); normalize(right); crossProduct(right, dir, up); normalize(up); float viewMatrix[16], aux[16]; viewMatrix[0] = right[0]; viewMatrix[4] = right[1]; viewMatrix[8] = right[2]; viewMatrix[12] = 0.0f; viewMatrix[1] = up[0]; viewMatrix[5] = up[1]; viewMatrix[9] = up[2]; viewMatrix[13] = 0.0f; viewMatrix[2] = -dir[0]; viewMatrix[6] = -dir[1]; viewMatrix[10] = -dir[2]; viewMatrix[14] = 0.0f; viewMatrix[3] = 0.0f; viewMatrix[7] = 0.0f; viewMatrix[11] = 0.0f; viewMatrix[15] = 1.0f; setTranslationMatrix(aux, -posX, -posY, -posZ); multMatrix(viewMatrix, aux); glBindBuffer(GL_UNIFORM_BUFFER, matricesUniBuffer); glBufferSubData(GL_UNIFORM_BUFFER, ViewMatrixOffset, MatrixSize, viewMatrix); glBindBuffer(GL_UNIFORM_BUFFER, 0); }
What i will try is to separate the rotation of your object and the translation requested for your screen position, in 2 different matrices. At each frame, I would compute the rotation matrice with the code inside your C3DModel::setRotationMatrix and the translation with C3DModel::setTranslationMatrix, combine them in a fresh new model matrice and apply it to your object. Keep in mind that the order matters, if you rotate first the object will turn around the origin in your obj file, if you rotate after the translation it will rotate around the worl origin (like a planet around the sun, the sun would be the origin). In the end, it would looks like: void C3DModel::render(void){ float* rotation = createRotation(angle, x, y, z); float* translation = createTranslation(x, y, z); float* updatedModel = mul(rotation, translation) //order matters setModel(updatedModel); }
opengl - matrix transformation for multiple objects
I can't get myobject1, myobject2, and myobject3 to have their own rotation rendered. They rotate but all facing the same direction. rotate() stops working after glDrawElements gets called. It only starts working again if I call glutSwapBuffers() in render(). But then my screen flickers, but the models are rendered the way I want them. In other words: before any render() is called, rotate() works fine... but using rotate() after any render() is called, rotate() does nothing... because for rotate() to work again, I need to call glutSwapBuffer() every time I draw an object, which makes rotate() work correctly for myobject1, myobject2, and myobject3, but then screen then flickers. void setModelMatrix() { glBindBuffer(GL_UNIFORM_BUFFER, matricesUniBuffer); glBufferSubData(GL_UNIFORM_BUFFER, ModelMatrixOffset, MatrixSize, modelMatrix); glBindBuffer(GL_UNIFORM_BUFFER,0); } void setIdentityMatrix(float *mat, int size) { for (int i = 0; i < size * size; ++i) mat[i] = 0.0f; for (int i = 0; i < size; ++i) mat[i + i * size] = 1.0f; } void multMatrix(float *a, float *b) { float res[16]; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { res[j*4 + i] = 0.0f; for (int k = 0; k < 4; ++k) { res[j*4 + i] += a[k*4 + i] * b[j*4 + k]; } } } memcpy(a, res, 16 * sizeof(float)); } void rotate(float angle, float x, float y, float z) { float aux[16]; setRotationMatrix(aux,angle,x,y,z); multMatrix(modelMatrix,aux); setModelMatrix(); } void setRotationMatrix(float *mat, float angle, float x, float y, float z) { float radAngle = DegToRad(angle); float co = cos(radAngle); float si = sin(radAngle); float x2 = x*x; float y2 = y*y; float z2 = z*z; mat[0] = x2 + (y2 + z2) * co; mat[4] = x * y * (1 - co) - z * si; mat[8] = x * z * (1 - co) + y * si; mat[12]= 0.0f; mat[1] = x * y * (1 - co) + z * si; mat[5] = y2 + (x2 + z2) * co; mat[9] = y * z * (1 - co) - x * si; mat[13]= 0.0f; mat[2] = x * z * (1 - co) - y * si; mat[6] = y * z * (1 - co) + x * si; mat[10]= z2 + (x2 + y2) * co; mat[14]= 0.0f; mat[3] = 0.0f; mat[7] = 0.0f; mat[11]= 0.0f; mat[15]= 1.0f; } void recursive_render () { //myobject->ry+=0.0001f; for (unsigned int n=0; n < scene->mNumMeshes; ++n) { glBindBufferRange(GL_UNIFORM_BUFFER, materialUniLoc, myobject->Meshes[scene->mMeshes[n]].uniformBlockIndex, 0, sizeof(struct MyMaterial)); glBindTexture(GL_TEXTURE_2D, myobject->Meshes[scene->mMeshes[n]].texIndex); glBindVertexArray(myobject->Meshes[nd->mMeshes[n]].vao); glDrawElements(GL_TRIANGLES,myobject->Meshes[scene->mMeshes[n]].numFaces*3,GL_UNSIGNED_INT,0); } } void render() { setIdentityMatrix(modelMatrix,4); rotate(myobject->ry, 0.0, 1.0, 0.0); scale(scaleFactor, scaleFactor, scaleFactor); recursive_render(scene->mRootNode); } void renderScene(void) { myobject1.ry = 50.0f; myobject2.ry = 150.0f; myobject3.ry = 270.0f; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); setCamera(camX,camY,camZ,0,0,0); glUseProgram(program); glUniform1i(texUnit,0); myobject = &myobject1; render(); myobject = &myobject2; render(); myobject = &myobject3; render(); glutSwapBuffers(); }