I began implementing a hierarchical scene graph in my Java/OpenGL project with basic entities/objects that have a position component, and that know both their parent entity and their child entity(s).
public class Entity
{
private Entity parent;
private ArrayList<Entity> children = new ArrayList<Entity>();
private Vector3f pos = new Vector3f(0,0,0); //simplified transformation
addChild(Entity child){...}
setParent(Entity parent){...}
public Vector3f getPos(){ return pos; }
public void setPos(Vector3f pos){this.pos = pos}
//this is my non-functional attempt at creating hierarchical movement
public void setRelativePos(Vector3f pos)
{
this.setPos(parent.getPos().add(pos)); //position relative to parent
for(Entity child : children)
{
//how the child relatives to the newly moved parent
vec3 relativePos = child.getPos().sub(getPos());
child.setRelativePos(relativePos);
}
}
}
What I had in mind was that children will move relative to their parent when the parent's position is changed/set.
From what you are describing, I think that when you move an Entity, you want to move all its children.
Your recursion has no stopping condition, and probably causes a stack overflow.
It also has a confusing name, setPos, which implies a simple setter, but that's not what it does. You should have different methods for each type of movevent. Ex : translate, rotate, etc...
You should do something like this :
// simple setter
public void setPos(Vector3f pos)
{
this.pos = pos;
}
// translation movement
public void translate(Vector3f delta)
{
// translate the current Entity
setPos (getPos().add(delta));
// translate the children
for (Entity child : children)
child.translate (delta);
}
Related
For example: a folder is a composite object, and a file is a leaf.
Folder 1
-- Folder 2
--- File 1
Here i know that File 1 is three levels deep in the composite of Folder 1. What methods could I make so that I can keep track of how deep File 1 is?
Image this classes(Component is parent class that just define methods)
class Leaf : Component
{
public int deep;
public override void Operation()
{
console.WriteLine("Leaf");
}
}
And for composite:
class Composite : Component
{
public int deep;
protected List<Component> _children = new List<Component>();
public override void Add(Component component)
{
this._children.Add(component);
}
public override void Operation()
{
foreach (Component component in this._children)
{
component.Operation();
component.deep = component.deep+1;
}
}
}
The main idea is component.deep = component.deep+1; and you can access to each object deep with deep variable.
I want to do a material explosion. This means that given a product, I want to populate in a tree that has all the sub-components that are required to produce that product. Let's say to produce a table, I need 1 tabletop, 4 legs, 8 screws and 1 can of paint. Therefore, once I have this information, I can understand how much of these sub-components will be required to build 10 tables, by multiplying 10 with quantities required to build 1 table.
So given a material, I first populate it as the root node then I recursively fetch sub-components and start building the tree. My limitation is that when I fetch this information from another service I can only get immediate children, which means children at a single level.
Structure of my N-array tree looks like this:
public class Node<T> {
private T data = null;
private Node<T> parent = null;
private List<Node<T>> children = new ArrayList<Node<T>>();
public Node(T data) {
this.data = data;
}
public Node(T data, Node<T> parent) {
this.data = data;
this.parent = parent;
}
public List<Node<T>> getChildren() {
return children;
}
public Node<T> getParent() {
return parent;
}
public void setParent(Node<T> parent) {
this.parent = parent;
}
public void addChild(T data) {
Node<T> child = new Node<T>(data);
this.addChild(child);
}
public void addChild(Node<T> child) {
child.setParent(this);
this.children.add(child);
}
public void addChildren(List<Node<T>> children) {
for (Node t : children) {
t.setParent(this);
}
this.children.addAll(children);
}
public T getData() {
return this.data;
}
public void setData(T data) {
this.data = data;
}
public boolean isRoot() {
return (this.parent == null);
}
public boolean isLeaf() {
return this.children.size() == 0;
}
public void removeParent() {
this.parent = null;
}
private class InOrderIterator implements Iterator<T> {
private final Queue<Node<T>> queue = new LinkedList<Node<T>>();
public InOrderIterator(Node<T> tree) {
queue.add(tree);
}
#Override
public boolean hasNext() {
return !queue.isEmpty();
}
#Override
public T next() {
Node<T> node = queue.remove();
queue.addAll(node.children);
return node.getData();
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
}
public Iterable<T> inOrderTraversal = () -> (Iterator<T>) new InOrderIterator(Node.this);
}
Now I create the root node, here the max depth is the level of tree up to which I want to fetch sub-components and construct the tree. The default quantity is 1, and the root level is 0.
protected Node<Material> doMaterialExplosion(final String partNumber, final Integer maxDepth) {
Node<Material> root = new Node<>(Material.builder()
.productPartNumber(partNumber)
.materialPartNumber(partNumber)
.materialQuantity(DEFAULT_QUANTITY)
.level(ROOT_LEVEL)
.parentPartNumber(null)
.build());
return doMaterialExplosion(root, partNumber, maxDepth);
}
The product part number is the main product that has to be produced, material part number is the sub-component required to produce that product, material quantity is the quantity of that material required, the level is the tree level, and parent part number is the immediate parent of the subcomponent. So, for the root node, there will be no parent part number, but for all other sub-components, there will be a parent part number. Also, note that the product part number will not change in any node, as it specifies the main product that is being produced.
The code snippet to construct this tree recursively is:
private Node<Material> doMaterialExplosion(Node<Material> root,
final String partNumber, final Integer maxDepth) {
// Increment the level, in the tree
int childLevel = root.getData().getLevel() + 1;
if (maxDepth != null && childLevel <= maxDepth) {
// Fetch immediate sub-components, of a given material
List<SubComponent> subComponents = fetchData(partNumber);
Node<Material> child;
if (!subComponents.isEmpty()) {
LOG.info("'{}' child elements found for partNumber='{}'", subComponents.size(), partNumber);
for (SubComponents subComponent : subComponents) {
child = new Node<>(Material.builder()
.productPartNumber(root.getData().getProductPartNumber())
.materialPartNumber(subComponent.getMaterial())
.materialQuantity(subComponent.getMaterialQuantity())
.level(childLevel)
.parentPartNumber(root.getData().getMaterialPartNumber())
.build(), root);
root.addChild(child);
doMaterialExplosion(child, subComponent.getMaterial(), maxDepth);
}
}
}
return root;
}
The method fetch data, will give me a list of immediate subcomponents for the given part number, from another microservice.
What I am looking for is ways to improve my performance, because one can understand that, it can really get expensive if I want to create a tree that has many subcomponents, and each sub-component further has children and so on. Also, it will be expensive it the level of this tree construction is big. Let's say maybe up to level 10. And, also let's say based on some plan, I need to do this explosion for 50 products.
We also can't forget that this tree creation implementation is in one microservice, which gets data from another microservice. Therefore, for 50 products there can be a lot of network calls.
Limitation, we cannot have this implementation in the service where data is present. The biggest performance upgrade I am looking for is a way to reduce the time required to do material explosion for say N products.
At present, once I have this tree, I save it in a database, so that the next time I need a material explosion for the same product, I can get it much rapidly, this is also the reason for the structure of Material class, that has a product part number and parent part number.
Looking forward to your suggestions.
Data sharing is often difficult, but rou're right to try to keep the micro-service architecture here.
I can see 2 ways (and then a mix of the 2, perhaps):
Enhance the second micro-service API, so you can get a list of items from it, instead of requesting one by one (request machine gun!).
It's becoming a common API feature... think of it as a search on the id, or in a GraphQL way.
Organize a cache on your first micro-service, like btilly suggested, and perhaps even more aggresive. A cache in memory according to your previous requests, or in a local database (nosql?) fed by the master micro-service.
The only thing your architecture lets you do to improve is that while fetch a product, you can memoize what you're already fetching. So if a table has 4 legs, you fetch a table once, a leg once, then apply the leg 4x. Then when you look for another table, you just look it up.
I'm using the java game engine made by thebennybox to create my own engine. Previously I worked with UE4 where you could have Static Mesh Actors, in his engine this would probably be a GameObject with a MeshRenderer component attached to it:
GameObject staticMeshActor_Grass = new GameObject();
AddObject(staticMeshActor_Grass.addComponent(new MeshRenderer(
new Mesh("plane.obj"), new Material(
new Texture("T_Grass_BC.png"), 1, 8,
new Texture("T_Grass_N.png")))));
Now I'm trying to create a large field of these grass tiles but since these are all their individual GameObjects (or Actors in UE4 terms) after 16x16 tiles it starts to cripple the frame rate!
I believe I can solve this problem if I make instances of multiple static meshes inside one GameObject in order to make it performance friendly. In UE4 this feature is called 'Instanced Static Mesh Component' which allows for that and I would like to have something similar.
Here's the GameObject class made by thebennybox:
public class GameObject
{
private ArrayList<GameObject> m_children;
private ArrayList<GameComponent> m_components;
private Transform m_transform;
private CoreEngine m_engine;
public GameObject()
{
m_children = new ArrayList<GameObject>();
m_components = new ArrayList<GameComponent>();
m_transform = new Transform();
m_engine = null;
}
public GameObject AddChild(GameObject child)
{
m_children.add(child);
child.SetEngine(m_engine);
child.GetTransform().SetParent(m_transform);
return this;
}
public GameObject AddComponent(GameComponent component)
{
m_components.add(component);
component.SetParent(this);
return this;
}
public void InputAll(float delta)
{
Input(delta);
for(GameObject child : m_children)
child.InputAll(delta);
}
public void UpdateAll(float delta)
{
Update(delta);
for(GameObject child : m_children)
child.UpdateAll(delta);
}
public void RenderAll(Shader shader, RenderingEngine renderingEngine)
{
Render(shader, renderingEngine);
for(GameObject child : m_children)
child.RenderAll(shader, renderingEngine);
}
public void Input(float delta)
{
m_transform.Update();
for(GameComponent component : m_components)
component.Input(delta);
}
public void Update(float delta)
{
for(GameComponent component : m_components)
component.Update(delta);
}
public void Render(Shader shader, RenderingEngine renderingEngine)
{
for(GameComponent component : m_components)
component.Render(shader, renderingEngine);
}
public ArrayList<GameObject> GetAllAttached()
{
ArrayList<GameObject> result = new ArrayList<GameObject>();
for(GameObject child : m_children)
result.addAll(child.GetAllAttached());
result.add(this);
return result;
}
public Transform GetTransform()
{
return m_transform;
}
public void SetEngine(CoreEngine engine)
{
if(this.m_engine != engine)
{
this.m_engine = engine;
for(GameComponent component : m_components)
component.AddToEngine(engine);
for(GameObject child : m_children)
child.SetEngine(engine);
}
}
}
The AddObject() method shown in the first part comes from an abstract class and eventually calls the method AddChild(GameObject child) inside the GameObject class. As you can see we have an ArrayList of GameObjects and GameComponents. Now I would have to implement some method in order to support the creation of multiple mesh instances inside one GameObject.
I've already tried to add multiple MeshRenderer components to one GameObject but this didn't work out. Maybe someone has a suggestion how I might go about this?
if you're really interested and want to help me you can download the engine here: https://github.com/BennyQBD/3DGameEngine
Just use 'Open Projects From File System..' in eclipse, choose the directory of this folder and once you've done that you should be able to run the program.
Thanks a lot for your help!
this might be what you are looking for:
http://www.java-gaming.org/topics/issues-with-batching-meshes/37809/view.html
They mention that ThinMatrix has created a tutorial about instancing meshes, hope this helps you!
I see no getSource() method in PInputEvent class.
I want to get reference to an object, which handler was added to.
UPDATE
In the following example, three concentric circles created. Each bigger circle owns smaller one. Mouse click handler is attached to circle2. Since this circle owns circle3, handler triggers when clicked both circle2 and circle3, but not circle1.
How to obtain reference to circle2 from within handler if click was made to circle3?
Neither of tested methods help.
package test.piccolo;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolox.PFrame;
public class App {
#SuppressWarnings("serial")
public static void main(String[] args) {
new PFrame() {
public void initialize() {
PPath circle1 = PPath.createEllipse(-50, -50, 100, 100);
circle1.setPaint(null);
System.out.println("circle1 = " + circle1.toString());
getCanvas().getLayer().addChild(circle1);
PPath circle2 = PPath.createEllipse(-40, -40, 80, 80);
circle2.setPaint(null);
System.out.println("circle2 = " + circle2.toString());
circle1.addChild(circle2);
PPath circle3 = PPath.createEllipse(-30, -30, 60, 60);
circle3.setPaint(null);
System.out.println("circle3 = " + circle3.toString());
circle2.addChild(circle3);
circle2.addInputEventListener(new PBasicInputEventHandler() {
#Override
public void mouseClicked(PInputEvent event) {
Object o;
o = event.getSourceSwingEvent().getSource().toString();
System.out.println("event.getSourceSwingEvent().getSource() = " + o);
o = event.getComponent().toString();
System.out.println("event.getComponent() = " + o);
o = event.getPickedNode().toString();
System.out.println("event.getPickedNode() = " + o);
}
});
};
};
}
}
UPDATE 2
My requirement is to treat some topmost dummy node as wrapper for it's children. I want to attach handler to a parent and track all events underneath. At the same moment, parent can be a child of some more complex scene as a whole. So, I need to catch event at some intermediate level.
PInputEvent.getSourceSwingEvent() returns the underlying swing event - InputEvent, from that getSource() should give you the source, ie:
event.getSourceSwingEvent().getSource()
EDIT:
It appears that event.getSourceSwingEvent().getSource() is always a canvas. It makes sense as the event actually originated on canvas.
event.getPickedNode() is the actual picked node. It may be a child of a node that have a registered listener, such as circle3 in the posted sample code.
I am not sure what is the scenario and the reason for finding a node that registered a listener. In most cases, the desired output is the picked node. To find what you're looking for you may have a custom designated extension of PInputEventListener that can hold a reference to a node that registers it. It may be an overkill, depending on a situation. For example:
public static class MyEventHandler extends PBasicInputEventHandler {
private PNode node;
public MyEventHandler(PNode node) {
this.node = node;
}
public PNode getNode() {
return this.node;
}
}
Another hacky way that comes to mind is to traverse either a stack of objects in a pick path or an hierarchy of nodes to find a node that has this listener. For example to traverse the hierarchy of nodes (similarly it is also possible to enumerate nodes in event.getPath().getNodeStackReference()) :
public static PNode getRealEventSource(PInputEvent event, PInputEventListener listener) {
PNode node = event.getPickedNode();
while(node != null){
EventListenerList listeners = node.getListenerList();
if (listeners != null) {
if (Arrays.asList(listeners.getListenerList()).contains(listener)) {
return node;
}
}
node = node.getParent();
}
return null;
}
And then, invoke it like this from within the mouseClicked() method:
System.out.println("The real source:" + getRealEventSource(event, this));
I am developing a simulation of the world, where the World is represented by:
public class World {
Turtle turtle;
// .. basic constructors, getters, setters
}
and a Turtle is represented by:
public class Turtle {
List<Turtle> turtles;
// .. basic constructors, getters, setters
}
where a Turtle stands on the backs of its turtles and the World rests on one, main Turtle (who may have turtles underneath it). I want to represent this, in Swing, as a JTree.
So I code up a JTree and a TreeModel:
JTree tree = new JTree(new WorldModel(world.getTurtle());
public class WorldModel implements TreeModel {
private Turtle = null;
public WorldModel(Turtle turtle) {
this.turtle = turtle;
}
#Override
int getChildCount(Object object) {
return ((Turtle) object).getNumTurtles();
}
#Override
Object getChild(Object parent, int index) {
return ((Turtle) object).getTurtle(index);
}
// etc., you get the overbearing point
}
This works splendidly up until the point at which I change the Turtle I initially passed in to the TreeModel's constructor:
world.getTurtle().removeAllTurtleChildren();
How do I update my JList to reflect this change? Do I have to create a new TreeModel and set it again?
(I would like to stay away from DefaultTreeModel, if possible.)
add api that supports modifying the structure to the model:
public class WorldModel implements TreeModel {
...
public void removeAllChildren(Turtle parent) {
if (parent.getChildCount() == 0) return;
Turtle[] children = parent.getChildren();
int[] locations = new int[children.length());
for(int loc = 0; loc < locations.length; loc++) {
locations[i] = i;
}
parent.removeAllChildren();
List<Turtle> path = new ArrayList<>();
while (parent != null) {
path.add(0, parent);
parent = parent.getParent();
}
TreeModelEvent event = new TreeModelEvent(this, path, locations, children);
// for each listener
listener.treeNodesRemoved(event);
}
}
As you see, it's quite some work - you might reconsider not using DefaultTreeModel :-)