Calculate volume of FOV and loop inside - javascript

I want to improve performances in my game and for that, I need to loop inside the visible volume.
I know that this is very slow to calculate, but I really think that it'll be better that today.
I have these values:
Camera position: x, y, z
Camera rotation: rx, ry, rz
Render distance: d
Render function: r
I've tried this code but r is never executed:
const MAP_LIMIT = [150,25,150]; // Limit of the map (x,y,z)
(x=0,y=0,z=0,d=10,ox=0,oy=0,oz=0,r) => {
x = Int(x); // Int = Math.round
y = Int(y);
z = Int(z);
const RoundToMapLimit = (n=0,t=0) => n <= 0 ? 0 : (n >= MAP_LIMIT[t] ? MAP_LIMIT[t] : n);
const obj = new THREE.Object3D();
obj.position.set(x,y,z);
obj.rotation.set(ox,0,0);
obj.translateX(d);
const xRange = [RoundToMapLimit(x),RoundToMapLimit(obj.position.x)];
obj.translateX(-d);
obj.rotation.set(0,oy,0);
obj.translateY(d);
const yRange = [RoundToMapLimit(y,1),RoundToMapLimit(obj.position.y,1)];
obj.translateY(-d);
obj.rotation.set(0,0,oz);
obj.translateZ(d);
const zRange = [RoundToMapLimit(z,2),RoundToMapLimit(obj.position.z,2)];
for (let y2 = Math.min(...yRange); y2 < Math.max(...yRange); ++y2) {
for (let x2 = Math.min(...xRange); x2 < Math.max(...xRange); ++x2) {
for (let z2 = Math.min(...zRange); z2 < Math.max(...zRange); ++z2) {
r([x2,y2,z2]);
}
}
}
};
Can you please help me to fix this function ?
Thank you

Related

Collision detection and resolving in a generalized coordinate system

I have this game I'm working on with a 2 dimensional array with coordinates and a generalized coordinate system (i.e. player x = 0 and y = 0, it's standing in the first item in the array). I'm trying to work out a solution to collision detection and resolving, but I'm having a really hard time.
This is my code so far (detecting collisions but not resolving them correctly and I have just no clue how to fix thayut):
let xOffset = 0;
let yOffset = 0;
let self = this;
let a, b, c, d, e, f, g, h;
// get the 4 colliding tiles from the layout array
function reset() {
a = Math.floor(self.x);
b = Math.ceil(self.x);
c = Math.floor(self.y);
d = Math.ceil(self.y);
e = (currentClassRoom.layout[c] || [])[a];
f = (currentClassRoom.layout[c] || [])[b];
g = (currentClassRoom.layout[d] || [])[a];
h = (currentClassRoom.layout[d] || [])[b];
}
function X() {
// x collisions
// get the distance inside the block from corresponding direction
if (Walkable.indexOf(f) < 0 || Walkable.indexOf(h) < 0) { xOffset += -(self.x - a) }
if (Walkable.indexOf(e) < 0 || Walkable.indexOf(g) < 0) { xOffset += 1 - (self.x - a) }
}
function Y() {
// y collisions
// get the distance inside the block from corresponding direction
if (Walkable.indexOf(e) < 0 || Walkable.indexOf(f) < 0) { yOffset += 1 - (self.y - c) };
if (Walkable.indexOf(g) < 0 || Walkable.indexOf(h) < 0) { yOffset += -(self.y - c) };
}
// run and resolve
reset();
Y();
this.y += yOffset;
X();
this.x += xOffset;
Is there something wrong with my code or is a generalized coordinate system a bad idea in my case? I haven't made anything like this and can't seem to find solutions online (which might be an indicator that the way I'm thinking about this is bad but I just don't know)

Color quantization using euclidean distance gives jumpy results

I'm working on an art project which converts pixels of live video feed into corporate logos based on the distance (in RGB) between the colors of the two. While this functions, it gives a jittery result. Seem like some points in the color space teeter in a sort of superposition between two "closest" points. I'm attempting a sort of naive clustering solution right now because I believe any proper one will be too slow for live video. I'm wondering if anyone has any good ideas to solve this problem? I'll include my code and an example of the result. Thank you!
(imgs array is the logos)
current result: https://gifyu.com/image/fk2y
function distance(r1, g1, b1, bright1, r2, g2, b2, bright2) {
d =
((r2 - r1) * 0.3) ** 2 +
((g2 - g1) * 0.59) ** 2 +
((b2 - b1) * 0.11) ** 2 +
((bright2 - bright1) * 0.75) ** 2;
return Math.round(d);
}
function draw() {
if (x > 100 && z == true) {
video.loadPixels();
for (var y = 0; y < video.height; y++) {
for (var x = 0; x < video.width; x++) {
var index = (video.width - x - 1 + y * video.width) * 4;
var r = video.pixels[index];
var g = video.pixels[index + 1];
var b = video.pixels[index + 2];
var bright = (r + g + b) / 3;
let least = 9999999;
for (var i = 0; i < imgs.length; i++) {
if (
distance(
imgs[i].r,
imgs[i].g,
imgs[i].b,
imgs[i].bright,
r,
g,
b,
bright
) < least
) {
least = distance(
imgs[i].r,
imgs[i].g,
imgs[i].b,
imgs[i].bright,
r,
g,
b,
bright
);
place = imgs[i].img;
}
}
image(place, round(x * vScale), y * vScale, vScale, vScale);
}
}
}
}

polygon weird redrawing by adding & dragging dynamic points (flickering)

I have co-ordinates for the points by taking which I draw a polygon. I can add points dynamically on the edges of the polygon and when I drag any point it should drag only the connected lines. As points can be added later on the edges so the point co-ordinates need to be ordered/sorted and the polygon should be redrawn by taking the ordered/sorted points so that on dragging any point the lines connected to the dragged point only should be dragged/updated. So to order/sort the points I am sorting the co-ordinates(2D-points) clockwise using Graham Scan/ sorting by polar angle.
My sorting code is
I find the center of the polygon like
function findCenter(points) {
let x = 0,
y = 0,
i,
len = points.length;
for (i = 0; i < len; i++) {
x += Number(points[i][0]);
y += Number(points[i][1]);
}
return { x: x / len, y: y / len }; // return average position
}
Then I sort the points by finding angles of each point from the center like
function findAngle(points) {
const center = findCenter(points);
// find angle
points.forEach((point) => {
point.angle = Math.atan2(point[1] - center.y, point[0] - center.x);
});
}
//arrVertexes is the array of points
arrVertexes.sort(function (a, b) {
return a.angle >= b.angle ? 1 : -1;
});
But the problem I am facing is if I drag any point more towards opposite side and add a new point on the edges afterward and drag the newly added point the sorting of co-ordinates is not ordered exactly because of which there is a flickering while dragging.
Here is a pictorial view of the problem I am facing for quick understanding.
Initially my svg looks like
After this I add a point and dragged like
Then I added one more point like
once I drag the added point towards down, it redraws the polygon something like (is not it weird ?)
Actually It should be like
NOTE: I really don't know what logic should I apply to get the desire functionality. Seeking help from the community leads.
Demo App
So I am looking for a solution that won't give me weird redrawing of the lines. Only the connected lines to the dragged point should be dragged.
EDIT
I came up with MUCH BETTER solution. The only problem with this approach is, When I try to add a new point on left-vertical line and If I try to move it, that newly added point moves to top-horizontal line
Updated-Demo
I've fixed this bug with left line. Take a look: codepen.
I changed getClosestPointOnLines function (actually refactored a little):
as I understood, the result here is to get i - the index for the new point in array, so I moved the algorithm to new function getI
I changed getI to use not only n (current index), but just 2 any indexes: n1 and n2: const getI = (n1, n2) => {
So all your aXys[n] is now a1 and aXys[n - 1] is now a2.
the result of getI is return i; - this is what we want from this function
I added new function-helper updateI. It calls getI and check if there any positive result.
const updateI = (n1, n2) => {
const newI = getI(n1, n2);
if (newI !== undefined) {
i = newI;
return true;
}
};
So your loop over points is now:
for (let n = 1; n < aXys.length; n++) {
updateI(n, n - 1);
}
But we need to check "left" line separately (because it connects begin and end of the array):
if (updateI(aXys.length - 1, 0)) i = aXys.length;
Sorry, but I disabled part of your code. I did not check where do you use it:
if (i < aXys.length) {
let dx = aXys[i - 1][0] - aXys[i][0];
let dy = aXys[i - 1][1] - aXys[i][1];
x = aXys[i - 1][0] - dx * fTo;
y = aXys[i - 1][1] - dy * fTo;
}
So the final version of getClosestPointOnLines now looks like this:
function getClosestPointOnLines(pXy, aXys) {
var minDist;
var fTo;
var fFrom;
var x;
var y;
var i;
var dist;
if (aXys.length > 1) {
const getI = (n1, n2) => {
let i;
const a1 = aXys[n1];
const a2 = aXys[n2];
if (a1[0] != a2[0]) {
let a = (a1[1] - a2[1]) / (a1[0] - a2[0]);
let b = a1[1] - a * a1[0];
dist = Math.abs(a * pXy[0] + b - pXy[1]) / Math.sqrt(a * a + 1);
} else dist = Math.abs(pXy[0] - a1[0]);
// length^2 of line segment
let rl2 = Math.pow(a1[1] - a2[1], 2) + Math.pow(a1[0] - a2[0], 2);
// distance^2 of pt to end line segment
let ln2 = Math.pow(a1[1] - pXy[1], 2) + Math.pow(a1[0] - pXy[0], 2);
// distance^2 of pt to begin line segment
let lnm12 = Math.pow(a2[1] - pXy[1], 2) + Math.pow(a2[0] - pXy[0], 2);
// minimum distance^2 of pt to infinite line
let dist2 = Math.pow(dist, 2);
// calculated length^2 of line segment
let calcrl2 = ln2 - dist2 + lnm12 - dist2;
// redefine minimum distance to line segment (not infinite line) if necessary
if (calcrl2 > rl2) dist = Math.sqrt(Math.min(ln2, lnm12));
if (minDist == null || minDist > dist) {
if (calcrl2 > rl2) {
if (lnm12 < ln2) {
fTo = 0; //nearer to previous point
fFrom = 1;
} else {
fFrom = 0; //nearer to current point
fTo = 1;
}
} else {
// perpendicular from point intersects line segment
fTo = Math.sqrt(lnm12 - dist2) / Math.sqrt(rl2);
fFrom = Math.sqrt(ln2 - dist2) / Math.sqrt(rl2);
}
minDist = dist;
i = n1;
}
return i;
};
const updateI = (n1, n2) => {
const newI = getI(n1, n2);
if (newI !== undefined) {
i = newI;
return true;
}
};
for (let n = 1; n < aXys.length; n++) {
updateI(n, n - 1);
}
if (updateI(aXys.length - 1, 0)) i = aXys.length;
if (i < aXys.length) {
let dx = aXys[i - 1][0] - aXys[i][0];
let dy = aXys[i - 1][1] - aXys[i][1];
x = aXys[i - 1][0] - dx * fTo;
y = aXys[i - 1][1] - dy * fTo;
}
}
console.log(aXys[i - 1]);
return { x: x, y: y, i: i, fTo: fTo, fFrom: fFrom };
}
Working example on codepen.
You should not allow any point to be added that is not close to a line.
When the user clicks, use the distance from a point to a line algorithm to check each line to see if the click is within an acceptable distance of the line. Perhaps a few pixels. If more than one line is within an acceptable distance, perhaps choose the one that is closest.
You now know where in the array to insert the new point. It will be between the first and second points of the line that just matched.
If you do that, the shape drawing should just work.

Calculate rectangles angle knowing the outline positions (x/y)

I got an matrix of ones and zeros like this (& I hope you can get the rectangle of ones):
And I'd like to calculate the rectangles rotation angle.
So what I'm starting with: I now all of the positions (x/y-coordinates) of the rectangles outline (symbolized with ' ' (spaces) in the image above) and got them in an array like this:
var outline_positions = [[120,22],[122,22],...,[94,119],[93,119]]
So now my question: How is it possible to calculate the rectangles rotation-angle to the X-axis, knowing that the long side of the rectangle at angle 0° is parallel to the X-asis?
Because I got now idea how to start this code is all that I got so far:
var positions = [[120,22],[122,22],[120,22],[121,22],[122,22],[119,23],[125,23],[119,24],[127,24],[118,25],[129,25],[118,26],[131,26],[117,27],[132,27],[117,28],[134,28],[117,29],[137,29],[116,30],[139,30],[115,31],[141,31],[115,32],[142,32],[114,33],[142,33],[113,34],[142,34],[113,35],[142,35],[112,36],[141,36],[111,37],[140,37],[111,38],[140,38],[110,39],[139,39],[109,40],[139,40],[109,41],[138,41],[108,42],[138,42],[108,43],[137,43],[106,44],[137,44],[106,45],[136,45],[105,46],[136,46],[105,47],[135,47],[104,48],[135,48],[103,49],[134,49],[103,50],[134,50],[103,51],[133,51],[102,52],[132,52],[101,53],[132,53],[100,54],[131,54],[100,55],[131,55],[99,56],[130,56],[98,57],[129,57],[97,58],[128,58],[97,59],[128,59],[96,60],[127,60],[95,61],[127,61],[95,62],[126,62],[94,63],[126,63],[94,64],[125,64],[93,65],[124,65],[92,66],[124,66],[92,67],[124,67],[91,68],[123,68],[91,69],[122,69],[90,70],[121,70],[89,71],[121,71],[89,72],[120,72],[88,73],[120,73],[87,74],[119,74],[87,75],[118,75],[86,76],[118,76],[86,77],[116,77],[85,78],[116,78],[85,79],[116,79],[83,80],[115,80],[83,81],[115,81],[82,82],[115,82],[81,83],[114,83],[81,84],[113,84],[80,85],[113,85],[80,86],[112,86],[79,87],[112,87],[78,88],[112,88],[78,89],[111,89],[78,90],[110,90],[77,91],[110,91],[76,92],[109,92],[76,93],[109,93],[75,94],[108,94],[74,95],[107,95],[74,96],[107,96],[73,97],[106,97],[73,98],[105,98],[72,99],[105,99],[72,100],[104,100],[71,101],[104,101],[70,102],[103,102],[70,103],[103,103],[69,104],[102,104],[70,105],[102,105],[72,106],[101,106],[73,107],[101,107],[75,108],[100,108],[76,109],[100,109],[77,110],[99,110],[80,111],[98,111],[81,112],[98,112],[83,113],[97,113],[84,114],[96,114],[86,115],[96,115],[88,116],[96,116],[90,117],[95,117],[91,118],[94,118],[93,119],[94,119],[94,119],[93,119]]
Array.prototype.calculate_rotation = function() {
var array=this
var max_x = array.filter(e => e[0] === Math.max(... array.map(e => e[0])))[0];
var min_x = array.filter(e => e[0] === Math.min(... array.map(e => e[0])))[0]
return max_x[1]-min_x[1]
}
console.log(positions.calculate_rotation());
One approach could be as follows:
function calculate_rotation(arr){
var N = arr.length;
if(!N) return;
var xmin = arr[0][0];
var ymin = arr[0][1];
var A = arr[0];
var P = arr[0];
for(var i = 0; i < N; ++i){
var x = arr[i][0];
var y = arr[i][1];
if(x < xmin || (x == xmin && y < A[1])){
xmin = x;
A = [x, y];
}
if(y < ymin || (y == ymin && x > P[0])){
ymin = y;
P = [x, y];
}
}
return Math.atan2(P[1] - A[1], P[0] - A[0])*180/Math.PI;
}
The idea is to identify the left-most (A) and bottom-most (P) points. The rotation angle is then calculated with respect to the point A. Alternatively, one could do a second pass through the array, identify all points which are on the line segment connecting A and P and do a linear fit in order to obtain the slope.

Why is Firefox 30 times slower than Chrome, when calculating Perlin noise?

I have written a map generator in javascript, using classical perlin noise scripts I have found in various places, to get the functionality I want. I have been working in chrome, and have not experienced any problems with the map. However, when I tested it in firefox, it was incredibly slow - almost hanging my system. It fared better in the nightly build, but still 30 times slower than Chrome.
You can find a test page of it here:
http://jsfiddle.net/7Gq3s/
Here is the html code:
<!DOCTYPE html>
<html>
<head>
<title>PerlinMapTest</title>
</head>
<body>
<canvas id="map" width="100" height="100" style="border: 1px solid red">My Canvas</canvas>
<script src="//code.jquery.com/jquery-2.0.0.min.js"></script>
<script>
$(document).ready(function(){
//Log time in two ways
var startTime = new Date().getTime();
console.time("Map generated in: ");
var canvas = $("#map")[0];
var ctx = canvas.getContext("2d");
var id = ctx.createImageData(canvas.width, canvas.height);
var noiseMap = new PerlinNoise(500);
var startx = 0;
var starty = 0;
var value = 0;
for(var i = startx; i < canvas.width; i++){
for(var j = starty; j < canvas.height; j++){
value = noiseMap.noise(i,j, 0, 42);
value = linear(value,-1,1,0,255);
setPixel(id, i, j, 0,0,0,value);
}
}
ctx.putImageData(id,0,0);
var endTime = new Date().getTime();
console.timeEnd("Map generated in: ");
alert("Map generated in: " + (endTime - startTime) + "milliseconds");
});
function setPixel(imageData, x, y, r, g, b, a) {
index = (x + y * imageData.width) * 4;
imageData.data[index+0] = r;
imageData.data[index+1] = g;
imageData.data[index+2] = b;
imageData.data[index+3] = a;
}
//This is a port of Ken Perlin's "Improved Noise"
//http://mrl.nyu.edu/~perlin/noise/
//Originally from http://therandomuniverse.blogspot.com/2007/01/perlin-noise-your-new-best-friend.html
//but the site appears to be down, so here is a mirror of it
//Converted from php to javascript by Christian Moe
//Patched the errors with code from here: http://asserttrue.blogspot.fi/2011/12/perlin-noise-in-javascript_31.html
var PerlinNoise = function(seed) {
this._default_size = 64;
this.seed = seed;
//Initialize the permutation array.
this.p = new Array(512);
this.permutation = [ 151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
];
for (var i=0; i < 256 ; i++) {
this.p[256+i] = this.p[i] = this.permutation[i];
}
};
PerlinNoise.prototype.noise = function(x,y,z,size) {
if (size == undefined)
{
size = this._default_size;
}
//Set the initial value and initial size
var value = 0.0;
var initialSize = size;
//Add finer and finer hues of smoothed noise together
while(size >= 1)
{
value += this.smoothNoise(x / size, y / size, z / size) * size;
size /= 2.0;
}
//Return the result over the initial size
return value / initialSize;
};
//This function determines what cube the point passed resides in
//and determines its value.
PerlinNoise.prototype.smoothNoise = function(x, y, z){
//Offset each coordinate by the seed value
x += this.seed;
y += this.seed;
z += this.seed;
var orig_x = x;
var orig_y = y;
var orig_z = z;
var X = Math.floor(x) & 255, // FIND UNIT CUBE THAT
Y = Math.floor(y) & 255, // CONTAINS POINT.
Z = Math.floor(z) & 255;
x -= Math.floor(x); // FIND RELATIVE X,Y,Z
y -= Math.floor(y); // OF POINT IN CUBE.
z -= Math.floor(z);
var u = this.fade(x), // COMPUTE FADE CURVES
v = this.fade(y), // FOR EACH OF X,Y,Z.
w = this.fade(z);
var A = this.p[X ]+Y, AA = this.p[A]+Z, AB = this.p[A+1]+Z, // HASH COORDINATES OF
B = this.p[X+1]+Y, BA = this.p[B]+Z, BB = this.p[B+1]+Z; // THE 8 CUBE CORNERS,
return this.lerp(w, this.lerp(v, this.lerp(u, this.grad(this.p[AA ], x , y , z ), // AND ADD
this.grad(this.p[BA ], x-1, y , z )), // BLENDED
this.lerp(u, this.grad(this.p[AB ], x , y-1, z ), // RESULTS
this.grad(this.p[BB ], x-1, y-1, z ))),// FROM 8
this.lerp(v, this.lerp(u, this.grad(this.p[AA+1], x , y , z-1 ), // CORNERS
this.grad(this.p[BA+1], x-1, y , z-1 )), // OF CUBE
this.lerp(u, this.grad(this.p[AB+1], x , y-1, z-1 ),
this.grad(this.p[BB+1], x-1, y-1, z-1 ))));
};
PerlinNoise.prototype.fade = function(t) {
return t * t * t * ( ( t * ( (t * 6) - 15) ) + 10);
};
PerlinNoise.prototype.lerp = function(t, a, b) {
//Make a weighted interpolaton between points
return a + t * (b - a);
};
PerlinNoise.prototype.grad = function(hash, x, y, z) {
h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
u = h<8 ? x : y; // INTO 12 GRADIENT DIRECTIONS.
v = h<4 ? y : (h==12||h==14 ? x : z);
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
};
PerlinNoise.prototype.scale = function(n) {
return (1 + n)/2;
};
function linear(int, s1, s2, t1, t2)
{
t = [t1, t2];
s = [s1, s2];
rangeS = s1 - s2;
rangeT = t1 - t2;
if((s1 < s2 && t1 > t2) || (s1>s2 && t1<t2))
{
interpolated = ((int - s1) / rangeS*rangeT) + t1;
}
else
{
interpolated = ((int - s1) / rangeS)*rangeT + t1;
}
if(interpolated > Math.max.apply(Math, t))
{
interpolated = Math.max.apply(Math, t);
}
if(interpolated < Math.min.apply(Math, t))
{
interpolated = Math.min.apply(Math, t);
}
return interpolated;
}
</script>
</body>
</html>
I get 33 ms on Chrome, and 1051ms on Firefox 24 Nightly
The results are inconsistent though. Sometimes the Nightly results is as fast as chrome...
Do you know why there is so much variation in this particular instance?
I don't know enough about the theory of perlin noise to try optimizing the code, so don't know what to do.
I have found the culprit. The slowdown occurs when I have Firebug enabled. That extension must weigh it down.

Categories