World editor is an application that is used to create or compose every visual element in the other application. It is usually used to create game worlds (In this article, I assume ‘game’ will refer to ‘3D game’ unless it is specified). World editor is an important aspect of game development as it allows the game artists to set up the worlds as what they want them to be appeared in game. World editor itself is not a modeling tool, as it isn’t used to create the 3D models (though, it is used to create the terrain). In this article I will cover about how to combine java’s swing user interface with jMonkeyEngine (jME). I will assume you know the basic of java language, swing and jME.
This first step is quite easy. You only have to create the user interface with swing. You can design your own user interface. You just have to make sure that you have some place to put your editing tools and a canvas for your 3D viewport. For the canvas, we will use LWJGLCanvas which you can find at com.jmex.awt.lwjgl. It is inherited from java’s Canvas, so we can put it in our swing user interface.
It is the initial design of my UI. As you can see on the left side, I put JtabbedPane to place my editing tools, and on the right side I put LWJGLCanvas. For now, the canvas is still empty.
This code snippet below will show you how to create an instance of LWJGLCanvas.
You will also need an implementor class to implement your jME process on the canvas. We will create a simple one. Actually, this class behaves like SimplePassGame class which you should have already familiar with (If you don’t know, you can assume it like BaseGame with pass rendering capability added). We use pass rendering because we will need it to render our terrain which will use TerrainPass.
Here is the code snippet. You should know what the statements in the simpleSetup() do.
For this article, we will create a simple scene to check if our canvas is correctly set. You can add jME code insde the implementor class that you just created. You may override some methods which are inherited from SimplePassCanvasImpl such as simpleSetup(), simpleUpdate(), and simpleRender(). I will create a simple box.
You can change the scene with anything you like. Actually, we will change it with the terrain later.
Now we have to add control to the scene. We have to make the user can control what they want see in their editor. We will add some movements such as panning, rotating, and zooming the scene.
The first thing to do is creating a new mouse handler for the canvas. We can use MouseAdapter to do this. It has every mouse action we need.
I will explain from the simplest one, zooming. First we have to know how much we want out camera to move forward or backward. Then we have to get the camera from our implementor class. Then get the distance from the camera to the focus position. Initially, the focus will be at the center of the world. This focus position will be used again when we do rotation and its position will change as we pan the camera. For this reason, we have to store the focus position to a variable. The distance is only needed if we want to restrict our zooming capability, in this case we don’t want the scene is zoomed too close or surpassing the focus position. If you want to restrict your zooming, recalculate the zooming amount so it becamo zero after the camera reaches certain position, otherwise you can use your initial amount. After that, we only have to scale the normalized camera direction with the zooming amount and store the result as the new camera position. Here is the code to do that.
Maybe you wonder how we get the zooming amount. The answer is very simple, from your mouse input. The truth is you can also use keyboard to do that, but I prefer to use mouse because it is easier to calculate and combined with the other camera transformation. I will use mouse wheel scroll amount which we can get from MouseAdapter method as presented below. I also add the condition if the wheel is scrolled when left shift is pressed down, the zooming amount will be only half from normal. You can experiment on your own the value that suits you. You will notice that I use GameTaskQueueManager in this method. We need that to ensure the thread in our jME application and the awt thread run correctly.
Next action is panning the camera. Actually, it’s not too different with zooming. The differences are panning needs two direction to move the camera and when we pan the camera, we also have to pan the focus position. Moving in two directions is just as easy as moving in one direction in zooming. We only have to get the moving amount for each direction and also camera’s up and left direction. Then scale each camera’s direction with the corresponding moving amount and add them together. This way, we get the required Vector3f to move the camera and the focus position. Just add the vector to camera to move the camera and add it to focus to move the focus. Here is the code
Now we arrive at the hardest part of the camera transformation, rotation. It requires you to understand the operation of quaternion, process to rotate object about any point in 3D world, and if you want to restrict the rotation elevation, you also have to know some trigonometry. In rotation we have to use two axes as a pivot, world’s up axis to rotate right and left and camera’s left axis to rotate up and down. But unlike panning, we can’t directly calculate two axes rotation, so we have to rotate it twice. First, we have to get the amount of rotation that we want to occur. Because we only want to restrict rotation to up and down direction, we only need to recalculate the amount when we rotate it about left axis of the camera. Here we use some trigonometry to find the elevation (I won’t explain it here, learn some trigonometry if you want to know). For the rotation, we have to get the vector to move the camera to the focus position. Then rotate the vector about the axis by the amount you have calculated before. Finally, move the vector back with the rotated vector. You can now move the camera by the resulting vector. And also don’t forget to make your camera to look at the focus again (moving it with the vector doesn’t rotate the camera direction). Here is the code snippet.
The next part is about how to call the two previous methods we wrote. I present them together because actually they get similar input from the mouse. The actions happen when the user drags the mouse. The difference is the mouse button which is clicked. For panning I use middle button, and for rotation I use right button.
This is what we got so far. We will start to create the terrain in the next article.
© William Salim – WS08-1 – Software Laboratory Center