• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

[FRAGE] 2D distance functions in JavaScript übersetzen

salazar

New member
Hi,
vielleicht kann mir einer von euch helfen.
Ich habe diese wirklich schöne Seite für "2D distance functions" gefunden:
https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm

Mein Problem, ich bekomme die functions nicht in JavaScript übersetzt. Mit der ersten function sdCircle ging das noch klar:
HTML:
float sdCircle( vec2 p, float r )
{
  return length(p) - r;
}
Wird zu:
HTML:
float signedDistanceToCircle( p, center, radius )
{
  const dx = p.x - center.x;
  const dy = p.y - center.y;

  return Math.sqrt( dx * dx + dy * dy ) - radius;
}
Aber z.B. bei der sdBox function hört es schon auf:
HTML:
float sdBox( in vec2 p, in vec2 b )
{
    vec2 d = abs(p)-b;
    return length(max(d,vec2(0))) + min(max(d.x,d.y),0.0);
}
Wie beim circle habe ich ein Object p (Point) mit x und y, ein Object center (Box center) mit x und y und eine float/Number size.
Ich würde gerne die Distanz von p zur box mit der Größe size ermitteln.

Danke und Gruß

- - - Aktualisiert - - -

Hey, habe es hinbekommen.
Hier meine Lösung:
HTML:
function signedDistanceToBox( p, center, size ) {

  const offsetX = Math.abs( p.x - center.x ) - size / 2;
  const offsetY = Math.abs( p.y - center.y ) - size / 2;

  const offsetMaxX = Math.max( offsetX, 0 );
  const offsetMaxY = Math.max( offsetY, 0 );
  const offsetMinX = Math.min( offsetX, 0 );
  const offsetMinY = Math.min( offsetY, 0 );
  
  const unsignedDst = Math.sqrt( offsetMaxX * offsetMaxX + offsetMaxY * offsetMaxY );
  const dstInsideBox = Math.max( offsetMinX, offsetMinY );

  return unsignedDst + dstInsideBox;
  
}

- - - Aktualisiert - - -








Hey,
jetzt ergibt sich doch noch eine Frage!

Auf der zuvor schon angesprochenen Seite: https://www.iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm gibt es eine sdTriangle function:
HTML:
float sdTriangle( in vec2 p, in vec2 p0, in vec2 p1, in vec2 p2 )
{
    vec2 e0 = p1-p0, e1 = p2-p1, e2 = p0-p2;
    vec2 v0 = p -p0, v1 = p -p1, v2 = p -p2;
    vec2 pq0 = v0 - e0*clamp( dot(v0,e0)/dot(e0,e0), 0.0, 1.0 );
    vec2 pq1 = v1 - e1*clamp( dot(v1,e1)/dot(e1,e1), 0.0, 1.0 );
    vec2 pq2 = v2 - e2*clamp( dot(v2,e2)/dot(e2,e2), 0.0, 1.0 );
    float s = sign( e0.x*e2.y - e0.y*e2.x );
    vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)),
                     vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))),
                     vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x)));
    return -sqrt(d.x)*sign(d.y);
}

Hier mein aktuell noch wenig erfolgreicher Versuch diese function in JavaScript zu überführen:
HTML:
function signedDistanceToTriangle( p, p0, p1, p2 ) {

  const edge0X = p1.x - p0.x;
  const edge0Y = p1.y - p0.y;
  const edge1X = p2.x - p1.x;
  const edge1Y = p2.y - p1.y;
  const edge2X = p0.x - p2.x;
  const edge2Y = p0.y - p2.y;

  const v0X = p.x - p0.x;
  const v0Y = p.y - p0.y;
  const v1X = p.x - p1.x;
  const v1Y = p.y - p1.y;
  const v2X = p.x - p2.x;
  const v2Y = p.y - p2.y;

  const pq0X = v0X - edge0X * clamp( dot( v0X, edge0X ) / dot( edge0X, edge0X ), 0, 1 );
  const pq0Y = v0Y - edge0Y * clamp( dot( v0Y, edge0Y ) / dot( edge0Y, edge0Y ), 0, 1 );
  const pq1X = v1X - edge1X * clamp( dot( v1X, edge1X ) / dot( edge1X, edge1X ), 0, 1 );
  const pq1Y = v1Y - edge1Y * clamp( dot( v1Y, edge1Y ) / dot( edge1Y, edge1Y ), 0, 1 );
  const pq2X = v2X - edge2X * clamp( dot( v2X, edge2X ) / dot( edge2X, edge2X ), 0, 1 );
  const pq2Y = v2Y - edge2Y * clamp( dot( v2Y, edge2Y ) / dot( edge2Y, edge2Y ), 0, 1 );
  
  const s = Math.sign( edge0X * edge2Y - edge0Y * edge2X );

  const dotPQ0X = dot( pq0X, pq0X );
  const dotPQ0Y = dot( pq0Y, pq0Y );
  const dotPQ1X = dot( pq1X, pq1X );
  const dotPQ1Y = dot( pq1Y, pq1Y );
  const dotPQ2X = dot( pq2X, pq2X );
  const dotPQ2Y = dot( pq2Y, pq2Y );
  
  const s0 = s * ( v0X * edge0Y - v0Y * edge0X );
  const s1 = s * ( v1X * edge1Y - v1Y * edge1X );
  const s2 = s * ( v2X * edge2Y - v2Y * edge2X );

  const dX = Math.min( Math.min( dotPQ0X, s0, dotPQ1X, s1 ), dotPQ2X, s2 );
  const dY = Math.min( Math.min( dotPQ0Y, s0, dotPQ1Y, s1 ), dotPQ2Y, s2 );

  //return -Math.sqrt( dX ) * Math.sign( dY );
  return -Math.sqrt( Math.abs( dX ) ) * Math.sign( dY );

}

function clamp( val, min, max ) {

  return Math.min( Math.max( min, val ), max );
  
}

function dot( v0, v1 ) {

  return v0 * v1 + v0 * v1;
  
}

Wie bei den anderen functions auch ist p wieder der Punkt (x,y) dessen Distanz es zu kalkulieren gilt zum triangle mit den Punkten p0 (x,y), p1 (x,y) und p2(x,y).
Ein Problem besteht auf jeden Fall in der letzten Zeile:
HTML:
return -Math.sqrt( dX ) * Math.sign( dY );
Denn
HTML:
-Math.sqrt( dX )
ergibt NaN. Und somit gibt natürlich die function immer NaN als Ergebnis zurück. dX ist immer negativ, und das darf bei Math.sqrt ja nicht sein?!
Ich vermute mal das Problem wird vorher schon wo im Code zu finden sein, auf dem Weg dX und dY zu berechnen. Nur leider komme ich nicht drauf. Vielleicht hat ja wer von euch den Überblick und kann helfen?

Besten Dank und Grüße
 
Zuletzt bearbeitet:
Ja, die function signedDistanceToTriangle funktioniert aktuell zwar, aber nicht so wie gedacht. Ich habe einen Workaround geschrieben, aber der ist weniger performant.
 
Zurück
Oben