Commit 4e889a03 by Alisa Jung

Kamera verschieben, um neues zentrum rotieren, unabh zoomen.

parent e2c4da19
#include "controller.h"
#include "myglwidget.h"
Controller::Controller()
{
modeCamera = true;
}
Controller::~Controller(){
}
void Controller::switchToModeCamera(){
qDebug("Bla");
modeCamera = true;
}
void Controller::switchToModeManipulate(){
modeCamera = false;
}
void Controller::processMousePressEvent(QMouseEvent *event, MyGLWidget *widget){
rightButtonPressed = false;
leftButtonPressed = false;
if (event->button() == Qt::RightButton){
rightButtonPressed = true;
lastClickPosition = event->pos();
qDebug() << "mouse press at " << lastClickPosition;
} else if (event->button() == Qt::LeftButton){
leftButtonPressed = true;
lastClickPosition = event->pos();
}
//TODO if widget was not selected before, set active.
}
void Controller::processMouseMoveEvent(QMouseEvent *event, MyGLWidget *widget){
//This didn't work properly, used bool to store state instead. if (event->button() == Qt::RightButton){
if (rightButtonPressed){
QPoint currentPosition = event->pos();
QPoint diff = currentPosition - lastClickPosition;
lastClickPosition = currentPosition;
if (modeCamera){
widget->translateCamera(-0.01*diff.x(),0.01*diff.y());
} else{
widget->translateQube(0.01*diff.x(),-0.01*diff.y());
}
}else if (leftButtonPressed){
QQuaternion q = computeRotation(event->pos());
if (modeCamera){
//TODO nur bei perspective widget
//TODO widget->rotateCamera
widget->rotateCamera(q);
}else{
widget->rotateQube(q);
}
}
}
void Controller::setScreenScenter(QPoint center){
screenCenter = center;
}
QQuaternion Controller::computeRotation(QPoint newPosition){
//according to https://www.opengl.org/wiki/Object_Mouse_Trackball
double radius = std::min(screenCenter.x(),screenCenter.y());
//translate touches around screen center
double xOld = ((double)(lastClickPosition.x() - screenCenter.x()));
double yNew = ((double)(lastClickPosition.y() - screenCenter.y()));
double xNew = ((double)(newPosition.x() - screenCenter.x()));
double yOld = ((double)(newPosition.y() - screenCenter.y()));
lastClickPosition = newPosition;
//https://www.opengl.org/wiki/Object_Mouse_Trackball#Sit_and_spin
//compute z coordinates ether on sphere or on hyperbolic sheet
double zOld, zNew;
double rsquareover2 = radius*radius/2.0;
double xyOld = xOld*xOld + yOld*yOld;
double xyNew = xNew*xNew + yNew*yNew;
if (xyOld < rsquareover2){
zOld = sqrt(radius*radius - xyOld);
qDebug() << "z old 1 " << zOld;
}else{
zOld = rsquareover2/(sqrt(xyOld));
qDebug() << "z old 2 " << zOld;
}
if(xyNew < rsquareover2){
zNew = sqrt(radius*radius - xyNew);
}else{
zNew = rsquareover2/sqrt(xyNew);
}
// set V_1 and V_2 (Vectors on Sphere around screen center, corresponding to input
QVector3D v1 = QVector3D(xOld,yOld,zOld);
v1.normalize();
QVector3D v2 = QVector3D(xNew,yNew,zNew);
v2.normalize();
//Compute normal of plane through v1 and v2 -> rotation axis
QVector3D n = QVector3D::crossProduct(v1,v2);
n.normalize();
//and theta (angle between v1 and v2)
double theta = acos(QVector3D::dotProduct(v1,v2));
//Accumulate Rotation
QQuaternion q = QQuaternion(cos(theta/2.0),sin(theta/2)*n);
q.normalize();
qDebug() << "quaternion diff " << q << "xo " << xOld << "yo " << yOld << " x new " << xNew << " ynew " << yNew;
qDebug() << "v1 " << v1 << ", v2 " << v2;
return q;
}
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <QGLWidget>
#include <gl/GLU.h>
#include <QDebug>
#include <QWheelEvent>
#include <QQuaternion>
#include <QMatrix4x4>
#include <math.h>
#include <QVector3D>
#include <QGLShaderProgram>
#include <QGLShader>
#include <QDebug>
#include <QObject>
class MyGLWidget;
class Controller : public QObject
{
Q_OBJECT
public:
Controller();
~Controller();
//processes input and might call follow up functions in widget
void processMousePressEvent(QMouseEvent* event, MyGLWidget* widget);
//processes mouse movement, calls some translate / rotate function in widget
void processMouseMoveEvent(QMouseEvent* event, MyGLWidget* widget);
void setScreenScenter(QPoint center);
private:
bool modeCamera;
bool rightButtonPressed;
bool leftButtonPressed;
QPoint screenCenter;//Center of screen in pixel coordinates
QPoint lastClickPosition;
QQuaternion computeRotation(QPoint newPosition);
public slots:
void switchToModeCamera();
void switchToModeManipulate();
};
#endif // CONTROLLER_H
...@@ -18,14 +18,14 @@ SOURCES += main.cpp\ ...@@ -18,14 +18,14 @@ SOURCES += main.cpp\
scenegraph.cpp \ scenegraph.cpp \
primitive.cpp \ primitive.cpp \
rigidbodytransformation.cpp \ rigidbodytransformation.cpp \
widgetfront.cpp controller.cpp
HEADERS += mainwindow.h \ HEADERS += mainwindow.h \
myglwidget.h \ myglwidget.h \
scenegraph.h \ scenegraph.h \
primitive.h \ primitive.h \
rigidbodytransformation.h \ rigidbodytransformation.h \
widgetfront.h controller.h
RESOURCES += \ RESOURCES += \
helloqube.qrc helloqube.qrc
......
...@@ -76,7 +76,8 @@ MainWindow::MainWindow(QWidget *parent) ...@@ -76,7 +76,8 @@ MainWindow::MainWindow(QWidget *parent)
setStatusBar(statusBar); setStatusBar(statusBar);
//4.0 Widget //4.0 Widget
myGLWidget = new MyGLWidget(this); controller = new Controller();
myGLWidget = new MyGLWidget(controller,this);
setCentralWidget(myGLWidget); setCentralWidget(myGLWidget);
//4.1.1 connect shading actions to slot //4.1.1 connect shading actions to slot
...@@ -114,18 +115,22 @@ MainWindow::MainWindow(QWidget *parent) ...@@ -114,18 +115,22 @@ MainWindow::MainWindow(QWidget *parent)
//TODO connect slot //TODO connect slot
toolBar->addAction(modeCameraAction); toolBar->addAction(modeCameraAction);
toolBar->insertSeparator(modeCameraAction); toolBar->insertSeparator(modeCameraAction);
connect(modeCameraAction,SIGNAL(triggered(bool)),controller,SLOT(switchToModeCamera()));
modeManipulateAction = new QAction("Manipulation Mode", toolBar); modeManipulateAction = new QAction("Manipulation Mode", toolBar);
modeManipulateAction->setIcon(QIcon(":/grapa-a2-iconset/select.png")); modeManipulateAction->setIcon(QIcon(":/grapa-a2-iconset/select.png"));
modeManipulateAction->setCheckable(true); modeManipulateAction->setCheckable(true);
//TODO connect slot //TODO connect slot
toolBar->addAction(modeManipulateAction); toolBar->addAction(modeManipulateAction);
connect(modeManipulateAction,SIGNAL(triggered(bool)),controller,SLOT(switchToModeManipulate()));
modeSwitchGroup = new QActionGroup(toolBar); modeSwitchGroup = new QActionGroup(toolBar);
modeSwitchGroup->addAction(modeCameraAction); modeSwitchGroup->addAction(modeCameraAction);
modeSwitchGroup->addAction(modeManipulateAction); modeSwitchGroup->addAction(modeManipulateAction);
//2 Switch view modes //2 Switch view modes
viewButton = new QToolButton(toolBar); viewButton = new QToolButton(toolBar);
viewButton->setIcon(QIcon(":/grapa-a2-iconset/viewports.png")); viewButton->setIcon(QIcon(":/grapa-a2-iconset/viewports.png"));
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <myglwidget.h> #include <myglwidget.h>
#include <QSlider> #include <QSlider>
#include <QToolButton> #include <QToolButton>
#include <controller.h>
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
...@@ -67,6 +68,8 @@ private: ...@@ -67,6 +68,8 @@ private:
//4.1.1 Slider //4.1.1 Slider
QSlider* tesselationSlider; QSlider* tesselationSlider;
Controller* controller;
public slots : public slots :
void showAboutBox ( ) ; void showAboutBox ( ) ;
}; };
......
#include "myglwidget.h" #include "myglwidget.h"
#include "controller.h"
MyGLWidget::MyGLWidget(QWidget *parent) MyGLWidget::MyGLWidget(Controller* c, QWidget *parent)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent) : QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
{ {
MyGLWidget::modeCamera = true;
tesselation = 1; tesselation = 1;
qubeRotationQuaternion = QQuaternion(); qubeRotation = QQuaternion();
cameraRotation = QQuaternion();
translatex = 0; translatex = 0;
translatey = 0; translatey = 0;
cameraX = 0;
cameraY = 0;
cameraZ = 0;
camRotCenter = QVector3D(0,0,0);
cameraZoom = cameraZoomDefault; cameraZoom = cameraZoomDefault;
clickStartPosition = QPoint(0,0); clickStartPosition = QPoint(0,0);
rightButtonPressed = false; rightButtonPressed = false;
controller = c;
} }
MyGLWidget::~MyGLWidget() MyGLWidget::~MyGLWidget()
...@@ -109,24 +117,47 @@ void MyGLWidget::paintGL(){ ...@@ -109,24 +117,47 @@ void MyGLWidget::paintGL(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); glLoadIdentity();
//zoom camera //cam rotation
glTranslatef(0,0,cameraZoom);//Kamera sitzt sonst in (0,0,0) und man sieht nichts (duh) QMatrix4x4 camRot = QMatrix4x4();
camRot.rotate(cameraRotation);
//for translation
double qubeWidth = 1.0;
double dist = qubeWidth/(double)tesselation;
//for cube rotation
QMatrix4x4 m = QMatrix4x4();
m.rotate(qubeRotation);
//for cube translation //for cube translation
QMatrix4x4 translateRot1 = QMatrix4x4(1,0,0,translatex,0,1,0,translatey,0,0,1,0,0,0,0,1); QMatrix4x4 translateRot1 = QMatrix4x4(1,0,0,translatex,0,1,0,translatey,0,0,1,0,0,0,0,1);
//for cube rotation QMatrix4x4 translateCamera = QMatrix4x4(1,0,0,cameraX,0,1,0,cameraY,0,0,1,cameraZ,0,0,0,1);
QMatrix4x4 m = QMatrix4x4();
m.rotate(qubeRotationQuaternion); QMatrix4x4 zoomCameraMatrix = QMatrix4x4(1,0,0,0,0,1,0,0,0,0,1,cameraZoom,0,0,0,1);
// //zoom camera
// glTranslatef(0,0,cameraZoom);//Kamera sitzt sonst in (0,0,0) und man sieht nichts (duh)
// glTranslatef(cameraX,cameraY,0);//TODO anständig machen, kamerarotation fehlt noch.
//stack matrices //stack matrices
glMultMatrixf(translateRot1.data());//Punkte zurück schieben damit rotation um qube zentrum ist // glMultMatrixf(translateRot1.data());//Punkte zurück schieben damit rotation um qube zentrum ist
glMultMatrixf(m.data()); // glMultMatrixf(m.data());
//So scheint das zumindest für die Kamera zu funktionieren:
//1. ins Rotationszentrum verschieben - Wenn Rotationszentrum geändert wird, schon rotation berücksichtigen
//2. Rotieren
//3. Zoomen
glMultMatrixf(zoomCameraMatrix.data());
glMultMatrixf(camRot.data());
glTranslatef(camRotCenter.x(),camRotCenter.y(),camRotCenter.z());
//tesselation
double qubeWidth = 1.0;
double dist = qubeWidth/(double)tesselation;
//4.1.1 Unit Qube + Tesselation + Diffuse Material //4.1.1 Unit Qube + Tesselation + Diffuse Material
{ {
...@@ -241,84 +272,33 @@ void MyGLWidget::resizeGL(int width, int height){ ...@@ -241,84 +272,33 @@ void MyGLWidget::resizeGL(int width, int height){
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
screenCenter = QPoint((double)width/2.0,(double)height/2.0);//lieber zu oft casten bevors nicht tut... controller->setScreenScenter(QPoint((double)width/2.0,(double)height/2.0));//lieber zu oft casten bevors nicht tut...
} }
void MyGLWidget::mousePressEvent(QMouseEvent *event){ void MyGLWidget::mousePressEvent(QMouseEvent *event){
rightButtonPressed = false; controller->processMousePressEvent(event,this);
leftButtonPressed = false;
if (event->button() == Qt::RightButton){
rightButtonPressed = true;
clickStartPosition = event->pos();
qDebug() << "mouse press at " << clickStartPosition;
} else if (event->button() == Qt::LeftButton){
leftButtonPressed = true;
clickStartPosition = event->pos();
}
} }
void MyGLWidget:: mouseMoveEvent(QMouseEvent *event){ void MyGLWidget:: mouseMoveEvent(QMouseEvent *event){
//This didn't work properly, used bool to store state instead. if (event->button() == Qt::RightButton){ controller->processMouseMoveEvent(event,this);
if (rightButtonPressed){ }
QPoint currentPosition = event->pos();
QPoint diff = currentPosition - clickStartPosition;
clickStartPosition = currentPosition;
translatex += 0.01*diff.x();
translatey -= 0.01*diff.y();
updateGL();
}else if (leftButtonPressed){
//according to https://www.opengl.org/wiki/Object_Mouse_Trackball
double radius = std::min(screenCenter.x(),screenCenter.y());
//translate touches around screen center
double xOld = ((double)(clickStartPosition.x() - screenCenter.x()));
double yNew = ((double)(clickStartPosition.y() - screenCenter.y()));
QPoint newPosition = event->pos();
double xNew = ((double)(newPosition.x() - screenCenter.x()));
double yOld = ((double)(newPosition.y() - screenCenter.y()));
clickStartPosition = newPosition;
//https://www.opengl.org/wiki/Object_Mouse_Trackball#Sit_and_spin
//compute z coordinates ether on sphere or on hyperbolic sheet
double zOld, zNew;
double rsquareover2 = radius*radius/2.0;
double xyOld = xOld*xOld + yOld*yOld;
double xyNew = xNew*xNew + yNew*yNew;
if (xyOld < rsquareover2){
zOld = sqrt(radius*radius - xyOld);
}else{
zOld = rsquareover2/(sqrt(xyOld));
}
if(xyNew < rsquareover2){
zNew = sqrt(radius*radius - xyNew);
}else{
zNew = rsquareover2/sqrt(xyNew);
}
// set V_1 and V_2 (Vectors on Sphere around screen center, corresponding to input
QVector3D v1 = QVector3D(xOld,yOld,zOld);
v1.normalize();
QVector3D v2 = QVector3D(xNew,yNew,zNew); void MyGLWidget::translateCamera(double xDiff, double yDiff, double zDiff)
v2.normalize(); {
//in order to "move parallel to image plane", we have to rotate the image coordinates xDiff and yDiff by our current camera rotation.
camRotCenter += cameraRotation.conjugate().rotatedVector(QVector3D(xDiff,yDiff,zDiff));
updateGL();
}
//Compute normal of plane through v1 and v2 -> rotation axis void MyGLWidget::translateQube(double xDiff, double yDiff){
QVector3D n = QVector3D::crossProduct(v1,v2); translatex += xDiff;
n.normalize(); translatey += yDiff;
updateGL();
}
//and theta (angle between v1 and v2) void MyGLWidget::rotateQube(QQuaternion diff){
double theta = acos(QVector3D::dotProduct(v1,v2));
//Accumulate Rotation
QQuaternion q = QQuaternion(cos(theta/2.0),sin(theta/2)*n);
q.normalize();
/* /*
* Wikipedia: Two rotation quaternions can be combined into * Wikipedia: Two rotation quaternions can be combined into
* one equivalent quaternionby the relation: * one equivalent quaternionby the relation:
...@@ -326,12 +306,17 @@ void MyGLWidget:: mouseMoveEvent(QMouseEvent *event){ ...@@ -326,12 +306,17 @@ void MyGLWidget:: mouseMoveEvent(QMouseEvent *event){
* in which q′ corresponds to the rotation q1 followed by the rotation q2. * in which q′ corresponds to the rotation q1 followed by the rotation q2.
* (Note that quaternion multiplication is not commutative.) * (Note that quaternion multiplication is not commutative.)
*/ */
qubeRotationQuaternion = q*qubeRotationQuaternion; qubeRotation = diff*qubeRotation;
qubeRotationQuaternion.normalize(); qubeRotation.normalize();
updateGL(); updateGL();
} }
void MyGLWidget::rotateCamera(QQuaternion diff){
cameraRotation = diff*cameraRotation;
cameraRotation.normalize();
updateGL();
} }
//4.1.2 User Input: Zooming //4.1.2 User Input: Zooming
...@@ -384,9 +369,14 @@ void MyGLWidget::setTessellation(int t){ ...@@ -384,9 +369,14 @@ void MyGLWidget::setTessellation(int t){
} }
void MyGLWidget::resetCamera(){ void MyGLWidget::resetCamera(){
qubeRotationQuaternion = QQuaternion(); qubeRotation = QQuaternion();
translatex = 0; translatex = 0;
translatey = 0; translatey = 0;
cameraX = 0;
cameraY = 0;
cameraZ = 0;
camRotCenter = QVector3D(0,0,0);
cameraZoom = cameraZoomDefault; cameraZoom = cameraZoomDefault;
cameraRotation = QQuaternion();
updateGL(); updateGL();
} }
...@@ -12,18 +12,28 @@ ...@@ -12,18 +12,28 @@
#include <QGLShaderProgram> #include <QGLShaderProgram>
#include <QGLShader> #include <QGLShader>
class Controller;
class MyGLWidget : public QGLWidget class MyGLWidget : public QGLWidget
{ {
Q_OBJECT //from HelloGL Example Q_OBJECT //from HelloGL Example
public: public:
MyGLWidget(QWidget *parent = 0); MyGLWidget(Controller* c, QWidget *parent = 0);
~MyGLWidget(); ~MyGLWidget();
//From HelloGL example. //From HelloGL example.
QSize minimumSizeHint() const; QSize minimumSizeHint() const;
QSize sizeHint() const; QSize sizeHint() const;
/* Assignment 2*/
bool modeCamera;
void translateCamera(double xDiff, double yDiff, double zDiff = 0);
void translateQube(double xDiff, double yDiff);
void rotateCamera(QQuaternion diff);
void rotateQube(QQuaternion diff);
protected: protected:
//4.1 Core Functionality //4.1 Core Functionality
void initializeGL(); void initializeGL();
...@@ -33,13 +43,18 @@ protected: ...@@ -33,13 +43,18 @@ protected:
void mouseMoveEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event); void wheelEvent(QWheelEvent *event);
Controller* controller;
private: private:
//tesselation slider //tesselation slider
int tesselation; int tesselation;
//zoom camera //zoom camera
const double cameraZoomDefault = -5; const double cameraZoomDefault = -5;
double cameraX,cameraY,cameraZ;
double cameraZoom; double cameraZoom;
QQuaternion cameraRotation;
QVector3D camRotCenter;
//translate camera //translate camera
QPoint clickStartPosition; QPoint clickStartPosition;
...@@ -48,13 +63,15 @@ private: ...@@ -48,13 +63,15 @@ private:
//rotate cube //rotate cube
bool leftButtonPressed; bool leftButtonPressed;
QQuaternion qubeRotationQuaternion; QQuaternion qubeRotation;
QPoint screenCenter;//Center of screen in pixel coordinates QPoint screenCenter;//Center of screen in pixel coordinates
//Phong Shader //Phong Shader
QGLShaderProgram *phongShader; QGLShaderProgram *phongShader;
public slots: public slots:
//4.1.1 slots for shading modes //4.1.1 slots for shading modes
void shadeWireframeSlot(); void shadeWireframeSlot();
......
...@@ -5,20 +5,20 @@ RigidBodyTransformation::RigidBodyTransformation(Primitive child) ...@@ -5,20 +5,20 @@ RigidBodyTransformation::RigidBodyTransformation(Primitive child)
tx = 0; tx = 0;
ty = 0; ty = 0;
tz = 0; tz = 0;
rotation = new QQuaternion(); rotation = QQuaternion();
this->child = child; this->child = child;
} }
RigidBodyTransformation::setTranslation(double x, double y, double z=0){ void RigidBodyTransformation::setTranslation(double x, double y, double z){
tx = x; tx = x;
ty = y; ty = y;
tz = z; tz = z;
} }
RigidBodyTransformation::getRotation(){ QQuaternion RigidBodyTransformation::getRotation(){
return rotation; return rotation;
} }
RigidBodyTransformation::setRotation(QQuaternion newRotation){ void RigidBodyTransformation::setRotation(QQuaternion newRotation){
rotation = newRotation; rotation = newRotation;
} }
#ifndef RIGIDBODYTRANSFORMATION_H #ifndef RIGIDBODYTRANSFORMATION_H
#define RIGIDBODYTRANSFORMATION_H #define RIGIDBODYTRANSFORMATION_H
#include <QQuaternion>
#include <primitive.h>
class RigidBodyTransformation class RigidBodyTransformation
{ {
public: public:
RigidBodyTransformation(); RigidBodyTransformation(Primitive child);
void setTranslation(double x, double y, double z = 0); void setTranslation(double x, double y, double z);
void setRotation(QQuaternion newRotation); void setRotation(QQuaternion newRotation);
QQuaternion getRotation(); QQuaternion getRotation();
......
#include "widgetfront.h"
widgetFront::widgetFront()
{
}
#include "WidgetFront.h"
WidgetFront::WidgetFront(QWidget *parent)
: QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
{
tesselation = 1;
qubeRotationQuaternion = QQuaternion();
translatex = 0;
translatey = 0;
cameraZoom = cameraZoomDefault;
clickStartPosition = QPoint(0,0);
rightButtonPressed = false;
}
WidgetFront::~WidgetFront()
{
/*http://doc.qt.io/qt-4.8/qt-opengl-hellogl-example.html :
* We use a destructor to ensure that any OpenGL-specific
* data structures are deleted when the widget is no longer
* needed (although in this case nothing needs cleaning up).
*/
//In helloGL example: nothing needs cleaning up.
}
/*
* From Example
* We provide size hint functions to ensure that
* the widgetis shown at a reasonable size:
*/
QSize WidgetFront::minimumSizeHint() const
{
return QSize(50, 50);
}
/*
* From Example
* We provide size hint functions to ensure that
* the widgetis shown at a reasonable size:
*/
QSize WidgetFront::sizeHint() const
{
return QSize(600, 400);
}
void WidgetFront::initializeGL()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
//Phong Shader:
QGLShader* vert = new QGLShader(QGLShader::Vertex);
qDebug() << "new vert shader";
QGLShader* frag = new QGLShader(QGLShader::Fragment);
qDebug() << "new frag shader";
bool e = QFile::exists(":/phong.vert");
qDebug() << "vert exists" << e;
bool successVertex = vert->compileSourceFile(":/phong.vert");
if (!successVertex)qDebug() << "Vertex compilation failed.";
else qDebug() << "Vertex compiled.";
bool successFragment = frag->compileSourceFile(":/phong.frag");
if (!successFragment) qDebug() << "Frag failed";
else qDebug() << "frag success";
phongShader = new QGLShaderProgram(this);
phongShader->addShader(vert);
phongShader->addShader(frag);
phongShader->link();
shadeFlatSlot();//set up flat shading
qDebug() << "flat done";
// glEnable(GL_CULL_FACE);//backface culling.
// glCullFace(GL_BACK);//backface culling
// glEnable(GL_COLOR_MATERIAL); //Habe ich für glColor3f gebraucht. Wieder raus für Material. //In order to use both color and lighting you must activate openGL color materials
//4.1.1
/*
* The initial state of the OpenGL state machine is defined in
initializeGL(). Furthermore, you can set all OpenGL parameters
that will not change during program execution here as well, for
example, the background color.
*/
glEnable(GL_LIGHTING);//enable lighting.
glEnable(GL_LIGHT0);//enable an OpenGL light
/*
* https://msdn.microsoft.com/en-us/library/windows/desktop/dd373578%28v=vs.85%29.aspx
* The glLightfv function returns light source parameter values.
* GL_POSITION:
* The params parameter contains four floating-point values
* that specify the position of the light in homogeneous object
* coordinates. Both integer and floating-point values are
* mapped directly. Neither integer nor floating-point values
* are clamped.
*/
static GLfloat lightPosition[4] = {0.5, 0.0, 2.0, 1.0};
glLightfv(GL_LIGHT0,GL_POSITION,lightPosition);//set Position of light source.
}
void WidgetFront::paintGL(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//zoom camera
glTranslatef(cameraX,cameraY,cameraZoom);//Kamera sitzt sonst in (0,0,0) und man sieht nichts (duh)
//for translation
double qubeWidth = 1.0;
double dist = qubeWidth/(double)tesselation;
//for cube translation
QMatrix4x4 translateRot1 = QMatrix4x4(1,0,0,translatex,0,1,0,translatey,0,0,1,0,0,0,0,1);
//for cube rotation
QMatrix4x4 m = QMatrix4x4();
m.rotate(qubeRotationQuaternion);
//stack matrices
glMultMatrixf(translateRot1.data());//Punkte zurück schieben damit rotation um qube zentrum ist
glMultMatrixf(m.data());
//4.1.1 Unit Qube + Tesselation + Diffuse Material
{
GLfloat specularColor[] = {1,1,1};
GLfloat shininess[] = {128};//specular exponent
glMaterialfv(GL_FRONT,GL_SPECULAR,specularColor);
glMaterialfv(GL_FRONT,GL_SHININESS,shininess);
//vorne // z-Achse
// glColor3f(0,0,1);//blau //alt und doof
GLfloat blue[] = {0,0,1};
glMaterialfv(GL_FRONT,GL_DIFFUSE,blue);
glNormal3f(0,0,1);
glBegin(GL_QUADS);
for (int i = 0; i < tesselation; i++){
for (int j = 0; j < tesselation; j++){
glVertex3f(0.5-dist*i,0.5-dist*j,0.5);
glVertex3f(0.5-dist*(i+1),0.5-dist*j,0.5);
glVertex3f(0.5-dist*(i+1),0.5-dist*(j+1),0.5);
glVertex3f(0.5-dist*i,0.5-dist*(j+1),0.5);
}
}
glEnd();
//oben // y-Achse
GLfloat green[] = {0,1,0};
glMaterialfv(GL_FRONT,GL_DIFFUSE,green);
glNormal3f(0,1,0);
glBegin(GL_QUADS);
for (int i = 0; i < tesselation; i++){
for (int j = 0; j < tesselation; j++){
glVertex3f(0.5-dist*(i+1), 0.5, 0.5-dist*(j+1));
glVertex3f(0.5-dist*(i+1), 0.5, 0.5-dist*j);
glVertex3f(0.5-dist*i, 0.5, 0.5-dist*j);
glVertex3f(0.5-dist*i, 0.5, 0.5-dist*(j+1));
}
}
glEnd();
//rechts //x-Achse
GLfloat red[] = {1,0,0};
glMaterialfv(GL_FRONT,GL_DIFFUSE,red);
glNormal3f(1,0,0);
glBegin(GL_QUADS);
for (int i = 0; i < tesselation; i++){
for (int j = 0; j < tesselation; j++){
glVertex3f(0.5, 0.5-dist*i, 0.5-dist*j);
glVertex3f(0.5, 0.5-dist*(i+1), 0.5-dist*j);
glVertex3f(0.5, 0.5-dist*(i+1), 0.5-dist*(j+1));
glVertex3f(0.5, 0.5-dist*i, 0.5-dist*(j+1));
}
}
glEnd();
//hinten // z-Achse
GLfloat yellow[] = {1,0.9f,0};
glMaterialfv(GL_FRONT,GL_DIFFUSE,yellow);
glNormal3f(0,0,-1);
glBegin(GL_QUADS);
for (int i = 0; i < tesselation; i++){
for (int j = 0; j < tesselation; j++){
glVertex3f(0.5-dist*i, 0.5-dist*(j+1), -0.5);//4
glVertex3f(0.5-dist*(i+1), 0.5-dist*(j+1), -0.5);//3
glVertex3f(0.5-dist*(i+1), 0.5-dist*j, -0.5);//2
glVertex3f(0.5-dist*i, 0.5-dist*j, -0.5);//1
}
}
glEnd();
//links
GLfloat cyan[] = {0,1,1};
glMaterialfv(GL_FRONT,GL_DIFFUSE,cyan);
glNormal3f(-1,0,0);
glBegin(GL_QUADS);
for (int i = 0; i < tesselation; i++){
for (int j = 0; j < tesselation; j++){
glVertex3f(-0.5, 0.5-dist*i, 0.5-dist*(j+1));
glVertex3f(-0.5, 0.5-dist*(i+1), 0.5-dist*(j+1));
glVertex3f(-0.5, 0.5-dist*(i+1), 0.5-dist*j);
glVertex3f(-0.5, 0.5-dist*i, 0.5-dist*j);
}
}
glEnd();
//unten //-y
GLfloat magenta[] = {1,0,1};
glMaterialfv(GL_FRONT,GL_DIFFUSE,magenta);
glNormal3f(0,-1,0);
glBegin(GL_QUADS);
for (int i = 0; i < tesselation; i++){
for (int j = 0; j < tesselation; j++){
glVertex3f(0.5-dist*i, -0.5, 0.5-dist*(j+1));
glVertex3f(0.5-dist*i, -0.5, 0.5-dist*j);
glVertex3f(0.5-dist*(i+1), -0.5, 0.5-dist*j);
glVertex3f(0.5-dist*(i+1), -0.5, 0.5-dist*(j+1));
}
}
glEnd();
}
}
void WidgetFront::resizeGL(int width, int height){
double p = (double)width / (double)height;
qDebug() << "Resize to " << width << "," << height << ", Perspective: " << p;
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);//from HelloGL example
glLoadIdentity();
gluPerspective(45.0,p,0.1,1000);//set vof to 45°
glMatrixMode(GL_MODELVIEW);
screenCenter = QPoint((double)width/2.0,(double)height/2.0);//lieber zu oft casten bevors nicht tut...
}
void WidgetFront::mousePressEvent(QMouseEvent *event){
rightButtonPressed = false;
leftButtonPressed = false;
if (event->button() == Qt::RightButton){
rightButtonPressed = true;
clickStartPosition = event->pos();
qDebug() << "mouse press at " << clickStartPosition;
} else if (event->button() == Qt::LeftButton){
leftButtonPressed = true;
clickStartPosition = event->pos();
}
}
void WidgetFront:: mouseMoveEvent(QMouseEvent *event){
//This didn't work properly, used bool to store state instead. if (event->button() == Qt::RightButton){
if (rightButtonPressed){
QPoint currentPosition = event->pos();
QPoint diff = currentPosition - clickStartPosition;
clickStartPosition = currentPosition;
translatex += 0.01*diff.x();
translatey -= 0.01*diff.y();
updateGL();
}else if (leftButtonPressed){
//according to https://www.opengl.org/wiki/Object_Mouse_Trackball
double radius = std::min(screenCenter.x(),screenCenter.y());
//translate touches around screen center
double xOld = ((double)(clickStartPosition.x() - screenCenter.x()));
double yNew = ((double)(clickStartPosition.y() - screenCenter.y()));
QPoint newPosition = event->pos();
double xNew = ((double)(newPosition.x() - screenCenter.x()));
double yOld = ((double)(newPosition.y() - screenCenter.y()));
clickStartPosition = newPosition;
//https://www.opengl.org/wiki/Object_Mouse_Trackball#Sit_and_spin
//compute z coordinates ether on sphere or on hyperbolic sheet
double zOld, zNew;
double rsquareover2 = radius*radius/2.0;
double xyOld = xOld*xOld + yOld*yOld;
double xyNew = xNew*xNew + yNew*yNew;
if (xyOld < rsquareover2){
zOld = sqrt(radius*radius - xyOld);
}else{
zOld = rsquareover2/(sqrt(xyOld));
}
if(xyNew < rsquareover2){
zNew = sqrt(radius*radius - xyNew);
}else{
zNew = rsquareover2/sqrt(xyNew);
}
// set V_1 and V_2 (Vectors on Sphere around screen center, corresponding to input
QVector3D v1 = QVector3D(xOld,yOld,zOld);
v1.normalize();
QVector3D v2 = QVector3D(xNew,yNew,zNew);
v2.normalize();
//Compute normal of plane through v1 and v2 -> rotation axis
QVector3D n = QVector3D::crossProduct(v1,v2);
n.normalize();
//and theta (angle between v1 and v2)
double theta = acos(QVector3D::dotProduct(v1,v2));
//Accumulate Rotation
QQuaternion q = QQuaternion(cos(theta/2.0),sin(theta/2)*n);
q.normalize();
/*
* Wikipedia: Two rotation quaternions can be combined into
* one equivalent quaternionby the relation:
* q' = q_2*q_1'
* in which q′ corresponds to the rotation q1 followed by the rotation q2.
* (Note that quaternion multiplication is not commutative.)
*/
qubeRotationQuaternion = q*qubeRotationQuaternion;
qubeRotationQuaternion.normalize();
updateGL();
}
}
//4.1.2 User Input: Zooming
void WidgetFront::wheelEvent(QWheelEvent *event){
cameraZoom += 0.01*event->delta();//0.01 seemed to be a good factor
qDebug() << "Cam zoom delta " << event->delta() << " stored " << cameraZoom;
updateGL();
}
//4.1.1 slots for shading modes
void WidgetFront::shadeWireframeSlot(){
qDebug() << "Wireframe selected";
phongShader->release();
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);//Wireframe looks way cooler with both faces on
updateGL();
}
void WidgetFront::shadeFlatSlot(){
qDebug() << "Flat selected";
phongShader->release();
glShadeModel(GL_FLAT);
glPolygonMode(GL_FRONT,GL_FILL);
updateGL();
}
void WidgetFront::shadeGouraudSlot(){
qDebug() << "Gouraud selected";
phongShader->release();
glShadeModel(GL_SMOOTH);
glPolygonMode(GL_FRONT,GL_FILL);
updateGL();
}
void WidgetFront::shadePhongSlot(){
qDebug() << "Phong selected";
glPolygonMode(GL_FRONT,GL_FILL);
phongShader->bind();
updateGL();
}
//4.1.1 tesselation slot
void WidgetFront::setTessellation(int t){
qDebug() << "Tesselation: " << t;
tesselation = t;
updateGL();
}
void WidgetFront::resetCamera(){
qubeRotationQuaternion = QQuaternion();
translatex = 0;
translatey = 0;
cameraZoom = cameraZoomDefault;
updateGL();
}
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QGLWidget>
#include <gl/GLU.h>
#include <QDebug>
#include <QWheelEvent>
#include <QQuaternion>
#include <QMatrix4x4>
#include <math.h>
#include <QVector3D>
#include <QGLShaderProgram>
#include <QGLShader>
class WidgetFront : public QGLWidget
{
Q_OBJECT //from HelloGL Example
public:
WidgetFront(QWidget *parent = 0);
~WidgetFront();
//From HelloGL example.
QSize minimumSizeHint() const;
QSize sizeHint() const;
protected:
//4.1 Core Functionality
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void wheelEvent(QWheelEvent *event);
private:
//tesselation slider
int tesselation;
//zoom camera
const double cameraZoomDefault = -5;
double cameraZoom;
double cameraX, cameraY;
//translate camera
QPoint clickStartPosition;
bool rightButtonPressed;
double translatex, translatey;
//rotate cube
bool leftButtonPressed;
QQuaternion qubeRotationQuaternion;
QPoint screenCenter;//Center of screen in pixel coordinates
//Phong Shader
QGLShaderProgram *phongShader;
public slots:
//4.1.1 slots for shading modes
void shadeWireframeSlot();
void shadeFlatSlot();
void shadeGouraudSlot();
void shadePhongSlot();
void setTessellation(int t);
void resetCamera();
};
#endif // GLWIDGET_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment