Ai
1 Star 1 Fork 0

DGuco/qtproject

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
scene.cpp 36.63 KB
一键复制 编辑 原始数据 按行查看 历史
DGuco 提交于 2023-02-28 10:31 +08:00 . add box bug fix
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151
#include <QDebug>
#include "scene.h"
#include <QtGui/qmatrix4x4.h>
#include <QtGui/qvector3d.h>
#include <cmath>
#include <typeinfo>
#include "3rdparty/fbm.h"
void checkGLErrors(const QString& prefix)
{
switch (glGetError()) {
case GL_NO_ERROR:
//qDebug() << prefix << tr("No error.");
break;
case GL_INVALID_ENUM:
qDebug() << prefix << QObject::tr("Invalid enum.");
break;
case GL_INVALID_VALUE:
qDebug() << prefix << QObject::tr("Invalid value.");
break;
case GL_INVALID_OPERATION:
qDebug() << prefix << QObject::tr("Invalid operation.");
break;
case GL_STACK_OVERFLOW:
qDebug() << prefix << QObject::tr("Stack overflow.");
break;
case GL_STACK_UNDERFLOW:
qDebug() << prefix << QObject::tr("Stack underflow.");
break;
case GL_OUT_OF_MEMORY:
qDebug() << prefix << QObject::tr("Out of memory.");
break;
default:
qDebug() << prefix << QObject::tr("Unknown error.");
break;
}
}
//============================================================================//
// ColorEdit //
//============================================================================//
ColorEdit::ColorEdit(QRgb initialColor, int id)
: m_color(initialColor), m_id(id)
{
QHBoxLayout *layout = new QHBoxLayout;
setLayout(layout);
layout->setContentsMargins(0, 0, 0, 0);
m_lineEdit = new QLineEdit(QString::number(m_color, 16));
layout->addWidget(m_lineEdit);
m_button = new QFrame;
QPalette palette = m_button->palette();
palette.setColor(QPalette::Window, QColor(m_color));
m_button->setPalette(palette);
m_button->setAutoFillBackground(true);
m_button->setMinimumSize(32, 0);
m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
m_button->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
layout->addWidget(m_button);
connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(editDone()));
}
void ColorEdit::editDone()
{
bool ok;
QRgb newColor = m_lineEdit->text().toUInt(&ok, 16);
if (ok)
setColor(newColor);
}
void ColorEdit::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
QColor color(m_color);
QColorDialog dialog(color, 0);
dialog.setOption(QColorDialog::ShowAlphaChannel, true);
// The ifdef block is a workaround for the beta, TODO: remove when bug 238525 is fixed
#if 0 // Used to be included in Qt4 for Q_WS_MAC
dialog.setOption(QColorDialog::DontUseNativeDialog, true);
#endif
dialog.move(280, 120);
if (dialog.exec() == QDialog::Rejected)
return;
QRgb newColor = dialog.selectedColor().rgba();
if (newColor == m_color)
return;
setColor(newColor);
}
}
void ColorEdit::setColor(QRgb color)
{
m_color = color;
m_lineEdit->setText(QString::number(m_color, 16)); // "Clean up" text
QPalette palette = m_button->palette();
palette.setColor(QPalette::Window, QColor(m_color));
m_button->setPalette(palette);
emit colorChanged(m_color, m_id);
}
//============================================================================//
// FloatEdit //
//============================================================================//
FloatEdit::FloatEdit(float initialValue, int id)
: m_value(initialValue), m_id(id)
{
QHBoxLayout *layout = new QHBoxLayout;
setLayout(layout);
layout->setContentsMargins(0, 0, 0, 0);
m_lineEdit = new QLineEdit(QString::number(m_value));
layout->addWidget(m_lineEdit);
connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(editDone()));
}
void FloatEdit::editDone()
{
bool ok;
float newValue = m_lineEdit->text().toFloat(&ok);
if (ok) {
m_value = newValue;
m_lineEdit->setText(QString::number(m_value)); // "Clean up" text
emit valueChanged(m_value, m_id);
}
}
//============================================================================//
// TwoSidedGraphicsWidget //
//============================================================================//
TwoSidedGraphicsWidget::TwoSidedGraphicsWidget(QGraphicsScene *scene)
: QObject(scene)
, m_current(0)
, m_angle(0)
, m_delta(0)
, m_scale(0)
{
for (int i = 0; i < 2; ++i)
m_proxyWidgets[i] = 0;
}
void TwoSidedGraphicsWidget::setWidget(int index, QWidget *widget)
{
if (index < 0 || index >= 2)
{
qWarning("TwoSidedGraphicsWidget::setWidget: Index out of bounds, index == %d", index);
return;
}
GraphicsWidget *proxy = new GraphicsWidget;
//保证ui在场景的最顶层不会被其他item遮住
proxy->setZValue(100);
proxy->setWidget(widget);
if (m_proxyWidgets[index])
delete m_proxyWidgets[index];
m_proxyWidgets[index] = proxy;
proxy->setCacheMode(QGraphicsItem::ItemCoordinateCache);
//只显示当前的GraphicsWidget
if (index != m_current)
proxy->setVisible(false);
//把widget添加到场景中
qobject_cast<QGraphicsScene *>(parent())->addItem(proxy);
}
QWidget *TwoSidedGraphicsWidget::widget(int index)
{
if (index < 0 || index >= 2)
{
qWarning("TwoSidedGraphicsWidget::widget: Index out of bounds, index == %d", index);
return 0;
}
return m_proxyWidgets[index]->widget();
}
void TwoSidedGraphicsWidget::flipwidget()
{
m_delta = (m_current == 0 ? 5 : -5);
m_scale = 100;
animateFlip();
}
void TwoSidedGraphicsWidget::hidewidget()
{
m_scale = 100;
m_delta = 720 / 2 / (100 - 6);
animateHide();
}
void TwoSidedGraphicsWidget::showidget()
{
if (!m_proxyWidgets[m_current]->isVisible())
{
m_delta = (m_current == 0 ? 5 : -5);
m_scale = 6;
Scene* pScene = qobject_cast<Scene*>(parent());
if (pScene)
{
int width = pScene->width();
int high = pScene->height();
QRectF r = m_proxyWidgets[m_current]->boundingRect();
//移动至屏幕中央
m_proxyWidgets[m_current]->setPos(width / 2 - r.width() / 2, high / 2 - r.height() / 2);
m_proxyWidgets[m_current]->setVisible(true);
animateShow();
}
}
}
void TwoSidedGraphicsWidget::animateFlip()
{
m_angle += m_delta;
if (m_angle == 90) {
int old = m_current;
m_current ^= 1;
m_proxyWidgets[old]->setVisible(false);
m_proxyWidgets[m_current]->setVisible(true);
m_proxyWidgets[m_current]->setGeometry(m_proxyWidgets[old]->geometry());
}
QRectF r = m_proxyWidgets[m_current]->boundingRect();
QTransform anTransform;
//把坐标系移动到widget的中心
anTransform.translate(r.width() / 2, r.height() / 2);
//围绕y轴旋转
anTransform.rotate(m_angle - 180 * m_current, Qt::YAxis);
//还原坐标系
anTransform.translate(-r.width() / 2, -r.height() / 2);
m_proxyWidgets[m_current]->setTransform(anTransform);
if ((m_current == 0 && m_angle > 0) || (m_current == 1 && m_angle < 180))
QTimer::singleShot(25, this, SLOT(animateFlip()));
}
void TwoSidedGraphicsWidget::animateHide()
{
m_scale -= 2;
m_scale < 6 ? 6 : m_scale;
m_angle += m_delta;
//缩放到15时隐藏ui,显示新的item
if(m_scale == 6)
{
m_proxyWidgets[m_current]->setVisible(false);
Scene* pScene = qobject_cast<Scene*>(parent());
if (pScene)
{
QRectF r = m_proxyWidgets[m_current]->boundingRect();
QWidget* pWidget = m_proxyWidgets[m_current]->widget();
//添加一个item
pScene->addItem(new CircleItem(64, pWidget->pos().x() + r.width() / 2, pWidget->pos().y() + r.height() / 2));
}
}
QRectF r = m_proxyWidgets[m_current]->boundingRect();
QTransform anTransform;
anTransform.translate(r.width() / 2, r.height() / 2);
anTransform.rotate(m_angle, Qt::ZAxis);
anTransform.scale(m_scale / 100.0f, m_scale / 100.0f);
anTransform.translate(-r.width() / 2, -r.height() / 2);
m_proxyWidgets[m_current]->setTransform(anTransform);
if (m_scale > 6)
{
QTimer::singleShot(25, this, SLOT(animateHide()));
}
}
void TwoSidedGraphicsWidget::animateShow()
{
m_scale += 2;
m_angle += m_delta;
if (m_scale == 100)
{
QTransform anTransform;
m_proxyWidgets[m_current]->setTransform(anTransform);
m_delta = 0;
m_scale = 0;
m_angle = (m_current == 0) ? 0 : 180;
return;
}
QRectF r = m_proxyWidgets[m_current]->boundingRect();
QTransform anTransform;
anTransform.translate(r.width() / 2, r.height() / 2);
anTransform.rotate(m_angle, Qt::ZAxis);
anTransform.scale(m_scale / 100.0f, m_scale / 100.0f);
anTransform.translate(-r.width() / 2, -r.height() / 2);
m_proxyWidgets[m_current]->setTransform(anTransform);
if (m_scale < 100)
{
QTimer::singleShot(25, this, SLOT(animateShow()));
}
}
QVariant GraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemPositionChange && scene()) {
QRectF rect = boundingRect();
QPointF pos = value.toPointF();
QRectF sceneRect = scene()->sceneRect();
if (pos.x() + rect.left() < sceneRect.left())
pos.setX(sceneRect.left() - rect.left());
else if (pos.x() + rect.right() >= sceneRect.right())
pos.setX(sceneRect.right() - rect.right());
if (pos.y() + rect.top() < sceneRect.top())
pos.setY(sceneRect.top() - rect.top());
else if (pos.y() + rect.bottom() >= sceneRect.bottom())
pos.setY(sceneRect.bottom() - rect.bottom());
return pos;
}
return QGraphicsProxyWidget::itemChange(change, value);
}
void GraphicsWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
{
setCacheMode(QGraphicsItem::ItemCoordinateCache);
QGraphicsProxyWidget::resizeEvent(event);
}
void GraphicsWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setRenderHint(QPainter::Antialiasing, false);
QGraphicsProxyWidget::paint(painter, option, widget);
painter->setRenderHint(QPainter::Antialiasing, true);
}
void GraphicsWidget::closeEvent(QCloseEvent* event)
{
QWidget* pWidget = widget();
if (pWidget)
{
if (pWidget->inherits("RenderOptionsDialog"))
{
qobject_cast<RenderOptionsDialog *>(pWidget)->emitHideWidget();
event->ignore();
}
else if ((pWidget->inherits("ItemDialog")))
{
qobject_cast<ItemDialog *>(pWidget)->emitHideWidget();
event->ignore();
}
}
}
//============================================================================//
// RenderOptionsDialog //
//============================================================================//
RenderOptionsDialog::RenderOptionsDialog()
: QDialog(0, Qt::CustomizeWindowHint | Qt::WindowTitleHint)
{
setWindowOpacity(0.75);
setWindowTitle(tr("Options (double click to flip)"));
QGridLayout *layout = new QGridLayout;
setLayout(layout);
layout->setColumnStretch(1, 1);
int row = 0;
QList<QString> filter = QStringList("*.par");
QList<QFileInfo> files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable);
foreach (QFileInfo fileInfo, files) {
QFile file(fileInfo.absoluteFilePath());
if (file.open(QIODevice::ReadOnly)) {
while (!file.atEnd()) {
QList<QByteArray> tokens = file.readLine().simplified().split(' ');
QList<QByteArray>::const_iterator it = tokens.begin();
if (it == tokens.end())
continue;
QByteArray type = *it;
if (++it == tokens.end())
continue;
QByteArray name = *it;
bool singleElement = (tokens.size() == 3); // type, name and one value
char counter[10] = "000000000";
int counterPos = 8; // position of last digit
while (++it != tokens.end()) {
m_parameterNames << name;
if (!singleElement) {
m_parameterNames.back() += '[';
m_parameterNames.back() += counter + counterPos;
m_parameterNames.back() += ']';
int j = 8; // position of last digit
++counter[j];
while (j > 0 && counter[j] > '9') {
counter[j] = '0';
++counter[--j];
}
if (j < counterPos)
counterPos = j;
}
if (type == "color") {
layout->addWidget(new QLabel(m_parameterNames.back()));
bool ok;
ColorEdit *colorEdit = new ColorEdit(it->toUInt(&ok, 16), m_parameterNames.size() - 1);
m_parameterEdits << colorEdit;
layout->addWidget(colorEdit);
connect(colorEdit, SIGNAL(colorChanged(QRgb,int)), this, SLOT(setColorParameter(QRgb,int)));
++row;
} else if (type == "float") {
layout->addWidget(new QLabel(m_parameterNames.back()));
bool ok;
FloatEdit *floatEdit = new FloatEdit(it->toFloat(&ok), m_parameterNames.size() - 1);
m_parameterEdits << floatEdit;
layout->addWidget(floatEdit);
connect(floatEdit, SIGNAL(valueChanged(float,int)), this, SLOT(setFloatParameter(float,int)));
++row;
}
}
}
file.close();
}
}
layout->addWidget(new QLabel(tr("Texture:")));
m_textureCombo = new QComboBox;
connect(m_textureCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(textureChanged(int)));
layout->addWidget(m_textureCombo);
++row;
layout->addWidget(new QLabel(tr("Shader:")));
m_shaderCombo = new QComboBox;
connect(m_shaderCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(shaderChanged(int)));
layout->addWidget(m_shaderCombo);
++row;
layout->setRowStretch(row, 1);
}
int RenderOptionsDialog::addTexture(const QString &name)
{
m_textureCombo->addItem(name);
return m_textureCombo->count() - 1;
}
int RenderOptionsDialog::addShader(const QString &name)
{
m_shaderCombo->addItem(name);
return m_shaderCombo->count() - 1;
}
void RenderOptionsDialog::emitParameterChanged()
{
foreach (ParameterEdit *edit, m_parameterEdits)
edit->emitChange();
}
void RenderOptionsDialog::emitHideWidget()
{
emit widgetHide();
}
void RenderOptionsDialog::setColorParameter(QRgb color, int id)
{
emit colorParameterChanged(m_parameterNames[id], color);
}
void RenderOptionsDialog::setFloatParameter(float value, int id)
{
emit floatParameterChanged(m_parameterNames[id], value);
}
void RenderOptionsDialog::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
emit doubleClicked();
}
//============================================================================//
// ItemDialog //
//============================================================================//
ItemDialog::ItemDialog()
: QDialog(0, Qt::CustomizeWindowHint | Qt::WindowTitleHint)
{
setWindowTitle(tr("Items (double click to flip)"));
setWindowOpacity(0.75);
resize(160, 100);
QVBoxLayout *layout = new QVBoxLayout;
setLayout(layout);
QPushButton *button;
button = new QPushButton(tr("Add Qt box"));
layout->addWidget(button);
connect(button, SIGNAL(clicked()), this, SLOT(triggerNewQtBox()));
button = new QPushButton(tr("Add circle"));
layout->addWidget(button);
connect(button, SIGNAL(clicked()), this, SLOT(triggerNewCircleItem()));
button = new QPushButton(tr("Add square"));
layout->addWidget(button);
connect(button, SIGNAL(clicked()), this, SLOT(triggerNewSquareItem()));
layout->addStretch(1);
}
void ItemDialog::emitHideWidget()
{
emit widgetHide();
}
void ItemDialog::triggerNewQtBox()
{
emit newItemTriggered(QtBoxItem);
}
void ItemDialog::triggerNewCircleItem()
{
emit newItemTriggered(CircleItem);
}
void ItemDialog::triggerNewSquareItem()
{
emit newItemTriggered(SquareItem);
}
void ItemDialog::mouseDoubleClickEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
emit doubleClicked();
}
//============================================================================//
// Scene //
//============================================================================//
Scene::Scene(int width, int height, int maxTextureSize)
: m_distExp(600)
, m_frame(0)
, m_maxTextureSize(maxTextureSize)
, m_currentShader(0)
, m_currentTexture(0)
, m_box(0)
, m_vertexShader(0)
, m_environment(0)
, m_environmentShader(0)
, m_environmentProgram(0)
{
setSceneRect(0, 0, width, height);
m_trackBalls[0] = TrackBall(0.05f, QVector3D(0, 1, 0), TrackBall::Sphere);
m_trackBalls[1] = TrackBall(0.005f, QVector3D(0, 0, 1), TrackBall::Sphere);
m_trackBalls[2] = TrackBall(0.0f, QVector3D(0, 1, 0), TrackBall::Plane);
//渲染设置对话框
m_renderOptions = new RenderOptionsDialog;
m_renderOptions->move(20, 120);
m_renderOptions->resize(m_renderOptions->sizeHint());
connect(m_renderOptions, SIGNAL(colorParameterChanged(QString,QRgb)), this, SLOT(setColorParameter(QString,QRgb)));
connect(m_renderOptions, SIGNAL(floatParameterChanged(QString,float)), this, SLOT(setFloatParameter(QString,float)));
connect(m_renderOptions, SIGNAL(textureChanged(int)), this, SLOT(setTexture(int)));
connect(m_renderOptions, SIGNAL(shaderChanged(int)), this, SLOT(setShader(int)));
m_itemDialog = new ItemDialog;
connect(m_itemDialog, SIGNAL(newItemTriggered(ItemDialog::ItemType)), this, SLOT(newItem(ItemDialog::ItemType)));
m_twoSidedGraphicsWidget = new TwoSidedGraphicsWidget(this);
m_twoSidedGraphicsWidget->setWidget(0, m_renderOptions);
m_twoSidedGraphicsWidget->setWidget(1, m_itemDialog);
connect(m_renderOptions, SIGNAL(doubleClicked()), m_twoSidedGraphicsWidget, SLOT(flipwidget()));
connect(m_itemDialog, SIGNAL(doubleClicked()), m_twoSidedGraphicsWidget, SLOT(flipwidget()));
connect(m_renderOptions, SIGNAL(widgetHide()), m_twoSidedGraphicsWidget, SLOT(hidewidget()));
connect(m_itemDialog, SIGNAL(widgetHide()), m_twoSidedGraphicsWidget, SLOT(hidewidget()));
addItem(new QtBox(64, width - 64, height - 64));
addItem(new QtBox(64, width - 64, 64));
addItem(new QtBox(64, 64, height - 64));
addItem(new QtBox(64, 64, 64));
initGL();
m_timer = new QTimer(this);
m_timer->setInterval(20);
connect(m_timer, SIGNAL(timeout()), this, SLOT(update()));
m_timer->start();
m_cameraPos = QVector3D(0.0, 0.0, 1.0);
m_cameraFront = QVector3D(0, 0, -40);
m_cameraUp = QVector3D(0, 1, 0);
}
Scene::~Scene()
{
if (m_box)
delete m_box;
foreach (GLTexture *texture, m_textures)
if (texture) delete texture;
if (m_mainCubemap)
delete m_mainCubemap;
foreach (QGLShaderProgram *program, m_programs)
if (program) delete program;
if (m_vertexShader)
delete m_vertexShader;
foreach (QGLShader *shader, m_fragmentShaders)
if (shader) delete shader;
if (m_environmentShader)
delete m_environmentShader;
if (m_environmentProgram)
delete m_environmentProgram;
}
void Scene::initGL()
{
//生成有圆角的立方体的顶点数组和索引数组并绑定
m_box = new GLRoundedBox(0.25f/*圆角大小*/, 1.0f/*缩放比*/, 20/*每一个圆角的顶点数,顶点数越多越圆润*/);
//编译顶点着色器
m_vertexShader = new QGLShader(QGLShader::Vertex);
m_vertexShader->compileSourceFile(QLatin1String(":/res/boxes/basic.vsh"));
//天空盒渲染程序准备
{
QStringList list;
list << ":/res/boxes/cubemap_posx.jpg" << ":/res/boxes/cubemap_negx.jpg" << ":/res/boxes/cubemap_posy.jpg"
<< ":/res/boxes/cubemap_negy.jpg" << ":/res/boxes/cubemap_posz.jpg" << ":/res/boxes/cubemap_negz.jpg";
//初始化立方体贴图
m_environment = new GLTextureCube(list, qMin(1024, m_maxTextureSize));
//编译天空盒着色器
m_environmentShader = new QGLShader(QGLShader::Fragment);
m_environmentShader->compileSourceFile(QLatin1String(":/res/boxes/skybox.fsh"));
//创建天空盒可编程渲染管线程序
m_environmentProgram = new QGLShaderProgram;
//顶点着色器
m_environmentProgram->addShader(m_vertexShader);
//像素着色器
m_environmentProgram->addShader(m_environmentShader);
//链接程序
m_environmentProgram->link();
}
//噪声数据
{
const int NOISE_SIZE = 128;
m_noise = new GLTexture3D(NOISE_SIZE, NOISE_SIZE, NOISE_SIZE);
QRgb *data = new QRgb[NOISE_SIZE * NOISE_SIZE * NOISE_SIZE];
memset(data, 0, NOISE_SIZE * NOISE_SIZE * NOISE_SIZE * sizeof(QRgb));
QRgb *p = data;
float pos[3];
for (int k = 0; k < NOISE_SIZE; ++k) {
pos[2] = k * (0x20 / (float)NOISE_SIZE);
for (int j = 0; j < NOISE_SIZE; ++j) {
for (int i = 0; i < NOISE_SIZE; ++i) {
for (int byte = 0; byte < 4; ++byte) {
pos[0] = (i + (byte & 1) * 16) * (0x20 / (float)NOISE_SIZE);
pos[1] = (j + (byte & 2) * 8) * (0x20 / (float)NOISE_SIZE);
*p |= (int)(128.0f * (noise3(pos) + 1.0f)) << (byte * 8);
}
++p;
}
}
}
m_noise->load(NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, data);
delete[] data;
}
//所有的boxes设置
{
m_mainCubemap = new GLRenderTargetCube(512);
QStringList filter;
QList<QFileInfo> files;
//加载所有的png图片
m_currentTexture = 0;
filter = QStringList("*.png");
files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable);
foreach(QFileInfo file, files) {
GLTexture *texture = new GLTexture2D(file.absoluteFilePath(), qMin(256, m_maxTextureSize), qMin(256, m_maxTextureSize));
if (texture->failed()) {
delete texture;
continue;
}
m_textures << texture;
m_renderOptions->addTexture(file.baseName());
}
//加载所有的像素着色器程序
m_currentShader = 0;
filter = QStringList("*.fsh");
files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable);
foreach(QFileInfo file, files) {
//排除天空壳
QString fileName = file.fileName();
if(fileName.indexOf("skybox") != -1)
{
continue;
}
if (fileName.indexOf("box_shader") != -1)
{
continue;
}
QGLShaderProgram *program = new QGLShaderProgram;
QGLShader* shader = new QGLShader(QGLShader::Fragment);
shader->compileSourceFile(file.absoluteFilePath());
// The program does not take ownership over the shaders, so store them in a vector so they can be deleted afterwards.
program->addShader(m_vertexShader);
program->addShader(shader);
if (!program->link()) {
qWarning("Failed to compile and link shader program");
qWarning("Vertex shader log:");
qWarning() << m_vertexShader->log();
qWarning() << "Fragment shader log ( file =" << file.absoluteFilePath() << "):";
qWarning() << shader->log();
qWarning("Shader program log:");
qWarning() << program->log();
delete shader;
delete program;
continue;
}
m_fragmentShaders << shader;
m_programs << program;
m_renderOptions->addShader(file.baseName());
program->bind();
program->release();
}
m_renderOptions->emitParameterChanged();
}
}
// If one of the boxes should not be rendered, set excludeBox to its index.
// If the main box should not be rendered, set excludeBox to -1.
void Scene::renderBoxes(const QMatrix4x4 &projection_mat, const QMatrix4x4 &view_mat, const QMatrix4x4 &model_mat, int skybox)
{
QMatrix4x4 lightview = view_mat * model_mat;
QMatrix4x4 invView = (view_mat * model_mat).inverted();
// If multi-texturing is supported, use three saplers.
if (glActiveTexture) {
//设置texture0当前选择的纹理(GL_TEXTURE?需要跟m_programs[i]->setUniformValue("tex", GLint(0))第二个参数的数保持一致)
glActiveTexture(GL_TEXTURE0);
m_textures[m_currentTexture]->bind();
//天空壳纹理
glActiveTexture(GL_TEXTURE0 + m_environment->textureId());
m_environment->bind();
//设置texture2为3d噪声
glActiveTexture(GL_TEXTURE0 + m_noise->textureId());
m_noise->bind();
} else {
m_textures[m_currentTexture]->bind();
}
if (skybox)
{
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
glDepthFunc(GL_LEQUAL);
//天空壳
if (glActiveTexture && skybox)
{
QMatrix4x4 skymodel_mat(model_mat);
skymodel_mat.scale(20.0f, 20.0f, 20.0f);
QMatrix3x3 normal_mat = (view_mat * skymodel_mat).normalMatrix();
m_environmentProgram->bind();
//告诉着色器环境纹理使用第二个纹理
m_environmentProgram->setUniformValue("env", m_environment->textureId());
m_environmentProgram->setUniformValue("projection_mat", projection_mat);
m_environmentProgram->setUniformValue("view_mat", view_mat);
m_environmentProgram->setUniformValue("model_mat", skymodel_mat);
m_environmentProgram->setUniformValue("normal_mat", normal_mat);
m_environmentProgram->setUniformValue("lightview", lightview);
m_environmentProgram->setUniformValue("render_type", 1);
setLights(m_environmentProgram);
m_box->draw(m_environmentProgram);
m_environmentProgram->release();
m_environment->unbind();
}
glDepthFunc(GL_LESS);
}
else
{
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
//渲染环形立方体
for (int i = 0; i < m_programs.size(); ++i)
{
QMatrix4x4 cubemodel_mat;
cubemodel_mat.rotate(m_trackBalls[1].rotation());
cubemodel_mat = model_mat * cubemodel_mat;
cubemodel_mat.rotate(360.0f * i / m_programs.size(), 0.0f, 0.0f, 1.0f);
cubemodel_mat.translate(2.0f, 0.0f, 0.0f);
cubemodel_mat.scale(0.3f, 0.6f, 0.6f);
//法线矩阵
QMatrix3x3 normal_mat = (view_mat * cubemodel_mat).normalMatrix();
if (glActiveTexture) {
m_environment->bind();
}
m_programs[i]->bind();
//告诉着色器环境纹理
m_programs[i]->setUniformValue("tex", GLint(0));
//告诉着色器环境纹理
m_programs[i]->setUniformValue("env", m_environment->textureId());
//告诉着色器环境噪声紋理
m_programs[i]->setUniformValue("noise", m_noise->textureId());
m_programs[i]->setUniformValue("invView", invView);
m_programs[i]->setUniformValue("projection_mat", projection_mat);
m_programs[i]->setUniformValue("view_mat", view_mat);
m_programs[i]->setUniformValue("model_mat", cubemodel_mat);
m_programs[i]->setUniformValue("normal_mat", normal_mat);
m_programs[i]->setUniformValue("lightview", lightview);
m_programs[i]->setUniformValue("light_position", QVector4D(0.0f, 0.0f, 1.0f, 0.0f));
m_programs[i]->setUniformValue("light_ambient", QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
m_programs[i]->setUniformValue("light_diffuse", QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
m_programs[i]->setUniformValue("light_specular", QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
m_programs[i]->setUniformValue("material_specular", QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
m_programs[i]->setUniformValue("material_shininess", 1.0F);
m_environmentProgram->setUniformValue("render_type", 0);
setLights(m_programs[i]);
m_box->draw(m_programs[i]);
m_programs[i]->release();
if (glActiveTexture) {
m_environment->unbind();
}
}
//渲染中心的立方体
{
QMatrix4x4 cubemodel_mat;
cubemodel_mat.rotate(m_trackBalls[0].rotation());
cubemodel_mat = model_mat * cubemodel_mat;
QMatrix3x3 normal_mat = (view_mat * cubemodel_mat).normalMatrix();
if (glActiveTexture) {
m_mainCubemap->bind();
}
m_programs[m_currentShader]->bind();
m_programs[m_currentShader]->setUniformValue("tex", GLint(0));
m_programs[m_currentShader]->setUniformValue("env", m_environment->textureId());
m_programs[m_currentShader]->setUniformValue("noise", m_noise->textureId());
m_programs[m_currentShader]->setUniformValue("invView", invView);
m_programs[m_currentShader]->setUniformValue("projection_mat", projection_mat);
m_programs[m_currentShader]->setUniformValue("view_mat", view_mat);
m_programs[m_currentShader]->setUniformValue("model_mat", cubemodel_mat);
m_programs[m_currentShader]->setUniformValue("lightview", lightview);
m_programs[m_currentShader]->setUniformValue("normal_mat", normal_mat);
m_programs[m_currentShader]->setUniformValue("lightview", lightview);
m_programs[m_currentShader]->setUniformValue("light_position", QVector4D(0.0f, 0.0f, 1.0f, 0.0f));
m_programs[m_currentShader]->setUniformValue("light_ambient", QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
m_programs[m_currentShader]->setUniformValue("light_diffuse", QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
m_programs[m_currentShader]->setUniformValue("light_specular", QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
m_programs[m_currentShader]->setUniformValue("material_specular", QVector4D(1.0f, 1.0f, 1.0f, 1.0f));
m_programs[m_currentShader]->setUniformValue("material_shininess", 1.0F);
m_environmentProgram->setUniformValue("render_type", 0);
setLights(m_programs[m_currentShader]);
m_box->draw(m_programs[m_currentShader]);
m_programs[m_currentShader]->release();
if (glActiveTexture) {
m_mainCubemap->unbind();
}
}
if (glActiveTexture) {
glActiveTexture(GL_TEXTURE2);
m_noise->unbind();
glActiveTexture(GL_TEXTURE0);
}
m_textures[m_currentTexture]->unbind();
}
}
void Scene::initOpenGLParams()
{
//glClearColor(0.25f, 0.25f, 0.5f, 1.0f);
//初始化openl功能开关
glEnable(GL_DEPTH_TEST); //开启深度测试
glEnable(GL_CULL_FACE); //开启遮挡剔除
glEnable(GL_LIGHTING); //开启灯源
glEnable(GL_COLOR_MATERIAL);//开启图形(材料)根据光线的照耀进行反射。
glEnable(GL_TEXTURE_2D); //开启二维文理
glEnable(GL_NORMALIZE); //开启法向量
float materialSpecular[] = { 0.5f, 0.5f, 0.5f, 1.0f };
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 32.0f);
}
void Scene::setLights(QGLShaderProgram* program)
{
if (program)
{
QVector4D lightDir(0.0f, 0.0f, 1.0f, 0.0f );
QVector4D lightam(0.2,0.2,0.2,1.0 );
QVector4D lightdif(0.8,0.8,0.8,1.0 );
QVector4D lightspe(1.0,1.0,1.0,1.0f );
QVector4D materialSpecular(0.5f, 0.5f, 0.5f, 1.0f);
//光照位置
program->setUniformValue("light_position", lightDir);
//环境光颜色
program->setUniformValue("light_ambient", lightam);
//漫反射光颜色
program->setUniformValue("light_diffuse", lightdif);
//镜面反射光颜色
program->setUniformValue("light_specular", lightspe);
//材质反射光颜色
program->setUniformValue("material_specular", materialSpecular);
//材质镜面反射指数[0,128]
program->setUniformValue("material_shininess", 32.0f);
}
}
void Scene::drawBackground(QPainter *painter, const QRectF &rect)
{
float width = float(painter->device()->width());
float height = float(painter->device()->height());
//使用opengl绘制3d背景
{
//准备绘制
painter->beginNativePainting();
//初始化opengl参数
initOpenGLParams();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//投影变换矩阵(有两种:正射投影和透视投影),这里我们创建一个透视投影
//https://learnopengl-cn.github.io/01%20Getting%20started/08%20Coordinate%20Systems/
QMatrix4x4 projection;
projection.perspective(60.0, width / height, 0.01, 20.0);
//渲染天空壳
{
//观察矩阵(眼睛的位置)
QMatrix4x4 view;
//天空壳不随w,a,s,d移动
view.lookAt(QVector3D(0.0, 0.0, 1.0), QVector3D(0, 0, -20), QVector3D(0, 1, 0));
//模型变换矩阵
QMatrix4x4 model;
view.rotate(m_trackBalls[2].rotation());
view.translate(QVector3D(0, 0, -2.0f * std::exp(m_distExp / 1200.0f)));
renderBoxes(projection, view, model, 1);
}
//渲染立方体
{
//观察矩阵(眼睛的位置)
QMatrix4x4 view;
view.lookAt(m_cameraPos, m_cameraPos + m_cameraFront, m_cameraUp);
//模型变换矩阵
QMatrix4x4 model;
view.rotate(m_trackBalls[2].rotation());
view.translate(QVector3D(0, 0, -2.0f * std::exp(m_distExp / 1200.0f)));
renderBoxes(projection, view, model,0);
}
++m_frame;
//结束绘制
painter->endNativePainting();
}
}
QPointF Scene::pixelPosToViewPos(const QPointF& p)
{
return QPointF(2.0 * float(p.x()) / width() - 1.0,
1.0 - 2.0 * float(p.y()) / height());
}
void Scene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsScene::mouseMoveEvent(event);
if (event->isAccepted())
return;
if (event->buttons() & Qt::LeftButton) {
m_trackBalls[0].move(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
event->accept();
} else {
m_trackBalls[0].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
}
if (event->buttons() & Qt::RightButton) {
m_trackBalls[1].move(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
event->accept();
} else {
m_trackBalls[1].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
}
if (event->buttons() & Qt::MidButton) {
m_trackBalls[2].move(pixelPosToViewPos(event->scenePos()), QQuaternion());
event->accept();
} else {
m_trackBalls[2].release(pixelPosToViewPos(event->scenePos()), QQuaternion());
}
}
void Scene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsScene::mousePressEvent(event);
if (event->isAccepted())
return;
if (event->buttons() & Qt::LeftButton) {
m_trackBalls[0].push(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
event->accept();
}
if (event->buttons() & Qt::RightButton) {
m_trackBalls[1].push(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
event->accept();
}
if (event->buttons() & Qt::MidButton) {
m_trackBalls[2].push(pixelPosToViewPos(event->scenePos()), QQuaternion());
event->accept();
}
}
void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsScene::mouseReleaseEvent(event);
if (event->isAccepted())
return;
if (event->button() == Qt::LeftButton) {
m_trackBalls[0].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
event->accept();
}
if (event->button() == Qt::RightButton) {
m_trackBalls[1].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
event->accept();
}
if (event->button() == Qt::MidButton) {
m_trackBalls[2].release(pixelPosToViewPos(event->scenePos()), QQuaternion());
event->accept();
}
}
void Scene::wheelEvent(QGraphicsSceneWheelEvent * event)
{
QGraphicsScene::wheelEvent(event);
if (!event->isAccepted())
{
m_distExp -= event->delta();
if (m_distExp < -8 * 120)
m_distExp = -8 * 120;
if (m_distExp > 10 * 120)
m_distExp = 10 * 120;
event->accept();
}
}
void Scene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsScene::mouseDoubleClickEvent(event);
//获取双击的item
QGraphicsItem* item = mouseGrabberItem();
if (item)
{
//如果圆环
if (item->type() == ItemBase::ItemCircle)
{
m_twoSidedGraphicsWidget->showidget();
delete item;
item = NULL;
}
}
}
void Scene::keyPressEvent(QKeyEvent *event)
{
float camraSpeed = 0.05f;
if (event->key() == Qt::Key_W)
{
m_cameraPos += camraSpeed * m_cameraFront;
}
else if (event->key() == Qt::Key_A)
{
m_cameraPos -= (QVector3D::crossProduct(m_cameraFront, m_cameraUp) * camraSpeed).normalized();
}
else if (event->key() == Qt::Key_S)
{
m_cameraPos -= camraSpeed * m_cameraFront;
}
else if (event->key() == Qt::Key_D)
{
m_cameraPos += (QVector3D::crossProduct(m_cameraFront, m_cameraUp) * camraSpeed).normalized();
}
}
void Scene::setShader(int index)
{
if (index >= 0 && index < m_fragmentShaders.size())
m_currentShader = index;
}
void Scene::setTexture(int index)
{
if (index >= 0 && index < m_textures.size())
m_currentTexture = index;
}
void Scene::setColorParameter(const QString &name, QRgb color)
{
// set the color in all programs
foreach (QGLShaderProgram *program, m_programs) {
program->bind();
program->setUniformValue(program->uniformLocation(name), QColor(color));
program->release();
}
}
void Scene::setFloatParameter(const QString &name, float value)
{
// set the color in all programs
foreach (QGLShaderProgram *program, m_programs) {
program->bind();
program->setUniformValue(program->uniformLocation(name), value);
program->release();
}
}
void Scene::newItem(ItemDialog::ItemType type)
{
QSize size = sceneRect().size().toSize();
switch (type) {
case ItemDialog::QtBoxItem:
addItem(new QtBox(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
break;
case ItemDialog::CircleItem:
addItem(new CircleItem(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
break;
case ItemDialog::SquareItem:
addItem(new SquareItem(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
break;
default:
break;
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/DGuco/qtproject.git
git@gitee.com:DGuco/qtproject.git
DGuco
qtproject
qtproject
master

搜索帮助