Jump to content

[SOLVED] VR Vive + CIGI setup and collision issue


photo

Recommended Posts

Hi,

I am trying to setup a project with both VR Vive and CIGI feature/plugin combined.
Both demo on these topics helped a lot.
VR template seems to diff a bit with a ComponentSystem self declare as WorldLogic.
All files are in uploaded archive CL-AHD_Vive-CIGI-issue.zip; this code prob doesn't properly implement ComponentSystem direction given by VR template..

I'd like to address 2 points:

  • CIGI / Vive setup camera and player
  • Issue when moving on collision detection, prob. due to updates non sync

1. My attempt to attach Vive camera position to CIGI component (be-200) is in VRPlayerVive::init()
.. and I'm really not sure it is OK. E.g. <item name="player_height" type="float">-1.75</item> in unigine.cfg.. a negative height.. new concept.

[..]
	Cigi::CigiClientInterface* cigi = (Cigi::CigiClientInterface*)Engine::get()->getPluginData(Engine::get()->findPlugin("CigiClient"));
	PlayerDummyPtr playerCigi = cigi->getView(0)->getPlayer();
	player->setParent(playerCigi->getNode());
	controller_0->setParent(playerCigi->getNode());
	controller_1->setParent(playerCigi->getNode());
	player->setWorldTransform(playerCigi->getWorldTransform());
[..]

At CIGI load of be-200, cameras ref positions are init scanning be-200 children, see ComponentSystem::be200_created, to be then accessible through num keys 0..10

	// keyboard
	if (!Console::get()->getActivity())
	{
		//scan over all potential predefined cameras
		for (int i = 0; i < 10; i++)
			if (App::get()->getKeyState(48 + i))
				if (m_cameras.size() > i)
				{
					auto a = m_cameras[i]->getWorldPosition();
					if (m_playerPC)
						m_playerPC->getPlayer()->setWorldPosition(m_cameras[i]->getWorldPosition());
					if (m_playerVR)
						//m_playerVR->getPlayer()->setWorldPosition(m_cameras[i]->getWorldPosition()); //not good
						m_playerVR->setPlayerWorldPosition(m_cameras[i]->getWorldPosition()); //deal with Vive head position
				}
	}

In addition, there is a possibility to switch between CIGI player (m_playerVR) and free one (m_playerPC) with space bar.

	// switch the camera by press the SPACE button
	if (App::get()->clearKeyState(' ') && !Console::get()->getActivity())
	{
		auto current_player = Game::get()->getPlayer();
		if (!current_player || current_player != m_playerPC->getPlayer())
		{
			m_playerPC->getPlayer()->setWorldTransform(current_player->getWorldTransform());
			Game::get()->setPlayer(m_playerPC->getPlayer());
		}
		else
		{
			//if (Engine::get()->findPlugin("AppVive") != -1) //only if VR
			if (m_playerVR) //only if defined
			{
				m_playerCigi->setWorldTransform(current_player->getWorldTransform()); //m_playerCigi is parent of m_playerVR
				Game::get()->setPlayer(m_playerVR->getPlayer());
			}
		}
	}

 

2. When flying by CIGI, collision between buttons put on be-200 (camera-left, camera-right) and Vive controller lose accuracy depending on speed and up to a point there's not anymore interaction.
On attached screen shoots:

  • Vive-CIGI-flying_OK is with be-200 fixed (init, freeze or reset)
  • Vive-CIGI-flying_OK is with be-200 flying, and controller box (in red) is jumping ahead and clearly not consistent to controller position, with collision detection not working properly

 

Thanks in advance for code review and suggestions!

Kind regards,
Charles

Vive-CIGI-flying_KO.PNG

Vive-CIGI-flying_OK.PNG

Edited by Lales.Charles
Link to comment

Hi, Charles!

CIGI / Vive setup camera and player
Just remember:
Without VR:
- Pivot point of the PlayerDummy and PlayerSpectator is at "eye" level
- Pivot point of the PlayerActor is at "foot" level
With VR:
- Pivot point of the PlayerDummy, PlayerSpectator and PlayerActor is at "foot" level

<item name="player_height" type="float">-1.75</item> in unigine.cfg.. a negative height.. new concept.
I think now you understand. CIGI uses the camera at eye level, but Vive at foot level. And you need to lower the camera a little.

Issue when moving on collision detection, prob. due to updates non sync
I think it is because interpolation works in Syncker. Try to disable it:
syncker_manager->getSyncker()->setInterpolation(0);
The thing is interpolation takes you back in time for the interpolation period (40ms by default), but all math (collision detection) works in real time.


Best regards,
Alexander

Link to comment

Hi,

Sorry but I tried different setup, nothing satisfying up to now.
Can you simply / clearly specify the right combination player type / parent / transform in regards of below expected behavior?

I try to get with VR Vive + CIGI activated:

  • Predefined ref positions, picked as seat instead of eyes, in order to handle any body trunk length.
    User / player won't stand up but seat in aircraft.
  • When switching from one ref pos to another one, I put the headset on the real seat in order for the Vive to reset its position.
    User can then put back the headset on his head, then eye position take into account trunk length automatically.
  • If required, camera position can be freely updated (translation only) with keyboard.
  • CIGI can update aircraft position and orientation -> camera should follow / be attached.

For example up to now / based on VR template, I switch between VRPlayerPC (PlayerSpectator) and VRPlayerVive (PlayerDummy) both setup with cigi->getView(0)->getPlayer() as parent.
Without VR it is fine, VRPlayerPC is the only one activated and get right ref pos at "eye" level as you precised.
With VR, it doesn't look good at all:

  • With the same ref pos, the Vive headset / camera is placed above the aircraft.
    You say all player type are "foot" level.. but even if I put the headset on the floor, I don't see the correct camera ref pos.. but above.
  • VRPlayerVive display shorter length of aircraft, as it is compressed, whereas back to VRPlayerPC there is no such deformation.
    Both go through same init (Fov, ZNear, ZFar, PostMaterials) when registred by VRPlayerSpawner init.

Sorry if it is basic concept but I still don't get them..
Thanks in advance!

Kind regards,
Charles

Link to comment

Hi,

Uploaded new CL-AHD_Vive-CIGI-camera-ref-pos.zip with as very few update 2 spheres / cameras added on wings in front of engines.

Procedure:

  • compile, launch launch_debug.bat
  • in CIGI wnd, click Run IG Master
  • world loaded empty
  • in HostEmulator_Win32_v3.3.3_IG folder, start Hemu3.exe, ignore warning, add entity 118 Be200
  • use space bar to switch from PlayerPC to PlayerVR, both under CigiPlayer parent
  • key 0..1 are all camera scanned / found in be200 node (loaded through CIGI)
  • 7 -> left little white sphere in front of engine, 8 -> right one

Attached screen shoot show camera view when pushing key 8. Instead of exact right sphere position, we are located way above, little right.
Same issue with key 7 and left sphere / camera ref position..

By the way, there is no absolute need to switch between 2 players, PCplayer and VRplayer.
VR template propose these two players to handle Vive or not, in my case I derived this usage.

Can you suggest suitable setup to get:

  • CIGI as master
  • Vive (or PC if not) under
  • Predefined ref pos to exactly (re)set Vive headset position
  • Possibility to move (translation only, block rotation) with key board in case predefined pos are not enough

Kind regards,
Charles

 

Vive-position.PNG

Vive-position-right.PNG

Link to comment

Hi Charles,

How to fix Vive headset position:
1) Add to VRPlayerVR.cpp file right after "head = NodeDummy::create();" the next line:

head->setParent(player->getNode());

2) In ComponentSystem.cpp instead of "m_playerVR->getPlayer()->setWorldPosition(m_cameras->getWorldPosition()); //not good" use this:

PlayerPtr p = m_playerVR->getPlayer();
p->setWorldTransform(
	m_cameras[i]->getWorldTransform() *			// point VR camera ("foot/seat") to the target
	Mat4(rotateX(-90.0f) * rotateY(90.0f)) *		// correct m_cameras[i] rotations (because they look up)
	translate(-m_playerVR->getHead()->getPosition())	// put "eyes" to the "foot/seat" position
);


Now i tell you what is going on here. To render the final image AppVive plugin get the current player transform (position + rotation) and apply to it current HMD relative transform. The node itself does not move with the HMD. It stays in place. And it points to the origin (which was set during Vive setup).

P.S. And...  I recommend you not to write the code inside the ComponentSystem.cpp file. Because it can be difficult to migrate your code when we will release a new version of the Component System. It is better to use AppWorldLogic for this.
 

Best regards,
Alexander

  • Like 1
Link to comment

Hi,

Thank you very much, result is satisfying!
I commented the line Mat4(rotateX(-90.0f) * rotateY(90.0f)) since CIGI rotation on load seems to make it not required..

Regarding keeping ComponentSystem.cpp intact -> I do agree and understand, I broke design to make it quickly working.
Where would you add key board interaction (switching playerVR/playerPC or cameras ref pos)?
I mean, ComponentSystem declare itself as Engine::get()->addWorldLogic(this); therefore I don't use explicit AppWorldLogic with init and update..

Finally, regarding interaction when flying (with CIGI), deactivating syncker fixes rendering but not collision detection
syncker_manager->getSyncker()->setInterpolation(0);
Red box follow perfectly the aircraft, but collision (vibration and trigger) start to be random..

Kind regards,
Charles

Link to comment

Hi Charles,


Where would you add key board interaction (switching playerVR/playerPC or cameras ref pos)?
I mean, ComponentSystem declare itself as Engine::get()->addWorldLogic(this); therefore I don't use explicit AppWorldLogic with init and update..

Why? There can be a lot of WorldLogics.
The preferred pipeline is:
AppSystemLogic::update(): system logic, not related to a specific world.
For example: main menu, world loading, system calls...
AppWorldLogic::update(): world logic that not related to specific nodes in specific world (because WorldLogic works with any loaded world).
For example: global keyboard/mouse interactions, render settings, camera switching...
ComponentBase::update(): logic for a particular object (node) in the loaded world.
For example: rotation of a specific node, custom Player control, behavior of a specific device in a cockpit...


Red box follow perfectly the aircraft, but collision (vibration and trigger) start to be random.
I found the reason of that behavior: spatial tree! Add to the void VRPlayerVive::update():

void VRPlayerVive::update()
{
	// ...	

	World::get()->updateSpatial(); // add this line!
	grab_update(0, controller_valid[0], getControllerAxis(0, BUTTON::GRIP), getControllerButtonDown(0, BUTTON::TRIGGER));
	grab_update(1, controller_valid[1], getControllerAxis(1, BUTTON::GRIP), getControllerButtonDown(1, BUTTON::TRIGGER));

	// ...
}

World::get()->getIntersection() uses spatial tree information to check the intersection. But, by default spatial tree updates right after all user code was executed (for performance reasons). One can say that this function works in the previous frame. World::get()->updateSpatial() updates spatial tree immediately.


Best regards,
Alexander

Link to comment

Hi,

Thanks for precision regarding preferred pipeline and moreover for fixes working like a charm ;)
I don't if it is trivial for you, but to me it is not and I'm glad to get such support!

Kind regards,
Charles

Link to comment
  • morbid changed the title to [SOLVED] VR Vive + CIGI setup and collision issue

Hi,

Just confirmation to make sure it is possible and right: is it possible to define multiple WorldLogic..?

I mean, is it fine to both use:

  • engine->main(&system_logic, &world_logic, NULL); from main, with Unigine::WorldLogic world_logic;
  • Engine::get()->addWorldLogic(this); from ComponentSystem, with class ComponentSystem : public Unigine::WorldLogic

Checking VR template src, it was the reason I put some logic in ComponentSystem and avoid to define my own AppWorldLogic..

Kind regards,
Charles

Link to comment

Hi Charles,

Is it possible to define multiple WorldLogic..?
Yes of course!
The source code of the "main" function is very simple and looks like this:

void Engine::main(Unigine::SystemLogic *system_logic, Unigine::WorldLogic *world_logic, Unigine::EditorLogic *editor_logic)
{
	addSystemLogic(system_logic);
	addWorldLogic(world_logic);
	addEditorLogic(editor_logic);

	while (!isDone())
	{
		doUpdate();
		doRender();
		doSwap();
	}
}

You can use Engine::get()->addWorldLogic() and Engine::get()->removeWorldLogic() anywhere in your program. WorldLogics are stored in a simple vector and the Engine calls their methods (update, render, flush) sequentially in the order of adding to this vector.

Best regards,
Alexander

  • Like 1
Link to comment

Thanks ;)

Well, I do have a question then.. how can I expose PlayerVR and PlayerPC e.g. to AppWorldLogic?

  • AppSystemLogic::init() calls
    • ComponentSystem::get()->registerComponent<VRPlayerSpawner>();
  • VRPlayerSpawner::init() calls 
    • ComponentSystem::get()->registerComponent<VRPlayerVive>();
    • ComponentSystem::get()->addComponent<VRPlayerVive>(player->getNode()); creates VRPlayerVive

In order to grad both players, I added in ComponentSystem::init()
(ugly I know..)

	//try to find back players
	for (auto i = components.begin(); i != components.end(); ++i)
		for (int k = 0; k < i->data.size(); k++)
		{
			ComponentBase *c = i->data[k];
			auto vrPlayer = dynamic_cast<VRPlayerVive*>(c);
			auto pcPlayer = dynamic_cast<VRPlayerPC*>(c);
			if (vrPlayer)
				m_playerVR = vrPlayer;
			if (pcPlayer)
				m_playerPC = pcPlayer;
		}

How is it possible to expose it properly?
E.g. using getComponent
auto m_playerVR = ComponentSystem::get()->getComponent<VRPlayerVive>(?);

Thanks in advance.
Kind regards,
Charles

Edited by Lales.Charles
Link to comment

Hi,

It was planned that you will not be able to create VRPlayerPC and VRPlayerVive players at the same time. Either one or the other. And, you can use a singleton VRPlayer::get() to get VRPlayer component pointer that can be cast to VRPlayerPC or VRPlayerVive via dynamic_cast. But, if you want to use it both...

auto m_playerVR = ComponentSystem::get()->getComponent<VRPlayerVive>(?); 
You need to get the pointer to the node to get the VRPlayerVive component.
But, i recommend to you create a simple singleton in VRPlayerVive and VRPlayerPC classes (like in VRPlayer):

class VRPlayerVive : public VRPlayerVR
{
public:
	VRPlayerVive() { instance = this; }
	virtual ~VRPlayerVive() { instance = nullptr; }
	static VRPlayerVive *get() { return instance; }

private:
	static VRPlayerVive *instance;
};

VRPlayerVive *VRPlayerVive::instance;

Then: auto m_playerVR = VRPlayerVive::get(); 

Best regards,
Alexander

Link to comment
  • 2 weeks later...

Hi,

Sorry I come back on this issue, just found one quite related to this.
You can directly debug CL-AHD_Vive-CIGI-issue.zip:

  • add Be200 thanks to CIGI HE
  • remove it

Error thrown.

CIGI-button-remove_KO.PNG.91bfbec8d2b676148d3e0ed016d87c24.PNG

Got equivalent error when closing the app if there is still entities loaded through CIGI.
I have this error since long.. just found out that it is related to this button / VRInteractable / ComponentBase.

Would you see how to fix it?

Kind regards,
Charles

Link to comment

Charles, the release is planned for December.

The crash you've faced is due to some modifications of CIGI plugin. May I ask you to send us source files? They are stored in <sdk_2.7.2.1\source\plugins\Network\CigiClient\*>.

Earlier we prompted Stephane to make some changes in it, probably it was caused by this custom fix.

Thank you.

How to submit a good bug report
---
FTP server for test scenes and user uploads:

Link to comment
×
×
  • Create New...