StarDust class on the wiki

I'm trying to figure out how to use this StarDust class on the wiki:

http://www.jmonkeyengine.com/wiki/doku.php?id=stardust



There doesn't seem to be any render functionality, attachChild() is never called and it doesn't extend Node or anything.



Any ideas? Or are some other better classes already exist for this purpose?

I've got my own revision I made for my game that seems to look a lot nicer to me:


package com.captiveimagination.gb.skybox;

/*
 * Created on Oct 24, 2004
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */

import java.util.Random;

import com.jme.math.Vector3f;
import com.jme.scene.Node;
import com.jme.scene.Point;
import com.jme.scene.state.*;
import com.jme.system.DisplaySystem;
import com.jme.bounding.BoundingBox;
import com.jme.renderer.ColorRGBA;

/**
 * @author zen, Matthew D. Hicks
 */
public class StarDust {
    public int numStars;
    public int blockSize;
    Point p[][][] = new Point[3][3][3];
    int old_sec_x=0;
    int old_sec_y=0;
    int old_sec_z=0;
    public Node node;
   
    public StarDust(int numStars, int blockSize) {
       this.numStars = numStars;
       this.blockSize = blockSize;
    }

    public void init(Node rootNode) {
        node = new Node("stardust");
        node.setIsCollidable(false);
        //
        // A star field
        //
        // in this first edition, just use the standard 'point' class
        // but in future would like to have a custom drawn one - where intensity
        // is related to distance?
        Random r = new Random();

        Vector3f[] vertexes = new Vector3f[numStars];
        for (int x=0; x<numStars; ++x) {
            vertexes[x] = new Vector3f( (r.nextFloat())*blockSize,
                                        (r.nextFloat())*blockSize,
                                        (r.nextFloat())*blockSize);
        }

        // all dust particles are white
        MaterialState ms = DisplaySystem.getDisplaySystem().getRenderer().createMaterialState();
       
        ms.setEmissive(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
        ms.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
        ms.setEnabled(true);
       
        AlphaState as = DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();
        as.setBlendEnabled(true);
        as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
        as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);
        as.setTestEnabled(false);
        as.setEnabled(true);

        for (int k=0; k<3; ++k) {
            for (int j=0; j<3; ++j) {
                for (int i=0; i<3; ++i) {
                    p[i][j][k] = new Point("stardust "+i+""+j+""+k, vertexes, null, null, null);
                    p[i][j][k].setLocalTranslation(
                            new Vector3f((i-1)*blockSize, (j-1)*blockSize, (k-1)*blockSize));
                    p[i][j][k].setModelBound(new BoundingBox());
                    p[i][j][k].updateModelBound();
                    node.attachChild(p[i][j][k]);
                }
            }
        }

        // We don't want the light to affect our dust
        node.updateWorldBound();
       
        node.setRenderState(ms);
        node.setRenderState(as);

        rootNode.attachChild(node);
        rootNode.updateWorldBound();
        rootNode.updateRenderState();
    }

    // ensure the viewer is surrounded by stars!
    public void update(Vector3f viewer) {
        // note: funny things happen when scaling things about the origin,
        // so for our purposes we compensate. (we could have used -0.5..0.5)
        // what we want is: -1000..0 -> -1
        //                  0..1000  -> 0
        //                  1000..2000 -> 1
        int sec_x = (int)((viewer.x / blockSize)+((viewer.x>0)?0:-1));
        int sec_y = (int)((viewer.y / blockSize)+((viewer.y>0)?0:-1));
        int sec_z = (int)((viewer.z / blockSize)+((viewer.z>0)?0:-1));

        // reduce garbage collection...
        if (sec_x != old_sec_x || sec_y != old_sec_y || sec_z != old_sec_z) {
            node.getLocalTranslation().set(sec_x*blockSize, sec_y*blockSize, sec_z*blockSize);
            old_sec_x = sec_x;
            old_sec_y = sec_y;
            old_sec_z = sec_z;
        }
    }
}



If there are no arguments I'll replace the version on the wiki with this one.

Here is an example of usage:

StarDust starDust = new StarDust(500, 1000);
starDust.init(rootNode);



In the update method of my game state:

starDust.update(ship.getPhysics().getLocalTranslation());



Hope that makes sense.

and please, make all variables "private" if possible…that's like an oop havoc :slight_smile:

hehe…yeah, realize this isn't my code, just updated by me to work better…we all know better than ME having anything but private variables. :o



I'll get that fixed before I post it on the wiki though.

Seems a bity jumpy to me :confused:

Yeah…if you don't extend it far enough it can look jump.  I made it sized to extend all the way to the skybox's limit so you never see new stars just "popping in".

Here's just a slight revamp so that its a node instead of holding a node inside of it.



import java.io.IOException;
import java.util.Random;

import com.jme.bounding.BoundingBox;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Node;
import com.jme.scene.Point;
import com.jme.scene.state.*;
import com.jme.system.DisplaySystem;
import com.jme.util.export.InputCapsule;
import com.jme.util.export.JMEExporter;
import com.jme.util.export.JMEImporter;
import com.jme.util.export.OutputCapsule;

public class StarDust extends Node
{
   private static final long serialVersionUID = 1L;
   
   public StarDust()
   {
      super();
   }
   
   public StarDust(String name)
   {
      super(name);
   }
   
    public StarDust(String name, int blockSize)
    {
       super(name);
       
       _blockSize = blockSize;
       
       setIsCollidable(false);
       
        // A star field
        //
        // in this first edition, just use the standard 'point' class
        // but in future would like to have a custom drawn one - where intensity
        // is related to distance?
        Random r = new Random();

        Vector3f[] vertexes = new Vector3f[_blockSize];
        for (int x = 0; x < _blockSize; ++x)
            vertexes[x] = new Vector3f( (r.nextFloat()) * _blockSize,
                                        (r.nextFloat()) * _blockSize,
                                        (r.nextFloat()) * _blockSize);
       
        // all dust particles are white
        MaterialState ms = DisplaySystem.getDisplaySystem().getRenderer().createMaterialState();
       
        ms.setEmissive(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
        ms.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
        ms.setEnabled(true);
       
        AlphaState as = DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();
        as.setBlendEnabled(true);
        as.setSrcFunction(AlphaState.SB_SRC_ALPHA);
        as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);
        as.setTestEnabled(false);
        as.setEnabled(true);

        for (int k = 0; k < 3; ++k)
        {
            for (int j = 0; j < 3; ++j)
            {
                for (int i = 0; i < 3; ++i)
                {
                   _points[i][j][k] = new Point("stardust "+i+""+j+""+k, vertexes, null, null, null);
                    _points[i][j][k].setLocalTranslation(new Vector3f((i-1) * _blockSize, (j-1) * _blockSize, (k-1) * _blockSize));
                    _points[i][j][k].setModelBound(new BoundingBox());
                    _points[i][j][k].updateModelBound();
                    attachChild(_points[i][j][k]);
                }
            }
        }

        // We don't want the light to affect our dust
        updateWorldBound();
          
        setRenderState(ms);
        setRenderState(as);
    }

    // ensure the viewer is surrounded by stars!
    public void update(Vector3f viewer)
    {
        // note: funny things happen when scaling things about the origin,
        // so for our purposes we compensate. (we could have used -0.5..0.5)
        // what we want is: -1000..0 -> -1
        //                  0..1000  -> 0
        //                  1000..2000 -> 1
        int secX = (int)((viewer.x / _blockSize) + ((viewer.x > 0) ? 0 : -1));
        int secY = (int)((viewer.y / _blockSize) + ((viewer.y > 0) ? 0 : -1));
        int secZ = (int)((viewer.z / _blockSize) + ((viewer.z > 0) ? 0 : -1));

        // reduce garbage collection...
        if ((secX != _oldSecX) || (secY != _oldSecY) || (secZ != _oldSecZ))
        {
           getLocalTranslation().set(secX * _blockSize, secY * _blockSize, secZ * _blockSize);
           _oldSecX = secX;
            _oldSecY = secY;
            _oldSecZ = secZ;
        }
    }
   
    public void write(JMEExporter e)
       throws IOException
    {
        super.write(e);
       
        OutputCapsule cap = e.getCapsule(this);
        cap.write(_blockSize, "blockSize", BLOCKSIZE);
    }

    @SuppressWarnings("unchecked")
    public void read(JMEImporter e)
       throws IOException
    {
        super.read(e);
       
        InputCapsule cap = e.getCapsule(this);
        _blockSize = cap.readInt("blockSize", BLOCKSIZE);
    }
   
    private int _blockSize = BLOCKSIZE;
    private Point _points[][][] = new Point[3][3][3];
    private int _oldSecX = 0;
    private int _oldSecY = 0;
    private int _oldSecZ = 0;
   
    private static final int BLOCKSIZE = 100;
}

could be nice with a super() and perhaps a possibility of providing a name (for super(name)). that's good to have

I suppose you are right, so therefore its done.


MrCoder said:

could be nice with a super() and perhaps a possibility of providing a name (for super(name)). that's good to have

Stars are also of different sizes and intensity. One way to acheive this is:



(in the triple for loop)


p[i][j][k].setPointSize(Math.random()>0.5?3f:2f);

Okay, this has been too much pasting of code:



http://captiveimagination.com/svn/public/cigame/trunk/src/com/captiveimagination/game/effect/StarDust.java



This is my new project for everything that I want to make available to the public, but doesn’t belong in jME, jME-Physics, JGN, etc.



If anyone has any code they’d like to contribute feel free to post here or on http://forum.captiveimagination.com.

i use the Stardust class in our project www.stardust.ch ;), it works flawlessly so far.

But I've got a question regarding the Name of Spatials.



In the stardust class, every Point gets a unique name.



points[j][k] = new Point("stardust " + i + "" + j + "" + k,

                            vertexes, null, null, null);



Is that really needed?

Or to ask differently, when are unique names needed?

Has anyone got a test class they could post for me - being lazy.  XD

Coincidentally i threw one together it's dirt simple.



package test;
 
import com.captiveimagination.game.effect.StarDust;
import com.jme.app.SimpleGame;
 
public class TestStarDust extends SimpleGame {
 
    @Override
    protected void simpleInitGame() {
        this.cam.setFrustumFar(1000);
        this.cam.update();
        StarDust dust = new StarDust("starDust", 1000, 1000, true);       
        rootNode.attachChild(dust);
        rootNode.updateModelBound();
        rootNode.updateWorldBound();
    }
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        SimpleGame game = new TestStarDust();
 
        game.setDialogBehaviour(SimpleGame.FIRSTRUN_OR_NOCONFIGFILE_SHOW_PROPS_DIALOG);
        game.start();
    }
 
}



I hacked around with the StarDust class to attempt to add random brightness and size, and posted it on my wiki (i didn't want to taint the jME wiki with my mad scientist experiments). Posted it here:

http://www.eventhorizongames.com/wiki/doku.php?id=jme_dumps:stardust:start

Something not quite right with this, it seems more dense when you peer into the middle of the StarDust node (where you initially spawned)

You are correct! I forgot to use the update(Vector3f position) method in the StarDust class.



If you don't do that then it looks really dense when you navigate completely outside of the starfield and then look back into it. That's because the StarField is really just 4 sectors of stars that you move through. You need to call the update(Vector3f position) which essentially wraps the sectors so that the star field moves with the user.



Here's the simpleUpdate() method that corrects that problem using the original StarDust class:



public class TestStarDust extends SimpleGame {
...
    protected void simpleUpdate() {
        //Get the current direction the camera is pointing in
        Vector3f camDirection = cam.getDirection();
        //Make sure we have starDust always surrounding us.
        dust.update(camDirection);
    }
...
}



Looking back at it, it's a bit non-intuitive for the StarDust class to have that update(Vector3f viewer) method, so I improved it by creating and attaching an internal controller to the StarDust node so that it will automatically update.

Is there some other way than using a Controller for the StarDust class to have it's update(Vector3f viewer) method called automatically and not through manually coding it in your simpleUpdate() method?

The full versions of my modified StarDust classes are on my wiki:
http://www.eventhorizongames.com/wiki/doku.php?id=jme_dumps:stardust:start

StarDust.java


   public StarDust(String name, int numStars, int blockSize, boolean randomizeSize, Camera cam) {
       ...
            StarDustController dustController = new StarDustController(this, cam);
            this.addController(dustController);
   }



StarDustController.java


package com.captiveimagination.game.effect;

import com.jme.renderer.Camera;
import com.jme.scene.Controller;

public class StarDustController extends Controller {

    /**
     * Used to track the StarField view direction
     */
    private Camera   cam  = null;

    private StarDust dust = null;

    public StarDustController(StarDust dust, Camera cam) {

        this.dust = dust;
        this.cam = cam;
    }

    @Override
    public void update(float time) {
        dust.update(cam.getDirection());
    }

}



TestStarDust.java


public class TestStarDust extends SimpleGame {

    private StarDust dust = null;
    @Override
    protected void simpleInitGame() {
        ...
        dust = new StarDust("starDust", 1000, 1000, true, cam);       
        ...
    }
    ...
}

shouldn't it be

dust.update(cam.getLocation());



instead of cam.getDirection()?

Yup, cam.getLocation() makes a lot more sense then direction. I was just testing you guys  :wink: , or perhaps because I was just winging it and it seemed to look correct when I ran it.

I've been playing around with this one for a while now. I like it a lot. However, what I would like is to have the dust that's farther away from me apear darker then the dust close by, seeing how they're supposed to be tiny particles, you should be able to see those close by better then those far off.



I can't figure out how to make this work though, I think I need to add some logic to the update method of the dust class to make this work, just can't figure out what. If you could point me in the right direction I would be a happy man…



Ok, I forgot to post what I tried thus far, so here goes. I added the following to the update method of the StarDust class:


List<Spatial> sectors = this.getChildren();
       
        // loop through all the sectors
        for (Spatial sector : sectors) {
           // in each sector, loop through all the points
           Point p = (Point)((Node)sector).getChild(0);
           // in each point loop through all the stars
           for (int i = 0; i < numStars; i++) {
              // for each star get the vertextbuffer. this is to determine the distance to the viewer
              FloatBuffer fb = p.getVertexBuffer(i);
              float x = viewer.x - fb.get(0);
              float y = viewer.y - fb.get(1);
              float z = viewer.z - fb.get(2);
              float distance = (float)Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2));
              // once we have the distance to the viewer, we can calculate the new alpha
              float alpha = distance / blockSize / 2;
              FloatBuffer c = p.getColorBuffer(i);
              c.put(4, alpha);
              // put the new alpha back in the color buffer
              p.setColorBuffer(i, c);
           }
           // update the render state of the point.
           p.updateRenderState();
        }



What I'm trying to do is get the distance of the dust particle to the viewer and edit the alpha of that particle accordingly. Thus making the particles further away more transparent, with the ones at blockSize distance being at alpha 0 and the ones being closest at alpha 1. But it doesn't seem to work, every particle stays at alpha 1.

Mark

Apart from this, I found something else. After flying in a straight line for a while, I found I can exit the stardust area. Turning around, you then see the stardust hanging there.