QT3D with C ++ and rotation - c++

I hope someone can help me with this problem. I am new to working with QT3D and I need to make a Qt3D application using QT C++ for a task, the problem I have is that I need to rotate the figure from a specific point but it always rotates from the center point. How can I specify that the rotation is made from one of the pivots in the figure? I need it to be able to simulate the movement of a pendulum. Please help someone who tells me how I can solve this problem, here is my code.
void window::paint(){
arm1 = new Qt3DExtras::QCylinderMesh();
arm1->setRadius(0.5);
arm1->setLength(3);
arm1Transform = new Qt3DCore::QTransform();
arm1Transform->setTranslation(QVector3D(-3, 3, 0));
arm1Transform->setScale(1.5f);
Qt3DExtras::QPhongMaterial *arm1Material = new Qt3DExtras::QPhongMaterial();
arm1Material->setDiffuse(Qt::red);
arm1Entity = new Qt3DCore::QEntity(rootEntity);
arm1Entity->addComponent(arm1);
arm1Entity->addComponent(arm1Material);
arm1Entity->addComponent(arm1Transform);
}
void window::on_pushButton_clicked(){
arm1Transform->setRotation(QQuaternion::fromAxisAndAngle(QVector3D(1.0f, 0.0f, 0.0f), angle++));
}
Thanks in advance.

You can make arm1Entity to be a child of a new QEntity. This new QEntity will be positioned at the point where you want to rotate from. So if you rotate the new QEntity, his child arm1Entity will rotate from the new QEntity's position.
EDIT code (not tested):
void window::paint(){
arm1PivotEntity = new Qt3DCore::QEntity(rootEntity);
arm1PivotTransform = new Qt3DCore::QTransform(arm1PivotEntity);
arm1PivotTransform->setTranslation(QVector3D(/*desired pivot position*/));
arm1PivotEntity->addComponent(arm1PivotTransform);
arm1 = new Qt3DExtras::QCylinderMesh();
arm1->setRadius(0.5);
arm1->setLength(3);
arm1Transform = new Qt3DCore::QTransform();
// as arm1 is now child of arm1 pivot, you need to set the relative position
arm1Transform->setTranslation(QVector3D(/*relative position to arm1pivot position*/));
arm1Transform->setScale(1.5f);
Qt3DExtras::QPhongMaterial *arm1Material = new Qt3DExtras::QPhongMaterial();
arm1Material->setDiffuse(Qt::red);
// made arm1 child of arm1pivot so it will inherits its rotation
arm1Entity = new Qt3DCore::QEntity(arm1PivotEntity);
arm1Entity->addComponent(arm1);
arm1Entity->addComponent(arm1Material);
arm1Entity->addComponent(arm1Transform);
}
void window::on_pushButton_clicked(){
arm1PivotTransform->setRotation(angle++));
}

Related

Qt 3D: How to draw a cube with different textures on each face?

I'm new to Qt 3D (C++), and while I'm training with my first 3D app, I couldn't achieve the following:
Creating a cube with 6 different textures on each face... Until now, this is what I've tried:
// Cuboid shape data
Qt3DExtras::QCuboidMesh *cuboid = new Qt3DExtras::QCuboidMesh();
// CuboidMesh Transform
Qt3DCore::QTransform *cuboidTransform = new Qt3DCore::QTransform();
cuboidTransform->setScale(2.0f);
Qt3DExtras::QTextureMaterial *textureMaterial = new Qt3DExtras::QTextureMaterial();
Qt3DRender::QTextureCubeMap *cubMap = new Qt3DRender::QTextureCubeMap();
Qt3DRender::QTextureImage *f1 = new Qt3DRender::QTextureImage();
Qt3DRender::QTextureImage *f2 = new Qt3DRender::QTextureImage();
Qt3DRender::QTextureImage *f3 = new Qt3DRender::QTextureImage();
Qt3DRender::QTextureImage *f4 = new Qt3DRender::QTextureImage();
Qt3DRender::QTextureImage *f5 = new Qt3DRender::QTextureImage();
Qt3DRender::QTextureImage *f6 = new Qt3DRender::QTextureImage();
f1->setSource(QUrl("qrc:/rc/images/cubemap1.png"));
f1->setFace(Qt3DRender::QAbstractTexture::CubeMapNegativeX);
f2->setSource(QUrl("qrc:/rc/images/cubemap2.png"));
f2->setFace(Qt3DRender::QAbstractTexture::CubeMapPositiveX);
f3->setSource(QUrl("qrc:/rc/images/cubemap3.png"));
f3->setFace(Qt3DRender::QAbstractTexture::CubeMapNegativeY);
f4->setSource(QUrl("qrc:/rc/images/cubemap4.png"));
f4->setFace(Qt3DRender::QAbstractTexture::CubeMapPositiveY);
f5->setSource(QUrl("qrc:/rc/images/cubemap5.png"));
f5->setFace(Qt3DRender::QAbstractTexture::CubeMapNegativeZ);
f6->setSource(QUrl("qrc:/rc/images/cubemap6.png"));
f6->setFace(Qt3DRender::QAbstractTexture::CubeMapPositiveZ);
cubMap->addTextureImage(f1);
cubMap->addTextureImage(f2);
cubMap->addTextureImage(f3);
cubMap->addTextureImage(f4);
cubMap->addTextureImage(f5);
cubMap->addTextureImage(f6);
textureMaterial->setTexture(cubMap);
//Cuboid
m_cuboidEntity = new Qt3DCore::QEntity(m_rootEntity);
m_cuboidEntity->addComponent(cuboid);
m_cuboidEntity->addComponent(textureMaterial);
m_cuboidEntity->addComponent(cuboidTransform);
But it gives me a black cube.
I've googled for an example, but all I find is written in OpenGl, which I'm not familiar with. I believe it's possible using Qt C++ Classes only.
I would appreciate your help.
This could be related to back face culling.
could you set the following in your renderer?
activeFrameGraph: ForwardRenderer {
...
frustumCulling: false
}
When using Skybox (which is basically a CuboidMesh with different images on it), this is mandatory. Could be needed here too.
Try using f1->setSource(QUrl::fromLocalFile("...")); instead f1->setSource(QUrl("..."));, etc.
And remember about Status

Positionning particle in node

Using cocos2d, I'm trying to replace a sprite (item in my code) with a particle system. This code is placed in my board class. This one works:
// Draw the particles
CCParticleSystem *particles = [[CCParticleSystem alloc] initWithDictionary:_popParticles];
particles.position = ccpSub(item.position,ccp(160,160));
particles.autoRemoveOnFinish = TRUE;
[self addChild:particles];
This one doesn't:
// Draw the particles
CCParticleSystem *particles = [[CCParticleSystem alloc] initWithDictionary:_popParticles];
particles.position = item.position;
particles.autoRemoveOnFinish = TRUE;
[self addChild:particles];
I tried player with this but without success:
particles.positionType = CCPositionTypeMake(CCPositionUnitUIPoints, CCPositionUnitUIPoints, CCPositionReferenceCornerBottomLeft);
My board is a 320x320 points CCSprite with anchor point set at 0.5, 0.5
When I log my item.position value, I get something relative to the bottom left corner of my board (from 30,30 to 290,290)
Is using ccpSub the correct way ?
When you destroy a node you also destroy all of it's children nodes, you said you add your particle to 'item' then you destroy that 'item', which means you have no particle anymore.

Rotating CCSprite thats an equilateral triangle

I have an CCSprite thats an equilateral triangle. I want to rotate the triangle in 60 degree increments holding its position.
The sprite is 126x110 (not square) setting the sprites rotation property in 60 degree increments changes the position of the sprite. How can i keep the sprite appear stationary at each rotation?
A bit more about this the center of the rectangle IS NOT the center of the sprite. So there is some adjustment needed when the rotation is needed to keep the center of the triangle appearing centered.
I think i came up with a long answer that needs to be approved..
// collect points.
self.point1 = CGPointMake(CGRectGetWidth(self.tile.boundingBox)/2, 0);
self.point2 = CGPointMake(CGRectGetWidth(self.tile.boundingBox), CGRectGetHeight(self.tile.boundingBox));
self.point3 = CGPointMake(0, CGRectGetHeight(self.tile.boundingBox));
// calculcate the mid point.
float midPointX = floor((self.point1.x + self.point2.x + self.point3.x)/3.0);
float midPointY = floor((self.point1.y + self.point2.y + self.point3.y)/3.0);
// stash the center of the triangle
self.triangleCenter = CGPointMake(midPointX, midPointY);
Then figure out new location of the center point based on rotation.. And animate there. (Sorry about hard coded center of the screen this was a rough test).
-(void) rotateToAngleAboutCenter:(float)angle {
// stash old values.
CGPoint oldPosition = self.tile.position;
float oldRotation = self.tile.rotation;
// reset the rotation
self.tile.rotation = 0;
// this is hard coded here currently the center of the screen.
self.tile.position = ccp(512, 384);
// figure out where our center point will be when we are rotated about the center.
CGPoint point = ccpRotateByAngle(self.triangleCenter, [self.tile anchorPointInPoints],-CC_DEGREES_TO_RADIANS(angle));
// convert the ppoint to local space.
point = [self.tile convertToWorldSpace:point];
point = [self convertToNodeSpace:point];
// reset the rotation and position.
self.tile.rotation = oldRotation;
self.tile.position = oldPosition;
// animate to new rotation/position.
CCMoveTo* moveTo = [CCMoveTo actionWithDuration:.25 position:point];
CCRotateTo* rotateTo = [CCRotateTo actionWithDuration:.25 angle:angle];
[self.tile runAction:moveTo];
[self.tile runAction:rotateTo];
}

MiniMap/PIP for OpenSceneGraph

So I am trying to create a mini-map/PIP. I have an existing program with scene that runs inside a Qt Widget. I have a class, NetworkViewer, which extends CompositeViewer. In NetworkViewer's constructor I call the following function. Notice the root is the scene which is populated elsewhere.
void NetworkViewer::init() {
root = new osg::Group() ;
viewer = new osgViewer::View( );
viewer->setSceneData( root ) ;
osg::Camera* camera ;
camera = createCamera(0,0,100,100) ;
viewer->setCamera( camera );
viewer->addEventHandler( new NetworkGUIHandler( (GUI*)view ) ) ;
viewer->setCameraManipulator(new osgGA::TrackballManipulator) ;
viewer->getCamera()->setClearColor(
osg::Vec4( LIGHT_CLOUD_BLUE_F,0.0f));
addView( viewer );
osgQt::GraphicsWindowQt* gw =
dynamic_cast( camera->getGraphicsContext() );
QWidget* widget = gw ? gw->getGLWidget() : NULL;
QGridLayout* grid = new QGridLayout( ) ;
grid->addWidget( widget );
grid->setSpacing(1);
grid->setMargin(1);
setLayout( grid );
initHUD( ) ;
}
The create camera function is as follows:
osg::Camera* createCamera( int x, int y, int w, int h ) {
osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
osg::ref_ptr traits
= new osg::GraphicsContext::Traits;
traits->windowName = "" ;
traits->windowDecoration = false ;
traits->x = x;
traits->y = y;
traits->width = w;
traits->height = h;
traits->doubleBuffer = true;
traits->alpha = ds->getMinimumNumAlphaBits();
traits->stencil = ds->getMinimumNumStencilBits();
traits->sampleBuffers = ds->getMultiSamples();
traits->samples = ds->getNumMultiSamples();
osg::ref_ptr camera = new osg::Camera;
camera->setGraphicsContext( new osgQt::GraphicsWindowQt(traits.get()) );
camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
camera->setViewMatrix(osg::Matrix::translate(-10.0f,-10.0f,-30.0f));
camera->setProjectionMatrixAsPerspective(
20.0f,
static_cast(traits->width)/static_cast(traits->height),
1.0f, 10000.0f );
return camera.release();
}
I have been looking at several camera examples and searching for a solution for a while to no avail. What I am really looking for is the background being my main camera which takes up most of the screen and displays the scene graph while my mini-map appears in the bottom right. It has the same scene as the main camera but is overlaid on top of it and has its own set of controls for selection etc since it will have different functionality.
I was thinking that perhaps by adding another camera as a slave I would be able to do this:
camera = createCamera(40,40,50,50) ;
viewer->addSlave(camera) ;
But this doesn't seem to work. If I disable the other camera I do see a clear area that it appears this camera was suppose to be rendering in (its viewport) but that doesn't help. I've played around with rendering order thinking it could be that to no avail.
Any ideas? What it the best way to do such a minimap is? What am I doing wrong? Also anyway to make the rendering of the minimap circular instead of rectangular?
I am not personnally using OpenSceneGraph, so I can't advise you on your code. I think the best is to ask in the official forums. But I have some ideas on the minimap:
First, you have to specify the basic features of your minimap. Do you want it to emphasize some elements of the scene, or just show the scene (ie, RTS-like minimap vs simple top-show of the scene) ?
I assume you do not want to emphasize some elements of the scene. I also assume your main camera is not really 'minimap-friendly'. So, the simplest is to create a camera with the following properties:
direction = (0,-1,0) (Y is the vertical axis)
mode = orthographic
position = controlled by what you want, for example your main camera
Now, for the integration of the image. You can:
set the viewport of the minimap camera to what you want, if your minimap is rectangular.
render the minimap to a texture (RTT) and then blend it through an extra rendering pass.
You can also search other engines forums (like Irrlicht and Ogre) to see how they're doing minimaps.

How do you stop OgreBullet Capsule from falling over?

I've just started implementing bullet into my Ogre project. I follows the install instructions here: http://www.ogre3d.org/tikiwiki/OgreBullet+Tutorial+1
And the rest if the tutorial here:
http://www.ogre3d.org/tikiwiki/OgreBullet+Tutorial+2
I got that to work fine however now I wanted to extend it to a handle a first person camera. I created a CapsuleShape and a Rigid Body (like the tutorial did for the boxes) however when I run the game the capsule falls over and rolls around on the floor, causing the camera swing wildly around.
I need a way to fix the capsule to always stay upright, but I have no idea how
Below is the code I'm using.
(part of) Header File
OgreBulletDynamics::DynamicsWorld *mWorld; // OgreBullet World
OgreBulletCollisions::DebugDrawer *debugDrawer;
std::deque<OgreBulletDynamics::RigidBody *> mBodies;
std::deque<OgreBulletCollisions::CollisionShape *> mShapes;
OgreBulletCollisions::CollisionShape *character;
OgreBulletDynamics::RigidBody *characterBody;
Ogre::SceneNode *charNode;
Ogre::Camera* mCamera;
Ogre::SceneManager* mSceneMgr;
Ogre::RenderWindow* mWindow;
main file
bool MinimalOgre::go(void)
{
...
mCamera = mSceneMgr->createCamera("PlayerCam");
mCamera->setPosition(Vector3(0,0,0));
mCamera->lookAt(Vector3(0,0,300));
mCamera->setNearClipDistance(5);
mCameraMan = new OgreBites::SdkCameraMan(mCamera);
OgreBulletCollisions::CollisionShape *Shape;
Shape = new OgreBulletCollisions::StaticPlaneCollisionShape(Vector3(0,1,0), 0); // (normal vector, distance)
OgreBulletDynamics::RigidBody *defaultPlaneBody = new OgreBulletDynamics::RigidBody(
"BasePlane",
mWorld);
defaultPlaneBody->setStaticShape(Shape, 0.1, 0.8); // (shape, restitution, friction)
// push the created objects to the deques
mShapes.push_back(Shape);
mBodies.push_back(defaultPlaneBody);
character = new OgreBulletCollisions::CapsuleCollisionShape(1.0f, 1.0f, Vector3(0, 1, 0));
charNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
charNode->attachObject(mCamera);
charNode->setPosition(mCamera->getPosition());
characterBody = new OgreBulletDynamics::RigidBody("character", mWorld);
characterBody->setShape( charNode,
character,
0.0f, // dynamic body restitution
10.0f, // dynamic body friction
10.0f, // dynamic bodymass
Vector3(0,0,0),
Quaternion(0, 0, 1, 0));
mShapes.push_back(character);
mBodies.push_back(characterBody);
...
}
You can lock the angular motion of the capsule in order to prevent it from tipping over. Ogre doesn't expose this functionality directly, but you should be able to access the underlying bullet rigid body to accomplish what you need:
characterBody->getBulletRigidBody()->setAngularFactor(btVector3(0.0f,1.0f,0.0f));
This would lock rotation on the xaxis and zaxis, preventing the capsule from tipping over, but allowing rotation around the yaxis, so that the character can still turn.
At some point you may want to looking into using a kinematic character controller, but that's an answer to a different question.