Vtk Qt scene with >50 (moving) actors - c++

I am trying to implement (fairly) simple scene where I have ~50 cubes which are moving in certain directions. The position of the cubes changes 20 times per second.
My first shoot was adding and removing actors from the scene. This approach just doesn't scale. Whole scene lags and user is unable to move the camera.
void draw(vtkRenderer *renderer)
{
renderer->RemoveAllViewProps();
for(const Cube& cube : cubes_)
{
vtkSmartPointer<vtkCubeSource> cube_source = vtkSmartPointer<vtkCubeSource>::New();
cube_source->Update();
cube_source->SetXLength(cube.lengt());
cube_source->SetYLength(cube.width());
cube_source->SetZLength(cube.height());
vtkSmartPointer<vtkPolyDataMapper> poly_mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
poly_mapper->SetInputConnection(cube_source->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(poly_mapper);
actor->SetPosition(cube.x(), cube.y(), cube.z());
renderer->AddActor(actor);
}
}
Second shot is a bit better. I have created "actor pool" where I reuse the actors and hide the ones which are not needed.
Still, moving camera is laggy and the rest of my UI (I have some additional widgets inside Vtk widget) seems to be laggy.
I couldn't find any relevant source for Vtk where scene is "dynamic". All examples preload all scene elements and further work with them. Can anyone tell me what am I doing wrong here?

this my visualization VTK example
.....
vtkSmartPointer<vtkRenderer> m_vtkRenderer;
vtkSmartPointer<MouseInteractor> m_mouseInteractor;
QVector<vtkActor* > m_parcellationActors;
QVector<vtkActor* > m_electrodesActors;
QVector<vtkFollower* > m_textActors;
QVector<vtkActor*> m_vectorFieldsActors;
QVector<vtkActor*> m_streamlinesActors;
......
void VisualizationWidget::create3DViewArea()
{
m_3DViewArea = new QStackedWidget(this);
m_vtkWidget = new QVTKWidget(m_3DViewArea);
m_vtkRenderer = vtkSmartPointer<vtkRenderer>::New();
m_vtkRenderer->SetBackground(0.4, 0.4, 0.4);
this->m_vtkWidget->GetRenderWindow()->AddRenderer(m_vtkRenderer);
m_mouseInteractor = vtkSmartPointer<MouseInteractor>::New();
m_mouseInteractor ->SetDefaultRenderer(m_vtkRenderer);
this->m_vtkWidget->GetRenderWindow()->GetInteractor()->SetInteractorStyle( m_mouseInteractor);
connect(m_mouseInteractor, &MouseInteractor::onActorSelected, this, &VisualizationWidget::onActorSelectedSlot);
m_vtkLoadingWidget = new LoadingWidget(m_3DViewArea);
m_vtkLoadingWidget->setIconPath(Icon::s_getTDCSLoadingGif);
m_3DViewArea->addWidget(m_vtkLoadingWidget);
m_3DViewArea->addWidget(m_vtkWidget);
}
void VisualizationWidget::setParcellationActors(QVector<vtkActor*> actors)
{
m_parcellationActors = actors;
for (int i = 0; i < m_parcellationActors.size(); ++i) {
m_vtkRenderer->AddActor(m_parcellationActors.at(i));
}
m_vtkWidget->update();
}
void VisualizationWidget::setElectrodesActors(QVector<vtkActor*> actors)
{
m_electrodesActors = actors;
for (int i = 0; i < m_electrodesActors.size(); ++i) {
m_vtkRenderer->AddActor(m_electrodesActors.at(i));
}
m_vtkWidget->update();
}
void VisualizationWidget::setElectrodesLabelsActors(QVector<vtkFollower*> actors)
{
m_textActors = actors;
for (int i = 0; i < m_textActors.size(); ++i) {
m_textActors.at(i)->SetCamera(m_vtkRenderer->GetActiveCamera());
m_vtkRenderer->AddActor(m_textActors.at(i));
}
m_vtkRenderer->ResetCamera();
m_vtkWidget->update();
}
void VisualizationWidget::setVectorFieldsActors(QVector<vtkActor*> actors)
{
for (int i = 0; i < m_vectorFieldsActors.size(); ++i) {
m_vtkRenderer->RemoveActor(m_vectorFieldsActors.at(i));
}
m_vectorFieldsActors = actors;
for (int i = 0; i < m_vectorFieldsActors.size(); ++i) {
changeActorOpacity(m_vectorFieldsActors[i], double(m_postProcResOpacSliders.at(i)->value()) / m_postProcResOpacSliders.at(i)->maximum());
m_vtkRenderer->AddActor(m_vectorFieldsActors.at(i));
}
m_vtkRenderer->ResetCamera();
m_vtkWidget->update();
}
void VisualizationWidget::setStreamlinesActors(QVector<vtkActor*> actors)
{
for (int i = 0; i < m_streamlinesActors.size(); ++i) {
m_vtkRenderer->RemoveActor(m_streamlinesActors.at(i));
}
m_streamlinesActors = actors;
for (int i = 0; i < m_streamlinesActors.size(); ++i) {
changeActorOpacity(m_streamlinesActors[i], double(m_streamLinesSlider->value()) / m_streamLinesSlider->maximum());
m_vtkRenderer->AddActor(m_streamlinesActors.at(i));
}
m_vtkRenderer->ResetCamera();
m_vtkWidget->update();
}
void VisualizationWidget::changeActorOpacity(vtkActor* actor, double opac)
{
actor->SetVisibility(opac > 0.05);
actor->GetMapper()->Modified();
actor->GetProperty()->SetOpacity(opac);
}

So afther some days of reaserch I managed to hack working solution:
vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
// as many points as you like
points->InsertNextPoint(-25, 0, 0);
points->InsertNextPoint(-35, 0, 0);
vtkSmartPointer<vtkFloatArray> scales = vtkSmartPointer<vtkFloatArray>::New();
scales->SetNumberOfComponents(3);
// same as number of points
scales->InsertNextTuple3(1, 1., 8.);
scales->InsertNextTuple3(1., 1., 10.);
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
polydata->SetPoints(points);
polydata->GetPointData()->SetVectors(scales);
vtkSmartPointer<vtkCubeSource> cubeSource = vtkSmartPointer<vtkCubeSource>::New();
vtkSmartPointer<vtkGlyph3D> glyph3D = vtkSmartPointer<vtkGlyph3D>::New();
glyph3D->OrientOff(); // disable orientation
glyph3D->SetScaleModeToScaleByVectorComponents(); // sacle along each axis
glyph3D->SetSourceConnection(cubeSource->GetOutputPort());
glyph3D->SetInputData(polydata);
glyph3D->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(glyph3D->GetOutputPort());
mapper->ScalarVisibilityOff(); // use color from actor
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->GetProperty()->SetColor(0, 1, 0); // this will change color for whole glyph
actor->SetMapper(mapper);
mapper->Update();
vtk_renderer->AddActor(actor);
Code from above will add as many cubes and you want using a single actor! (which was amazing performance boost in my case)
Further, if you want to update positions of the cubes, you just need to do following:
points->Reset();
points->InsertNextPoint(-25, 0, 0);
points->InsertNextPoint(-35, 0, 0);
scales->Reset();
scales->InsertNextTuple3(1, 1., 8.);
scales->InsertNextTuple3(1., 1., 10.);
polydata_->Modified();
// call render
(notice that I am not removing/adding actors to the scene which is another boost)

Related

Mouse control is lost after using vtk interactor

I'm trying to visualize a vtk unstructuredgrid mesh.
In order to get the coordinate of a point of my mesh I use the vtk interactor.
I'm able to get the point coordinate by selecting the point using OnRightButtonDown() "overrid"
. However, I loose control of my window . means I can not rotate, translate or zoom my mesh.
I tried to do use OnRightButtonDoubleClick() but this doesn't seem to work . Any idea how may I
get the node coordinate using the interactor without affecting the mouse event behavior or how to re-initialize it when the mouse button is Up...
foo
{
...
// vtk visualization
container = new QWidget(ui->graphicsView);
qvtkWidget = new QVTKOpenGLNativeWidget(container);
...
//Create and link the mapper actor and renderer together.
mapper = vtkSmartPointer<vtkDataSetMapper>::New();
actor = vtkSmartPointer<vtkActor>::New();
renderer = vtkSmartPointer<vtkRenderer>::New();
...
// add elements nodes
...
mapper->SetInputData(eleNodeIdsPtr);
actor->SetMapper(mapper);
renderer->AddActor(actor);
// ste up camera
renderer->SetBackground(0.06, 0.2, 0.5);
double pos[3] = { 0, 0.2, 1 };
double focalPoint[3] = { 0, 0, 0 };
double viewUp[3] = { 1, 1, 1 };
renderer->GetActiveCamera()->SetPosition(pos);
renderer->GetActiveCamera()->SetFocalPoint(focalPoint);
renderer->GetActiveCamera()->SetViewUp(viewUp);
renderer->GetActiveCamera()->Zoom(0.5);
//Add render
qvtkWidget->GetRenderWindow()->AddRenderer(renderer);
qvtkWidget->show();
// Select node
renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(qvtkWidget-
>GetRenderWindow());
vtkNew<InteractorStyle2> style;
renderWindowInteractor->SetInteractorStyle(style);
style->eleNodeIdsPtr = eleNodeIdsPtr;
style->xyzGlobalPtr = xyzGlobalPtr;
renderWindowInteractor->Initialize();
}
// Define interaction style
class InteractorStyle2 : public vtkInteractorStyleTrackballActor
{
public:
static InteractorStyle2* New();
vtkTypeMacro(InteractorStyle2, vtkInteractorStyleTrackballActor);
vtkNew<vtkNamedColors> color;
...
void OnLeftButtonDown() //...>>>This doesn't work!!
{
}
void OnLeftButtonDown() override // .. this work but the I can't controle the transformation anymore!!
{
this->PointPicker = vtkSmartPointer<vtkPointPicker>::New();
// Get the selected point
int x = this->Interactor->GetEventPosition()[0];
int y = this->Interactor->GetEventPosition()[1];
this->FindPokedRenderer(x, y);
this->PointPicker->Pick(this->Interactor->GetEventPosition()[0],
this->Interactor->GetEventPosition()[1],
0, // always zero.
this->Interactor->GetRenderWindow()
->GetRenderers()
->GetFirstRenderer());
if (this->PointPicker->GetPointId() >= 0)
{
this->StartPan();
this->SelectedPoint = this->PointPicker->GetPointId();
double p[3];
this->eleNodeIdsPtr->GetPoint(this->SelectedPoint, p);
std::cout << "p: " << p[0] << " " << p[1] << " " << p[2] << std::endl;
}
}
vtkSmartPointer<vtkPointPicker> PointPicker;
vtkIdType SelectedPoint;
vtkSmartPointer<vtkUnstructuredGrid> eleNodeIdsPtr;
vtkSmartPointer< vtkPoints > xyzGlobalPtr;
}
vtkStandardNewMacro(InteractorStyle2);
}
You should call the OnLeftButtonDown (or up) of the parent class, by adding this line at the end of your method impl:
vtkInteractorStyleTrackballActor::OnLeftButtonDown();
A similar example

Why the model is not displayed in the center of screen?

I want to show a point cloud with VTK. I inherit a class named VTKWidget from QVTKOpenGLNativeWidget, its constructor is that:
VTKWidget::VTKWidget(QVTKOpenGLNativeWidget* parent)
:QVTKOpenGLNativeWidget(parent)
{
QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());
_renderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
_render = vtkSmartPointer<vtkRenderer>::New();
_actor = vtkSmartPointer<vtkActor>::New();
_points = vtkSmartPointer<vtkPoints>::New();
_mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
_polyData = vtkSmartPointer<vtkPolyData>::New();
_verts = vtkSmartPointer<vtkCellArray>::New();
_polyData->SetPoints(_points);
_polyData->SetVerts(_verts);
_mapper->SetInputData(_polyData);
_actor->SetMapper(_mapper);
_actor->GetProperty()->SetColor(1.0, 0.0, 0.0);
_actor->GetProperty()->SetPointSize(2.0f);
_render->AddActor(_actor);
double color[] = {0.5, 0.5, 0.5};
_render->SetBackground(color);
_renderWindow->AddRenderer(_render);
//setRenderWindow(_renderWindow);
}
Points will be modified in the function updateData, the updateData function is that:
void VTKWidget::updateData(const QVector<QVector<QVector3D>>& data)
{
setRenderWindow(_renderWindow);
_points->Reset();
long long w = data.size();
long long h = data[0].size();
_points->SetNumberOfPoints(w * h);
_polyData->Reset();
_verts->Reset();
for (int i = 0; i < data.size(); ++i)
{
for (int j = 0; j < data[0].size(); ++j)
{
vtkIdType pid;
pid = _points->InsertNextPoint(data[i][j].x(), data[i][j].y(), data[i][j].z());
_verts->InsertNextCell(1, &pid);
}
}
_polyData->Modified();
_mapper->Update();
}
The question is that if the code setRenderWindow (_renderWindow); is in the constructor, the point cloud will not show in the center of this widget, but will be if the code is in the function updateData.
If you want to see the whole point cloud at the end of updateData, you should use _renderer->ResetCamera().
(https://vtk.org/doc/nightly/html/classvtkRenderer.html#ae8055043e676defbbacff6f1ea65ad1e)
The fact that the location of setRenderWindow() impact the rendering is a side effect.

C++ VTK reading and saving data from several files

I am new to VTK and my goal is to be able to store information from several files into a vector so then I can separately use filters on some files or show it on QVTKWidget.
My question is what type of vector should I create?
So far I have this:
class for Reader that are creating my reader and pushing it back:
template<class TReader> vtkDataSet *readVTKfile(std::string fileName)
{
vtkSmartPointer<TReader> reader =
vtkSmartPointer<TReader>::New();
reader->SetFileName(fileName.c_str());
reader->Update();
reader->GetOutput()->Register(reader);
return vtkDataSet::SafeDownCast(reader->GetOutput());
}
And here is the problem with how can I use it for my vector:
QStringList filenames = QFileDialog::getOpenFileNames(this, tr("Choose"), "", tr("Vtk files (*.vtk)"));
std::vector<std::string> inputFilenames(filenames.count());
if (!filenames.isEmpty())
{
for (int i = 0; i < filenames.count(); i++)
inputFilenames.push_back(filenames.at(i).toLocal8Bit().constData());
}
std::vector<vtkDataSet*> data(inputFilenames.size()); // what type it should be?
for (int i = 0; i < inputFilenames.size(); i++)
{
data[i] = readVTKfile<vtkGenericDataObjectReader>(inputFilenames[i]);
}
vtkSmartPointer<vtkPolyDataMapper> objectMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
//objectMapper->SetInputConnection(reader->GetOutputPort());
objectMapper->SetInputConnection(data[0]); // so then I can use it for example for showing?
vtkSmartPointer<vtkActor> objectActor =
vtkSmartPointer<vtkActor>::New();
objectActor->SetMapper(objectMapper);
// VTK Renderer
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(objectActor);
// VTK/Qt wedded
this->qvtkWidgetLeft->GetRenderWindow()->AddRenderer(renderer);
QStringList filenames = QFileDialog::getOpenFileNames(this, tr("Choose"), "", tr("Vtk files (*.vtk)"));
// use the range based for, and .toStdString if you wanna std::string from QString
std::vector<std::string> inputFilenames(filenames.count());
for(const auto& filename : filenames) {
inputFilenames.push_back(filename.toStdString());
}
// I'm not sure if this is the right type, but it's what the documentation uses
std::vector<vtkAlgorithmOutput*> data(inputFilenames.size());
for (int i = 0; i < inputFilenames.size(); i++)
{
data[i] = readVTKfile<vtkGenericDataObjectReader>(inputFilenames[i]);
}
vtkSmartPointer<vtkPolyDataMapper> objectMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
objectMapper->SetInputConnection(data[0]);
vtkSmartPointer<vtkActor> objectActor =
vtkSmartPointer<vtkActor>::New();
objectActor->SetMapper(objectMapper);
// VTK Renderer
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(objectActor);
// VTK/Qt wedded
this->qvtkWidgetLeft->GetRenderWindow()->AddRenderer(renderer);

c++ Opengl handle elements drawn

I am currently working on a game and I want to know if there is any way of handling with the elements i am drawing . For example : if i draw in a loop 100 cubes , how can i show / hide the cube number 15 or 63 or n ... I thought that initializing elements in a list would work , but i didn't find any property of it that could help.
GLuint cube;
cube = glGenLists(1);
glNewList(cube,GL_COMPILE);
for(int i = -30; i < 3; i++) {
for(int j = -30; j < 3; j++) {
glPushMatrix();
glTranslatef(i*2.0,0,j * 2.0);
Dcube();
glPopMatrix();
}
}
glEndList();
//something like : glDeleteList(cube); but that only works with entire list not with individual objects..
You have a display list, very good. So now you're back to using your regular language primitives to simply call that function.
std::array<bool, 100> cubes;
std::fill(cubes.begin(), cubes.end(), true);
cubes[15] = false;
cubes[63] = false;
for (bool drawCube : cubes) {
if (drawCube) {
// move a bit, perhaps using glTranslate
glCallList(cube);
}
}
OpenGL isn't your statekeeper. It just draws what you tell it to, you're responsible for keeping your objects.

Need help optimizing C++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have programmed a simple top-down car driving game that resembles the first GTA, on the GameBoyAdvance. I have used only vector graphics for doing so, and the GBA doesn't handle it very well; basically with 5 pedestrian instances it lags.
I don't have much experience in optimizing code, so I would like to know if there are some tweaks I could make to my code in order to make it run faster, not depending on the fact that it runs on a GBA.
The collision testing I use is SAT (separating axis theorem) as I've found it to be the easisest one for collision check with vector graphics; the game is very simple itself.
Here is the code:
/*
GTA Vector City
Author: Alberto Taiuti
Version: 2.0
*/
#include "Global.h"
#include <string.h>
#include <cstdio>
#include "font.h"
#include "CVector2D.h"
#include "CCar.h"
#include "CPed.h"
#include <vector>
#include <memory>
/* GLOBAL VARIABLES */
void CheckCollisionsRect(CRect *test_a, CRect *test_b);
std::vector<CVector2D> PrepVectors(CRect *shape);
CVector2D GetMinMaxShape(std::vector<CVector2D> vect_shape, CVector2D axis);
void CheckCollisionRectVSPoint(CRect *test_a, CVector2D *point);
/* MAIN */
// The entry point for the game
int main()
{
// Frame counter
uint32_t frames = 0;
// Previous & current buttons states
static uint16_t prev_buttons = 0, cur_buttons = 0;
// Put the display into bitmap mode 3, and enable background 2.
REG_DISPCNT = MODE4 | BG2_ENABLE;
// Set up the palette.
SetPaletteBG(BLACK, RGB(0, 0, 0)); // black
SetPaletteBG(WHITE, RGB(31, 31, 31)); // white
SetPaletteBG(GREY, RGB(15, 15, 15)); // grey
SetPaletteBG(RED, RGB(31, 0, 0)); // red
SetPaletteBG(GREEN, RGB(0, 31, 0)); // green
SetPaletteBG(BLUE, RGB(0, 0, 31)); // blue
// Create car instance
CCar *car = new CCar(50,50);
// Create a building
/*CRect *test_b = new CRect(100.0f, 100.0f, 30, 30);
CRect *test_c = new CRect(120.0f, 120.0f, 30, 30);
CRect *test_d = new CRect(30.0f, 30.0f, 30, 30);*/
// Pedestrian instances
int ped_number = 10; // Number of pedestrians
std::vector<CPed*> peds; // Ped. entities container (made of smart pointers)
typedef std::vector<CPed*>::iterator p_itor; // Iterator
for(int i = 1; i <= ped_number; i++)
{
peds.push_back(new CPed(i, RED, 2.0f));
}
// Check whether the game is over
bool end = false;
// Main loop
while (!end)
{
// Flip the screen
FlipBuffers();
//Clear the screen
ClearScreen8(BLACK);
// Update frame counter
frames ++;
// Get the current state of the buttons.
cur_buttons = REG_KEYINPUT;
// Handle Input
car->HandleInput(prev_buttons, cur_buttons);
// Logic
car->Update();
for(int i = 0; i < ped_number; i++)
{
peds[i]->Update();
}
for(int i = 0; i < ped_number; i++)
{
CheckCollisionRectVSPoint(car->shape, peds[i]->pos);
}
/*CheckCollisionsRect(car->shape, test_b);
CheckCollisionsRect(car->shape, test_c);
CheckCollisionsRect(car->shape, test_d);
CheckCollisionRectVSPoint(car->shape, test_ped->pos);*/
// Render
car->Draw();
for(int i = 0; i < ped_number; i++)
{
peds[i]->Draw();
}
/*test_b->DrawFrame8(GREEN);
test_c->DrawFrame8(WHITE);
test_d->DrawFrame8(RED);
test_ped->Draw();*/
prev_buttons = cur_buttons;
// VSync
WaitVSync();
}
// Free memory
delete car;
//delete test_b; delete test_c; delete test_d;
//delete test_ped;
for(p_itor itor = peds.begin(); itor != peds.end(); itor ++)// Delete pedestrians
{
peds.erase(itor);
}
return 0;
}
void CheckCollisionsRect(CRect *test_a, CRect *test_b)
{
// If the two shapes are close enough, check for collision, otherways skip and save calculations to the CPU
//if((pow((test_a->points[0]->x - test_b->points[0]->x), 2) + pow((test_a->points[0]->y - test_b->points[0]->y), 2)) < 25.0f)
{
// Prepare the normals for both shapes
std::vector<CVector2D> normals_a = test_a->GetNormalsAsArray();
std::vector<CVector2D> normals_b = test_b->GetNormalsAsArray();
// Create two containers for holding the various vectors used for collision check
std::vector<CVector2D> vect_test_a = PrepVectors(test_a);
std::vector<CVector2D> vect_test_b = PrepVectors(test_b);
// Get the min and max vectors for each shape for each projection (needed for SAT)
CVector2D result_P1 = GetMinMaxShape(vect_test_a, normals_a[1]); //
CVector2D result_P2 = GetMinMaxShape(vect_test_b, normals_a[1]); //
// If the two objects are not colliding
if(result_P1.y < result_P2.x || result_P2.y < result_P1.x)
{
return;
}
CVector2D result_Q1 = GetMinMaxShape(vect_test_a, normals_a[0]); // First axis couple
CVector2D result_Q2 = GetMinMaxShape(vect_test_b, normals_a[0]); //
if(result_Q1.y < result_Q2.x || result_Q2.y < result_Q1.x)
{
return;
}
CVector2D result_R1 = GetMinMaxShape(vect_test_a, normals_b[1]); //
CVector2D result_R2 = GetMinMaxShape(vect_test_b, normals_b[1]); //
if(result_R1.y < result_R2.x || result_R2.y < result_R1.x)
{
return;
}
CVector2D result_S1 = GetMinMaxShape(vect_test_a, normals_b[0]); // Second axis couple
CVector2D result_S2 = GetMinMaxShape(vect_test_b, normals_b[0]); //
if(result_S1.y < result_S2.x || result_S2.y < result_S1.x)
{
return;
}
// Do something
PlotPixel8(200, 10, WHITE);
PlotPixel8(200, 11, WHITE);
PlotPixel8(200, 12, WHITE);
}
}
// Check for collision between an OOBB and a point
void CheckCollisionRectVSPoint(CRect *test_a, CVector2D *point)
{
// Prepare the normals for the shape
std::vector<CVector2D> normals_a = test_a->GetNormalsAsArray();
// Create a container for holding the various vectors used for collision check
std::vector<CVector2D> vect_test_a = PrepVectors(test_a);
// Get projections for the OOBB (needed for SAT)
CVector2D result_P1 = GetMinMaxShape(vect_test_a, normals_a[1]);
float result_point = point->DotProduct(normals_a[1]);
// If the two objects are not colliding on this axis
if(result_P1.y < result_point || result_point < result_P1.x)
{
return;
}
CVector2D result_Q1 = GetMinMaxShape(vect_test_a, normals_a[0]);
result_point = point->DotProduct(normals_a[0]);
// If the two objects are not colliding on this axis
if(result_Q1.y < result_point || result_point < result_Q1.x)
{
return;
}
// Do something
PlotPixel8(200, 10, WHITE);
PlotPixel8(200, 11, WHITE);
PlotPixel8(200, 12, WHITE);
}
// Returns a container with projection vectors for a given shape
std::vector<CVector2D> PrepVectors(CRect *shape)
{
std::vector<CVector2D> vect;
// Create vectors for projection and load them into the arrays
for( uint16_t i=0; i < 5; i++)
{
// Get global position of vectors and then add them to the array
vect.push_back(shape->GetVectorGlobal(i));
}
return vect;
}
CVector2D GetMinMaxShape(std::vector<CVector2D> vect_shape, CVector2D axis)
{
// Set initial minimum and maximum for shape's projection vectors
float min_proj = vect_shape[1].DotProduct(axis);
float max_proj = vect_shape[1].DotProduct(axis);
// Calculate max and min projection vectors by iterating along all of the corners
for(uint16_t i = 2; i < vect_shape.size(); i ++)
{
float current_proj = vect_shape[i].DotProduct(axis);
// Select minimum projection on axis
if(current_proj < min_proj) // If current projection is smaller than the minimum one
min_proj = current_proj;
// Select maximum projection on axis
if(current_proj > max_proj) // If current projection is greater than the minimum one
max_proj = current_proj;
}
return (CVector2D(min_proj, max_proj)); // Return a vector2D as it is a handy way for returning a couple of values
}
Many thanks in advance to everyone and sorry for the messy code!
I gave it a really quick reading so I may have overlooked something. Well, there are obvious tips for improving performance such as passing vectors to functions by reference. Using prefix incrementation instead of postfix is also a good habit. These two rules are definitely nothing like 'premature optimization the, root of ...'. Do not delete pedestrians one by one but use std::vector::clear(). And If you claim you use smart pointers, you shoud, because it seems you have memory leak because you did not delete the pedestrian pointers. And use const keyword whereever possible. Once you make the obvious correction, and the speed is still not satisfactory, then you need to use profiler.
And read something about optimization, here for example: http://www.agner.org/optimize/optimizing_cpp.pdf
One thing leaps out at me (apart from the continuous passing of vectors by value rather than reference, which will be incredibly costly!)
In you collision detection, you're seeing if the car hits each pedestrian
for(int i = 0; i < ped_number; i++)
{
CheckCollisionRectVSPoint(car->shape, peds[i]->pos);
}
Then, in the collision detector, you're repeating a lot of the same processing on the car shape every time:-
// Prepare the normals for both shapes
std::vector<CVector2D> normals_a = test_a->GetNormalsAsArray();
// Create two containers for holding the various vectors used for collision check
std::vector<CVector2D> vect_test_a = PrepVectors(test_a);
.. etc...
You should rework that loop to create the normals etc for the car just once, and then reuse the results for each check against a pedestrian.