Skip to main content

User login

What is OpenID?
  • Log in using OpenID
  • Cancel OpenID login
  • Create new account
  • Request new password
Register
  • Home
  • Browse
    • 2D Art
    • 3D Art
    • Documents
    • Music
    • Sound Effects
    • Textures
    • Featured Tutorials
  • Submit Art
  • Collect
    • My Collections
    • Art Collections
  • Forums
  • FAQ
3D Art

Reverse Engineering "Ultima VII" Isometrics: WIP

Toeholds
Tuesday, April 27, 2010 - 06:42

The weeks' Friday Challenge is "homage", and the first thing that came to my mind is the unique style of Ultima 7.  A few days ago, I chatted with Bart on IRC about generating 2D-sprites from 3D-model, and thought I'll put 1+1 together...

...adding up to a PITA.  The graphical style of Ultima 7 comes from both the perspective as well as the rendering.  The perspective is a -135 oblique projection (thanks to the folks at Exult... I fiddled fruitlessly to get isometric to work); turns out that no major 3D modelling software supports this (non-)perspective.  Oblique projections are used in the ol' days for design/architecture, and organic forms are pretty hard to draw accurately.  (In U7's case, the severe distortion make it very hard to see if things are drawn correctly...)  The workaround is to have a camera with proper perspective pointing at a far, far away object that is appropriately offset from the scene you wish to render and xy-shift the line-of-sight.  After major fiddling, you end up with more-or-less the right perspective (I got sick of it when I was ~2-3 degrees off).

The rendering itself is mostly lit from the NW (top-left) direction, except for external architecture, where the shading is even throughout.  All images are outlined in a 1px black stroke (there are exceptions).  It's also very pixelated, but I think we don't need to emulate that aspect :)

An example follows.  Apparently there is a group that is trying to recreate/extend the original U7, so if nothing else, this stuff could be of interest to them!

  • Add new comment
bart
Tuesday, April 27, 2010 - 12:46
bart's picture

Couldn't you achieve this with an orthographic camera?

  • reply
Clint Bellanger
Tuesday, April 27, 2010 - 12:53
Clint Bellanger's picture

No 3D camera can produce what's in that screenshot.  Orthographic basically means items don't get smaller as they get further from the camera.  In this Ultima VII style, planes parallel to the ground are rendered without distortion but planes perpendicular to the ground have that 135 degree angle.

What might be possible is making 3D models as usual then using Shear transforms on the models themselves to approximate the desired shape.

  • reply
Clint Bellanger
Tuesday, April 27, 2010 - 13:03
Clint Bellanger's picture

This seems to work.  I took my Broken Tower and sheared the model the same amount on the X and Y planes.  Here's the Diablo isometric view compare to the faked Ultima VII perspective using Shearing.

 

 

  • reply
Toeholds
Tuesday, April 27, 2010 - 14:08

Good thinking pfunk!  I tried shearing the isometric output (which looks strange), but I haven't thought about shearing the model.  That would make accurate adjustments much easier to make. 

And now that you've put up an isometric and an oblique side-by-side, the latter looks bizarrely distorted.  Once upon a time, I spent many hours looking at this world with a strange perspective... be it any wonder that I look at the world with a strange perspective today? ;)  I wonder how the artists at Origin deal with 10,000 of these without much to work with back in the days...

  • reply
bart
Tuesday, April 27, 2010 - 14:02
bart's picture

I'm not sure that this is truly impossible with any 3d camera, as long as you allow for orthographic cameras and some intereststing transformations.  That view there is actually just an oddly scaled and rotated isometric view, which is possible with an orthographic camera:

 

  • reply
Toeholds
Tuesday, April 27, 2010 - 14:30

Bart, they are not fully convertible with only 2D transforms -- your solution is similar to pfunk's, although it requires a Z-compression on the model as opposed to a 3D-shear (actually, I like yours better - it's immediately obvious how to set this up with little/no experimentation).  The scaling can't (?) be done on the 2D level and maintain the isometric angles (is this true?).  In any case, this is quite cool -- it means that there's direct, automatable workflow from 3D to this flavor of 2D, via a combination of blender scripting and batch image operations.

  • reply
Toeholds
Tuesday, April 27, 2010 - 14:29

I just noticed that I didn't mention it in the first post.  The outline generation can be done at render time in Blender, or stroking the render in PS.  I did the above with blender, since I wanted to stroke the internal contours as well; but if it is to be scaled non-uniformly as part of the post-processing, stroking in PS at the end is the way to go.

  • reply
Clint Bellanger
Thursday, April 29, 2010 - 01:47
Clint Bellanger's picture

Start with a scene in 45 degree isometric.  Video game style, where the camera angle is Blender (60,0,45).

In Blender if you look at Buttons Window -> Scene -> Render Buttons -> Format, you can set the render aspect ratio.  Set AspY to half of AspX.  This is the same as taking regular rendered output and scaling X by 50%.  If you rendered a cube, the top of the cube will be a perfect square (though at a 45 degree angle).

We can then use Blender nodes to rotate the result 45 degrees.  The output:

Note this started as a cube, so there's a lot of "vertical" distortion.  So you might have to scale meshes to 50% Z before using this method.  Also notice the Edge seems to be applied after the Aspect, so the edge isn't distorted.

Blend file: http://clintbellanger.net/images/temp/UltimaVII.blend (I'm a Nodes noob so there might be a smarter setup).

For kicks, here is that tower again.  I pulled it into the above workflow scene and scaled Z by 50%.  Click "Re-render this layer" on the first node to create the composite.

  • reply
Lamoot
Thursday, April 29, 2010 - 04:13

When it comes to orthographic perspectives, there's loads of variables and variations, especially in the technical drawing field. Games use only a few of the options available. Anyway, one of the big differences between these two views is that Ultima has 2 of its world axes parallel to the view plane, while the standard 2:1 isometric perspective has only one of its axes parallel to the view plane (its vertical axis)

  • reply
Toeholds
Thursday, April 29, 2010 - 20:23

pfunk: You're the man :)  There's so much I need to learn about blender!

  • reply
Anonymous (not verified)
127.0.0.1
Friday, June 18, 2010 - 14:58

pfunked I am working on an Ultima 7 like RPG Construction Set as speak...but I do need couple of sample tileset to work around them. Is it possible pfunked you can make one single wall, door, one table and one tiny book sprite to work with? All I will simply constantly use it to work my engine around it for future graphics. If you want my email address you can find it at amiga500@gmail.com, thanks in advance.

  • reply
Clint Bellanger
Friday, June 18, 2010 - 16:48
Clint Bellanger's picture

amiga500, hopefully this will give you a starting point for development.  http://opengameart.org/content/perspective-walls-template

  • reply
Redshrike
Friday, July 9, 2010 - 17:28
Redshrike's picture

I've spent a long time working with games in this selfsame perspective (more in the tradition of Tibia, though, which blatantly borrowed and stole from U7), and as such I've seen a lot of discussion on this topic.  Probably the most thorough (if wordy) explanations I've seen was here: http://forum.phobosonline.com/viewtopic.php?f=8&t=4815 if anyone is interested in looking at it more.  Though to be honest it's not too hard to get the hang of the perspective just through practise.

And I must apologize for this sorta necro post, I've been away, but this is the one topic I know anything about... xD

  • reply
TheKingofDemons
Tuesday, February 15, 2011 - 13:49

Pfunked wanna help me add your nifty camera to Briswak? Diablo isometric i meant :) if you dunno how just tell me the specifics and what not. I will probly try editing my file and making it at that angle. :D Oldschool diablo here we come! And if i cant figure it out ima cry.

Just curious but why would systems not be able to make a camera at any angle you want it? This stuff does what its told if told correctly. Just wondering I don't know much about GUI/camera's.

  • reply
Clint Bellanger
Tuesday, February 15, 2011 - 13:46
Clint Bellanger's picture

TheKingofDemons:  I suppose I can offer some advice.

Is it a 3D game (e.g. OpenGL) or 2D?

If 2D, are you using 3D models to pre-render 2D sprites?

This perspective is definitely easy to use if you're doing pixel art, but 3D rendering is obviously tricky.  As you can see by all the above gymnastics.

  • reply
TheKingofDemons
Tuesday, February 15, 2011 - 13:52

It is a 3d direct x c++ game. trying to make it as fimiliar to diablo fans as I can and this camera is a bangin step.

  • reply
Clint Bellanger
Wednesday, February 16, 2011 - 08:54
Clint Bellanger's picture

If you want a Diablo camera the settings are easier.  Put the camera at angle (x,y,z) = (60,0,45).

If you want a pure engineering-schematic style Isometric view, Put the camera angle at (x,y,z) = (54.736,0,45) and set the camera to Orthogonal.

  • reply
TheKingofDemons
Wednesday, February 16, 2011 - 15:38

Heres the code what do I change lol. :D

void IsometricCamera::setPosition(float x, float z, float zoom) {
  static const float SCALING = 0.5f;

  D3DXMATRIX a, b;
  D3DXMatrixTranslation(&a, -x, 0.0f, -z);
  D3DXMatrixScaling(&b, 95.0*SCALING, 63.0*SCALING, 9.0*SCALING);
  D3DXMatrixMultiply(&a, &a, &b);

  const FLOAT SWIZZLE_MATRIX[] = {
    1.0,  0.0,  0.0,  0.0,
    0.0,  myTiltWorldFlag?(-0.67-1.0599993) : 0.0,  1.0,  0.0,
    0.0,  1.0,  0.0,  0.0,
    0.0,  0.0,  0.0,  1.0,
  };

  D3DXMATRIX swizzle(SWIZZLE_MATRIX);
  D3DXMatrixMultiply(&myLocationMatrix, &a, &swizzle);

  const FLOAT VIEW_MATRIX[] = {
    1.0,  0.0,    0.0,  0.0,
   0.0, -1.0,    0.0,  0.0,
   0.0,  0.0,   -1.0,  0.0,
   0.0,  0.0,  791.0*SCALING,  1.0,
  };

  const FLOAT PROJECTION_MATRIX[] = {
    4.414213, 0.000000,    0.00000,  0.000000,
    0.000000, 4.414213,    0.00000,  0.000000,
    0.000000, 0.000000,    1.14282,  1.000000,
    0.000000, 0.000000, -571.408*SCALING*zoom,    0.000000,
  };

  myViewMatrix = D3DXMATRIX(VIEW_MATRIX);
  myProjMatrix = D3DXMATRIX(PROJECTION_MATRIX);

  D3DXMatrixMultiply(&myViewMatrix, &myLocationMatrix, &myViewMatrix);
  D3DXMatrixIdentity(&myLocationMatrix);
}

 

Conveinently I think this is already set I am testing it not but mabye I broke it lol. So if anyone knows what I need to change in this please let me know.

  • reply

Add new comment

The content of this field is kept private and will not be shown publicly.
Right Column

More information about text formats

Filtered HTML

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd> <p> <br> <img> <del> <strike> <h1> <h2> <h3> <h4> <h5>
  • Lines and paragraphs break automatically.

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Attachments
You may attach one or more images to your post.
Files must be less than 200 MB.
Allowed file types: png gif jpg jpeg.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Fill in the blank.