The sprites I am using in my game have complex shapes and animations. Also I'm only interested in setting contact listeners for certain parts of the sprite. I would like to set fixtures for the specific contact areas of interest. How can I keep moving body fixtures in the right positions as I change the sprite animations frame by frame?
It`s not possible to change fixtures position. Only destroying and creating then again (but it will decrease performance).
Instead of it, you can create 2 separated bodies and get then together using joints. It will be the same behavior of 2 fixtures.
I don't know if this is a right approach or not but for it doesn't make any performance issue, so you can try it.
First you have to destroy the current fixture of the body after saving its last position.
float body_x=Body.getPosition().x;
float body_y=Body.getPosition().y;
Body.destroyFixture(Body.getFixtureList().get(0));
And then you have to create a new fixture for that body like this
Body.createFixture(createFixturePart(
body_x,
body_y,
Width,
Height,
Angle, 1, 1, 0, -1));
Here createFixturePart is my custumized function to create fixture of a body. You can have that while you create a body.And for the new fixture you can change the Width, height and Angle of the fixture according to your requirement. But don't re-create the fixture for every render cycle, instead change it only during the change of frame in the animation or whole animation.
createFixturePart Method
public FixtureDef createFixturePart(float x, float y, float width,
float height, float angle, int mass, int density, int type,
int groupIndex) {
PolygonShape shape = new PolygonShape();
shape.setAsBox(width, height);
shape.setAsBox(width / 2, height / 2, new Vector2(0, 0),
(float) Math.toRadians(angle));
MassData massData = new MassData();
massData.mass = mass;
bodyDef.position.y = y;
bodyDef.position.x = x;
Body body = worldbox.createBody(bodyDef);
body.setMassData(massData);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = density;
fixtureDef.filter.groupIndex = (short) groupIndex;
fixtureDef.restitution = 10;
return fixtureDef;
}
To change fixtures positions destory them, and create new fixtures at needed positions. But, I think, it is not good solution to change body fixtures, because it may corrupt simulation and decrease perfomance.
Related
I need to find the objects that fully/partly visible on the rendered screen. I know this can be done by coloring each object uniquely, rendering the scene, and detecting the colors that end up on the screen. This is a screen-space operation that would involve fiddling with the frame-buffer. Are there any special functions/helpers within three.js that do this more easily?
You can check if object is in view frustum of the camera. See Frustum in Three.js documentation.
One way to achieve this is to render your scene once with constant shading, colour-coding your objects as you need, with any anti-aliasing and other effects turned off, so that you can easily map a read pixel back to its object by its colour.
Then, you can read pixels from your render target, for which you can use three.js' WebGLRenderer.readRenderTargetPixels() (see docs). You can then read the colours out of the buffer you pass to it.
Something like this:
// Render your scene first, into a renderTarget. Then:
const buffer = new Uint8Array(width * height * 4);
this.renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer);
for (let i=0; i<buffer.length/4; ++i) {
const r = buffer[i*4 ];
const g = buffer[i*4 + 1];
const b = buffer[i*4 + 2];
const rgb = (r << 16) | (g << 8) | b;
// Do your mapping
}
This is very much just WebGL though, and don't know whether there might be a better way to do this within three.js.
I am creating a model of a solar system in processing, and after removing the background I noticed the planets were leaving a trail of their image behind them. The program runs fine when the background is back in, but I want to add a lot more and I am sure this is inefficient and will bog things down.
I am very new to processing, and I am really not sure how to solve this. Maybe delete previous images after a delay to create a shortened trail?
These are just the parts I think are important cherry picked from the code, this is just the example of one planet. Sorry if the code is clunky, any suggestions are happily accepted.
Planet p1;
void setup() {
mercury = loadImage("mercury.png")
p1 = new Planet(40, random(TWO_PI), 0.05);
}
void draw() {
//background(0)
translate(width / 2, height / 2);
p1.display1();
p1.orbit();
}
class Planet {
float radius;
float angle;
float distance;
float orbitSpeed;
Planet(float r, float d, float o) {
radius = r;
distance = d;
orbitSpeed = o;
angle = random(TWO_PI);
}
void orbit() {
angle = angle + orbitSpeed;
}
void display1() {
pushMatrix();
rotate(angle);
translate(distance, 0);
imageMode(CENTER);
image(mercury, radius, radius, 10, 10);
popMatrix();
}
}
I realized that this would probably happen, and I am not sure how to stop it.
The behavior you describe is simply the nature of computer graphics; it's how games, operating systems, and hardware displays all work – they clear and redraw everything every frame.
In Processing, graphic objects that are pushed to a buffer remain there indefinitely until the buffer is cleared or something is pushed on top of them (this is why the planets are leaving a trail without calling background() – previous frames remain in the buffer).
You are worried about the background() being inefficient. Don't be, as it's one of the fastest operations (simply sets the value of each pixel, as given by the user).
Processing does provide a clear() function, but this is equivalent to background(0).
If you're are still concerned about efficiency and speed, one way to speed up Processing is to use the FX2D renderer rather than default AWT renderer. Another way is cache drawn objects into PGraphics objects to prevent successive rasterization (since your planets are image files and not drawn with processing, you needn't worry about this).
Your code is simple enough that it doesn't need optimisations at this stage.
As micycle mentions, you are are drawing an image at a translated position, pretty similar to blitting.
In terms of the trails, one common trick you could use is not clear the screen completely, but draw a transparent rectangle as the background. The more transparency, the longer the trails.
Here's a tweaked version of your code:
// planet object
Planet p1;
// planet texture
PImage mercury;
void setup() {
size(300, 300);
// draw image from center
imageMode(CENTER);
// clear to black one
background(0);
// remove strokes (we'll use rect() later)
noStroke();
// set the fill to black but with 9/255 transparency (~3.5% transparent)
fill(0,9);
// init texture
mercury = loadImage("mercury.png");
// init planet
p1 = new Planet(40, random(TWO_PI), 0.05);
}
void draw() {
// draw a transparent rectangle instead of completely clearing the screen
rect(0,0,width,height);
// render planet
translate(width / 2, height / 2);
p1.display1();
p1.orbit();
}
class Planet {
float radius;
float angle;
float distance;
float orbitSpeed;
Planet(float r, float d, float o) {
radius = r;
distance = d;
orbitSpeed = o;
angle = random(TWO_PI);
}
void orbit() {
angle = angle + orbitSpeed;
}
void display1() {
pushMatrix();
rotate(angle);
translate(distance, 0);
image(mercury, radius, radius, 10, 10);
popMatrix();
}
}
It's an efficient quick'n'dirty hack as you won't need to store previous position and redraw multiple times, however it has it limitations in terms of the flexibility of the trails. Hopefully tweaking the fill() alpha parameter will get you the desired effect.
Later on if you're drawing many many many planets it things start running slow have a peak at VisualVM. Profile the CPU and see the methods that take the longest to complete and focus on those. Don't need to optimise everything, just the slowest calls. Remember that Processing have multiple renderers: JAVA2D is the default one, but there's also FX2D and P2D/P3D and they will behave differently. I strongly recommend optimising at the last moment (otherwise code might be less flexible and readable and will slow down development/iteration).
I am new to three.js and modifying some existing code.
The existing code is rendering a graph using "THREE.BufferGeometry" + "THREE.Points"
var geometryPc = new THREE.BufferGeometry();
var materialPc = new THREE.ShaderMaterial({....});
this.mesh = new THREE.Points(geometryPc, materialPc);
I am trying to put a label text on every node which moves with the node.
I tried:
I tried creating "THREE.Sprite" for each node and then assigning it positions relative to that node.
let texture = new THREE.Texture(canvas);
let spriteMaterial = new THREE.SpriteMaterial({map: texture, useScreenCoordinates: false});
let sprite = new THREE.Sprite(spriteMaterial);
Thats seems to be working but UI becomes too heavy when number of nodes are relatively high.
I would prefer to use "BufferGeometry" to create texts as well. But could not find a way to do that.
Is there any better way to put text on the nodes?
Your approach with sprites, altough by far the most obvious, unfortunately will not be sufficient. Each sprite, if I understand correctly, creates its own mesh with its own texture, so each causes a separate draw call. This approach is not scalable.
The way I did it was to make a shader capable of rendering different parts of an image and then make an image containing letters (in a monospace font). Then, to each point in geometry (a place where a label should be rendered), I pass such a set of parameters (shader attributes) for every letter rendered:
positionX: this.position.x, //position of entire label
positionY: this.position.y,
positionZ: this.position.z,
colorR: this.color.r,
colorG: this.color.g,
colorB: this.color.b,
colorA: this.visible ? (this.finalAlpha) : 0,
scale: this.camera.zoom, //scale must depend on camera zoom
spriteNumber: this.getTextPosition(lines[i][j]), //see below ;p
offset: j + i * 32768, //this is for positioning one particular letter,
//x and y merged together because I ran out of parameters
size: this.size
i and j are a "x" and "y" position of a letter in a label, the shader does offsetting by itself; other parameters should be more or less obvious :)
ParticleLabel.prototype.getTextPosition = function(symbol){
switch(symbol){
case '0': return 1;
case '1': return 2;
case '2': return 3;
(...)
case 'A': return 20;
case 'B': return 21;
case 'C': return 22;
(...)
I can't show entire code as I made it for a commercial solution, but I'll make an example on codepen or sth later on to show a working solution.
I want to update hud positon form 3d position to 2d when mouse moving. Since it may have a large number of 3d objects to project to the screen position, I meet a performance problem.
Are there any way to accelerate calculations? The following is how I calculate 3d object position on 2d screen.
function toScreenPosition(obj) {
var vector = new THREE.Vector3();
//calculate screen half size
var widthHalf = 0.5 * renderer.context.canvas.width;
var heightHalf = 0.5 * renderer.context.canvas.height;
//get 3d object position
obj.updateMatrixWorld();
vector.setFromMatrixPosition(obj.matrixWorld);
vector.project(this.camera);
//get 2d position on screen
vector.x = (vector.x * widthHalf) + widthHalf;
vector.y = -(vector.y * heightHalf) + heightHalf;
return {
x: vector.x,
y: vector.y
};
}
Rather than repositioning your HUD in world space every time your camera moves, add your HUD object(s) to your camera object, and position them only once. Then, when your camera moves, your HUD moves along with it, because the camera's transformation is cascaded to it's children.
yourCamera.add(yourHUD);
yourHUD.position.z = 10;
Note that doing it this way (or even positioning it the way you were) may allow scene objects to clip through your HUD geometry, or even appear between your HUD and the camera, obscuring the HUD. If that's what you want, great! If not, you could move your HUD to a second render pass, allowing it to remain "on top."
First, here is an example of your function rewritten for (almost) optimal performance as written in the comments above, the renderloop is obviously just an example to illustrate where to do which calls:
var width = renderer.context.canvas.width;
var height = renderer.context.canvas.height;
// has to be called whenever the canvas-size changes
function onCanvasResize() {
width = renderer.context.canvas.width;
height = renderer.context.canvas.height;
});
var projMatrix = new THREE.Matrix4();
// renderloop-function, called per animation-frame
function render() {
// just needed once per frame (even better would be
// once per camera-movement)
projMatrix.multiplyMatrices(
camera.projectionMatrix,
projMatrix.getInverse(camera.matrixWorld)
);
hudObjects.forEach(function(obj) {
toScreenPosition(obj, projMatrix);
});
}
// wrapped in IIFE to store the local vector-variable (this pattern
// is used everywhere in three.js)
var toScreenPosition = (function() {
var vector = new THREE.Vector3();
return function __toScreenPosition(obj, projectionMatrix) {
// this could potentially be left away, but isn't too
// expensive as there are 'needsUpdate'-checks in place
obj.updateMatrixWorld();
vector.setFromMatrixPosition(obj.matrixWorld);
vector.applyMatrix4(projectionMatrix);
vector.x = (vector.x + 1) * width / 2;
vector.y = (1 - vector.y) * height / 2;
// might want to consider returning a Vector3-instance
// instead, depends on how the result is used
return {x: vector.x, y: vector.y};
}
}) ();
But, considering you want to render a HUD, it would be better to do that independently of the main-scene, making all of the above computations obsolete and also allowing you to choose a different coordinate-system for sizing and positioning of HUD-elements.
I have an example for this here: https://codepen.io/usefulthink/pen/ZKPvPB. There I used an orthographic camera and a seperate scene to render HUD-Elements on top of the 3d-scene. No extra computations required. Plus I can specify the size and position of HUD-elements conveniently in pixel-units (The same would work using a perspective camera, only requires a bit more trigonometry to get it right).
Lets say I have a simple cube and some variables specifying its width, height and depth.
How do I update my THREE mesh when the w/h/d changes? (I have everything else like changelisteners etc). Do I update vertices directly? Or is it easier to just redraw everything?
I think easiest would be to create your cube with 1 unit dimensions (1x1x1). Then set the dimensions by scaling it:
mesh.scale.x = width;
mesh.scale.y = height;
mesh.scale.z = depth;
Not actually sure if mesh supports scale, if not, you can wrap it in Object3D
var obj = new THREE.Object3D();
obj.add(mesh);
obj.scale.x = width;
obj.scale.y = height;
obj.scale.z = depth;
Nothing stops you from modifying the vertices directly. I think you need to specify geometry.dynamic=true; and then geometry.verticesNeedUpdate=true; in that case.