Psychtoolbox Demos / Tutorials

The core code I use is here, lines 267-282: opticka/movieStimulus.m at master · iandol/opticka · GitHub – the important detail is just to check if a new texture is available, if it is, then delete the old one and draw the new one or just draw the old one. You need to be careful when closing textures as it can be easy to close the wrong one. I never got round to contributing that, I need to conform to Peter’s coding style but will put it on my todo…

A simple test (using my PTB toolbox):

m=metaStimulus; %meta stimulus handles multiple stimuli
m{1}=movieStimulus('xPosition',-5); %position is degrees from center
m{2}=dotsStimulus('xPosition',5);
s=screenManager;
open(s);
setup(m, s); %tell our stimuli the screen parameters
for i = 1:600; draw(m); animate(m); flip(s); end
close(s); reset(m);

You should see a dancing monkey and a random dots stimulus both running together. As an aside my default dancing monkey video also shows alpha transparent video support from PTB…

Thanks so much for sharing it! We will give it a try! :wink:

Latest Demo: “Coolness slider”.

Someone asked for a demo of an interactive slider which allows participants to report a continuous response on a scale. Here is the demo. You can move the slider with the mouse (click on the toggle and drag to move it). The current “coolness %” is reported and this value is used to colour some text on the screen.

https://www.peterscarfe.com/coolnessSlider.html

Enjoy

P

1 Like

Nice work man! That’ll be of good use for many i think.

1 Like

Couple of more demos…

First, one demonstrating how to get the bounding boxes of text in order to position text centred on a given point on the screen. This is contrasted with the standard way in which text is positioned.

https://www.peterscarfe.com/boundingBox.html

This method was used in the coolness slider demo and it seemed sensible to make a demo showing this point alone.

https://www.peterscarfe.com/coolnessSlider.html

Finally, an interactive Likert scale demo. This is like coolness slider, but with distinct points on a rating rate. This is another very standard way in which to get ratings. It again used the bounding boxes stuff.

https://www.peterscarfe.com/likertScale.html

Enjoy

P

1 Like

Another day another demo.

This one shows how to load a .obj 3D mesh and render it using a vertex buffer object (VBO). This allows very fast drawing of complex objects loaded from file.

https://www.peterscarfe.com/rotatingMesh.html

It is used in the code associated with our (coming soon) SolidSight Database.

https://www.peterscarfe.com/resources.html

We have also started the long job of making a comparable resource to the PTB demos for PsychoPy.

https://www.psychopy.org

We tend not to use PsychoPy in the lab due to the superiority of Psychtoolbox, however, it is becoming increasingly popular due to the popularity of Python. These demos will slowly start appearing.

https://www.peterscarfe.com/psychopytutorials.html

More to come…

Peter

2 Likes

I wonder how the sample code using VBO’s compares to the mesh rendering abilities of our moglmorpher() function, as demonstrated in MorphDemo.m and MorphTextureDemo.m? While it is mostly intended for fast morphing between different meshes of identical topology, and that’s what those demos show, it can also render sets of single meshes via VBO’s, similar to what is demonstrated at a lower level in this demo, using VBO’s (subfunctions like ‘renderMesh’, ‘render’, ‘renderToDisplayList’, ‘renderRange’ etc.) and stuff for good performance, and various other goodies, e.g., ‘renderNormals’, ‘getVertexPositions’. In principle moglmorpher() should do this stuff in a convenient higher level way, although I think our demos only show the morphing stuff, not the general mesh rendering stuff, which only was used by lab internal code.

Another thing to point out wrt. complex scenery are our bindings to the Horde3D rendering engine. I think they weren’t heavily advertised, and are even only stored in my GitHub repo:

They do allow for way more convenient rendering of complex 3D scenes, with less low level control though, than what can be done by low level use of OpenGL or what PTB ships in terms of helpers. The nice thing about Horde3D is that it is a lightweight rendering engine used for video games and such. Not at the level of Godot, Unity, Unreal, etc., but still quite capable.

Your demo code also mentions that you use readOB() from gptoolbox, because “…the LoadOBJFile included with Psychtoolbox fails to load many common .obj files.” - Is this also your experience if you set the optional preparse parameter of LoadOBJFile(filename, debug, preparse) to 0? preparse is 1 by default, which speeds up loading of suitable large OBJ files, but will fail on OBJ files which contain other than 3-component vertices, faces and texture coordinates. So preparse 0 should be slower but more robust against various OBJ’s.

In principle one could include readOBJ.m from gptoolbox and use it as a fallback for LoadOBJFile, given that gptoolbox is under a compatible MIT license which easily allows this, just by giving proper credit. LoadOBJFile btw. is an improved version of code originally contributed by William Harwin from University of Reading. It is a small world…

Thanks for the comments Mario.

Yes, many years ago I remember looking at moglmorpher et al. My memory corresponds with what you say. Basically they did far more than I needed. I needed a much more simple use case i.e. load and render a mesh. Plus wanted to attempt to understand things a bit more myself.

I remember being impressed by the Horde functionality. I think it is very much overlooked / not known.

With reference to the LoadOBJFile file. Yes, it fails with preparse 0 (attached screenshots). Basically, my understanding is that the .obj file format is a bit of a mess, with many variants (if that is the correct word). I have never been able to get it to work with any of the .obj files I have created via our scanners.

I actually use a modified version of some C++ code (mexed) from

https://libigl.github.io

This makes the loading dramatically faster. I reference readOBJ() in the demo so the user does not need to worry about mex stuff. Though I hope to provide something when we publish the SolidSight Database and Code.

I actually collaborate lots with William. Was funny to see the origin of LoadOBJFile().

P

Another Day another demo…

Experimental code: Posner cuing task. Demonstrates all the key elements of this basic widely used task.

Background here: https://en.wikipedia.org/wiki/Posner_cueing_task

Code here: https://www.peterscarfe.com/poserCuingExperiment.html

P

For learning / understanding your demo is certainly useful. For use in many cases, the moglmorpher() might be the better choice due to high-perf and lots of backwards compatibility with older systems or low end hardware, and lots of builtin useful functionality. moglmorpher() was basically one important component of a high-perf facial tracking + manipulation + animation system, developed by myself and used by various people at the MPI. It was wrapped by higher level code though for our use cases.

Yep, it is a fun thing for more complex environments. Was used for research in spatial 3D navigation and I think self-motion perception, in labs in Tuebingen, and I used it mostly to have less boring demos when I implemented initial VR HMD support in PTB. Unfortunately I don’t have any artistic skills or patience or time for 3D modelling, but I did spend some time building a 3D rendered model of the original NCC 1701 Enterprise for VR, by assembling sections of the ship from freely available models made by others on Google Sketchup. It was a bit too taxing for the graphics cards of ~2014 and I didn’t have the time to implement proper culling optimizations etc. Unfortunately the resulting model was something like 3 GB of data on disc, and not really easily redistributable with its license, so not suitable for a public demo. It’s also sad that the owners of the Star Trek franchise seem to be very keen on shutting down any, even non-commercial / hobbyist, projects of recreating those beautiful ships in great detail. I’d have loved to walk the corridors of that ship in VR…

But it certainly showed what one can do with Horde (could do, if one had actual 3D modelling skills), and was a fun few days of geeking out.

It’s surprising, as our pimped LoadOBJFile() is technically more capable than readOBJ(), so one would expect it to work in more cases than the other one, and also with sub-meshes and material definitions. But it hasn’t been updated much in a decade, and the OBJ file format is certainly rather complex for something that is supposed to be a “simple” data exchange format between applications, so there are various more exotic cases that neither our reader nor readOBJ won’t handle. It’s probably something simple that makes it fail if readOBJ works …

Ja, fast they are not. One of the cases where compiled code can make a drastic difference. The ‘preparsing’ in my code is just a hack to speed up the cases I needed for my and others research for the type of .obj’s we used - mostly 3D meshes of faces and facial expressions for high performance facial animation. I also used caching in my own code to read .obj’s slowly then save them as .mat files for fast loading…

-mario

1 Like