Related
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
I am trying to add bevel to a cylinder , but i am have an issue with calculating the normals for the bevel
the
this is how i am calculating the data for vertices
struct Vertices
{
float x;
float y;
float z;
}
float pieStartAngle = 0.0 * (M_PI / 180.0f);
float angleCircle = 0.0f;
// First fill all the position of vertices
for (int k = 0; k < totalNumberOfPies; k++)
{
for (int i = 0; i < segmentPerPie + 1; i++)
{
Vertices temp;
float initialAngle = pieStartAngle;
angleCircle = (stdvecValuePercent[k] / 100.0f) * totalAngle;
float angle = initialAngle + ((angleCircle *(M_PI / 180)) * i / segmentPerPie);
float x, y, z, tx, ty, tz;
float innerX, innerY, innerZ, innerTx, innerTy;
x = cos(angle) * (radius - bevel);
y = sin(angle) * (radius - bevel);
z = 0.0;
temp.x = x;
temp.y = y;
temp.z = z;
vertices.push_back(temp);
x = cos(angle) * radius;
y = sin(angle) * radius;
z = 0.0 + bevel;
temp.x = x;
temp.y = y;
temp.z = z;
vertices.push_back(temp);
}
pieStartAngle += angleCircle * (M_PI / 180);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
this is how i am calculating the data for normals , i am taking the cross product of three verices to get the vector perpendicular to the face.
for (int i = 0; i < vertices.size(); i++)
{
glm::vec3 vec1 = glm::vec3(vertices[i].x - vertices[i + 1].x, vertices[i].y - vertices[i + 1].y, vertices[i].z - vertices[i + 1].z);
glm::vec3 vec2 = glm::vec3(vertices[i].x - vertices[i + 2].x, vertices[i].y - vertices[i + 2].y, vertices[i].z - vertices[i + 2].z);
glm::vec3 crossProduct = glm::cross(glm::normalize(vec1), glm::normalize(vec2));
crossProduct = glm::normalize(crossProduct);
bevelData.push_back(vertices[i].x);
bevelData.push_back(vertices[i].y);
bevelData.push_back(vertices[i].z);
bevelData.push_back(crossProduct.x );
bevelData.push_back(crossProduct.y );
bevelData.push_back(crossProduct.z);
bevelData.push_back(0.0);
bevelData.push_back(0.0);
}
I want to setup the phong shading in my program, and I use "glm.h" to help me read and draw the .obj model. Because not all of the model have the vertex normal data in the file, I count it by myself and I check it's right.
But the shader just can correct in flat shader when I use "glmDraw(myObj, GLM_FLAT)" , it will use face normal to count it. I can't get the right effect when I use "glmDraw(myObj, GLM_SMOOTH)" use vertex normal to count. What's wrong in my code? It's my main program wrong? Or my shder program?
My main code:
#define GLEW_STATIC
#include <Windows.h> // for solving the Code::Blocks errors
#include <stdlib.h>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <GL/glew.h>
#include <GL/glut.h>
#include "textfile.h"
#include "glm.h"
#define PI 3.1415926535897
using namespace std;
GLMmodel *myObj = NULL;
GLMmodel *myObj_inner = NULL;
int width, height;
int start_x, start_y;
GLdouble theta = -PI/2, phi = PI / 2;
GLdouble eye_x = 0.0, eye_y = 0.0, eye_z = 0.0,
center_x = eye_x + sin(phi) * cos(theta), center_y = eye_y + cos(phi), center_z = 4*sin(phi) * sin(theta),
up_x = 0.0, up_y = 1.0, up_z = 0.0;
bool ridingMode = false;
float delta_x = 0.0, delta_y = 0.0, delta_z = 0.0;
float angle=0;
GLfloat vertices[][3] =
{{-0.5,-0.5,-0.5},
{0.5,-0.5,-0.5},
{0.5,0.5,-0.5},
{-0.5,0.5,-0.5},
{-0.5,-0.5,0.5},
{0.5,-0.5,0.5},
{0.5,0.5,0.5},
{-0.5,0.5,0.5}};
GLdouble lightTheta = 10.0;
GLfloat light0_ambient[] = {0.9, 0.9, 0.9, 1.0};
GLfloat light0_diffuse[] = {0.7, 0.7, 0.7, 1.0};
GLfloat light0_specular[] = {0.7, 0.7, 0.7, 1.0};
GLfloat light0_pos[]={0.0, 0.0, 0.0, 1.0};
GLfloat light0_shininess = 50;
GLfloat min_x, max_x, min_y, max_y, min_z, max_z;
GLfloat bound_size[3];
GLfloat bound_center[3];
vector<int> *point_tri = NULL;
bool show = true;
void polygon(int a, int b, int c , int d)
{
/* draw a polygon via list of vertices */
glBegin(GL_POLYGON);
glVertex3fv(vertices[a]);
glVertex3fv(vertices[b]);
glVertex3fv(vertices[c]);
glVertex3fv(vertices[d]);
glEnd();
}
void cube(void)
{
/* map vertices to faces */
polygon(0,3,2,1);
polygon(2,3,7,6);
polygon(0,4,7,3);
polygon(1,2,6,5);
polygon(4,5,6,7);
polygon(0,1,5,4);
}
void draw_bounding_box()
{
glScalef(bound_size[0],bound_size[1],bound_size[2]);
glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_BACK, GL_LINE);
cube();
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_FILL);
glScalef(1/bound_size[0],1/bound_size[1],1/bound_size[2]);
}
void setShaders()
{
GLhandleARB v = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB),
f = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB),
p;
char *vs = NULL, *fs = NULL;
vs = textFileRead("myshader.vert");
fs = textFileRead("myshader.frag");
const char * vv = vs;
const char * ff = fs;
glShaderSourceARB(v, 1, &vv, NULL);
glShaderSourceARB(f, 1, &ff, NULL);
free(vs);free(fs);
glCompileShaderARB(v);
glCompileShaderARB(f);
p = glCreateProgramObjectARB();
glAttachObjectARB(p,v);
glAttachObjectARB(p,f);
glLinkProgramARB(p);
glUseProgramObjectARB(p);
glUniform1iARB(glGetUniformLocationARB(p, "texture"), 0);
glUniform3fARB(glGetUniformLocationARB(p, "light"), light0_pos[0], light0_pos[1], light0_pos[2]);
glUniform4fARB(glGetUniformLocationARB(p, "l_ambient"), light0_ambient[0], light0_ambient[1], light0_ambient[2], light0_ambient[3] );
glUniform4fARB(glGetUniformLocationARB(p, "l_diffuse"), light0_diffuse[0], light0_diffuse[1], light0_diffuse[2], light0_diffuse[3] );
glUniform4fARB(glGetUniformLocationARB(p, "l_specular"), light0_specular[0], light0_specular[1], light0_specular[2], light0_specular[3] );
glUniform1fARB(glGetUniformLocationARB(p, "l_shininess"), light0_shininess );
}
void display(void)
{
/* display callback, clear frame buffer and z buffer,
rotate cube and draw, swap buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(eye_x, eye_y, eye_z, center_x, center_y, center_z, up_x, up_y, up_z);
//lighting
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_AMBIENT, light0_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular);
glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
setShaders();
glPushMatrix();
glTranslatef(-bound_center[0], -bound_center[1], -bound_center[2]);
if(show){
// glPolygonMode(GL_FRONT, GL_LINE);
// glPolygonMode(GL_BACK, GL_LINE);
// glmDraw(myObj, GLM_FLAT);
glmDraw(myObj,GLM_SMOOTH);
// glmDraw(myObj,GLM_NONE);
// glPolygonMode(GL_FRONT, GL_FILL);
// glPolygonMode(GL_BACK, GL_FILL);
}
glPopMatrix();
draw_bounding_box();
glutSwapBuffers();
glutPostRedisplay();
}
void mouse(int btn, int state, int x, int y)
{
if(state == GLUT_DOWN)
{
start_x = x;
start_y = y;
}
}
void mouseMotion(int x, int y)
{
theta += 2 * static_cast<double> (x - start_x) / width;
if(theta > 2 * PI) theta -= 2 * PI;
if(theta < -2 * PI) theta += 2 * PI;
GLdouble tmp = phi;
phi += 2 * static_cast<double> (y - start_y) / height;
if(phi > 0 && phi < PI)
center_y = eye_y + bound_size[1] * cos(phi);
else
phi = tmp;
center_x = eye_x + bound_size[0] * sin(phi) * cos(theta);
center_z = eye_z + bound_size[2] * sin(phi) * sin(theta);
start_x = x;
start_y = y;
}
void keyboard(unsigned char key,int x,int y)
{
//²¾°Ê
if(key == 'q' || key == 'Q') //quit
{
glmDelete(myObj);
delete point_tri;
exit(0);
}
if(key == 'w' || key == 'W') //move forward
{
eye_x += 0.1 * bound_size[0] * sin(phi) * cos(theta);
eye_y += 0.1 * bound_size[1] * cos(phi);
eye_z += 0.1 * bound_size[2] * sin(phi) * sin(theta);
center_x += 0.1 * bound_size[0] * sin(phi) * cos(theta);
center_y += 0.1 * bound_size[1] * cos(phi);
center_z += 0.1 * bound_size[2] * sin(phi) * sin(theta);
}
if(key == 's' || key == 'S') //move backward
{
eye_x -= 0.1 * bound_size[0] * sin(phi) * cos(theta);
eye_y -= 0.1 * bound_size[1] * cos(phi);
eye_z -= 0.1 * bound_size[2] * sin(phi) * sin(theta);
center_x -= 0.1 * bound_size[0] * sin(phi) * cos(theta);
center_y -= 0.1 * bound_size[1] * cos(phi);
center_z -= 0.1 * bound_size[2] * sin(phi) * sin(theta);
}
if(key == 'a' || key == 'A') //move left
{
eye_x += 0.1 * bound_size[0] * sin(phi) * sin(theta);
eye_z += -0.1 * bound_size[2] * sin(phi) * cos(theta);
center_x += 0.1 * bound_size[0] * sin(phi) * sin(theta);
center_z += -0.1 * bound_size[2] * sin(phi) * cos(theta);
}
if(key == 'd' || key == 'D') //move right
{
eye_x += -0.1 * bound_size[0] * sin(phi) * sin(theta);
eye_z += 0.1 * bound_size[2] * sin(phi) * cos(theta);
center_x += -0.1 * bound_size[0] * sin(phi) * sin(theta);
center_z += 0.1 * bound_size[2] * sin(phi) * cos(theta);
}
if(key == 'r' || key == 'R') // up
{
eye_y += 0.1 * bound_size[1];
center_y += 0.1 * bound_size[1];
}
if(key == 'f' || key == 'F') // down
{
eye_y -= 0.1 * bound_size[1];
center_y -= 0.1 * bound_size[1];
}
if(key == 'z' || key == 'Z')
{
theta = -PI/2, phi = PI / 2;
eye_x = 0.0, eye_y = 0.0, eye_z = 0.0 + 2.0 * bound_size[2],
center_x = eye_x + sin(phi) * cos(theta), center_y = eye_y + cos(phi), center_z = 4*sin(phi) * sin(theta);
}
if(key == 'b' || key == 'B') // down
{
show = !show;
}
if(key=='+')
{
lightTheta += 10.0;
}
else if(key=='-')
{
lightTheta -= 10.0;
}
if(key==27)
{
exit(0);
}
}
void special(int key, int x, int y)
{
if(key == GLUT_KEY_UP) // look up
if(phi - 0.02 > 0) phi -= 0.02;
if(key == GLUT_KEY_DOWN) // look down
if(phi + 0.02 < PI) phi += 0.02;
if(key == GLUT_KEY_LEFT) // turn left
{
theta -= 0.1;
if(theta <= -2 * PI) theta += 2 * PI;
}
if(key == GLUT_KEY_RIGHT) // turn right
{
theta += 0.1;
if(theta >= 2 * PI) theta -= 2 * PI;
}
center_x = eye_x + bound_size[0] * sin(phi) * cos(theta);
center_y = eye_y + bound_size[1] * cos(phi);
center_z = eye_z + bound_size[2] * sin(phi) * sin(theta);
}
void myReshape(int w, int h)
{
width = w;
height = h;
float ratio = w * 1.0 / h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, w, h);
gluPerspective(50.0, ratio, 0.1, 100000.0);
glMatrixMode(GL_MODELVIEW);
}
void bounding_box()
{
//cout << myObj->vertices[3 * 1 + 0] << " " << myObj->vertices[3 * 1 + 1] << " " << myObj->vertices[3 * 1 + 2] << endl;
min_x = max_x = myObj->vertices[3 * 1 + 0];
min_y = max_y = myObj->vertices[3 * 1 + 1];
min_z = max_z = myObj->vertices[3 * 1 + 2];
for(int i = 1 ; i <= myObj->numvertices ; i += 1)
{
if (myObj->vertices[3 * i + 0] < min_x) min_x = myObj->vertices[3 * i + 0];
if (myObj->vertices[3 * i + 0] > max_x) max_x = myObj->vertices[3 * i + 0];
if (myObj->vertices[3 * i + 1] < min_y) min_y = myObj->vertices[3 * i + 1];
if (myObj->vertices[3 * i + 1] > max_y) max_y = myObj->vertices[3 * i + 1];
if (myObj->vertices[3 * i + 2] < min_z) min_z = myObj->vertices[3 * i + 2];
if (myObj->vertices[3 * i + 2] > max_z) max_z = myObj->vertices[3 * i + 2];
}
bound_size[0] = max_x - min_x;
bound_size[1] = max_y - min_y;
bound_size[2] = max_z - min_z;
bound_center[0] = (max_x + min_x)/2.0;
bound_center[1] = (max_y + min_y)/2.0;
bound_center[2] = (max_z + min_z)/2.0;
eye_z = eye_z + 2.0 * bound_size[2];
light0_pos[0] += 1.25 * bound_size[0];
light0_pos[1] += 1.25 * bound_size[1];
light0_pos[2] += 1.25 * bound_size[2];
}
void recount_normal()
{
point_tri = new vector<int>[myObj->numvertices + 1];
for(int i = 0 ; i < myObj->numtriangles ; i += 1)
{
for(int j = 0 ; j < 3 ; j += 1)
{
bool add = true;
for(int k = 0 ; k < point_tri[myObj->triangles[i].vindices[j]].size() ; k += 1)
{
GLfloat *temp = &myObj->facetnorms[3 * point_tri[myObj->triangles[i].vindices[j]][k]];
if(*temp == myObj->facetnorms[3 * (i+1) + 0] && *(temp + 1) == myObj->facetnorms[3 * (i+1) + 1] && *(temp + 2) == myObj->facetnorms[3 * (i+1) + 2])
{
add = false;
break;
}
}
if(add)
point_tri[myObj->triangles[i].vindices[j]].push_back(i + 1);
}
}
for(int i = 1 ; i <= myObj->numvertices ; i += 1)
{
sort(point_tri[i].begin(),point_tri[i].begin() + point_tri[i].size());
}
myObj->numnormals = myObj->numvertices;
myObj->normals = new GLfloat[3 * (myObj->numnormals + 1)];
for(int i = 1 ; i <= myObj->numnormals ; i += 1)
{
GLfloat temp[3] = {0.0 , 0.0 , 0.0};
for(int j = 0 ; j < point_tri[i].size() ; j += 1)
{
temp[0] += myObj->facetnorms[3 * point_tri[i][j] + 0];
temp[1] += myObj->facetnorms[3 * point_tri[i][j] + 1];
temp[2] += myObj->facetnorms[3 * point_tri[i][j] + 2];
}
GLfloat normal_length = sqrt(pow(temp[0],2) + pow(temp[1],2) + pow(temp[2],2));
temp[0] /= normal_length;
temp[1] /= normal_length;
temp[2] /= normal_length;
myObj->normals[3 * i + 0] = temp[0];
myObj->normals[3 * i + 1] = temp[1];
myObj->normals[3 * i + 2] = temp[2];
}
myObj_inner->numnormals = myObj_inner->numvertices;
myObj_inner->normals = new GLfloat[3 * (myObj_inner->numnormals + 1)];
}
void init()
{
bounding_box();
recount_normal();
}
int main(int argc, char **argv)
{
myObj = glmReadOBJ("test_model/cube.obj");
myObj_inner = glmReadOBJ("test_model/cube.obj");
glmFacetNormals(myObj);
init();
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(1000,1000);
glutCreateWindow("Zometool");
glutDisplayFunc(display);
glutReshapeFunc(myReshape);
glutMouseFunc(mouse);
glutMotionFunc(mouseMotion);
glutKeyboardFunc(keyboard);
glutSpecialFunc(special);
glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
glewInit();
glutMainLoop();
return 0;
}
My vertex shader:
varying vec3 N;
varying vec3 v;
void main(void)
{
v = vec3(gl_ModelViewMatrix * gl_Vertex);
N = normalize(gl_ModelViewMatrix * gl_Normal);
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
My fragment shader:
uniform vec4 l_ambient;
uniform vec4 l_diffuse;
uniform vec4 l_specular;
uniform vec3 light;
uniform float l_shininess;
varying vec3 N;
varying vec3 v;
void main (void)
{
vec3 lightWeighting;
vec3 lightDirection = normalize(light.xyz - v);
vec3 normal = N;
float specularLightWeighting = 0.0;
vec3 eyeDirection = normalize(-v);
vec3 reflectionDirection = normalize(-reflect(L,N));
specularLightWeighting = pow(max(dot(reflectionDirection, eyeDirection), 0.0), l_shininess);
float diffuseLightWeighting = max(dot(normal, lightDirection), 0.0);
lightWeighting = l_ambient
+ l_specular * specularLightWeighting
+ l_diffuse * diffuseLightWeighting;
gl_FragColor = gl_FrontLightModelProduct.sceneColor + lightWeighting;
}
My cube.obj:
# Blender v2.62 (sub 0) OBJ File: ''
# www.blender.org
mtllib cube.mtl
o Cube
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
v 1.000000 1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
usemtl Material
s off
f 1 2 3 4
f 5 8 7 6
f 1 5 6 2
f 2 6 7 3
f 3 7 8 4
f 5 1 4 8
My cube.mtl:
# Blender MTL File: ''
# Material Count: 1
newmtl Material
Ns 96.078431
Ka 0.000000 0.000000 0.000000
Kd 0.640000 0.640000 0.640000
Ks 0.500000 0.500000 0.500000
Ni 1.000000
d 1.000000
illum 2
flat image:
smooth image:
I'm trying to code my custom implementation of Opengl glRotatef(angle,x,y,z) function.
I wrote the rotation matrix, but when I try to use it, the effect is not the same as the original function. Here is my code;
void mglRotate(float angle, float x, float y, float z)
{
float angle_rad = angle * (PI/180.0f);
float c = cos(angle_rad);
float s = sin(angle_rad);
float t = 1 - c;
float m[16] = {
c+x*x*t,y*x*t+z*s,z*x*t-y*s,0,
x*y*t-z*s,c+y*y*t,z*y*t+x*s,0,
x*z*t+y*s,y*z*t-x*s,z*z*t+c,0,
0,0,0,1
};
glMultMatrixf(m);
}
Where is my mistake?
There is a library glm, that does exactly the same thing as old openGL functions. You can compare your implementation with implementation in glm and figure it out :)
template <typename T>
GLM_FUNC_QUALIFIER detail::tmat4x4<T> rotate
(
detail::tmat4x4<T> const & m,
T const & angle,
detail::tvec3<T> const & v
)
{
T a = radians(angle);
T c = cos(a);
T s = sin(a);
detail::tvec3<T> axis = normalize(v);
detail::tvec3<T> temp = (T(1) - c) * axis;
detail::tmat4x4<T> Rotate(detail::tmat4x4<T>::null);
Rotate[0][0] = c + temp[0] * axis[0];
Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2];
Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1];
Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2];
Rotate[1][1] = c + temp[1] * axis[1];
Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0];
Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1];
Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0];
Rotate[2][2] = c + temp[2] * axis[2];
detail::tmat4x4<T> Result(detail::tmat4x4<T>::null);
Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2];
Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2];
Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2];
Result[3] = m[3];
return Result;
}
The one thing that seems wrong to me in your code is that you don't normalize the axis.
I need to obtain some data from an openGL rotation matrix. I need to obtain the equivalent euler angles (already did it), the equivalent quaternion (did it, but just copying it from the Internet) and the equivalent axis-angle.
I dont know if a rotation matrix can be expresed as a single rotation of a certain angle around an certain vector. Are these equivalent? If they are, how can I obtain one from the other?
Also, i would like to understand better the meaning of a quaternion, and the insides of a rotation matrix. Where should i go to learn about this?
Yes any rotation matrix/unit quaternion is equivalent to a rotation around a single axis. If we call this axis n and the angle theta then the quaternion for this rotation is:
[n * sin(theta / 2) cos(theta / 2)]
To reconstruct this use acos on the w element of the quaternion to get theta / 2. After you have theta you can divide x,y and z component with sin(theta / 2) to reconstruct the axis.
Here's a function which converts a 3x3 matrix into an axis, angle (using a quatention, so perhaps theres a more efficient way which bypasses that step).
void axis_angle_from_mat3(float r_axis[3], float *r_angle, float mat[3][3])
{
float q[4];
/* -------------------------------------------------------------------- */
/* matrix to quaternion */
double tr, s;
float tmat[3][3];
/* work on a copy */
memcpy(tmat, mat, sizeof(tmat));
/* normalize the matrix */
int i;
for (i = 0; i < 3; i++) {
float d = (tmat[i][0] * tmat[i][0] + tmat[i][1] * tmat[i][1] + tmat[i][2] * tmat[i][2]);
if (d > 1.0e-35f) {
d = sqrtf(d);
tmat[i][0] /= d;
tmat[i][1] /= d;
tmat[i][2] /= d;
}
else {
tmat[i][0] = 0.0f;
tmat[i][1] = 0.0f;
tmat[i][2] = 0.0f;
d = 0.0f;
}
}
tr = 0.25 * (double)(1.0f + tmat[0][0] + tmat[1][1] + tmat[2][2]);
if (tr > (double)1e-4f) {
s = sqrt(tr);
q[0] = (float)s;
s = 1.0 / (4.0 * s);
q[1] = (float)((double)(tmat[1][2] - tmat[2][1]) * s);
q[2] = (float)((double)(tmat[2][0] - tmat[0][2]) * s);
q[3] = (float)((double)(tmat[0][1] - tmat[1][0]) * s);
}
else {
if (tmat[0][0] > tmat[1][1] && tmat[0][0] > tmat[2][2]) {
s = 2.0f * sqrtf(1.0f + tmat[0][0] - tmat[1][1] - tmat[2][2]);
q[1] = (float)(0.25 * s);
s = 1.0 / s;
q[0] = (float)((double)(tmat[1][2] - tmat[2][1]) * s);
q[2] = (float)((double)(tmat[1][0] + tmat[0][1]) * s);
q[3] = (float)((double)(tmat[2][0] + tmat[0][2]) * s);
}
else if (tmat[1][1] > tmat[2][2]) {
s = 2.0f * sqrtf(1.0f + tmat[1][1] - tmat[0][0] - tmat[2][2]);
q[2] = (float)(0.25 * s);
s = 1.0 / s;
q[0] = (float)((double)(tmat[2][0] - tmat[0][2]) * s);
q[1] = (float)((double)(tmat[1][0] + tmat[0][1]) * s);
q[3] = (float)((double)(tmat[2][1] + tmat[1][2]) * s);
}
else {
s = 2.0f * sqrtf(1.0f + tmat[2][2] - tmat[0][0] - tmat[1][1]);
q[3] = (float)(0.25 * s);
s = 1.0 / s;
q[0] = (float)((double)(tmat[0][1] - tmat[1][0]) * s);
q[1] = (float)((double)(tmat[2][0] + tmat[0][2]) * s);
q[2] = (float)((double)(tmat[2][1] + tmat[1][2]) * s);
}
}
/* normalize the quat */
float len;
len = sqrtf(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);
if (len != 0.0f) {
q[0] /= len;
q[1] /= len;
q[2] /= len;
q[3] /= len;
}
else {
q[1] = 1.0f;
q[0] = q[2] = q[3] = 0.0f;
}
/* -------------------------------------------------------------------- */
/* quaternion to axis angle */
float ha, si;
ha = acosf(q[0]);
si = sinf(ha);
*r_angle = ha * 2;
if (fabsf(si) < FLT_EPSILON)
si = 1.0f;
r_axis[0] = q[1] / si;
r_axis[1] = q[2] / si;
r_axis[2] = q[3] / si;
}