This week has so far had an AU theme to it, just as last week we talked exclusively aboutLeapMotionandAutoCAD. Perhaps I’m sub-consciously shifting this blog to a weekly-themed format? Hmm.
Like many of you, I’m sure, I received an email over the weekend to let me know that the recorded sessions from Autodesk University 2012 are now available online (for anyone with a valid AU online account).
There is loads of great content up there on the AU Online site. I strongly recommend checking out the content from the other members of my team who presented at AU 2012, for instance, even if these particular sessions were unfortunately also not recorded:
Well-documented approach for creating AutoCAD apps that work with Google App Engine
Please feel free to post comments with links to other sessions that people might find of interest (posting links to your own is fine, too, as long as they’re at least vaguely development-focused). I know the ADN team presented many well-received and valuable sessions at AU 2012, for instance.
As part of my preparation for AU 2012, I’ve been working on updating the various Windows 8 samples I’ll be showing to work with the RTM version of the OS. The first to be migrated was the Apollonian Viewer for WinRT, which is part of the cloud & mobile series from earlier in the year.
The project was easy enough to get working: I mostly had to update to version 2.3.0 (or 2.3.1, as this was the latest available) of SharpDX and made a few minor code changes (there was previously a SafeDispose() function that seems to have disappeared and a Colors class has been renamed Color) on top of the changes that were made in my update to the original post.
With my AUv recording out of the way, I’ve been starting to think more seriously about my AU sessions, over the last few days. The “big one” (with 100+ registered attendees and counting) is about moving code from a desktop application to the cloud, and will basically summarise the process I followed in my “cloud & mobile” series of earlier in the year. Which means I’ll go through the process of pulling some code out of a desktop-based application and placing it behind a web-service, before calling the service from a variety of platforms/environments (AutoCAD via .NET, iOS, Android, WinRT, Unity 3D and WebGL).
Pretty much all of these should be easily demoable during the session, but I was a bit concerned about the Android piece: until now I’ve only been able to execute the Android version of my Apollonian Viewer application on my Kindle Fire device, which doesn’t have an easy way of connecting to a projector. So I set out with the intention of getting the app working on my desktop (whether inside Windows or OS X), so that I wouldn’t even have to worry about cables or connectivity issues.
There were two main routes open to me for this. The first (which I should probably point out didn’t work for my particular situation, before anyone starts trying it without reading to the end) was presented by Philippe Leefsma, over on ADN’s Cloud & Mobile DevBlog: to install a Virtual Machine based on Android-x86, a x86 port of the Android OS. It took my a while to track down a usable “generic” ISO image: they seem not to have posted one for the latest version, 4.0-RC2 – all the versions posted for download are targeting specific hardware configurations – so I ended up having to take a chance on an unstable nightly build posted here.
Following the steps Philippe suggested, I managed to get a new Android VM sitting alongside the ones I have for Windows 7 & 8 on my Parallels Desktop installation on OS X:
When launched, it started a fancy new Android session directly on my desktop:
Running netcfg inside a terminal window on the device told me its IP address, which I could then use to connect to it via adb. From there it was straightforward to debug on the device, connecting to it from my project in Eclipse. This also installed the app, so that can we can also see it in our list when not debugging:
Launching it, though, leads to a crash:
The reason it didn’t work – and I half knew this, but wanted to go through the process of setting this up, anyway – was that OpenGL ES 2.0 is not supported by Android-x86, at least not right now.
Which left the second option… to get the Android emulator to run OpenGL ES 2.0. The good news is that since earlier this year this has been possible, it seems. It was a bit fiddly to set up – this page helped a lot – but it took me some time to actually get a GPU-enabled emulator instance running OpenGL ES 2.0.
Here are the settings I used – I found I couldn’t set the “GPU emulation” hardware setting on an existing emulator, for some reason, but creating a new virtual device solved that:
One of the major issues was that even if it’s possible to get the emulator set as GPU-enabled the emulator reports itself as not supporting OpenGL ES 2.0. So in your code you need to find a way to suppress the standard check again this property when you’re testing with an emulator.
Thankfully Rajawali, the 3D framework I’m using for my application, added this capability some time ago. It was a simple matter to change the application to set the protected checkOpenGLVersion boolean to false, which allowed the application to execute and me to find the remaining issues to fix (which basically comprised the fact that for performance reasons 3D primitives – such as Spheres, the only one my application creates – no longer have a default material attached, so we have to create one).
And so I could run the application inside an OpenGL ES 2.0-capable emulator. Yay!
Here’s the base environment:
Here are the applications:
And here are the launch screens for the Apollonian Viewer:
And finally we see our spheres, even if the lighting looks like it needs some adjustment:
Now that I have at least the basics working, I’ll probably get back to working on the core material. At some point I may take the time to see what’s up with the lighting – perhaps my lights need adjustment or I’m using the wrong material – but for now I’m just happy to see the app working inside an emulator.
Last week, I received confirmation that I’ll be presenting a few different classes at AU 2012, which will be held at the Mandalay Bay Hotel in Las Vegas from November 27-28. My main sessions, this year, are in some way focused on cloud & mobile technologies.
The subject matter of the first lecture is the recently completed cloud & mobile series, where we’ll look at moving desktop functionality to the cloud and using it from a variety of mobile environments:
CP1914 – Moving code to the cloud – it’s easier than you think!
It has a companion roundtable session – which I believe is scheduled to happen directly after it – that will hopefully be broader (and with plenty of relevant input from participants).
CP4342-R – Cloud and mobile developer round-table
The second lecture is going to look at the MetroCADbrowserapplication I wrote for Windows 8 (and will, of course, go into some detail on WinRT and writing Metro-style applications). I may also talk a little about creating a 3D WinRT application (which will be covered primarily in the first lecture).
CP1921 – Developing a simple Metro-style application for Windows 8
Similar to the last few years, I’ll also be part of two panel sessions…
CP1482 – AutoCAD – Meet the Experts
CP3573 – AutoCAD Programming Gurus Go Head to Head
The first is a general Q&A with AutoCAD experts (and I have it on good authority that there’ll be a few new faces from Autodesk in attendance, this year – more than just the “usual suspects” :-).
The second is a fun – and challenging – session where the panel gets thrown a set of 10 questions by the audience, and basically have the duration of the session to present solutions (or guidance on how to do so).
Although the “call for proposals” has now closed for physical AU sessions, it’s possible to submit class proposals for AU Virtual until August 3rd. (It’s likely I’ll also be presenting a virtual session, this year – more on that later, should it end up happening.)
Right, that’s about it from me for the month of July…
Tomorrow is Autodesk’s annual football (yes, meaning soccer) tournament in Europe. This year, it’s being hosted in Switzerland, which is going to make travel much more straightforward. :-) In recent years, I’ve played for a divisional team – largely made up of members of the ADN organisation – but given my recent change of role I’ve opted to play for one of the local teams, giving me the chance to train with the team for which I’ll be playing. In theory, the team I’m part of is our second team (called Dynamo Helvetia and made up of players who want to play for the love of the game, rather than the glory ;-), but during our most recent practice match we gave our first team (Sparta Helvetia) a pretty good run for their money. Besides the two Swiss teams, we’ll have players coming in from all over Europe and the US. It should be a fun tournament!
After that, we’re heading off on holiday for three weeks, visiting friends and family in France and the UK (although hopefully we won’t regret hitting the London area as the Olympics starts – fingers crossed). I may be able to post the odd update from the road – and do have the odd post queued up, to keep some information trickling through – but please don’t expect me to respond to comments or emails until I’m back in August.
You might consider this another “horizontal” blog, in the sense that over time it will prove to be a valuable resource for people using our products (and, I suspect, many people who don’t) in all the industries we serve.
It seems like a good time to provide a bit of background on these DevBlogs and the motivation behind them…
It’s clear our ADN team is focusing more of its resources on providing public information and assistance. The trend started several years ago, during the time I was part of that team: between our developer blogs, our Plugins of the Month, the My First Plugin material and a gradual increase in our presence on the API discussion groups.
All this has been part of a broader strategy to do more for customers who don’t necessarily see the benefit of paying an annual fee to be part of the ADN program.
One further piece of this strategy is going to be unveiled during the coming weeks (we’re just working on some back-end infrastructure before the public launch). Without giving too much away, I will say that I expect many of this blog’s readers to find it pretty interesting. Watch this space! :-)
Update:
For those of you interested in an aggregated feed of the various developer-oriented Autodesk blogs, I went ahead and updated the Yahoo! Pipe I originally created some time ago to include the various ADN DevBlogs. As I know AlexF will be pinging me for it, anyway, as soon as he sees this post. ;-)
As we reach the end of this long series of posts on moving code to the cloud – and a look at ways to use the functionality from a wide variety of applications, many of them on mobile devices – I felt it was worth putting together a quick summary post to reinforce the overall message (which may have been a bit lost in the sheer volume of information).
Firstly, here are the posts in this series, including those looking at the original creation of the “desktop” application functionality:
Here are the client application projects I’ve posted for Android, iOS & WinRT.
Perhaps it’s time to say a few words about the experience I had with each of these environments…
Unity3D was great and would certainly allow you to create a 3D app that could be used in any of the other environments (with the possible exception of WinRT for now, at least). I’d definitely consider this again to create a cross-platform 3D app.
Android surprised me: I really liked the language (Java), the chosen 3D framework (Rajawali) and the development tool (Eclipse).
WebGL & Three.js proved to be both easy to use and extremely powerful. Definitely an area to watch as WebGL gets more browser support, especially on mobile platforms.
iOS was very strange for me, but didn’t prove to be so awful to develop for: while I found the Objective-C syntax to be quite jarring and the Xcode tool to be both confusing and somewhat unstable, the capabilities of the platform and its primary language were quite mature: you can do quite a lot with relatively few lines of (admittedly pretty weird-looking ;-) code. I found iSGL3D reasonably good, although I was ultimately disappointed with the results I was personally able to get from it.
WinRT was fairly familiar – given my history with .NET – although the lack of a higher-level framework (with a simple sphere primitive, for instance) meant I struggled more with this than I’d have thought. I hope/expect that to be addressed by somebody at some point: while SharpDX allowed me to at least use C# to create a Metro-style Direct3D app, I really would have benefited from a higher abstraction layer to code against.
And to conclude…
This series was really intended to demonstrate that there are significant benefits in making core algorithms cloud-based, not only from an architectural perspective, but from the broad range of applications it enables you to provide to your customers in the long term. And also that this technology really isn’t hard: most of the client apps took a day or two to develop and none took more than a week.
I’ve chosen to deal with graphical data in this series of posts – mainly to make them more visually interesting – but it’s arguably even more compelling to broaden the reach of associated, non-graphical design data using this kind of approach.
Hopefully some of you have followed along with these posts, and derive at least some benefit from seeing similar code working in a variety of languages on a variety of technology stacks. It’s certainly been a fun one to work on: diving so deeply into the respective technologies has at times been challenging but highly educational. :-)
After starting the sub-seriesfocused on iOS, I held off completing it until I could actually test the code on a physical iOS device. A big thanks to Andy Chang from our Toronto office for getting me set up with the ADP membership and my iPad 2 added to the list of usable development devices.
I won’t talk about the steps needed to provision apps for iOS devices – there seems to be enough information available on the web for that – but I will say it ended up being less complicated than I expected. That’s not to say it’s easy to package things up for posting to the App Store – I haven’t gone through that, myself – but just deploying the app to a physical device for testing was reasonably straightforward.
That said, there was some non-trivial work needed to get an app working on both the iOS simulator and a physical device, mainly due to our use of the iSGL3D. The issue came, in this case, from the fact that iSGL3D has a problem with ARC (Automatic Reference Counting). The path of least resistance ended up being to build it into a universal, static library, which could then be used to build an iOS app that targets both the iOS Simulator (which is i386-based, as it works on the Mac) and the physical, ARM-based iOS device.
I’m still not very happy with the lighting I was able to get working using iSGL3D: the “out-of-the-box” lighting capabilities – presumably built into the base material types – were much nicer with Three.js or Rajawali. I did my best by reading up on iSGL3D lighting, OpenGL lighting and even going back to basics on diffuse, ambient and specular lighting, but the results weren’t as good as I’d have liked. This is probably down to me, rather than the iSGL3D framework, per se, but still.
Here’s the latest version in action on the iOS simulator (which turns out to be comparable to the physical device, graphics-wise, even if the framerate is indeed much lower):
That's it for the sub-series on iOS (for now, at least) and for the overall series on cloud & mobile (from a technical perspective). In the next post, we’ll take a look back at the series and comment on the journey we’ve been on for the last month or so.
In the last post, we created another, basic 3D viewer for the data from our Apollonian web-service – this time using HTML5 via Three.js. In this post, we’ll extend the code to listen for keyboard events and manipulate the model according to user-input, as well as enabling feature detection of WebGL (allowing the same implementation to call into the canvas rendering code when WebGL isn’t present).
We’re introducing keyboard-based commands to enable zoom, rotate (meaning spin, although not continuously) and the change of levels:
+
Zoom in
-
Zoom out
, or %
Rotate left
. or /
Rotate right
& or a
Rotate up
( or z
Rotate down
0 – 9
Change level (0 == 10)
You’ll see some strange choices for some of the rotate keys, above: on browsers other than Chrome, the keypress event gets called with symbols representing the arrow keys (left: ‘%’ right: ‘/’ up: ‘&’ down: ‘(‘). But because of an issue with Chrome that means its doesn’t receive the keypress event for arrow keys, we’re also checking for other characters, too (left: ‘,’ right ‘.’ up: ‘a’ down: ‘z”).
For changing levels: we might also have confirmed the change of level with the user via a message-box, but in the end I felt it wasn’t too disruptive to just do it.
Before we see the code, here’s a quick demo video and a link to the page:
[Errata: I mistakenly said “level 5” in the below video instead of “level 10”, and I also should have reinforced that the view was really using WebGL rather than basic HTML5 Canvas.]
// On Firefox we need event.which rather than keyCode
var code = event.keyCode ? event.keyCode : event.which;
switch (String.fromCharCode(code))
{
case'-': // Zoom out
zoomScale -= 0.1;
break;
case'+': // Zoom in
zoomScale += 0.1;
break;
case'=': // Reset view
zoomScale = 1;
root.rotation.x = 0;
root.rotation.y = 0;
break;
case'\'': // Rotate right
case'.':
yRotation = rotInc;
break;
case'%': // Rotate left
case',':
yRotation = -rotInc;
break;
case'&': // Rotate up
case'a':
xRotation = -rotInc;
break;
case'(': // Rotate down
case'z':
xRotation = rotInc;
break;
case'0':
case'1':
case'2':
case'3':
case'4':
case'5':
case'6':
case'7':
case'8':
case'9':
var level = code - '0'.charCodeAt();
populateWithLevel(level == 0 ? 10 : level);
break;
}
}
);
populateWithLevel(10);
}
function populateWithLevel(level)
{
// Make sure we're not already changing levels
if (changingLevel)
return;
changingLevel = true;
// If we already have a level loaded, remove the
// root from the scene and delete it
if (root != null)
{
scene.remove(root);
delete root;
}
// Make sure CORS is enabled
jQuery.support.cors = true;
// Call our web-service with the appropriate level
$.ajax(
{
url:
'http://apollonian.cloudapp.net/api/spheres/1/' +
level,
crossDomain: true,
data: {},
dataType: "json",
error: function(err)
{
alert(err.statusText);
},
success: function(data)
{
// Create the spheres' materials
var materials =
[
new THREE.MeshLambertMaterial({ color: 0x000000 }),
new THREE.MeshLambertMaterial({ color: 0xFF0000 }),
new THREE.MeshLambertMaterial({ color: 0xFFFF00 }),
new THREE.MeshLambertMaterial({ color: 0x00FF00 }),
new THREE.MeshLambertMaterial({ color: 0x00FFFF }),
new THREE.MeshLambertMaterial({ color: 0x0000FF }),
new THREE.MeshLambertMaterial({ color: 0xFF00FF }),
new THREE.MeshLambertMaterial({ color: 0xA9A9A9 }),
new THREE.MeshLambertMaterial({ color: 0x808080 }),
new THREE.MeshLambertMaterial({ color: 0xD3D3D3 }),
new THREE.MeshLambertMaterial({ color: 0xFFFFFF }),
new THREE.MeshLambertMaterial({ color: 0xFFFFFF })
];
// Set up the sphere vars
var rootRad = 0.01, segs = 9, rings = 9;
// Create our root object
var sphereGeom =
new THREE.SphereGeometry(rootRad, segs, rings);
// Create the mesh from the geometry
root =
new THREE.Mesh(sphereGeom, materials[0]);
scene.add(root);
// Process each sphere, adding it to the scene
$.each(
data,
function (i, item)
{
// Get shortcuts to our JSON data
var x = item.X, y = item.Y, z = item.Z,
rad = item.R, level = item.L;
var length = Math.sqrt(x * x + y * y + z * z);
// Only add spheres near the edge of the outer one
// (and only the front half if not animating)
if (
length + rad > 0.99 &&
(animateWithWebGL || z > 0)
)
{
// Create the mesh from the geometry
var sphere =
new THREE.Mesh(sphereGeom, materials[level]);
sphere.position.x = x;
sphere.position.y = y;
sphere.position.z = z;
var scaledRad = rad / rootRad;
sphere.scale.x = scaledRad;
sphere.scale.y = scaledRad;
sphere.scale.z = scaledRad;
root.add(sphere);
}
}
);
// Draw!
renderer.render(scene, camera);
changingLevel = false;
}
}
);
}
function animate()
{
requestAnimationFrame(animate);
render();
}
function render()
{
if (root != null)
{
// Apply rotations around X and/or Y
if (xRotation != 0)
{
root.rotation.x += xRotation;
xRotation = 0;
}
if (yRotation != 0)
{
root.rotation.y += yRotation;
yRotation = 0;
}
}
// Apply the zoom
camera.position.z = 4 / zoomScale;
camera.lookAt(scene.position);
renderer.render(scene, camera);
}
</script>
</body>
</html>
A few things to note:
The hasWebGL() function returns true if the browser supports the use of WebGL. We use the result of this function to determine whether to create and use a WebGL or a Canvas renderer.
We use jQuery to assign a handler to the document’s keypress() event.
We need to check event.keyCode in most browsers but event.which on Firefox.
When changing levels we set a flag: if we kick off multiple level changes – very easy to do with the longer-loading levels – then we run the risk of stomping on our geometry list… safest to protect it with a rudimentary critical section.
That’s about all there is to it. The application itself works surprisingly well on WebGL-enabled browsers. If I use it for long enough, I can usually crash the page in Chrome (as you’ll see from the demo video), but in Firefox the page is rock solid (which leads me to be believe it’s a browser issue rather than a problem with the code).
Since publishing the last post (and this one was already pretty well baked, too), Jeff Geer has pointed me at the trackball capability in Three.js, which allows you to more simply create a user-interface to control 3D orientation of your model. In the next post we’ll take a look at integrating that – probably alongside some of the existing keypress-enabled level changing – to see what that provides.
After looking at how to bring data from our Apollonian web-service into Unity3D, Android and iOS over the last few weeks, it seemed natural to extend this series to cover HTML. A big thanks to Jeff Geer for suggesting Three.js, which is the HTML5-based framework I ended up adopting for this project.
I like Three.js for a number of reasons: just as jQuery (another library I’ve used in this project, to good effect) attempts to abstract away the messiness inherent in supporting multiple browsers, Three.js does the same for the world of browser-resident 3D.
The other main reason I like Three.js is that it’s open source. I know, I know – I work for a proprietary software vendor… :-) But unless there’s a trusted, proprietary vendor providing platform technology, I really do prefer to have the peace of mind of having access to the framework’s source. And for my adjacent, experimental projects, I tend not to want to spend money on fully-fledged toolkits/frameworks, either, which means I gravitate to open source tools, or at least those that have versions available for free.
In terms of getting started with Three.js, the online tutorial deals with creating a simple scene with a sphere in it, so that was just perfect. :-)
The coding was reasonably straightforward: the main issue – on all fronts – was to enable cross-domain scripting of our web-service. On the server side, we had done so using a crossdomain.xml file when we first needed to call it from Unity, but we needed to go one step further, this time: we had to modify the Web.config file of our ASP.NET project and redeploy the project to Windows Azure. Not a big deal, but it needed doing.
The only difference between the two HTML files is the value of the animateWithWebGL flag, which obviously causes a slightly different code-path to be followed in a few places.
To see them both in action on my system, here’s a quick video:
To compare how the canvas-based viewer looks on different OS/browser combinations, here are those I’ve tested. The results are mostly pretty decent, although Safari on OS X had something very strange going on (whereas it worked fine in the iOS emulator on the same system).
In the next post, we’re going to make a few enhancements to this HTML5-based viewer: we’ll add support for keyboard events – to enable zoom, rotate and changing levels, in particular – as well as implementing feature detection to use WebGL automatically when available or to default to the use of the canvas renderer, otherwise.
Recent Comments
Archives
More...