Related
When I use glRotatef to change the diretion of the objects(table and cups) which are created by my own using plenty of triangles(I know it seems a little bit stupid QAQ), the lighting effects change weirdly as if the light position has also changed. However the lighting effects on teapot which is directly invoked by using glutSolidTeapot acts normally. I think that invoking glRotatef will not change the light position, so I cannot figure out where comes the problems.
The code is shown below:
#include<GLFW\glfw3.h>
#include<GL/glut.h>
#include<math.h>
#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS
//系统屏幕大小初始化
GLint SCREEN_WIDTH = 0;
GLint SCREEN_HEIGHT = 0;
//窗口大小初始化
GLint window_width = 1000;
GLint window_height = 800;
//中心坐标计算
#define MIDWIDTH window_width/2
#define MIDHEIGHT window_height/2
//设置模型旋转角度
GLfloat xAngle = 0.0f;
GLfloat yAngle = 0.0f;
//设置模型初始距离
GLfloat distancex;
GLfloat distancey;
//受支持的点大小范围
GLfloat sizes[2];
//受支持的点大小增量
GLfloat step;
GLfloat mat_ambient_skew[] = { 0,0,0,0 };
GLfloat mat_diffuse_skew[] = { 0,0,0,0 };
GLfloat mat_specular_skew[] = { 0,0,0,0 };
GLfloat low_shininess[] = { 3.0 };
//线框0 or 实体1
GLint l_or_r = 1;
GLboolean mouseLeftDown = false; //鼠标左键按下状态,默认是未按下
//缩放倍数
GLfloat times = 0.8f;
//定义光源的颜色和位置
GLfloat ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f }; //环境光
GLfloat position[] = { 10.0f,10.0f,10.0f,1.0f }; //光源位置
GLfloat matEmission[] = { 1.0f, 1.0f, 1.0f, 1.0 }; //反射光颜色
GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; //漫射光
GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; //镜面反射
GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f }; // 环境
GLfloat mat_diffuse[] = { 0.5f, 0.5f, 0.5f, 1.0f }; // 散射
GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // 镜面反射
GLfloat high_shininess[] = { 18.0f }; // 镜面反射指数为
GLfloat no_mat[] = { 0.0f, 0.0f, 0.0f, 1.0f }; // 无材质颜色
void init() {
GLfloat local_view[] = { 0.0 };
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
//glLightfv(GL_LIGHT0, GL_SPECULAR, mat_specular);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, local_view);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
// 启用光照
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, matEmission);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, high_shininess);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, no_mat);
}
void translate()
{
//glColor3f(0.0f, 1.0f, 1.0f);
glScalef(times, times, times);
glTranslatef(distancex, distancey, 0);
glRotatef(xAngle, 1.0f, 0.0f, 0.0f);
glRotatef(yAngle, 0.0f, 1.0f, 0.0f);
}
void drawCube(double l, double w, double h, double x, double y, double z) {
glPushMatrix();
translate();
glTranslated(x, y, z);
glScaled(l, w, h);//沿x y z轴缩放 先缩放 再平移 一开始中心在原点
glColor3f(0.7, 0.35, 0.01);
if (l_or_r == 0) glutWireCube(1);
else if (l_or_r == 1) glutSolidCube(1);
glPopMatrix();
}
GLvoid DrawCircleArea(float height, float top, float bot, int num_segments, int cup) {
if (l_or_r == 0) {
glPolygonMode(GL_BACK, GL_LINE);//线框
glPolygonMode(GL_FRONT, GL_LINE);//线框
}
else if (l_or_r == 1) {
glPolygonMode(GL_BACK, GL_FILL);//实体
glPolygonMode(GL_FRONT, GL_FILL);//实体
}
GLfloat vertex[4];
const GLfloat delta_angle = 2.0 * 3.1415926 / num_segments;
int h = height;
float cx = 0;
float cy = 0;
float cz = 0;
// 画底面
glBegin(GL_TRIANGLES);
for (int i = 0; i <= num_segments; i++) {
int j = i + 1;
vertex[0] = cx;
vertex[1] = cy;
vertex[2] = cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
vertex[0] = cos(delta_angle * i) * bot + cx;
vertex[1] = cy;
vertex[2] = sin(delta_angle * i) * bot + cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
vertex[0] = cos(delta_angle * j) * bot + cx;
vertex[1] = cy;
vertex[2] = sin(delta_angle * j) * bot + cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
}
glEnd();
if (cup != 1) { // 画顶面
glBegin(GL_TRIANGLE_FAN);
for (int i = 0; i <= num_segments; i++) {
int j = i + 1;
vertex[0] = cx;
vertex[1] = cy + h;
vertex[2] = cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
vertex[0] = cos(delta_angle * i) * top + cx;
vertex[1] = cy + h;
vertex[2] = sin(delta_angle * i) * top + cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
vertex[0] = cos(delta_angle * j) * top + cx;
vertex[1] = cy + h;
vertex[2] = sin(delta_angle * j) * top + cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
}
glEnd();
}
for (int i = 0; i <= num_segments; i++) { // 画侧面
int j = i + 1;
glBegin(GL_TRIANGLES);
vertex[0] = cos(delta_angle * i) * bot + cx;
vertex[1] = cy;
vertex[2] = sin(delta_angle * i) * bot + cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
vertex[0] = cos(delta_angle * j) * bot + cx;
vertex[1] = cy;
vertex[2] = sin(delta_angle * j) * bot + cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
vertex[0] = cos(delta_angle * j) * top + cx;
vertex[1] = cy + h;
vertex[2] = sin(delta_angle * j) * top + cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
vertex[0] = cos(delta_angle * i) * top + cx;
vertex[1] = cy + h;
vertex[2] = sin(delta_angle * i) * top + cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
vertex[0] = cos(delta_angle * j) * top + cx;
vertex[1] = cy + h;
vertex[2] = sin(delta_angle * j) * top + cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
vertex[0] = cos(delta_angle * i) * bot + cx;
vertex[1] = cy;
vertex[2] = sin(delta_angle * i) * bot + cz;
vertex[3] = 1.0;
glVertex4fv(vertex);
glEnd();
}
}
void MydrawCylinder(GLdouble l, GLdouble w, GLdouble h,
GLdouble x, GLdouble y, GLdouble z,
GLdouble base, GLdouble top, GLdouble height,
GLint slices, GLint stacks, GLint cup,
GLfloat r, GLfloat g, GLfloat b) {
if (l_or_r == 0) {
glPolygonMode(GL_BACK, GL_LINE);//线框
glPolygonMode(GL_FRONT, GL_LINE);//线框
}
else if (l_or_r == 1) {
glPolygonMode(GL_BACK, GL_FILL);//实体
glPolygonMode(GL_FRONT, GL_FILL);//实体
}
glPushMatrix();
translate();
glTranslated(x, y, z);
glScaled(l, w, h);//沿x y z轴缩放 先缩放 再平移 一开始中心在原点
glColor3f(r, g, b); // 桌子颜色
DrawCircleArea(height, top, base, slices, cup);
glPopMatrix();
}
void drawTeapot() {
//FILE* filePtr = fopen("./1.bmp", "rb");
glPushMatrix();
// 平滑处理
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH, GL_NICEST);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH, GL_NICEST);
glEnable(GL_POLYGON_SMOOTH);
glHint(GL_POLYGON_SMOOTH, GL_NICEST);
translate();
glColor3f(0., 0.35, 0.01); // 茶壶颜色
// 线框 or 实体
if (l_or_r == 0) glutWireTeapot(3.0f);
else if (l_or_r == 1) glutSolidTeapot(3.0f);
glPopMatrix();
}
void display() {
init();
glClearColor(0.7f, 0.9f, 1.0f, 0.3f); // 背景颜色
glClearStencil(1);
glEnable(GL_STENCIL_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //清空颜色缓冲和深度缓冲
//设置观察点的位置,这里设置为从 - z轴观察
glLoadIdentity();
// GLdouble base, GLdouble top, GLdouble height, GLint slices, GLint stacks
// 桌子 table
MydrawCylinder(1, 1, 1, 0, -4.2, 0, 15, 15, 2, 100, 100, 0, 0.66, 0.47, 0.294);
MydrawCylinder(1, 1, 1, 0, -(4.2 + 15), 0, 0.75, 0.75, 15, 12, 100, 0, 0.66, 0.47, 0.294);
MydrawCylinder(1, 1, 1, 0, -(4.2 + 15 + 1), 0, 5, 5, 1, 100, 100, 0, 0.66, 0.47, 0.294);
// 四个杯子 four cups
int far = 5; // 杯子距离中心距离
MydrawCylinder(1, 1, 1, far, -2.2, -far, 0.5, 0.75, 2, 12, 100, 1, 0.478, 0.827, 0.475);
MydrawCylinder(1, 1, 1, -far, -2.2, far, 0.5, 0.75, 2, 12, 100, 1, 0.478, 0.827, 0.475);
MydrawCylinder(1, 1, 1, far, -2.2, far, 0.5, 0.75, 2, 12, 100, 1, 0.478, 0.827, 0.475);
MydrawCylinder(1, 1, 1, -far, -2.2, -far, 0.5, 0.75, 2, 12, 100, 1, 0.478, 0.827, 0.475);
// teapot
drawTeapot();
glutSwapBuffers();
}
void changeSize(GLint width, GLint height) { // 窗口改变尺寸
GLfloat ratio;
GLfloat coordinatesize = 16.0f;
if ((width == 0) || (height == 0))
return;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
ratio = (GLfloat)width / (GLfloat)height;
if (width < height)
glOrtho(-coordinatesize, coordinatesize, -coordinatesize / ratio, coordinatesize / ratio, -coordinatesize, coordinatesize);
else
glOrtho(-coordinatesize * ratio, coordinatesize * ratio, -coordinatesize, coordinatesize, -coordinatesize, coordinatesize);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void menuFunc(int key) {
switch (key) {
case 1:
l_or_r = 0;
break;
case 2:
l_or_r = 1;
break;
case 3:
position[0] -= 10.0;
break;
case 4:
position[0] += 10.0;
break;
case 5:
position[2] += 10.0;
break;
case 6:
position[2] -= 10.0;
break;
}
glutPostRedisplay();
}
void setMenu() { // 设置鼠标右键菜单
int mainMenu;
int slrMenu;
int lightPositionMenu;
slrMenu = glutCreateMenu(menuFunc);
glutAddMenuEntry("线框", 1);
glutAddMenuEntry("实体", 2);
lightPositionMenu = glutCreateMenu(menuFunc);
glutAddMenuEntry("向下", 3);
glutAddMenuEntry("向上", 4);
glutAddMenuEntry("向外", 5);
glutAddMenuEntry("向内", 6);
mainMenu = glutCreateMenu(menuFunc);
glutAddSubMenu("线框 or 实体", slrMenu);
glutAddSubMenu("光照位置", lightPositionMenu);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutPostRedisplay();
}
void keyFunc(int key, int x, int y) //键盘控制
{
//旋转
if (key == GLUT_KEY_UP) xAngle -= 5.0f; //绕x轴顺时针旋转
else if (key == GLUT_KEY_DOWN) xAngle += 5.0f; //绕x轴逆时针旋转
else if (key == GLUT_KEY_LEFT) yAngle -= 5.0f; //绕y轴顺时针旋转
else if (key == GLUT_KEY_RIGHT) yAngle += 5.0f; //绕y轴逆时针旋转
//缩放
if (key == GLUT_KEY_F1) times += 0.2f;
else if (key == GLUT_KEY_F2) times -= 0.2f;
glutPostRedisplay();
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
SCREEN_WIDTH = glutGet(GLUT_SCREEN_WIDTH);
SCREEN_HEIGHT = glutGet(GLUT_SCREEN_HEIGHT);
glutCreateWindow(" ");
glutReshapeWindow(window_width, window_height);
setMenu();
glutReshapeFunc(changeSize);
glutDisplayFunc(display);
glutSpecialFunc(keyFunc);
glutMainLoop();
return 0;
}
The shadow of teapot does not match that of the table, and if rotate the table, the reflect light of teapot doesn't change it's postion while the reflect light of table changing weirdly.
image1
image2
I'm trying to make a program where I'm able to zoom in & out on the figures I've drawn, but is not doing it; it's switching the orientation of the figures and if I keep scrolling, it just disappears. The function that are suppose to be executed for this to work are the MouseFunc() along with the renderScene(). Any explanation for the problem or help is welcomed.
#include"glut.h"
#include<cmath>
#include<iostream>
using namespace std;
float xr = 0, yr = 0; //to control the object's movement from left to right
// XZ position of the camera
float x = 0.0f, z = 5.0f; //Module 4
float angleX = 0.0f; //Module 4
//Shift + ArrowKey rotation
float transX = 0.0f;
float transY = 0.0f;
float rotY = 0.0f;
//end
//Mouse Commands
//float ZoomFactor = 0.5;
GLfloat theta3 = 0;
GLfloat phi = 0;
GLfloat rho = 5;
GLfloat camX = 0;
GLfloat camY = 0;
GLfloat camZ = 0;
GLfloat upX = 0;
GLfloat upY = 0;
GLfloat upZ = 0;
//end
GLfloat angle = 0.0f;
int refreshmill = 1;
void timer(int value) { //to control the rotation of the object
glutTimerFunc(refreshmill, timer, 0);
}
void myDisplay(void) {
//Circle One
float theta;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1, 0, 0);
glPushMatrix();
glBegin(GL_POLYGON);
for (int x = 0; x < 360; x++) {
theta = x * 3.142 / 180;
glVertex2f(150 * cos(theta) + xr, 150 * sin(theta) + yr);
}
glEnd();
glPopMatrix();
//Circle Two
float theta2;
glPushMatrix();
glTranslatef(0.5f, 0.0f, 0.0f); // rotation
glRotatef(angle, 0.0f, 0.0f, -0.5f); // rotation
glBegin(GL_POLYGON);
glColor3f(0, 0, 1);
for (int x = 0; x < 360; x++) {
theta2 = x * 3.142 / 180;
glVertex2f(150 + 15 * cos(theta2) + xr, 15 * sin(theta2) + yr);
}
angle += 0.2; // rotation
glEnd();
glPopMatrix();
//Draw Star
glColor3ub(119, 193, 15);
glPushMatrix();
glBegin(GL_POLYGON);
glVertex2d(15 + xr, 60 + yr);
glVertex2d(75 + xr, 75 + yr); //right peak
glVertex2d(15 + xr, 90 + yr);
glVertex2d(0 + xr, 150 + yr); //Up-peak Changed
glVertex2d(-15 + xr, 90 + yr);
glVertex2d(-75 + xr, 75 + yr);
glVertex2d(-15 + xr, 60 + yr);
glVertex2d(0 + xr, 0 + yr);
glEnd();
glPopMatrix();
}
//Close code
void handleKeypress(unsigned char key, int x, int y){
switch (key){
case 27: //when the escape key is pressed the program will exit.
exit(0);
}
}
//Movement of drawing
void keyboard(int key, int x, int y) {
float fraction = 0.1f;
bool shift = false;
int mod = glutGetModifiers();
if (mod == GLUT_ACTIVE_SHIFT) {
shift = true;
}
if (!shift) {
switch (key) {
case GLUT_KEY_RIGHT: xr++; break;
case GLUT_KEY_LEFT: xr--; break;
case GLUT_KEY_UP: angleX -= 1.0f; break; //Module 4
case GLUT_KEY_DOWN: angleX += 1.0f; break; //Module 4
}
}
else {
switch (key) {
case GLUT_KEY_LEFT:// Rotación del dibujo hacia la izquierda en el eje de Y
rotY -= 1.0f;
break;
case GLUT_KEY_RIGHT:// Rotación del dibujo hacia la derecha en el eje de Y
rotY += 1.0f;
break;
}
}
}
//Mouse Function
void MouseFunc(int button, int state, int x, int y){
if (button > 4){
rho = rho + 3.0;
}
else (button < 3);{
rho = rho - 3.0;
}
}
void renderScene(void) {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0, 1.0, 0.0);
glRotatef(rotY, 0.0, 1.0, 0.0); //Rotation with Shift + ArrowKey
GLfloat camX = rho * cos(theta3*3.1415926f / 180)*sin(phi*3.1415926f / 180);
GLfloat camY = rho * sin(theta3*3.1415926f / 180);
GLfloat camZ = rho * cos(theta3*3.1415926f / 180)*cos(phi*3.1415926f / 180);
// Reduce theta slightly to obtain another point on the same longitude line on the sphere.
GLfloat dt = 1;
GLfloat eyeXtemp = -rho * cos((theta3 - dt)*3.1415926f / 180)*sin(phi*3.1415926f / 180);
GLfloat eyeYtemp = -rho * sin((theta3 - dt)*3.1415926f / 180);
GLfloat eyeZtemp = -rho * cos((theta3 - dt)*3.1415926f / 180)*cos(phi*3.1415926f / 180);
// Connect these two points to obtain the camera's up vector.
GLfloat upX = eyeXtemp - camX;
GLfloat upY = eyeYtemp - camY;
GLfloat upZ = eyeZtemp - camZ;
// Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Set the camera
gluLookAt(camX, camY, camZ, 0, 0, 0, upX, upY, upZ);
gluLookAt(x, 0.0f, z, x, 0.0f, z - 1.0f, 0.0f, 1.0f, 0.0f); //Module 4
glRotatef(angleX, 1, 0, 0); //Module 4
myDisplay();
glFlush();
glutPostRedisplay();
glutSwapBuffers();
}
void init() {
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(0.0f, 0.1f, 0.1f, 0.0f);
glOrtho(-250, 250, -250, 250, -250, 250); //IMPORTANT- Define from negative to positive
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
// init GLUT and create window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(0, 0);
glutCreateWindow("Homework: Circle");
// register callbacks
glutDisplayFunc(renderScene);
glutTimerFunc(0,timer,0);
glutKeyboardFunc(handleKeypress);
glutSpecialFunc(keyboard);
glutMouseFunc(MouseFunc);
// OpenGL init
init();
// enter GLUT event processing cycle
glutMainLoop();
}
Is wired to set a perspective and an orthographic projection. Delete the perspective projection gluPerspective:
void init() {
glClearColor(0, 0, 0, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluPerspective(0.0f, 0.1f, 0.1f, 0.0f); <---- delete
glOrtho(-250, 250, -250, 250, -250, 250);
glMatrixMode(GL_MODELVIEW);
}
If you want to zoom, the the orthographic projection has to be changed (glOrtho). The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport.
Implement a mouse wheel event, which changes the zoom, in a restricted range:
e.g.
GLdouble zoom = 0.0f;
void MouseFunc(int button, int state, int x, int y){
GLdouble min_z = -100.0;
GLdouble max_z = 100.0;
if (button == 4 && zoom < max_z) {
zoom += 3.0;
}
else if (button == 3 && zoom > min_z) {
zoom -= 3.0;
}
}
Modify the orthographic projection, dependent on the zoom in the display loop renderScene:
void renderScene(void) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLdouble ortho = 250 + zoom;
glOrtho(-ortho, ortho, -ortho, ortho, -250, 250);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// [...]
}
I want to make the codes that draw trajectory as the object's moving when I clicked any position on the screen.
I set the initial center point as a starting point. And I want to set the other point with mouse button clicked (destination point) as variables but I can't figure out how to do this.
float v1[3] = { -35.0f, 22.5f, 0.0f };
float v2[3] = { -35.0f, -22.5f, 0.0f };
float v3[3] = { 0.0f, 42.5f, 0.0f };
float v4[3] = { 0.0f, -42.5f, 0.0f };
float v5[3] = { 35.0f, 22.5f, 0.0f };
float v6[3] = { 35.0f, -22.5f, 0.0f };
This is the initial position of the object. (6-point star with 2 triangles)
float px, py;
float center_s[3] = { 0.0f, 0.0f, 0.0f };
float center_d[3] = { px, py, 0.0f };
center_s is the starting point and center_d is the destination point with variable px, py.
void lines(void) {
glColor3f(1.0, 0.0, 0.0);
glPointSize(5);
glBegin(GL_POINTS);
glVertex3fv(center_s);
glLineWidth(1);
glBegin(GL_LINES);
glVertex3fv(center_s);
glVertex3fv(center_d);
}
This function draws trajectory with red lines from center_s to center_d. Also it draws a center point.
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
x = mx;
y = glutGet(GLUT_WINDOW_HEIGHT) - my;
px = x + 35.0;
py = y + 42.5;
glutIdleFunc(lines);
}
glutPostRedisplay();
break;
Here is the problem. When the left mouse button is pressed, the star has to move to the clicked position and calculates the center point of the position and draw the line. But if I run these codes, the movement trajectory is not drawn.
Please let me know what the problem is. Plus, the star must move at a constant speed to the clicked location. (Not teleportation)
Following is the full codes:
#include <stdlib.h>
#include <GL/glut.h>
float v1[3] = { -35.0f, 22.5f, 0.0f };
float v2[3] = { -35.0f, -22.5f, 0.0f };
float v3[3] = { 0.0f, 42.5f, 0.0f };
float v4[3] = { 0.0f, -42.5f, 0.0f };
float v5[3] = { 35.0f, 22.5f, 0.0f };
float v6[3] = { 35.0f, -22.5f, 0.0f };
float px, py;
float center_s[3] = { 0.0f, 0.0f, 0.0f };
float center_d[3] = { px, py, 0.0f };
static GLfloat spin = 0.0;
float x = 400.0f, y = 442.5f;
float color1[3] = { 1.0f, 1.0f, 1.0f };
float color2[3] = { 1.0f, 1.0f, 1.0f };
int mode = 1;
int rotate = 1;
void init(void);
void triangle_1(void);
void triangle_2(void);
void lines(void);
void display(void);
void spinDisplay_1(void);
void spinDisplay_2(void);
void reshape(int, int);
void changeColor(int);
void mouse(int, int, int, int);
////////////////////////////////////////////////////////////////////
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(300, 300);
glutCreateWindow("6-Point Star");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutMainLoop();
return 0;
}
////////////////////////////////////////////////////////////////////
void init(void) {
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
}
void triangle_1(void) {
glColor3fv(color1);
glBegin(GL_TRIANGLE_FAN);
glVertex3fv(v1);
glVertex3fv(v4);
glVertex3fv(v5);
glEnd();
}
void triangle_2(void) {
glColor3fv(color2);
glBegin(GL_TRIANGLE_FAN);
glVertex3fv(v2);
glVertex3fv(v3);
glVertex3fv(v6);
glEnd();
}
void lines(void) {
glColor3f(1.0, 0.0, 0.0);
glPointSize(5);
glBegin(GL_POINTS);
glVertex3fv(center_s);
glLineWidth(1);
glBegin(GL_LINES);
glVertex3fv(center_s);
glVertex3fv(center_d);
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glTranslatef(x, y, 0.0f);
glRotatef(spin, 0.0, 0.0, 1.0);
triangle_1();
triangle_2();
glPopMatrix();
glutSwapBuffers();
}
void spinDisplay_1(void) {
spin = spin + 2.0;
if (spin > 360.0) {
spin = spin - 360.0;
}
glutPostRedisplay();
}
void spinDisplay_2(void) {
spin = spin - 2.0;
if (spin < 360.0) {
spin = spin + 360.0;
}
glutPostRedisplay();
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 500.0, 0.0, 500.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void changeColor(int n) {
if (n == 1) {
color1[0] = 0.0f, color1[1] = 0.0f, color1[2] = 1.0f;
color2[0] = 0.0f, color2[1] = 1.0f, color2[2] = 0.0f;
}
else if (n == 2) {
color1[0] = 1.0f, color1[1] = 1.0f, color1[2] = 1.0f;
color2[0] = 1.0f, color2[1] = 1.0f, color2[2] = 1.0f;
}
}
void mouse(int button, int state, int mx, int my) {
switch (button) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
x = mx;
y = glutGet(GLUT_WINDOW_HEIGHT) - my;
px = x + 35.0;
py = y + 42.5;
glutIdleFunc(lines);
}
glutPostRedisplay();
break;
case GLUT_MIDDLE_BUTTON:
if (state == GLUT_DOWN) {
if (mode == 1) {
changeColor(mode);
mode = 2;
}
else if (mode == 2) {
changeColor(mode);
mode = 1;
}
}
glutPostRedisplay();
break;
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN)
if (rotate == 1) {
glutIdleFunc(spinDisplay_1);
rotate = 2;
}
else if (rotate == 2) {
glutIdleFunc(spinDisplay_2);
rotate = 1;
}
break;
default:
break;
}
}
You're missing a few glEnd() and unless you have other plans for center_s and center_d then you don't need them. As x and y is center_s, while px and py is center_d.
So first of all in mouse() just assign the mouse position to px and py instead of x and y.
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
px = mx;
py = glutGet(GLUT_WINDOW_HEIGHT) - my;
}
Now next you need a way to obtain the delta time. Delta time is the time passed since the last frame. For ease I added the following code to the top of display().
int timeNow = glutGet(GLUT_ELAPSED_TIME);
float delta = (float)(timeNow - timeLastFrame) / 1000.0f;
timeLastFrame = timeNow;
Remember to declare int timeLastFrame = 0; among your global variables.
Now (still in display()) we can calculate the direction of the travel path. We do this by calculating the difference between the two points. Then calculate the length and normalize the difference.
float dx = px - x;
float dy = py - y;
float length = sqrt(dx * dx + dy * dy);
dx /= length;
dy /= length;
Now you just put it all together.
if (length > 1.0f) {
x += dx * speed * delta;
y += dy * speed * delta;
}
So while length > 1.0 then we move towards px and py at the speed of float speed = 100.0f; (declare this among your global variables as well).
Just to reemphasize. Yes, do delete glutIdleFunc(lines) from mouse(). Then we add it in display() instead. The full extend of display() should look like this now:
void display(void) {
int timeNow = glutGet(GLUT_ELAPSED_TIME);
float delta = (float)(timeNow - timeLastFrame) / 1000.0f;
timeLastFrame = timeNow;
float dx = px - x;
float dy = py - y;
float length = sqrt(dx * dx + dy * dy);
dx /= length;
dy /= length;
if (length > 1.0f) {
x += dx * speed * delta;
y += dy * speed * delta;
}
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glTranslatef(x, y, 0.0f);
glRotatef(spin, 0.0, 0.0, 1.0);
triangle_1();
triangle_2();
glPopMatrix();
lines();
glutSwapBuffers();
glutPostRedisplay();
}
Remember glutPostRedisplay(). If not then it won't redraw and thus not animate. Also remember to #include <math.h> for sqrt().
Everything before glClear() could be moved to your glutIdleFunc() callback.
Since there was no need for center_s and center_d then lines() can be boiled down to:
void lines(void) {
glColor3f(1.0, 0.0, 0.0);
glPointSize(5);
glBegin(GL_POINTS);
glVertex2f(px, py);
glEnd();
glLineWidth(1);
glBegin(GL_LINES);
glVertex2f(x, y);
glVertex2f(px, py);
glEnd();
}
The result should look something like this:
For future reference. If you don't want to do the linear algebra by hand. Then you can use something like GLM.
I'm trying to do selection in opengl but it is not working.
I draw objects I receive from a .obj file (v, vn, f, o and such indices). Each object consists from "groups" and each group is a group of GL_POLYGON.
Here is the draw function:
void draw(GLenum mode) {
glBegin(GL_LINES);
glColor3f(1, 0, 0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(100.0, 0.0, 0.0);
glColor3f(0, 0, 1);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 100.0, 0.0);
glColor3f(0, 1, 0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 100.0);
glEnd();
glColor4f(1.0, 1.0, 1.0, 1.0);
if (changeFOV) {
fovAngle += fovScale;
changeFOV = false;
setTransformations();
}
for (unsigned int i = 0; i < objects.size(); i++) {
objectItem currObject = objects[i];
for (unsigned int j = 0; j < currObject.getGroups().size(); j++) {
group currGroup = currObject.getGroups().at(j);
for (unsigned int k = 0; k < currGroup.getFs().size(); k++) {
if (mode == GL_SELECT)
glPushName(currGroup.getName());
glPushMatrix();
vector<pair<int, int> > currF = currGroup.getFs()[k];
glBegin(GL_POLYGON);
for (unsigned int kk = 0; kk < currF.size(); kk++) {
Vector3f currVertex = vertexes.at(
(currF.at(kk).first - 1 >= 0) ?
currF.at(kk).first - 1 : 0);
Vector3f currNormal = vertexesNormal.at(
(currF.at(kk).second - 1 >= 0) ?
currF.at(kk).second - 1 : 0);
glNormal3f(currNormal.x, currNormal.y, currNormal.z);
glVertex3f(currVertex.x / 1, currVertex.y / 1,
currVertex.z / 1);
}
glEnd();
glPopMatrix();
}
}
}
}
The drawing works ok and I see the object on the screen.
This is all the picking procedure
/* PICKING */
void processHits(GLint hits, GLuint *buffer) {
float z1, z2;
for (int i = 0; buffer[i] > 0; i += 5) {
z1 = buffer[i + 1] / 4294967295.0;
z2 = buffer[i + 2] / 4294967295.0;
printf("z1 = %f ,z2 = %f zValue = %f\n", z1, z2, zValue[0]);
if ((zValue[0] <= z1 + 0.0001 && zValue[0] >= z2 - 0.0001)
|| (zValue[0] >= z1 - 0.0001 && zValue[0] <= z2 + 0.0001)) { //try to locate which name is correlated with the pressed pixel according to z value
ii = buffer[i + 3];
jj = buffer[i + 4];
}
}
}
void startPicking(GLuint *selectionBuf) {
glSelectBuffer(bufSize, selectionBuf); //declare buffer for input in selection mode
glRenderMode(GL_SELECT); //change to selecting mode
glInitNames(); //initialize names stack
glPushName(-1); //push name
}
void pick(int button, int x, int y) {
//use selection mode to pick
glReadPixels(x, viewport[3] - y, 1, 1, GL_RGBA, GL_FLOAT, pix);
//printf("depth = %f, x = %d, y = %d\n",pixels[(viewport[3]-y)*512+x],x,viewport[3]-y);
glMatrixMode(GL_PROJECTION);
glReadPixels((GLdouble) x, (GLdouble) viewport[3] - y, 2, 2,
GL_DEPTH_COMPONENT, GL_FLOAT, zValue);
glPushMatrix(); //saves current projection matrix
startPicking(selectionBuf); //preper selection mode
glLoadIdentity();
gluPickMatrix((GLdouble) x, (GLdouble) viewport[3] - y, 1, 1, viewport); //change matrices so only the area of the picking pixel can be seen.
gluPerspective(fovAngle, 1, near, far); //return to perspective state
glMatrixMode(GL_MODELVIEW);
draw(GL_SELECT); //draws board on background
hits = glRenderMode(GL_RENDER); //gets hits number
glMatrixMode(GL_PROJECTION);
glPopMatrix(); //restores projection matrix
glMatrixMode(GL_MODELVIEW);
processHits(hits, selectionBuf); //check hits
if(hits > 0)
printf("touched: %d\n",selectionBuf[3]);
//printf("depth %f hits: %d\n\n",pixels[(viewport[3]-y)*512+x], hits);
if (zValue[0] < 1.0) {
isPick = true;
xx = x;
yy = y;
if (button == GLUT_RIGHT_BUTTON)
zMove = true;
else
zMove = false;
}
}
the pick function is called when the mouse is clicked (using opengl mouse function).
The error I'm receiving is that no objects appears to be hit when clicking on an object.
I'm using Ubuntu 14.04 LTS with Opengl 3.0
I don't know how to ask or what specifically ask, I would appreciate some inputs on the code if you see something wrong..
You seemed to have missed using glPopName()
GLNames used in the selection buffer are pushed on a stack. So unless you call glPopName() the stack would never unwind. The working of this is similar to the calls glPushMatrix() and glPopMatrix().
Typically this is what the code flow looks like.
//Push the name of the primitives on top of selection stack
glPushName(...)
//Set Transformations / Draw the primitives
..
..
//Pop the name (Clear the stack for pushing another name)
glPopName();
I'm trying to draw simple circle with C++/OpenGl
my code is:
#include <GL/glut.h>
#include <math.h>
void Draw() {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glColor3f (0.0, 0.0, 0.0);
glVertex3f (0.1, 0.1, 0.0);
glVertex3f (0.9, 0.1, 0.0);
glVertex3f (0.9, 0.9, 0.0);
glVertex3f (0.1, 0.9, 0.0);
glEnd();
glFlush();
}
void DrawCircle(float cx, float cy, float r, int num_segments)
{
glBegin(GL_LINE_LOOP);
for(int ii = 0; ii < num_segments; ii++)
{
float theta = 2.0f * 3.1415926f * float(ii) / float(num_segments);//get the current angle
float x = r * cosf(theta);//calculate the x component
float y = r * sinf(theta);//calculate the y component
glVertex2f(x + cx, y + cy);//output vertex
}
glEnd();
}
void Initialize() {
glClearColor(1.0, 1.0, 1.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
}
int main(int iArgc, char** cppArgv) {
glutInit(&iArgc, cppArgv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(950, 500);
glutInitWindowPosition(200, 200);
glutCreateWindow("Universum");
Initialize();
glutDisplayFunc(Draw);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
DrawCircle(0.5, 0.5, 0.2, 5);
glutMainLoop();
return 0;
}
I'm beginner with OpenGL and now i'm starting to learn,
Can someone please explain me why i don't get the circle (i only see the black box),
Thanks!
It looks like immediately after you draw the circle, you go into the main glut loop, where you've set the Draw() function to draw every time through the loop. So it's probably drawing the circle, then erasing it immediately and drawing the square. You should probably either make DrawCircle() your glutDisplayFunc(), or call DrawCircle() from Draw().
#include <Windows.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define window_width 1080
#define window_height 720
void drawFilledSun(){
//static float angle;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0, 0, -10);
int i, x, y;
double radius = 0.30;
//glColor3ub(253, 184, 19);
glColor3ub(255, 0, 0);
double twicePi = 2.0 * 3.142;
x = 0, y = 0;
glBegin(GL_TRIANGLE_FAN); //BEGIN CIRCLE
glVertex2f(x, y); // center of circle
for (i = 0; i <= 20; i++) {
glVertex2f (
(x + (radius * cos(i * twicePi / 20))), (y + (radius * sin(i * twicePi / 20)))
);
}
glEnd(); //END
}
void DrawCircle(float cx, float cy, float r, int num_segments) {
glBegin(GL_LINE_LOOP);
for (int ii = 0; ii < num_segments; ii++) {
float theta = 2.0f * 3.1415926f * float(ii) / float(num_segments);//get the current angle
float x = r * cosf(theta);//calculate the x component
float y = r * sinf(theta);//calculate the y component
glVertex2f(x + cx, y + cy);//output vertex
}
glEnd();
}
void main_loop_function() {
int c;
drawFilledSun();
DrawCircle(0, 0, 0.7, 100);
glutSwapBuffers();
c = getchar();
}
void GL_Setup(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glEnable(GL_DEPTH_TEST);
gluPerspective(45, (float)width / height, .1, 100);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitWindowSize(window_width, window_height);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutCreateWindow("GLUT Example!!!");
glutIdleFunc(main_loop_function);
GL_Setup(window_width, window_height);
glutMainLoop();
}
This is what I did. I hope this helps. Two types of circle are here. Filled and unfilled.
There is another way to draw a circle - draw it in fragment shader.
Create a quad:
float right = 0.5;
float bottom = -0.5;
float left = -0.5;
float top = 0.5;
float quad[20] = {
//x, y, z, lx, ly
right, bottom, 0, 1.0, -1.0,
right, top, 0, 1.0, 1.0,
left, top, 0, -1.0, 1.0,
left, bottom, 0, -1.0, -1.0,
};
Bind VBO:
unsigned int glBuffer;
glGenBuffers(1, &glBuffer);
glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*20, quad, GL_STATIC_DRAW);
and draw:
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
glEnableVertexAttribArray(ATTRIB_VERTEX);
glEnableVertexAttribArray(ATTRIB_VALUE);
glVertexAttribPointer(ATTRIB_VERTEX , 3, GL_FLOAT, GL_FALSE, 20, 0);
glVertexAttribPointer(ATTRIB_VALUE , 2, GL_FLOAT, GL_FALSE, 20, BUFFER_OFFSET(12));
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
Vertex shader
attribute vec2 value;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
varying vec2 val;
void main() {
val = value;
gl_Position = projectionMatrix*viewMatrix*vertex;
}
Fragment shader
varying vec2 val;
void main() {
float R = 1.0;
float R2 = 0.5;
float dist = sqrt(dot(val,val));
if (dist >= R || dist <= R2) {
discard;
}
float sm = smoothstep(R,R-0.01,dist);
float sm2 = smoothstep(R2,R2+0.01,dist);
float alpha = sm*sm2;
gl_FragColor = vec4(0.0, 0.0, 1.0, alpha);
}
Don't forget to enable alpha blending:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
UPDATE: Read more
We will find the value of X and Y from this image. We know, sinθ=vertical/hypotenuse and cosθ=base/hypotenuse from the image we can say X=base and Y=vertical. Now we can write X=hypotenuse * cosθ and Y=hypotenuse * sinθ.
Now look at this code
void display(){
float x,y;
glColor3f(1, 1, 0);
for(double i =0; i <= 360;){
glBegin(GL_TRIANGLES);
x=5*cos(i);
y=5*sin(i);
glVertex2d(x, y);
i=i+.5;
x=5*cos(i);
y=5*sin(i);
glVertex2d(x, y);
glVertex2d(0, 0);
glEnd();
i=i+.5;
}
glEnd();
glutSwapBuffers();
}
glBegin(GL_POLYGON); // Middle circle
double radius = 0.2;
double ori_x = 0.0; // the origin or center of circle
double ori_y = 0.0;
for (int i = 0; i <= 300; i++) {
double angle = 2 * PI * i / 300;
double x = cos(angle) * radius;
double y = sin(angle) * radius;
glVertex2d(ori_x + x, ori_y + y);
}
glEnd();
Here is a code to draw a fill elipse, you can use the same method but replacing de xcenter and y center with radius
void drawFilledelipse(GLfloat x, GLfloat y, GLfloat xcenter,GLfloat ycenter) {
int i;
int triangleAmount = 20; //# of triangles used to draw circle
//GLfloat radius = 0.8f; //radius
GLfloat twicePi = 2.0f * PI;
glBegin(GL_TRIANGLE_FAN);
glVertex2f(x, y); // center of circle
for (i = 0; i <= triangleAmount; i++) {
glVertex2f(
x + ((xcenter+1)* cos(i * twicePi / triangleAmount)),
y + ((ycenter-1)* sin(i * twicePi / triangleAmount))
);
}
glEnd();
}
I have done it using the following code,
glBegin(GL.GL_LINE_LOOP);
for(int i =0; i <= 300; i++){
double angle = 2 * Math.PI * i / 300;
double x = Math.cos(angle);
double y = Math.sin(angle);
gl.glVertex2d(x,y);
}
glEnd();
glBegin(GL_POLYGON);
double x = 2;
double y = 2;
for (int i = 0; i <= 360; i++) {
glVertex2d(x * sin(i), y * cos(i));
}
glEnd();