Hey everyone, I've started my first table a few month ago and thought I would share the progress here. This will be my first complete release on VPX, so, advices, help and beta testing is very welcomed !
Before starting with the first topic, I would like to give some credits and big thanks to a lot of people. Creating a table happens to be a huge task that would be nearly impossible without all the work of the community. So, in no particular order, I would like to thank:
- The VPX team, Toxie and Fuzzel, wihout whom nothing would be possible,
- JPSalas, for all the shared content (the table is based upon the 3.1 physics table from JPSalas), the incredible original tables to inspire from, and all the always positive posts in the forums!
- Scottywik, for all the content from the Orbital website as well as the original tables which provide great sources of inspiration and references,
- Flupper for the content (Dome, ramp,…), but moreover for the detailed explanations which help a huge lot (especially, the Whirlwind rebuild WIP thread, and the ramp tutorial),
- Fleep for the incredible WIP thread on Theatre of Magic sound rebuild and for the Fleep sounds,
- nFozzy for the incredible physics improvments, it gave the table a new play style,
- Nailbuster, for the PinUp player framework
- Iakki and Wylte, for the 'RTX Ball Shadow', it's nice
- VPForum and VPUniverse (and sadly dead VPinball) for giving a place for the community to exist and share contents and thoughts.
I decided to start this topic since other WIPs helped me a lot, but since this is my first table, this is very likely that some informations in this thread will be wrong. Most of the development is a try and guess, so sometimes I guess wrongly! Please correct me when this will be the case. In the same logic, the following posts describe how I worked. I'm pretty sure there are far better ways. It's just my try at it.
I really don't know when this will be finished. I started in april 2021, with not that much free time, so do not expect a release anytime soon.
Table Design
My favorite tables are Cue Ball Wizard (especially the drop target racks), Disney's Tron Legacy (the fast play, the modes that lead to a nice final), Terminator 2 (again fast flow, the gun, the overall mood), Attack from Mars (it's just plain fun). So, when the table design started in early april, I tried to sum up what I liked in these tables and what I wanted in Space Ark ;
- A fast gameplay (powerfull flipper bats, fast orbits and ramps, combos, value making loops,…),
- A "quest" with a nice final (like the sea of simulation, then Portal in Tron, or attacking Mars,…),
- The possibility to stack modes and multiballs (like in Tron, or T2),
- As much as possible, different tasks (shots) for different modes (avoid the shoot the flashing lanes, with different lanes, but have a gun shot, orbits, sccops, targets,…).
So from all of this, I tried to build (and play) a basic table and settle a ruleset. The screenshots of the different steps are below. It also shows the evolution on the graphics.

In the end, I decided in favor of a design with a large (empty) playfield (for the final mode which implies a lower playfield, and to have long and fast shots), with 4 orbits & 2 ramps, 2 sccops, 1 gun (like T2 or walking dead). The ruleset being simple: lite the mode with the bottom lane, perform the expected shots for each mode (scoops/moving drop target ramping up the center before it reaches it/drop target with the gun/moving target with the plunger/orbits to start an AFM's strobe multiball). The remaining 2 aims are 2 multiballs : one with an add-a-ball allowing to play the mode in the same time (shoot all loops, then start in right sccop), one traditionnal (shoot all the targets, then lock 3 ball in center scoop).
What I have learned:
- Scottywik was right when he advises against placing the bumper in the lower part of the playfield. I failed to find a nice design with them at the bottom since they close the access to a big part of the playfield.
- Second set of flipper bats were a bad idea ; they often block the ball when shooting for the orbits, and defeat the fast play I wanted.
- Before moving on to more advanced graphic rendering, there is a need for quite a lot of play testing until things are not moving after each test.
Graphics : overall process
Graphics being the part I enjoy the most, I decided to spend a lot of time on this part. So I will go into depth. As you can see in the previous post, there are mainly 2 phases:
- First when the table design is not stabilized, I used only VPX objects which allows for fast iterations and adjustment,
- Then when things were settling down, I separated (and simplified) VPX objects, keeping them only for the physics and add 3D primitives for the visual part.
During the first part of the process, the aim is just to be able to perform fast iterations and to evalaute if the game is fun. So this has to be kept simple. I used native VPX objects (ramps, walls,…) with native VPX materials, and a single Inkscape vector file used to export 2 textures ; one for the playfield, one for the plastics and the insert lights (more on this later, in the post about inserts).
The second phase aims at improving the graphics ;
- Re-work everything in 3D (it allows to detect all the little errors everywhere and serve as a base for all the other improvments, it also allows to add all the little details),
- Create advanced materials for all the elements (for example for the apron made of rough plastic,…),
- Create nicer inserts (add depth, use differents textures between lit/unlit,…),
- Add soft shadows and indirect lighting by precomputing it in an advanced renderer,
- Adjust color grading.
All these steps are described in the following posts. I will just give here some general feedback on this:
- I did start without organizing the things cleanly, without a clean understanding of VPX lighting and material handling,… At some point, I had to stop, and spend time understanding how all the things interact together (hence the following post).
- Another thing is that, whilst VPX is perfect for placing walls, ramps,…, it is not practical to places primitives (screws, decorative wires, toys,…). I had started to place them before the graphic rebuild. I think this was a mistake: when I started using primitives, I should have created my 3D model replica in Blender and always work from there.
- When starting to have a 3D model replica, you need a clean and fast workflow to export/import between Blender and VPX. In the end, I settled to the following setup in Blender:
- Import OBJ: Clamp Size: 0.1 / -Y Forward / -Z Up
- Export OBJ: Selection only / Scale: 0.1 / -Y Forward / -Z Up / Triangulate faces
- Being able to easily compare VPX render and Blender Cycle render is a key point to easily detect and adjust what is wrong or off. To do so, you have to setup a POV file in VPX which corresponds to the Blender camera (so copy the inclination from Blender camera, set lay off to 0, place the camera at the right position), and setup a small html file that allows side-by-side (and with a slider) comparison. You can find my solution in this post.
Graphics : VPX lighting
As stated before, at some points, it became clear that just testing and trying would not allow to reach a clean result, so I tried to understand how the VPX renderer works. The good news is that the code is opensource, available and clean. The most interesting part are the shaders here : VPX Github. I will give my understanding (which may be wrong) that helped me for the following steps.
First, the code shows the differences between flashers and primitives ; Flashers do not go through the lighting path, and they can be processed with either modulated or additive blending. So flashers are not directly concerned by VPX lighting, but they can be used to fake some lighting if used with additive blending (adding light, more on this later in the post regarding inserts).
Regarding the lighting, there are 2 different paths, one for metallic materials, one for the others.
Metallic materials color is computed by aggregating these 3 parts :
- An ambient 'glossy' lighting, based on the reflection vector, modulated by the texture,
- Blend with an ambient 'specular' lighting, based on the reflection vector, modulated by the texture,
- For non opaque materials, add the transmited light from below.
Other materials color seems to be computed by aggregating :
- An ambient 'diffuse' lighting, based on the surface normal, modulated by the texture,
- An ambient 'glossy' lighting, based on the reflection vector, modulated by the texture,
- Blend with an ambient 'specular' lighting, based on the reflection vector, modulated by the texture,
- For non opaque materials, add the transmited light from below.
The color obtained is blend with the non lit texture according to the 'disable lighting' parameter of the object.
The 'transmited light from below', as I understand it, is the ligtht accumulated from the light halos below the object.
The screen reflection is added afterward to this.
With this understanding (even if not perfect), it allowed to setup the things for the inserts, the ramp indirect lighting, the vu-meters (inserts with lots of lights stacked together), integrate precompute lighting (be it diffuse or glossy).
Graphics : Inserts
The inserts were very difficult to implement right (and I'm still somewhat unsatisfied with them…). Here are the steps and ressources I followed.
The initial design for insert was what I think is the 'normal' way of doing it: they were drawn on the playfield (there are great resources from Scottywik, or Schreibi, see the resource post), with a light using the same texture (the playfield one).
The second design was the same but placing the lights on the plastic texture as well (inserts are on parts of the texture were there is no plastics anyway), and using it instead of the playfield one for 2 reasons:
- It allowed to color the text black, therefore avoiding light to spread on it and keeping it more readable,
- I had a big black polygon in Inkscape over the lights which I could change the alpha value, allowing to adjust the light intensity of all the inserts.
The third iteration was the same as the second, but recreating all the inserts images myself (in Blender) to give them some depth (I pre-rendered them from a little angle instead of rendering them from above).
Then, I discovered Flupper's post in Whirlwind WIP and I understood why I was not able to get what I wanted:
- You need at least 2 different images (on/off) to render the interaction of light inside the inserts (especially for 'star' plastic inserts): using the texture and the VPX generated light (a falloff pattern) can not account for the complex reflexion in some inserts (star pattern, or the small dots one for example),
- Blender (Cycle in fact) is a great renderer but it hits its limits when rendering lit inserts. Flupper proposes a solution of using another renderer (LuxCore).
Following this, I started a fourth iteration consisting on implementing what Flupper describes in his posts. To sum it up:
- Create a model for each insert
- Render unlit, with only image based environment lighting,
- Render it lit, without environment lighting, using LuxCore renderer,
- Create primitives for the table for the 'off' state inserts, then for the 'on' state inserts, these one being slightly bigger.
- Add everything to the table, and place light halos below these primitives.
And it works really nicely!
Here are the unlit/lit texture for the used inserts:

The only part that was still not satisfying were the Vu-meter since with this setup, inserts which are placed very near each other bleed the one to the other. For these, I used the understanding seen above about the flashers which allows to perform additive blending. So I kept the off state primitive and texture, but for the on state, I placed a small halo light with very low level and also placed a flasher with lit texture just above the off primitive. Then I sync the flasher opacity to the light state using VPX 10.7 function to get the live state of the light.
I will end up this lengthy post with a focus on the last point: syncing lights and flashers. Latest VPX 10.7 add a function that allows to read the live state of any light. This is really great for original tables that rely a lot on the light sequencer. With this new function, I was able to add a small 'light replicate' code block that reads the state of a light and replicates it to other lights or to flashers (implementing flasher fading as well). This is used for the vu-meter inserts, as well to add a little light halo on the playfield for the bigger inserts, or to sync 2 lights like on the thruster at the back of the spaceships, or even for the dome flashers which are made using 2 lamps and no flashers: one lamp for the bulb using transmit lighting, one large for the table lighting).
And to give more visual feedback, here are the lit/unlit from initial design, then blender render, then blender+luxcore render:

Graphics : Global Illumination
After inserts, I moved to pre-compute global illumination. After seeing all the incredible tables which are being made lately (VPW team si just incredible on this, and obviously the screenshots in Flupper's Whirlwind post are just crazy), I absolutely wanted this. It happened to not be so easy.
The first try was to UV unwrap my 3D model replica in Blender, then bake the 'combined' texture with Gi On and Gi Off. It happened to be not that simple. First unwrapping is not a simple task. It is a skill in itself, and I d'ont have it. So I made my best, and end up splitting my scene in groups, then unwrap them (edit all models, mark seams where sensible, use the UV unwrapper, then correct the result by hand). Then I realized that part of the lighting is view dependent (glossy reflections and refractions) which needed special handling.
Regarding reflections, the problem is that the reflection depends on the point of view, but when baking, Blender Cycle considers that the viewer is along the normal of the baked surface. The result is good for diffuse reflection (which is not view dependent) but not for glossy reflection. I first tried to have a different way of baking for glossy material:
- First render from a natural point of view,
- Then unwrap by projecting along this point of view,
- Then perfom a bake for the model using either the projected render from previous point or the computed one when the point was not visible from the previous render (backfacing).
I was not abe to get a satisfying result with this process. I thought about baking with a renderer that supports fixed point of view glossy baking (I think Octane renderer can do this) but finally went a simpler way. Since the problem is the way Blender Cycle compute the reflection vector when baking, we can specify a fake surface normal that will lead to the expected reflection vector, then we plug this in the normal input of all the glossy reflection shader, and it works! It has the added benefit of allowing to see directly inside Blender what the result will look like when the viewer moves away from the fake view point.
Here is the blender cycle node setup for fixed glossy reflection shading:

Regarding refractions (light that goes through a material, outputing with another direction than the one it had when entering the material), the problem only appears on transparent surfaces, that is to say the plastic ramps and the bumper caps. I did not find a good solution for this but since the problem is limited to thin plastic surface which are lit from above as well from below, I tried a dedicated approach that seems ok to me.
For the ramps, I inspired (again!) from Flupper's work and created ramps texture by performing 2 bakes ; one for the alpha (with a complete fake shader), then one for the color (with a normal refraction shader), and combine them using Blender compositor to get a texture to apply in VPX. I then use VPX lighting (direct and transmitted) to give a nice result.
For the bumper caps, I made it simpler: I simply performed an opaque bake of the reflection/refraction then used it with a fixed transparency level and it feels ok for me (at least for the moment ; there is room for improvment here).
When all of this is done, you just have to import everything in VPX, set the disable lighting to 1 (see post on lighting) and toggle the textures in the script depending on wether the Gi is on or off.
As a side note, I will add that taking the time to create a small script to automate the blender bake process is worth it (for reference, you can find mine in this You can find my solution in this post as an example to ease the things to create yours). Another side note is that I initially performed denoising of the baked textures. It happened to be a bad idea since with it, you loose all the little details (for example the rough texture of the apron,...).
Graphics : Final Color Grading
With all the above work, I was fairly happy with the graphics but I felt that the color was too 'video game' looking. When using the side by side comparison between VPX (video game looking) and Blender (more balanced render), this was somewhat obvious.
The difficult part was to understand what was off and correct it. So going back to VPX shaders, it seems that VPX loads texture in sRGB color space, performs all of its rendering then perform a sort of tonemapping (see FBShader.hlsl and Helpers.fxh). Another thing I learnt is that Blender perform its view transform (including color grading) when baking, and it performs it again when compositing. So if you use Blender compositor on a baked texture(I did), you are applying the view transform twice.
Knowing that, it appears that I needed to adjust Blender view transform for baking to get the same colors as in the blender render (with untouched view transform). From this I went guess and try, and ended it up with this Blender bake setup: View transform = Filmic / Look= None / Exposure = -1.5 / Gamma = 1.
Here is the resulting comparison with from left to right: Corrected VPX screenshot / Reference Blender render

Physics : adding nFozzy physics, adapting parameters
At this point, the table started looking and play good. So I decided, why not try nFozzy physics. I followed the tutorials and video available on the net, and.. everything went fine ! So, this will be the shortest post, just to say that in the end, it is fairly simple, well documented and gives incredible results. It's really worth it.
The only parts I had to adapt were the flipper bats parameters to have enough power (since I want a fast table, were ramps are placed at the very top), and to avoid too high bounces on them (therefore adapting the falloff parameter).
I did not implemented yet the rubber dampener since I'm aready happy with the physics but this is something I will likely look at in the future.
One thing I need to clarify before sharing the table is wether nFozzy is ok with sharing these improvments (I did not find any clear license or sharing notice on the web).
And that's all for tonight!
I will try to update this post with the currently being worked topics:
- Sounds : adding Fleep sounds, balancing everything, musics/sounds/voice overs [around 50% progress]
- DMD : adding FlexDMD [around 25% progress]
- Backglass : creating the Pup Pack [around 20% progress]
Edit: finally discovered VPF Image Host and added the images.
Edited by vbousquet, 16 September 2021 - 02:18 PM.




Top










Contributor












are all trademarks of VPFORUMS.