Monday, October 26, 2015

Astromech Updates - Speculars & Physics

Time for some more pretty pictures, screenshotted just now from Astromech in the other window:

In Soviet Russia, Caffeine goes inside of you!
Recognize it? It's my second favorite molecule, the one that's powered much of Astromech's development so far. The still shot doesn't entirely do it justice, so I'll have to make a video shortly. Watching the molecule "fold up" from its usual flat schematic is a small revelation.

And yes, that's the "Starship Imagination" lurking in the background. You'll be seeing a lot of it. (You gotta have somewhere comfy to sit, when contemplating the universe.)

The colours? Blue is nitrogen, red is oxygen, grey/white is carbon. Most of what you're looking at are the 'P' orbitals overlapping. Oxygen has two coloured 'lobes' available for bonding, nitrogen has Three, Carbon of course has the full set of four. Things are scaled so a hydrogen atom's 1S orbital would be about a meter across, so the entire molecule is about the 'size' of a small building.

This is not your normal ball-and-stick molecular model, and yes it's harder to see the core structure as a result... but nature isn't as neat and tidy as our schematics would prefer. This is my own small attempt to better show the reality of what a molecule "looks like", if you could shrink yourself to its scale. Ghost-like waves of probability dominate, not little billiard balls.

Sensors are reading Wake-up-juice, Captain! We're saved!
There's been several advances in the code required to make all this happen:

- Scripting System
- Multiple scene models
- Physics Engine
- Specular Shaders (for that 'shiny' look)

In particular, the molecule is a huge "hinge and spring" system built with the cannon.js physics engine, with imported Blender 3D assets for each atom.

In fact, since I like to show the code, here's the part of the script that assembles the molecule:

{"collada":{ "id":"hydrogen", "url":"asset/collada/atomic/hydrogen.dae", "transform":"scale(0.75)" }},
{"collada":{ "id":"oxygen",   "url":"asset/collada/atomic/oxygen.dae",   "transform":"scale(0.75)" }},
{"collada":{ "id":"nitrogen", "url":"asset/collada/atomic/nitrogen.dae", "transform":"scale(0.75)" }},
{"collada":{ "id":"carbon",   "url":"asset/collada/atomic/carbon.dae",   "transform":"scale(0.75)" }},

{"collada":{ "id":"carbon",   "model":"translate(  0 -1 -20)" }}, {"physics":{ "model":"carbon.1", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"carbon",   "model":"translate(  0  9 -20)" }}, {"physics":{ "model":"carbon.2", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"carbon",   "model":"translate( 16  4 -20)" }}, {"physics":{ "model":"carbon.3", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"nitrogen", "model":"translate(  8 12 -20)" }}, {"physics":{ "model":"nitrogen.1", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"nitrogen", "model":"translate(  8 -4 -20)" }}, {"physics":{ "model":"nitrogen.2", "proxy":{ "type":"sphere", "radius":2 } }},

{"collada":{ "id":"carbon",   "model":"translate( -8 12 -20)" }}, {"physics":{ "model":"carbon.4", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"carbon",   "model":"translate(-16  0 -20)" }}, {"physics":{ "model":"carbon.5", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"nitrogen", "model":"translate( -8 -6 -20)" }}, {"physics":{ "model":"nitrogen.3", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"nitrogen", "model":"translate(-16  8 -20)" }}, {"physics":{ "model":"nitrogen.4", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"oxygen",   "model":"translate( -8 20 -20)" }}, {"physics":{ "model":"oxygen.1", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"oxygen",   "model":"translate(-20 -6 -20)" }}, {"physics":{ "model":"oxygen.2", "proxy":{ "type":"sphere", "radius":2 } }},

{"collada":{ "id":"carbon",   "model":"translate(-8 -12 -20)" }}, {"physics":{ "model":"carbon.6", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"carbon",   "model":"translate(-20 12 -20)" }}, {"physics":{ "model":"carbon.7", "proxy":{ "type":"sphere", "radius":2 } }},
{"collada":{ "id":"carbon",   "model":"translate( 16 18 -20)" }}, {"physics":{ "model":"carbon.8", "proxy":{ "type":"sphere", "radius":2 } }},

{"physics":{ "constraint":[
{"type":"point", "force":0.1, "from":{"model":"carbon.1", "point":[0,4,0]},  "to":{"model":"carbon.2", "point":[0,0,4]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.1", "point":[0,0,4]},  "to":{"model":"carbon.2", "point":[0,4,0]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.1", "point":[4,0,0]},  "to":{"model":"nitrogen.2", "point":[0,0,4]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.1", "point":[-4,0,0]}, "to":{"model":"nitrogen.3", "point":[4,0,0]}},

{"type":"point", "force":0.1, "from":{"model":"carbon.2", "point":[0,4,0]},  "to":{"model":"nitrogen.1", "point":[0,0,4]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.2", "point":[-4,0,0]}, "to":{"model":"carbon.4", "point":[4,0,0]}},

{"type":"point", "force":0.1, "from":{"model":"carbon.3", "point":[0,4,0]},  "to":{"model":"nitrogen.1", "point":[4,0,0]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.3", "point":[0,0,4]},  "to":{"model":"nitrogen.2", "point":[0,4,0]}},

{"type":"point", "force":0.1, "from":{"model":"carbon.4", "point":[0,4,0]},  "to":{"model":"oxygen.1", "point":[0,4,0]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.4", "point":[0,0,4]},  "to":{"model":"oxygen.1", "point":[4,0,0]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.4", "point":[-4,0,0]}, "to":{"model":"nitrogen.4", "point":[4,0,0]}},

{"type":"point", "force":0.1, "from":{"model":"carbon.5", "point":[0,0,4]},  "to":{"model":"nitrogen.3", "point":[0,4,0]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.5", "point":[0,4,0]},  "to":{"model":"nitrogen.4", "point":[0,0,4]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.5", "point":[-4,0,0]}, "to":{"model":"oxygen.2", "point":[4,0,0]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.5", "point":[4,0,0]},  "to":{"model":"oxygen.2", "point":[0,4,0]}},

{"type":"point", "force":0.1, "from":{"model":"carbon.6", "point":[0,4,0]},  "to":{"model":"nitrogen.3", "point":[0,4,0]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.7", "point":[0,0,4]},  "to":{"model":"nitrogen.4", "point":[0,0,4]}},
{"type":"point", "force":0.1, "from":{"model":"carbon.8", "point":[-4,0,0]},  "to":{"model":"nitrogen.1", "point":[0,4,0]}},

{"type":"spring", "length":40, "force":0.001, "from":{"model":"carbon.1"},  "to":{"model":"carbon.3"}},
{"type":"spring", "length":40, "force":0.0001, "from":{"model":"carbon.1"},  "to":{"model":"carbon.4"}},
{"type":"spring", "length":40, "force":0.0001, "from":{"model":"carbon.1"},  "to":{"model":"carbon.5"}},
{"type":"spring", "length":40, "force":0.0001, "from":{"model":"carbon.1"},  "to":{"model":"carbon.6"}},
{"type":"spring", "length":40, "force":0.0001, "from":{"model":"carbon.1"},  "to":{"model":"carbon.7"}},
{"type":"spring", "length":40, "force":0.0001, "from":{"model":"carbon.1"},  "to":{"model":"nitrogen.1"}},
{"type":"spring", "length":40, "force":0.0001, "from":{"model":"carbon.1"},  "to":{"model":"nitrogen.4"}},
{"type":"spring", "length":30, "force":0.001, "from":{"model":"carbon.6"},  "to":{"model":"oxygen.1"}},
{"type":"spring", "length":40, "force":0.001, "from":{"model":"carbon.6"},  "to":{"model":"carbon.3"}},
{"type":"spring", "length":20, "force":0.001, "from":{"model":"carbon.7"},  "to":{"model":"oxygen.1"}},
{"type":"spring", "length":20, "force":0.001, "from":{"model":"carbon.7"},  "to":{"model":"oxygen.2"}},
{"type":"spring", "length":40, "force":0.001, "from":{"model":"carbon.8"},  "to":{"model":"oxygen.2"}}

A little chunky, but that's it. Really. And yes, this is a rather fake system using springs to 'prop open' the molecule rather than simulating all the interatomic repulsive forces, but hey, you need to have room to improve.

Thursday, October 15, 2015

Google Drive Hosting? Not anymore.

So, this has been a kick in the teeth...

"Beginning August 31st, 2015, web hosting in Google Drive for users and developers will be deprecated. You can continue to use this feature for a period of one year until August 31st, 2016, when we will discontinue serving content via[doc id].

In the time since we launched web hosting in Drive, a wide variety of public web content hosting services have emerged. After careful consideration, we have decided to discontinue this feature and focus on our core user experience."

This is enormously bad. Not just for me, for everyone. I don't know how to communicate what the knock-on effects could be, but this is probably the end of "free" file hosting on the internet. It's certainly a major problem for my Astromech project, which currently uses Google Drive for users to store and publish their 3D assets.

If you're happy with an entirely corporate internet landscape, where every byte is bought and paid for by someone and the prerequisite for getting published is a credit card, then welcome to the new world.

But to me, that's not what the internet was for. The people who built the 'net were scientists and students, educators and children, a segment of the population which pretty much by definition doesn't have any money. Just time, and passion, and knowledge.

Now if you think "hang on, there's still lots of free file hosting services", then remember that none of them want you serving files out the 'back end' to all an sundry, like a website does. Filenames are obfuscated. Relative paths are broken. Logins are required. On Amazon, a whole eight machines can access the data! Eight!

Sure there's and MediaFire, but they want the chance to put splash advertising in front of the download. That doesn't work for AJAX includes.

The keyword here is "direct links". That's what lets you copy a directory of HTML and images to a server and all the hyperlinks work as intended. So /doc.html can refer to /image.png and the server knows to get it from the same place just next-door. If you copy a directory to DropBox, for example, each file gets 'stored' in what seems like a different randomly named directory, (although the 'base' filename is there) And don't even _try_ pulling down the public directory list and extracting the file paths. They're heavily obfuscated.

What really concerns me is that once Google kick everyone off their free hosting, the 'parasites' will move on to DropBox or Amazon or OneDrive and work out how to gank those systems. Then they will fall like dominoes playing a game of hot potato. And the abusers won't stop, because they have a vested interest. Basically, all the porn will just shift to the next service, and the next. Or into hacked accounts, since they're now valuable for their storage space. (And the problem will get twice as hard to fix. It's easy to blow away sock-puppet accounts, not so easy when they're hijacking real ones.)

And you can bet that other services, like blogger, will have to clamp down on their file uploads too. Or go away entirely. Otherwise it's just Google playing whack-a-mole with itself.

What will vanish is all those little one-person technical sites that served a useful purpose, but had no revenue streams. $200 a year is a lot for a vanity site. They will all just quietly turn off August 16 next year, and it will be like GeoCities shutting down, all over again. Vast chunks of unique content will disappear. Individuals have no place anymore. The porn and cat videos and corporations will remain. Sort of like a neutron bomb for the internet.

So, thanks Google. You've finally gone off the rails from your core promise of "We want more and better internet for everyone!" and added the caveat "So long as you can pay." And you'll have to go back to downloading exabytes of data that you used to store 'locally'. Hope that works out for you.

I'm sorry, but monetizing our friendship means you ain't my friend anymore. You pretended, offered me some nice tools, and used my hard work as the bait for the corporate switch, And you gave a one-paragraph transparently fictitious reason for doing so. That's not something I forgive. If you're going to carelessly destroy months of work, then I - at least - deserve the real reason.

"After careful consideration, we have decided..." Fuck you, Google.

Monday, October 12, 2015

Astromech Beta2 - coming soon

With all projects, you reach that point where it's all downhill from here. In the Sisyphean sense that you rolled that bloody rock all the way up the bloody hill in the expectation that it would, eventually, get easier all of a sudden.'re always looking for that point where you can give it a good shove, and the momentum builds on it's own, enough to maybe get you half-way over that next hill so long as you run fast enough to keep up. That next hill which you only just now can actually see, but really, you always knew was going to be there.

Well, Astromech is reaching that stage. Several highly-experimental chunks of code are coming together nicely. The first release wasn't much more than a poorly implemented asset manager, allowing a few disconnected media files to be dumped into a 3D environment from common editors.

None of that connected particularly well with the inner workings of Astromech, which has modules that do everything from Delaunay triangulation to Keplerian orbital mechanics to real-time digital signal processing of data coming from telescope sensors.

These are all hidden away in javascript modules that aren't finished, let alone documented. There's a scripting interface I haven't had time to work on that's supposed to connect to the inter-client comms system that's only used for chat, right now.

But everything is working, in it's way. All the prototype problems are solved. The Google Realtime API was giving me some grief until I rewired my head and figured out how it's meant to be used. (quick version: DO NOT store tree-like structures using the API. Flatten them into unordered tabular lists, and keep lots of lists. Otherwise, the multi-user undo/redo system will give you a bad time.)

What's coming soon is the new Astromech "editor" app, which is a near-complete rework of the old list of lists system. The new set of available objects is too large to maintain this approach, and so new ideas are needed. (Or perhaps, some old ideas need revisiting. Duh duh daaa!)

Also, the GUI-based editors for the DSP chain and Panel systems are done at last. Getting these two vast wodges available in the pointy-clicky interface has been a long road, but they are absolutely core to the idea of what Astromech is... not just a pretty face, but a tool for accomplishing some nifty science.

The DSP editor has the job of allowing the user to connect together processing blocks like 2D Fourier transforms, convolutions, etc. similar to the "node editor" in Blender, which creates complicated material and animation effects by mixing together an "algebra" of core operators.

Blender struggles to implement this functionality in a simple way, and it's got full control over the user's screen, mouse, and keyboard. My editor is usable on an iPad.

So is the Panel Layout editor, which creates hierarchical box layouts for UI and text displays that are applied to surfaces in the scene. Panels are a kind of sprite-driven micro-language for information displays. They made some early appearances in this blog, but have been missing from the recent demos, until I could make them available for everyone. In essence, chunks of JSON text are rendered to 'compressed' textures, which make use of "superpixels" (or "sprites" in the old days) that come from a common font/symbol swatch used by every panel in the system.

That means the first display console takes a fair chunk of GPU texture memory for the font swatch, but after that each (high resolution) text panel uses as much extra memory as an old-school character-based Teletext display. There's a massive global saving in texture memory, while still getting crisp-edged text on every surface.

There's more than a few cutting edges still sticking out, though, so I have to make another smoothing pass or two, a process of simply grinding away until - well, not until it's perfect - but at least has a chance to solve more problems than it would cause,  To be worth the time cost of learning how to work it.

One day, I hope to completely erase the line between "editor" and "scene", and have all these tools available while inside the 3D environment. That's a few hills over, though.