 |
Home | Changes | Index | Search | Go
Import Content from Blender into Project Wonderland
Blender is an open-source 3D modeling tool. It can export many formats, some of which can be imported into Project Wonderland. Here are some initial instructions on how to import content generated in Blender into a Wonderland world.
We hope to make the art import process much easier in the future, but for now importing artwork requires developers who are comfortable building and installing the Project Wonderland software.
Getting Started
Here are the tools you'll need:
- Blender. I used version 2.44 for Mac OS X.
- Project Wonderland. You will need a built and working Wonderland source directory.
- Wonderland Artwork. You will need to download the Wonderland artwork locally to add your own content.
- J3dFly. You will need to install J3dFly to convert data to the Wonderland format.
Install Blender according to the instructions for your platform. Check out the source for Project Wonderland, Wonderland artwork and J3dFly into a common directory. I used the following commands:
$ mkdir wl-blender
$ cd wl-blender/
$ cvs -d :pserver:username@cvs.dev.java.net:/cvs co lg3d-wonderland lg3d-wonderland-art j3dfly
Where username is my java.net login.
Once everything is checked out, you'll need to configure Wonderland to use local artwork. You can do this by creating the file lg3d-wonderland/my.build.properties. Add the lines:
wonderland.useLocalArt=true
To the file. The useLocalArt property tells the Wonderland client to load artwork locally, by default from the ../lg3d-wonderland-art directory.
The next step is to configure Wonderland to use an empty world. Using an empty world will mean that we see just the models we are adding, and not all the default models that come with Wonderland. Once you know your models are working properly, you can integrate them into the entire world. To accomplish this, we are going to create a new Wonderland File System and tell our client to use it instead of the default world (for more information about the Wonderland File System, see http://wiki.java.net/bin/view/Javadesktop/ProjectWonderlandWFS).
$ cd lg3d-wonderland/src/worlds/
In this directory you will see a number of other directories ending in "-wfs"; each one represents a "world" in Wonderland File System format. Create a new directory here for your world using the same naming convention, e.g. "test-wfs" -- the "-wfs" is important! All Wonderland File System world directories end in "-wfs".
Now add the following line to the "my.build.properties" file you created earlier:
wonderland.wfs.root=file://BASEPATH/lg3d-wonderland/src/worlds/YOURWORLD-wfs
substituting BASEPATH with the path to where your lg3d-wonderland directory resides, and YOURWORLD for the name of your world directory (e.g. "test-wfs").
We can now load up Wonderland with our new, empty world. Open two terminals and "cd" to the lg3d-wonderland directory in each. In one terminal run:
$ ant run-sgs
And in the other run:
$ ant run
You should see something like figure 1, a very empty world.
Figure 1. A minimal world
|
If that is done, we can start the last piece, J3dFly. If you have Java3D installed system-wide, you should be able to run J3dFly? with the following command:
$ cd j3dfly
$ ant run-j3dfly
I don't have Java3D installed, so I had to modify the J3dFly build.xml script to add in the Java3D classpath. First I added the following line to j3dfly/build.xml:
<property name="extra_libs" location="./extra_libs"/>
<property name="j3d_libs" location="../lg3d-wonderland/ext/macosx/jars"/>
<property name="build.dir" location="build"/>
On Linux, this is as follows:
<property name="extra_libs" location="./extra_libs"/>
<property name="j3d_libs" location="../lg3d-wonderland/ext/linux/jars"/>
<property name="build.dir" location="build"/>
I also added the following to =j3dfly/J3dFly/build.xml:
<target name="compile">
<javac ...>
<classpath>
...
<pathelement location="${extra_libs}/jai_core.jar"/>
<pathelement location="${j3d_libs}/j3dcore.jar"/>
<pathelement location="${j3d_libs}/j3dutils.jar"/>
<pathelement location="${j3d_libs}/vecmath.jar"/>
</classpath>
</javac>
</target>
<target name="run">
<java ...>
...
<jvmarg value="-Djava.library.path=${j3d_libs}/../native"/>
<classpath>
...
<pathelement location="${extra_libs}/jai_codec.jar"/>
<pathelement location="${j3d_libs}/j3dcore.jar"/>
<pathelement location="${j3d_libs}/j3dutils.jar"/>
<pathelement location="${j3d_libs}/vecmath.jar"/>
<pathelement location="${j3d_libs}/jogl.jar"/>
<pathelement location="${j3d_libs}/gluegen-rt.jar"/>
</classpath>
</javac>
</target>
Depending on your platform, you may need to change these values a bit and add or remove some libraries.
Now that J3dFly is all set, you should be able to run it as above:
$ cd j3dfly
$ ant run-j3dfly
Once Wonderland and J3dFly are running properly, we are ready to move on to Blender.
Exporting your model from Blender
Download and install the Blender X3D? Exporter from here: http://www.bitbucket.ca/~acheater/blender/ -- while the default X3D? exporter included with Blender will work, it does not export normal information, so all your textured models (i.e. models for which color information is determined by a bitmap image file) will render completely flat and unshaded (which you may prefer for aesthetic reasons).
The next step is to use Blender to create your model. In this case, we'll keep things simple by just using a cube. If you're using the default startup scene in blender, then you'll be ready to go -- otherwise, simply add a cube to your scene.
A simple cube in Blender
|
If you're using the default startup scene, you should have a cube with a material already applied to it (named "Material").
So now that we have a 3d model, we need to color it by using a 2d texture. I'm going to assume that you already understand how to layout UVs and save out a reference image of the UV layout -- there are a number of resources available that explain how to do this -- but for a cube with the same texture on each side the uv layout is pretty much done for you. I personally like to arrange my Blender windows such that I have the UV Editor in one window and the 3d view in another:
Laying out UVs
|
For my texture I downloaded a nice photo of plywood from http://www.cgtextures.com/ -- this one is 800x595 pixels:
Photo of plywood
|
The first thing we need to do is optimize the image for Wonderland. Optimizing images is an important part of enabling the world to render quickly and with a good framerate. When optimizing, the following things need to be taken into consideration:
- Image size: the image only needs to be as large as it will be displayed on-screen. For example, let's say you are creating a texture for a sign that appears over a doorway. If the sign is placed such that it will never take up more than 300 pixels wide on-screen, then the image doesn't need to be any larger than 300 pixels wide.
- Power of two:Because of the way rendering engines work, images whose dimensions are in powers of two (e.g. 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, etc.) generally require less processing and therefore can speed up rendering, so resize your images accordingly.
- Square: Blender assumes all texture images are square, so to make things easier make sure your images are cropped or scaled to be square.
- File size: smaller files require less memory and load faster, so it's a good idea to make your files as small as possible while maintaining a reasonable level of quality. At this point it's a good time to consider what file format to use. I recommend JPG or PNG, depending on what you want to do with your image. JPG offers a high-level of compression at the expense of quality. PNG offers some compression while maintaining image quality, and can support transparency.
Our plywood image is quite large, rectangular, and its dimensions are not in powers of two, so let's fix that:
Optimized texture
|
Now the image is a reasonable 256x256 and ready to be used as a texture. Note that I saved it as a PNG file -- it was originally a JPG, and while resaving it as a JPG could significantly decrease the filesize, it would also introduce some additional noise into the image and wash out the colors somewhat. To preserve the quality of the image I resaved it as a PNG which provides some compression but is (in this case) lossless.
Now we are ready to import the image into Blender.
Begin by going into the Shading panel:
Now bring up the Texture buttons:
Change the texture type to "Image":
Click the "Load" button and select the image to import:
Now that the image is loaded into Blender, we can load it into the UV Editor to get it to display on the model:
And behold, a plywood box:
Once you have your model and texture ready, there's one more thing to do before exporting. Since Blender uses a Z-up coordinate system and Wonderland is Y-up, rotate the entire model -90 degrees X to have it face in the right direction. Now export to X3D? using the exporter you installed (see above). Be sure to pick the one labeled "X3D" in the menu (the other is the default Blender exporter that doesn't export normals):
Save the file as "cube.x3d". Please note that the x3d file assumes the image is in the same directory, so copy the image file to the x3d file's directory (if necessary) before trying to load the x3d in J3dFly?.
Importing your model into J3dFly
In J3dFly, select File->Import, and import the model, cube.x3d. You may not be able to see the model at first, because it loads behind you. To see it, select Viewing Platform->Orbit and use the mouse to control the viewport camera:
- Zoom: Mousewheel, MMB, or Alt/Option+LMB
- Pan: RMB or Ctrl/Command+LMB
- Rotate: LMB
Zoom out a bit and your model should appear:
Plywood box in J3dFly
|
Now we need to export it for use in Wonderland. In J3dFly, select Plugins->Wonderland->Export to Wonderland. This should bring up a dialog:
Export from J3dFly
|
Don't worry too much about the options, just notice the name that gets exported, and then click the Export button. My model was called cube.x3d, and I can now verify that a file called lg3d-wonderland-art/compiled_models/models/cube.j3s.gz exists in my Wonderland project. J3dfly will not copy textures, so you will need to copy the texture manually into lg3d-wonderland-art/compiled_models/textures/cube/.
Adding your model to your world
To add the model you just created to your world, you need to create a file in the "-wfs" directory you created earlier; this file essentially describes the content of the world.
Copy the text below into a new xml file whose name ends with "-wlc" (e.g. "test-wlc.xml"):
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0-dp" class="java.beans.XMLDecoder">
<object class="org.jdesktop.lg3d.wonderland.darkstar.server.setup.BasicCellGLOSetup">
<void property="cellGLOClassName">
<string>org.jdesktop.lg3d.wonderland.extracells.server.cell.MultiModelCellGLO</string>
</void>
<void property="origin">
<void index="0">
<double>0.0</double>
</void>
<void index="1">
<double>0.0</double>
</void>
<void index="2">
<double>0.0</double>
</void>
</void>
<void property="cellSetup">
<object class="org.jdesktop.lg3d.wonderland.extracells.common.MultiModelCellSetup">
<void property="models">
<array class="org.jdesktop.lg3d.wonderland.extracells.common.MultiModelCellModel">
<object class="org.jdesktop.lg3d.wonderland.extracells.common.MultiModelCellModel">
<void property="modelFile">
<string>models/cube.j3s.gz</string>
</void>
</object>
</array>
</void>
</object>
</void>
</object>
</java>
A brief breakdown of what this xml code means (for more information see the Wonderland File System tutorial at http://wiki.java.net/bin/view/Javadesktop/ProjectWonderlandWFS):
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0-dp" class="java.beans.XMLDecoder">
<object class="org.jdesktop.lg3d.wonderland.darkstar.server.setup.BasicCellGLOSetup">
<void property="cellGLOClassName">
<string>org.jdesktop.lg3d.wonderland.extracells.server.cell.MultiModelCellGLO</string>
</void>
<void property="origin">
<void index="0">
<double>0.0</double>
</void>
<void index="1">
<double>0.0</double>
</void>
<void index="2">
<double>0.0</double>
</void>
</void>
<void property="cellSetup">
<object class="org.jdesktop.lg3d.wonderland.extracells.common.MultiModelCellSetup">
<void property="models">
<array class="org.jdesktop.lg3d.wonderland.extracells.common.MultiModelCellModel">
This is the basic setup code for a new section of the world, describing its origin in 3d space and what type of Cell(s) we're working with. This code can vary somewhat, depending on the configuration of the world and the desired Cell-type(s), but for our purposes the provided code should suffice. Notice the last line of this snippet indicates we're starting an array -- this array will be populated with objects, each of which describes an object in the world.
<object class="org.jdesktop.lg3d.wonderland.extracells.common.MultiModelCellModel">
<void property="modelFile">
<string>models/cube.j3s.gz</string>
</void>
<void property="location">
<array class="double">
<double>0</double>
<double>0</double>
<double>0</double>
</array>
</void>
<void property="rotation">
<array class="double">
<double>0</double>
<double>0</double>
<double>0</double>
<double>0</double>
</array>
</void>
<void property="instanced">
<boolean>true</boolean>
</void>
</object>
Here we're describing an object, its Cell-type, and (since this Cell-type loads in a model) which model file will be loaded, in this case "models/cube.j3s.gz" (the file created earlier in the tutorial). We're also providing some optional information about the object's location (in 3d coordinates x, y, z) and rotation (in degrees about the axes x, y, z, and in radians). The "instanced" boolean is useful if the model you are loading will be used more than once, for example if you want a number of chairs in your world and you want them all to use the same model file, it makes sense to simply reuse the model file already loaded into the world; this boolean flag enables exactly this feature.
For now, we're only going to place a single object in the world, but if we wanted to add more objects to the world, we'd simply repeat the code above for each object, making adjustments to location and/or rotation accordingly. Then we close up the array and the rest of the file with the remaining xml code.
</array>
</void>
</object>
</void>
</object>
</java>
Now start Wonderland again with two windows, one which runs:
$ ant run-sgs
And one which runs:
$ ant run
If all goes well, you should see your model load at the same location as your avatar If you back up a little way, the world should look something like this:
Plywood box model in world
|
Congratulations! You've imported a model into Wonderland!
One final note. Since Wonderland caches models, if you update your model in Blender, you will need to re-export it and then run:
$ ant clean-cache
To ensure that a new model is downloaded.
To Do
|