将2D SDF函数转换为JavaScript

将2D SDF函数转换为JavaScript,javascript,math,shader,translate,Javascript,Math,Shader,Translate,我想将这个非常好的页面中的一些2D SDF函数转换为JavaScript: 我已经可以翻译函数sdCircle和sdBox了。我想翻译所有函数并直接在JavaScript中使用它们。目前我正在研究sdTriangle函数。我在这里再也走不动了。sdTriangle总是返回NaN。我猜问题发生在计算dX和dY的过程中,但我绝对不确定误差在哪里 我已经成功地将sdCircle和sdBox翻译成JavaScript float sdCircle( vec2 p, float r ) { retu

我想将这个非常好的页面中的一些2D SDF函数转换为JavaScript:

我已经可以翻译函数sdCircle和sdBox了。我想翻译所有函数并直接在JavaScript中使用它们。目前我正在研究sdTriangle函数。我在这里再也走不动了。sdTriangle总是返回NaN。我猜问题发生在计算dX和dY的过程中,但我绝对不确定误差在哪里

我已经成功地将sdCircle和sdBox翻译成JavaScript

float sdCircle( vec2 p, float r )
{
  return length(p) - r;
}
变成:

function signedDistanceToCircle( p, center, radius ) {

  const dx = p.x - center.x;
  const dy = p.y - center.y;

  return Math.sqrt( dx * dx + dy * dy ) - radius;

}
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;

}

变成:

function signedDistanceToCircle( p, center, radius ) {

  const dx = p.x - center.x;
  const dy = p.y - center.y;

  return Math.sqrt( dx * dx + dy * dy ) - radius;

}
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;

}
你可以在这里看到整个过程:

现在是关于sdTriangle函数的:

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);
}
以下是我的尝试:

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 );

}

function clamp( val, min, max ) {

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

}

function dot( v0, v1 ) {

  return v0 * v1 + v0 * v1;

}
目标是计算从点p到具有点p0、p1和p2的三角形的距离,函数标记为DistanceToTriangle

如前所述,该函数始终返回NaN或错误值。 有人看到错误并能帮助我吗


谢谢

NaN来自最终的
Math.sqrt(dX)
其中
dX
为负,计算正确的点积应该可以减轻这一点:
函数点(a,b){返回a.x*b.x+a.y*b.y;}
NaN来自最终的
Math.sqrt(dX)
其中
dX
为负,计算正确的点积应该可以缓解这一问题:
函数点(a,b){return a.x*b.x+a.y*b.y;}

没有检查整个代码,但是
函数看起来非常可疑。你不能仅仅通过传递向量的一个分量来计算点积。嗨,谢谢你的回答。很有可能!你认为dot函数应该是什么样子的呢?我还没有看完全部代码,但是
dot
函数看起来非常可疑。你不能仅仅通过传递向量的一个分量来计算点积。嗨,谢谢你的回答。很有可能!你认为点函数正确的样子是什么?嗨,谢谢你的回答。我试图相应地调整点函数。不幸的是,它不起作用。嗨,谢谢你的回答。我试图相应地调整点函数。不幸的是,它没有起作用。