I have tweened an object (its x property) with tweenlite, and I want to measure the instantaneous speed during the tween, at a given moment.
I know I could make an array that constantly records recent x values at onUpdate, and then take the difference. But are there more efficient ways of doing this?
Don't understand why you need the speed, but, it's simple math. You already know the distance the object will travel and the time it needs to arrive on destination. So,
speedTimeUnit = distanceTraveled/timeNeededToArrive;
or if you need to know speed in frames
speedFramesUnit = distanceTraveled/(timeNeededToArrive*frameRate);
Of course, this is in case that time is in seconds ...
No, there isn't another way to measure it.
Anyway you need to know the distance between two points and moving time, and if you have animation in timeline the only way to know these params it to measure it. If your tween is linear, you can store the initial position and timestamp and at any moment the instantaneous speed will be:
var origPos:Point = new Point(obj.x, obj.y);
var origTimestamp:Number = getTimer();
var currentPos:Point = new Point();
currentPos.x = obj.x;
currentPos.y = obj.y;
var speed:Number = currentPos.subtract(origPos).length/(getTimer() - origTimestamp);
If you don't sure whether tween leaner or not replace origPos and origTimestamp after each measurement.
Related
I have a Three.js App and I wanna limit the zoom for the scene, because logically at some zoom the user can get inside of my 3D object, which in my oppinion is not a really good UX.
I tried scene.maxZoom = number; but did not work. What can I do?
Here is the code: https://github.com/AlinAlexandruPeter/code/blob/main/code.js
You don't need Three.js to limit the range of numbers, just simple JavaScript. Use Math.min(a, b) to get the lower of the two values.
const MAX_ZOOM = 2.5;
// Clamp user input to 2.5 and below
camera.zoom = Math.min(userInput, MAX_ZOOM);
With this approach, if userInput = 3, it will get clamped at 2.5. There's also Math.max() if you want to clamp it on the lower range.
I've got a row dimensional array of values that I want to visualize in 3D and I'm using scene kit under OS X for it. I've done it in a clumsy manner by using each column as a point on the X axis, each row as a point on the Z axis, and each value as a normalized point on the Y axis -- I place a sphere at the vector defined by each data point. It works but it doesn't look too good.
I've also done this by building a mesh of lines based on #Matthew's function in Drawing a line between two points using SceneKit (the answer he posted, not the original question). For each point I use his function to draw two lines - one between my current point and the next point to the right and another between my current point and the next point towards the front (except when there is no additional column/row, of course).
Using the second method, my results look much better... however the performance is quite hideous! It takes quite a long time to complete the initial rendering, and if I use a trackpad/mouse to rotate or translate the scene, I might as well get a cup of coffee to wait until my system is usable again (and this is not much hyperbole). Using the sphere method, things render and update very quickly.
Any advice on how to improve the performance when using the lines method? (Note that I am not trying to add both lines and spheres at the same time.) Code-wise, the only difference between approach is which of the following methods gets called (and that for each point, addPixelAt... is called once, but addLineAt... is called twice for most points).
- (SCNNode *)addPixelAtRow:(CGFloat)row Column:(CGFloat)column size:(CGFloat)size color:(NSColor *)color
{
CGFloat radius = 0.5;
SCNSphere *ball = [SCNSphere sphereWithRadius:radius*1.5];
SCNMaterial *material = [SCNMaterial material];
[[material diffuse] setContents:color];
[[material specular] setContents:color];
[ball setMaterials:#[material]];
SCNNode *ballNode = [SCNNode nodeWithGeometry:ball];
[ballNode setPosition:SCNVector3Make(column, size, row)];
[_baseNode addChildNode:ballNode];
return ballNode;
}
- (SCNNode *)addLineFromRow:(CGFloat)row1 Column:(CGFloat)column1 size:(CGFloat)size1
toRow2:(CGFloat)row2 Column2:(CGFloat)column2 size2:(CGFloat)size2 color:(NSColor *)color
{
SCNVector3 positions[] = {
SCNVector3Make(column1, size1, row1),
SCNVector3Make(column2, size2, row2)
};
int indices[] = {0, 1};
SCNGeometrySource *vertexSource = [SCNGeometrySource geometrySourceWithVertices:positions count:2];
NSData *indexData = [NSData dataWithBytes:indices length:sizeof(indices)];
SCNGeometryElement *element = [SCNGeometryElement geometryElementWithData:indexData
primitiveType:SCNGeometryPrimitiveTypeLine
primitiveCount:1
bytesPerIndex:sizeof(int)];
SCNGeometry *line = [SCNGeometry geometryWithSources:#[vertexSource] elements:#[element]];
SCNMaterial *material = [SCNMaterial material];
[[material diffuse] setContents:color];
[[material specular] setContents:color];
[line setMaterials:#[material]];
SCNNode *lineNode = [SCNNode nodeWithGeometry:line];
[_baseNode addChildNode:lineNode];
return lineNode;
}
From the data that you've shown in your question I would say that your main problem is the number of draw calls. Your's is in the tens of thousands, which is way too much. It should probably be a lot closer to ~100.
The reason why you have so many draw calls is that you have so many distinct objects in your scene (each line). The better (but more advanced solution) would probably be to generate a single element for the entire mesh that consists of all the lines. If you want to achieve the same rendering with that mesh (with a color from cold to warm based on the height) then you could do that in a shader modifier.
However, in your case I would start by flattening all the lines (since that would be the smallest code change and should still have a significant performance improvement in your case).
(Optimizing performance is always an iterative process. Once you fix one thing there will be another thing which is the most expensive operation. Without your code I can only say what would help with the current performance problem)
Create an empty node (without adding it to your scene) and generate all the lines, adding them to this node. Then create a flattened copy of that node by calling flattenedClone on the node that contains all the lines
SCNNode *nodeWithAllTheLines = [SCNNode node];
// create all the lines and add them to it...
SCNNode *flattenedNode = [nodeWithAllTheLines flattenedClone];
[_baseNode addChildNode:flattenedNode];
When you do this you should see a significant drop in the number of draw calls (the number after the diamond in the statistics) and hopefully a big increase in performance.
I've just started learning THREE and have been messing about with the three.js example of controllable MD2 characters to try and fashion it into a 3rd person shooter kind of game. I've been trying to write a simple algorithm for the enemy characters and I'm pretty sure that ray-casting would be ideal.The whole idea is that the enemies should stop rotating once they're facing the player. But Here's the problem that's giving me sleepless nights! :
Let's say, the enemy object is the origin for the ray caster ray. No matter what direction I set for the direction of that ray ( even, for example (1,0,0) - the positive x-axis), the ray's direction is always pointing towards the center of the scene!!!
Please help! haven't been able to find any Example online for this kind of use for the ray caster (apart from collision detection which I really don't need at the moment).
If all you want is for enemies to stop rotating when they are looking at the player, I would consider just checking the direction between them, as it's a lot faster than casting a ray to see if it intersects:
// Assuming `enemy` is a THREE.Mesh
var targetDir = enemy.position.clone().sub(player.position).normalize();
var currentDir = (new THREE.Vector3()).applyMatrix4(enemy.matrixWorld).sub(enemy.position).normalize();
var amountToRotate = currentDir.sub(targetDir);
var offset = amountToRotate.length();
Then rotate each axis no more than the value for that axis in amountToRotate if offset is greater than some threshold.
That said, here is how you use a Raycaster, given the variables above:
var raycaster = new THREE.Raycaster(enemy.position, targetDir);
var intersections = raycaster.intersectObject(player);
Note that if you are running any of the above code in an animation loop, it will create a lot of garbage collection churn because you are constantly creating a bunch of new objects and then immediately throwing them away. A better pattern, which is used a lot in the library itself, is to initialize objects once, copy values to them if you need to, and then use those copies for computation. For example, you could create a function to do your raycasting for you like this:
var isEnemyLookingAtPlayer = (function() {
var raycaster = new THREE.Raycaster();
var pos = new THREE.Vector3();
return function(enemy) {
raycaster.ray.origin.copy(enemy.position);
raycaster.ray.direction.copy(pos.copy(enemy.position).sub(player.position).normalize());
return !!raycaster.intersectObject(player).length;
};
})();
I have an animation with about 20 frames. I need to be able to access local transforms for each bone for a given animation frame. I know how to access the bone and its local transform (a sample of the code)
Transform root, spine1;
getChildFromName(gameObj, "Jnt_Root", out root);
getChildFromName(root, "Jnt_Spine1", out spine1);
spine1.localRotation = someValue;
All of this works fine, but I don't know the values I'm getting are from which animation frame? I assume its from frame 1 (can verify using debugger but that's not the point)
The questions is how to get and set these values for a specific frame? Thanks!
Something like this should work for getting the current transforms:
AnimationState state = animation["your_animation"];
state.enabled = true;
state.normalizedTime = (1.0f/totalAnimationTime) * specificFrame;
animation.Sample();
// get all transforms of this animation, extract your root and spine from here.
Transform[] transforms = animation.gameObject.GetComponentsInChildren<Transform>();
Or if you're trying to sample while the animation is running you could do something like:
if(animation["your_animation"].normalizedTime > 0.3 && animation["your_animation"].normalizedTime < 0.5) {
//... do something at this point in time. You'll have to figure out the frame
//from the time
}
Last I checked you can't explicitly extract a particular frame. But if you know the total length of your animation (time-wise), you can move the animation to that point with something like: (1.0f/totalAnimationTime) * specificFrame; (this assumes the keyframes are uniformly spaced.)
Once stored you should be able to modify the transforms directly but I've never tried.
I extracted country outline data from somewhere and successfully managed to convert it into an array of lat-lng coordinates that I can feed to Google maps API to draw polyline or polygons.
The problem is that that there are about 1200+ points in that shape. It renders perfectly in Google maps but I need to reduce the number of points from 1200 to less than 100. I don't need a very smooth outline, i just need to throw away the points that I can live without. Any algorithm or an online tool that can help me reduce the number of points is needed.
Found this simple javascript by Bill Chadwick. Just feed in the LatLng to an array and pass in to the source arguments in a function here Douglas Peucker line simplification routine
it will output an array with less points for polygon.
var ArrayforPolygontoUse= GDouglasPeucker(theArrayofLatLng,2000)
var polygon=new google.maps.Polygon({
path:ArrayforPolygontoUse,
geodesic:true,
strokeColor:"#0000FF",
strokeOpacity:0.8,
strokeWeight:2,
fillColor:"#0000FF",
fillOpacity:0.4,
editable:true
});
theArrayofLatLng is an array of latlng that you collected using google maps api.
The 2000 value is kink in metres. My assumption is, the higher the value, more points will be deleted as an output.
For real beginners:
Make sure you declare the js file on your html page before using it. :)
<script type="text/javascript" src="js/GDouglasPeucker.js"></script>
I think MapShaper can do this online
Otherwise, implement some algorithm
If you can install postgis which i think is easy as they provide an installer then you can import the data and execute snaptogrid() or st_simplify() for which i cannot find an equivalent in mysql.If you decide to go with postgis which i recommend cause it will help you down the road i can provide you with the details.
Now for an easy custom solution you can reduce size by cutting or rounding some of the last digits of the coords and then merge the same coords resulting actually in a simple snaptogrid().
Hope it helps
I was looking for exactly the same thing and found Simplify.js. It does exactly what you want and is incredibly easy to use. You simply pass in your coordinates and it will remove all excess points.
simplify(points, tolerance, highQuality)
The points argument should contain an array of your coordinates formatted as {x: 123, y: 123}. (Afterwards you can convert it back to the format you wish.)
The tolerance should be the precision in decimal degrees. E.g. 0.0001 for 11 meters. Increasing this number will reduce the output size.
Set highQuality to true for better results if you don't mind waiting a few milliseconds longer.
Mostly likely what you want to divide the points into 2 half and want to try my Javascript function:
function shortenAndShow ( polyline, color ) {
var dist = 0, copyPoints = Array ( );
for ( var n = 0, var end = polyline.getVertexCount ( ) - 1; n < end ; n++ ) {
dist += polyline.getVertex ( n ).distanceFrom ( polyline.getVertex ( n +1 ) );
copyPoints.push ( polyline.getVertex (n) );
}
var lastPoint = copyPoints [copyPoints.length-1];
var newLine = new GPolyline (copyPoints, color, 2, 1);
gmap2.addOverlay ( newLine );
}
I agree the Unreason's anwser,The website support GeoJson,I used it in my website,and it cut down my geoJson ,But I think you also need this world country geo Json