如何隐藏3D绘图中不可见的元素?

2023-12-03

我正在尝试绘制显示波纹的 3D 图像:

function myFunc(x, y) {
  let zRipple =
    Math.pow(2, -0.005 * (Math.abs(x) + Math.abs(y))) *
    Math.cos(((x * x + y * y) * 2 * pi) / 180 / width) *
    height;

  return zRipple;
}

这里的宽度和高度是定义绘图区域的常量,在我的测试中等于 200。

我的方法基于我从 30 年前读过的一篇文章中回忆起的内容,现在正在努力回忆。

这个想法是:

  • 将整个画板分割成10个像素的网格

  • 对于网格的每个“单元格”,沿 Y 轴和 X 轴画一条线到最近的单元格(step=10,ds=0.0

    for (let x3 = width; x3 >= - width; x3 -= step) {
      for (let y3 = -height; y3 <= height; y3 += step) {
        for (let s = 0; s < step; s += ds) {
          let x = x3 + s;
            if (x < width) {
              let z3 = myFunc(x, y3);
              drawPixel3d(x, y3, z3);
            }
          }
    
          for (let s = 0; s < step; s += ds) {
            let y = y3 + s;
            if (y < height) {
              let z3 = myFunc(x3, y);
              drawPixel3d(x3, y, z3);
            }
          }
        }
      }
    }
    

以下是将 3d 坐标转换为 2d 坐标的方法:

function drawPixel3d(x3, y3, z3) {
  let x2 = (x3 + y3) * Math.sin((60 * pi) / 180);
  let y2 = z3 - ((x3 - y3) * Math.sin((30 * pi) / 180)) / 4;
  drawPixel(x2, y2);
}

正如您从下图中看到的,我得到了一个不错的图形,但有一个问题:我绘制了所有点,而不仅仅是那些点VISIBLE.

3d Ripple

问题:如何检查是否需要显示某个像素?

根据我在那篇文章中的记忆,我们应该遵循以下方法:

  • 从场景的前部开始绘制(我相信我是这么做的,如果点带有坐标(宽度,-高度),则最接近观察者或屏幕)
  • 对于每个像素列 - 记住“Z”坐标,并且仅在 Z 坐标大于最后记录的像素时才绘制新像素

为了实现这一点,我修改了“drawPixel3d”方法:

function drawPixel3d(x3, y3, z3) {
  let x2 = (x3 + y3) * Math.sin((60 * pi) / 180);
  let y2 = z3 - ((x3 - y3) * Math.sin((30 * pi) / 180)) / 4;

  let n = Math.round(x2);
  let visible = false;
  if (zs[n] === undefined) {
    zs[n] = z3;
    visible = true;
  } else {
    if (z3 > zs[n]) {
      visible = z3 > zs[n];
      zs[n] = z3;
    }
  }

  if (visible) drawPixel(x2, y2);
}

但结果却出乎意料:

enter image description here

我做错了什么?或者另一个问题:如何绘制简单的 3D 图形?

Thanks!

附:程序的最后一段(说明实际绘图过程中 Y 坐标的反转):

function drawPixel(x: number, y: number) {
  ctx.fillRect(cX + x, cY - y, 1, 1); // TS-way to draw pixel on canvas is to draw a rectangle
}   // cX and cY are coordinates of the center of the drawing canvas

附言我对算法解决方案有一个想法,因此添加了一个“算法”标签:也许这个社区的人可以提供帮助?


您的表面是凹的,这意味着您无法使用基于面法线和相机视图方向之间的点积的简单方法。

为此,您有 3 个明显的选择。

  1. 使用光线追踪

    当你得到表面的解析方程时,这可能是更好的方法

  2. 使用深度缓冲来掩盖不可见的东西

    当渲染线框时,您需要分两遍完成此操作:

    1. 渲染不可见的填充表面(仅填充深度缓冲区而不是屏幕)
    2. 渲染线框

    您的深度缓冲区条件还必须包含相等的值,因此z<=depth[y][x] or z>=depth[y][x]

    但是,您需要使用面部渲染(三角形或四边形...),我认为这是软件渲染,因此如果您不熟悉此类内容,请参阅:

    • 如何光栅化旋转矩形(通过 setpixel 在 2d 中)
    • 填充三角形的算法
  3. 通过利用拓扑来使用深度排序

    如果您没有视图变换,那么您的x,y,z坐标直接对应于相机空间坐标,然后您可以在其中渲染网格从后到前只需通过对 for 循环和迭代方向进行排序(常见于等距意见)。这不需要深度缓冲,但是您需要渲染填充QUADS 以获得正确的输出(边框设置为绘图颜色,内部填充背景颜色)。

我确实去了#2方法。当我将最后一个链接移植到 3D 中时,我得到了这个(C++ 代码):

//---------------------------------------------------------------------------
const int col_transparent=-1;   // transparent color
class gfx_main
    {
public:
    Graphics::TBitmap *bmp; // VCL bitmap for win32 rendering
    int **scr,**zed,xs,ys;  // screen,depth buffers and resolution
    struct pbuf             // convex polygon rasterization line buffer
        {
        int x,z;            // values to interpolate during rendering
        pbuf()  {}
        pbuf(pbuf& a)   { *this=a; }
        ~pbuf() {}
        pbuf* operator = (const pbuf *a) { *this=*a; return this; }
        //pbuf* operator = (const pbuf &a) { ...copy... return this; }
        } *pl,*pr;          // left,right buffers
    gfx_main();
    gfx_main(gfx_main& a)   { *this=a; }
    ~gfx_main();
    gfx_main* operator = (const gfx_main *a) { *this=*a; return this; }
    //gfx_main* operator = (const gfx_main &a) { ...copy... return this; }
    void resize(int _xs=-1,int _ys=-1);
    void clear(int z,int col);              // clear buffers
    void pixel(int x,int y,int z,int col);  // render 3D point
    void line(int x0,int y0,int z0,int x1,int y1,int z1,int col); // render 3D line
    void triangle(int x0,int y0,int z0,int x1,int y1,int z1,int x2,int y2,int z2,int col); // render 3D triangle
    void _triangle_line(int x0,int y0,int z0,int x1,int y1,int z1); // this is just subroutine
    };
//---------------------------------------------------------------------------
gfx_main::gfx_main()
    {
    bmp=new Graphics::TBitmap;
    scr=NULL;
    zed=NULL;
    pl =NULL;
    pr =NULL;
    xs=0; ys=0;
    resize(1,1);
    }
//---------------------------------------------------------------------------
gfx_main::~gfx_main()
    {
    if (bmp) delete bmp;
    if (scr) delete[] scr;
    if (zed)
        {
        if (zed[0]) delete[] zed[0];
        delete[] zed;
        }
    if (pl) delete[] pl;
    if (pr) delete[] pr;
    }
//---------------------------------------------------------------------------
void gfx_main::resize(int _xs,int _ys)
    {
    // release buffers
    if (scr) delete[] scr;
    if (zed)
        {
        if (zed[0]) delete[] zed[0];
        delete[] zed;
        }
    if (pl) delete[] pl;
    if (pr) delete[] pr;
    // set new resolution and pixelformat
    if ((_xs>0)&&(_ys>0)) bmp->SetSize(_xs,_ys);
    xs=bmp->Width;
    ys=bmp->Height;
    bmp->HandleType=bmDIB;
    bmp->PixelFormat=pf32bit;
    // allocate buffers
    scr=new int*[ys];
    zed=new int*[ys];
    zed[0]=new int[xs*ys];              // allocate depth buffer as single block
    for (int y=0;y<ys;y++)
        {
        scr[y]=(int*)bmp->ScanLine[y];  // screen buffer point directly to VCL bitmap (back buffer)
        zed[y]=zed[0]+(y*xs);           // just set pointers for each depth line instead of allocating it
        }
    pl=new pbuf[ys];
    pr=new pbuf[ys];
    }
//---------------------------------------------------------------------------
int rgb2bgr(int col)                    // just support function reversing RGB order as VCL/GDI and its direct pixel access are not the same pixelformat
    {
    union
        {
        BYTE db[4];
        int  dd;
        } c;
    BYTE q;
    c.dd=col;
    q=c.db[0]; c.db[0]=c.db[2]; c.db[2]=q;
    return c.dd;
    }
//---------------------------------------------------------------------------
void gfx_main::clear(int z,int col)
    {
    // clear buffers
    int x,y;
    col=rgb2bgr(col);
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
        {
        scr[y][x]= 0x00000000; // black
        zed[y][x]=-0x7FFFFFFF; // as far as posible
        }
    }
//---------------------------------------------------------------------------
void gfx_main::pixel(int x,int y,int z,int col)
    {
    col=rgb2bgr(col);
    if ((x>=0)&&(x<xs)&&(y>=0)&&(y<ys))         // inside screen
     if (zed[y][x]<=z)                          // not after something already rendered (GL_LEQUAL)
        {
                                  zed[y][x]=z;  // update depth
        if (col!=col_transparent) scr[y][x]=col;// update color
        }
    }
//---------------------------------------------------------------------------
void gfx_main::line(int x0,int y0,int z0,int x1,int y1,int z1,int col)
    {
    int i,n,x,y,z,kx,ky,kz,dx,dy,dz,cx,cy,cz;
    // DDA variables (d)abs delta,(k)step direction
    kx=0; dx=x1-x0; if (dx>0) kx=+1;  if (dx<0) { kx=-1; dx=-dx; }
    ky=0; dy=y1-y0; if (dy>0) ky=+1;  if (dy<0) { ky=-1; dy=-dy; }
    kz=0; dz=z1-z0; if (dz>0) kz=+1;  if (dz<0) { kz=-1; dz=-dz; }
    n=dx; if (n<dy) n=dy; if (n<dz) n=dz; if (!n) n=1;
    // integer DDA
    for (x=x0,y=y0,z=z0,cx=cy=cz=n,i=0;i<n;i++)
        {
        pixel(x,y,z,col);
        cx-=dx; if (cx<=0){ cx+=n; x+=kx; }
        cy-=dy; if (cy<=0){ cy+=n; y+=ky; }
        cz-=dz; if (cz<=0){ cz+=n; z+=kz; }
        }
    }
//---------------------------------------------------------------------------
void gfx_main::triangle(int x0,int y0,int z0,int x1,int y1,int z1,int x2,int y2,int z2,int col)
    {
    int x,xx0,xx1,y,yy0,yy1,z,zz0,zz1,dz,dx,kz,cz;
    // boundary line coordinates to buffers
    _triangle_line(x0,y0,z0,x1,y1,z1);
    _triangle_line(x1,y1,z1,x2,y2,z2);
    _triangle_line(x2,y2,z2,x0,y0,z0);
    // y range
    yy0=y0; if (yy0>y1) yy0=y1; if (yy0>y2) yy0=y2;
    yy1=y0; if (yy1<y1) yy1=y1; if (yy1<y2) yy1=y2;
    // fill with horizontal lines
    for (y=yy0;y<=yy1;y++)
     if ((y>=0)&&(y<ys))
        {
        if (pl[y].x<pr[y].x){ xx0=pl[y].x; zz0=pl[y].z; xx1=pr[y].x; zz1=pr[y].z; }
        else                { xx1=pl[y].x; zz1=pl[y].z; xx0=pr[y].x; zz0=pr[y].z; }
              dx=xx1-xx0;
        kz=0; dz=zz1-zz0; if (dz>0) kz=+1;  if (dz<0) { kz=-1; dz=-dz; }
        for (cz=dx,x=xx0,z=zz0;x<=xx1;x++)
            {
            pixel(x,y,z,col);
            cz-=dz; if (cz<=0){ cz+=dx; z+=kz; }
            }
        }
    }
//---------------------------------------------------------------------------
void gfx_main::_triangle_line(int x0,int y0,int z0,int x1,int y1,int z1)
    {
    pbuf *pp;
    int i,n,x,y,z,kx,ky,kz,dx,dy,dz,cx,cy,cz;
    // DDA variables (d)abs delta,(k)step direction
    kx=0; dx=x1-x0; if (dx>0) kx=+1;  if (dx<0) { kx=-1; dx=-dx; }
    ky=0; dy=y1-y0; if (dy>0) ky=+1;  if (dy<0) { ky=-1; dy=-dy; }
    kz=0; dz=z1-z0; if (dz>0) kz=+1;  if (dz<0) { kz=-1; dz=-dz; }
    n=dx; if (n<dy) n=dy; if (n<dz) n=dz; if (!n) n=1;
    // target buffer according to ky direction
    if (ky>0) pp=pl; else pp=pr;
    // integer DDA line start point
    x=x0; y=y0;
    // fix endpoints just to be sure (wrong division constants by +/-1 can cause that last point is missing)
    if ((y0>=0)&&(y0<ys)){ pp[y0].x=x0; pp[y0].z=z0; }
    if ((y1>=0)&&(y1<ys)){ pp[y1].x=x1; pp[y1].z=z1; }
    // integer DDA (into pbuf)
    for (x=x0,y=y0,z=z0,cx=cy=cz=n,i=0;i<n;i++)
        {
        if ((y>=0)&&(y<ys))
            {
            pp[y].x=x;
            pp[y].z=z;
            }
        cx-=dx; if (cx<=0){ cx+=n; x+=kx; }
        cy-=dy; if (cy<=0){ cy+=n; y+=ky; }
        cz-=dz; if (cz<=0){ cz+=n; z+=kz; }
        }
    }
//---------------------------------------------------------------------------

只需忽略/移植 VCL 内容即可。我刚刚添加了z坐标插值和渲染以及深度缓冲区。渲染代码如下所示:

//---------------------------------------------------------------------------
gfx_main gfx;
//---------------------------------------------------------------------------
float myFunc(float x,float y)
    {
    float z;
    x-=gfx.xs/2;
    y-=gfx.ys/2;
    z=sqrt(((x*x)+(y*y))/((gfx.xs*gfx.xs)+(gfx.ys*gfx.ys)));    // normalized distance from center
    z=((0.25*cos(z*8.0*M_PI)*(1.0-z))+0.5)*gfx.ys;
    return z;
    }
//---------------------------------------------------------------------------
void view3d(int &x,int &y,int &z)   // 3D -> 2D view (projection)
    {
    int zz=z;
    z=y;
    x=x +(y/2)-(gfx.xs>>2);
    y=zz+(y/2)-(gfx.ys>>2);
    }
//---------------------------------------------------------------------------
void draw()
    {
    int i,x,y,z,ds,x0,y0,z0,x1,y1,z1,x2,y2,z2,x3,y3,z3,col;

    gfx.clear(-0x7FFFFFFF,0x00000000);

    // render
    ds=gfx.xs/50;
    for (i=0;i<2;i++)   // 2 passes
     for (y=ds;y<gfx.ys;y+=ds)
      for (x=ds;x<gfx.xs;x+=ds)
        {
        // 4 vertexes of a quad face
        x0=x-ds; y0=y-ds; z0=myFunc(x0,y0);
        x1=x;    y1=y0;   z1=myFunc(x1,y1);
        x2=x;    y2=y;    z2=myFunc(x2,y2);
        x3=x0;   y3=y;    z3=myFunc(x3,y3);
        // camera transform
        view3d(x0,y0,z0);
        view3d(x1,y1,z1);
        view3d(x2,y2,z2);
        view3d(x3,y3,z3);
        if (i==0) // first pass
            {
            // render (just to depth)
            col=col_transparent;
            gfx.triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,col);
            gfx.triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,col);
            }
        if (i==1) // second pass
            {
            // render wireframe
            col=0x00FF0000;
            gfx.line(x0,y0,z0,x1,y1,z1,col);
            gfx.line(x1,y1,z1,x2,y2,z2,col);
            gfx.line(x2,y2,z2,x3,y3,z3,col);
            gfx.line(x3,y3,z3,x0,y0,z0,col);
            }
        }
// here gfx.scr holds your rendered image
//---------------------------------------------------------------------------

别忘了打电话gfx.resize(xs,ys)渲染前视图的分辨率。正如你所看到的,我在这里使用了不同的函数(无关紧要),输出:

preview

这里同样没有深度条件pixel(x,y,z,col)

no depth test

The pbuf结构保存将在水平线的最后渲染插值中插值的所有内容。因此,如果你想要 gourard、纹理或其他任何东西,你只需将变量添加到这个结构中,并将插值添加到代码中(模仿pbuf[].z插值代码)

然而这种方法有一个缺点。您当前的方法是逐个像素地对一个轴进行插值,另一个轴则按网格大小步进。这个是按网格大小步进两个轴。因此,如果您想要具有相同的行为,您可能会执行第一遍1 x 1四边形而不是ds x ds然后像现在一样做线条。如果您视图中的 1 对应于像素,那么您可以单独对像素执行此操作,而无需进行面部渲染,但是您可能会面临输出中出现漏洞的风险。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何隐藏3D绘图中不可见的元素? 的相关文章

  • 检索受“rowspan”影响的行的列索引的最有效方法是什么?

    考虑下表 table thead tr th th th A th th B th th C th tr thead tbody tr th 1 th td Apples td td Oranges td td Pears td tr tb
  • 删除队列中的最后一个元素

    我需要删除队列的最后一个元素 我唯一可以使用的操作是 Peek 获取第一个元素而不删除它 Enqueue element 向队列末尾插入一个元素 Dequeue 删除第一个元素 IsEmpty true 或 false 队列是否为空 而且我
  • 寻找距离原点最近的 100 颗恒星的算法

    首先让我提出正确的问题 问 有一个文件包含超过一百万个点 x y 每个点代表一颗星星 a b 处有一颗行星地球 现在 任务是构建一种算法 返回距离地球最近的 100 颗恒星 您的算法的时间和空间复杂度是多少 这个问题在各种采访中被问过很多次
  • 我需要一个支持高效随机访问和 O(k) 插入和删除的容器

    我再次尝试问同样的问题question https stackoverflow com questions 3808708 delete parts of a dynamic array and grow other 但我最终提出了一个不同
  • 点集子集的最小周长凸包

    给定平面上的 n 个点 没有 3 个共线 给定数字 k 找到 k 个点的子集 使得 k 个点的凸包在 k 个点的子集的任何凸包中具有最小周长 我可以想到一个简单的方法 运行时间为 O n k k log k 找到大小为 k 的每个子集的凸包
  • 有人可以解释以下异或属性

    我的一个论坛提到给定的数组n数字 arr 0 n 1 以下条件成立 is the xor运算符 f l r f 0 r f 0 l 1 where f l r arr l arr l 1 arr r 我检查了上面的数组数量和不同的值l an
  • 将字符串中的“奇怪”字符转换为罗马字符

    我需要能够将用户输入仅转换为 a z 罗马字符 不区分大小写 所以 我感兴趣的角色只有26个 然而 用户可以输入他们想要的任何 形式 的字符 西班牙语 n 法语 e 和德语 u 都可以包含用户输入中的重音符号 这些重音符号会被程序删除 我已
  • 如何仅使用单个数组在 JavaScript 中模拟调用堆栈

    我正在看维基百科页面 https en wikipedia org wiki Call stack在调用堆栈上 并尝试理解这个图像 据我所知 哈哈 const memory memory 0 3 top of stack pointer m
  • 分而治之策略来确定列表中是否有超过 1/3 的相同元素

    我正在使用分治算法来确定列表中是否有超过 1 3 的元素相同 例如 1 2 3 4 不 所有元素都是唯一的 1 1 2 4 5 是的 其中 2 个是相同的 没有排序 是否有分而治之的策略 我陷入了如何划分的困境 def is valid i
  • 用 C++ 生成 AST

    我正在用 C 制作一个解释器 到目前为止我已经有了词法分析器来生成标记 问题是我不确定如何生成 行走 解析树 我正在考虑使用数组数组来制作解析树 但我不确定如何以正确的顺序将标记实际插入到解析树中 我不确定是自上而下 左右还是自下而上 左右
  • 使用多级解决方案计算二维网格中的最近邻

    我有一个问题 在 x y 大小的网格中 我提供了一个点 并且我需要找到最近的邻居 在实践中 我试图在 pygame 中找到距离光标最近的点 该点跨越颜色距离阈值 计算如下 sqrt rgb1 0 rgb2 0 2 rgb1 1 rgb2 1
  • C# 中的 strstr() 等效项

    我有两个byte 我想找到第二个的第一次出现byte 在第一个byte 或其中的一个范围 我不想使用字符串来提高效率 翻译第一个byte to a string会效率低下 基本上我相信就是这样strstr 在 C 中做 最好的方法是什么 这
  • 子序列和

    给定一个整数数组 例如 1 2 3 1 查找是否存在总和为0并返回它 例如 1 2 3 or 2 3 1 检查每个子序列是O n 2 这效率太低了 有改进的想法吗 创建一个新数组 其中每个元素等于前一个元素加上该元素的总和 Input 1
  • CSS3DObject 始终位于 WebGL Mesh 前面

    我正在混合CSS3D Renderer with WebGL Renderer to add HTML3D 空间中的元素WebGL场景 这CSS3DObject在前面WebGL网格即使WebGL Renderer具有较高的 z index
  • 归并排序中递归树的高度log(n)+1是怎么来的

    我按照 stackoveflow 的建议阅读了一些问题和答案 我正在遵循 cormen 的 算法简介 一书进行自学 那本书里已经解释得很清楚了 但唯一没有解释的是如何在合并排序分析中计算树的高度 如果在后面的章节中对此进行解释的话 我仍然在
  • Florian 的 Grisu2 算法如何工作?

    我遇到了一个关于将 double 转换为 ascii 的问题 经过搜索 我得到了 Florian 的论文 使用整数快速准确地打印浮点数 http www cs tufts edu nr cs257 archive florian loits
  • 举例解释bpe(字节对编码)?

    有人可以帮忙解释一下背后的基本概念吗BPE模型 除了这张纸 https arxiv org abs 1508 07909 目前还没有那么多解释 到目前为止我所知道的是 它通过将罕见和未知的单词编码为子词单元序列来实现开放词汇表上的 NMT
  • Java递归方法求阶乘返回负输出[重复]

    这个问题在这里已经有答案了 我知道这是溢出 但问题是 20 是相对较小的数字 这不应该发生 对吧 有没有更好的方法来查找大数 例如 1000 的阶乘 而不会得到这种奇怪的结果 public class RecursiveFunctionsE
  • Matlab:3D 堆积条形图

    我正在尝试创建一个 3D 堆积条形图 如这个问题所示 Matlab 中的 3D 堆叠条形图 https stackoverflow com questions 13156133 3d stacked bars in matlab 5D 然而
  • 二维滑动窗口最小值/最大值

    假设我们得到一个大小为 NxN 的像素整数矩阵和一个整数 k 窗口大小 我们需要使用滑动窗口找到矩阵中的所有局部最大值 或最小值 这意味着 如果某个像素与其周围窗口中的所有像素相比具有最小 最大 值 则应将其标记为最小 最大 有一种著名的滑

随机推荐

  • 如何从运行 iOS 9 的用户获取崩溃日志

    虽然我们以前能够在以下情况下获取崩溃日志用户与 iTunes Connect 同步 at Library Logs CrashReporter MobileDevice 现在大多数用户不这样做 因此 iOS9上获取崩溃日志的新流程是此处概述
  • Xcode 4.4.1 在 OSX Mavericks 下无法正常工作

    例子 iOS 3 1 3 的组织者显示 摘要丢失 键 它可能会因下一个崩溃数据而崩溃 未捕获异常 NSInternalInconsistencyException 未找到所需密钥 locatorclass 的扩展 Xcode Device
  • Cygwin 不支持 glibc

    Cygwin 常见问题解答包含以下 glibc 在哪里 的信息 Cygwin 不提供 glibc 它使用 newlib 来代替 它提供了很多 但不是全部 相同的功能 将 glibc 移植到 Cygwin 会很困难 我很惊讶并检查了发布包 因
  • RenderTranform 不进行渲染变换

    所以我有一个画布和一个椭圆 并调用一个方法来像这样移动椭圆 public void moveElipse1ToCoordinate Point point Action action gt TranslateTransform moveTo
  • 将 CSS 中的第一个 Div 移动到第二个 Div 下方

    我的 html 代码如下所示 A 包装div 百分比宽度 向左浮动 包含 一个包含文本和链接的 div 一个包含图像的 Div 问题 我想要保持上面的编码顺序 但为了用户体验 我想使用 CSS 反转 div 顺序以获得如下内容 注意 包装器
  • 100%安全的照片上传脚本

    问题很简单 如何用php制作100 安全的照片上传脚本 是否有任何教程可以显示所有可能的安全差距 不要让我看这个问题 因为他们只谈论尺寸 但我想确定的是 没有人可以上传 shell 和其他东西 因为这是一个大网站 需要100 安全的照片上传
  • Google 登录 JavaScript 客户端无法在 PWA 应用上运行

    从昨天开始 当我使用gapi auth2在Android上安装的PWA应用程序上进行Google登录时 该应用程序打开浏览器窗口来选择用户 但它仍然是空白的 Android 上 Chrome 浏览器上的同一页面照常打开用户选择 代码是相同的
  • 使用数组和字典在 Swift 中实现多重映射

    我正在尝试在 Swift 中实现一个基本的多重映射 这是一个相关的 非功能性的 片段 class Multimap
  • ggplot2 中的图例,删除级别

    My data df lt data frame sp c LETTERS 1 8 tr c NS LS NS LS LS HS HS HS bv c 14 5 11 5 6 21 5 4 2 4 8 av c 0 0 14 21 48 4
  • 具有自定义声明的 Firebase 存储规则

    我无法让 Firebase Storage 使用自定义规则和自定义声明 在我的 Python 管理面板中 我执行以下操作来创建用户并分配声明 client id Standard Auth import firebase admin fro
  • 如何在保留对 self 的引用的同时调用变异方法?

    我在借阅检查员那里遇到了麻烦 for item in self xxx iter self modify self but not xxx item 上面的代码有效before我将一些代码重构为modify self but not xxx
  • MySQL:按字母顺序获取多个列中的唯一值

    如果我的表看起来像这样 id colA colB colC 1 red blue yellow 2 orange red red 3 orange blue cyan 我运行什么 SELECT 查询才能返回结果 蓝色 青色 橙色 红色 黄色
  • 在 Node 4.3 中使用 Buffer.from 时出现 TypeError Base64 不是函数

    我正在使用标准 Amazon 系统映像 linux x64 在 Node 4 3 上本地调试 lambda 函数 当我运行该程序时 在将 Base64 字符串解码为 utf 8 的函数中出现错误 错误说 Unhandled rejectio
  • 预检响应具有无效的 HTTP 状态代码:401 角度

    使用 Angular 和 Spring Boot 我们尝试向我们的服务添加身份验证 但由于某种原因 我们无法 打开 并从我们知道有效的 url 中获取数据 角度 this getMismatches function return http
  • Mockito - @Spy 与 @Mock [重复]

    这个问题在这里已经有答案了 我知道间谍调用对象上的真实方法 而模拟调用双对象上的方法 除非有代码味道 否则还应避免间谍 但是 间谍是如何工作的以及我应该何时实际使用它们 它们与模拟有何不同 从技术上讲 模拟 和 间谍 都是一种特殊的 测试替
  • XMLSerialize 和 EXCLUDE 基类

    我希望能够通过 XML 序列化子类 但从序列化中排除其基类 这是我的类 为 DataObjects NET 配置 Serializable HierarchyRoot public class MyClass Entity Field Ke
  • Spring Security 注销会话未失效

    我几乎尝试了在 StackOverflow 和其他地方可以找到的所有方法来使其工作 但仍然不起作用 我正在使用 Spring Framework 4 1 6 RELEASE Spring Security 4 0 0 RELEASE 我配置
  • 连接xsl中的两个字段

    我有一些 xml 字段 我需要将所有字段连接到一个字段中
  • 如何以编程方式告诉 Windows 任务栏打开(或关闭)给定的工具栏?

    我写了一个toolbar在任务栏上运行 不幸的是 安装后 用户必须手动启用它 有没有办法告诉资源管理器打开 或关闭 给定的工具栏 我希望安装程序 NSIS 在安装完成后打开工具栏 我意识到需要一个插件 我还想知道是否可以自动为所有用户启用工
  • 如何隐藏3D绘图中不可见的元素?

    我正在尝试绘制显示波纹的 3D 图像 function myFunc x y let zRipple Math pow 2 0 005 Math abs x Math abs y Math cos x x y y 2 pi 180 widt