如何在屏幕或窗口边界内的随机位置绘制点

时间:2018-10-11 19:27:52

标签: c++ winapi opengl visual-c++

我在我的Visual C ++应用程序中使用OpenGL库,我想在其中绘制100个随机位置的点,我想检查这些点是否是随机坐标或生成的随机位置在屏幕或窗口边界内。我很累使用(x,y,z)顶点选项,并使点沿着一条线垂直延伸。如果我尝试仅生成(x,y)并绘制它们,那么我的确会散布更多的点,但在窗口尺寸内肯定不是全部100。

我的代码如下:

GLfloat dots_vert[99];
for (int i = 0; i < 99; i++){

if (i % 2 == 0)
    dots_vert[i] = 0.0f;

else
    dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*100.0f - (100.0f / 2);
}


glEnable(GL_POINT_SMOOTH);
glPointSize(3.0f);
glEnableClientState(GL_VERTEX_ARRAY);

GLuint vbo_ID;
glGenBuffers(1, &vbo_ID);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ID);
glBufferData(GL_ARRAY_BUFFER, sizeof(dots_vert), dots_vert, GL_DYNAMIC_DRAW);
while (!GetAsyncKeyState(VK_DOWN)){
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ID);
glVertexAttribPointer(
    0,                  
    3,                  
    GL_FLOAT,           
    GL_FALSE,           
    0,                  
    (void*)0            
    );
glDrawArrays(GL_POINTS, 0, 100);
SwapBuffers(g_pOpenGLWindow->hDC);

1 个答案:

答案 0 :(得分:3)

让我指导您解决那些可立即在该代码中看到的明显错误。

首先,一个明显的第一个错误:您声称正在绘制100个点,但是dots_vert数组只有99个元素长。在以下循环中重复进行此操作,在此循环中,您从098总共99次。

所以首先:

GLfloat dots_vert[100];
for (int i = 0; i < 100; ++i)
{
    [...]
}

那里还有一个巨大的错误,但我们会保留下来,让我们继续。

第二个错误是有关OpenGL API和计算机图形学的知识。首先,您的目标是将点传递给GPU,因此您需要使用glVertexAttribPointer函数,您已经了解了很多。您想做的绝对第一件事是look at the glVertexAttribPointer reference documentation,因此您对自己的需求有了一个了解。您需要一个index,一个size,一个type,一个normalized标志,一个stride和一个offset

让我们看看参考文档对size参数的看法:

  

大小

     

指定每个通用顶点属性的组件数。必须为1、2、3、4。此外,glVertexAttribPointer接受符号常量GL_BGRA。初始值为4。

这很明显对于确定要传递给GPU的数据类型至关重要。您将参数设置为3,这意味着您有一个x,一个y和一个z。但是之前的代码与此矛盾。对于初学者来说,您的dots_vert数组的长度为100个元素,并且您希望绘制100个点,因此每个点足以容纳100/100 = 1个组件,而不是{{1} }。但更糟糕的是,3循环的内部与此进一步矛盾,所以让我们回过头来检查我之前提到的错误。

错误三号:您的for循环由一个for语句组成,您可以在其中将if {} else {}数组的当前元素设置为dots_vert的值(如果索引)循环的偶数为(0.0f,否则为if (i % 2 == 0)-50.0f之间的随机值。假设每个点有50.0f个分量,这意味着您仅生成1坐标,因此您在一个单一维度上工作。

很显然,这不是您要执行的操作,这还因为一半的点将是x,因此它们将全部重叠。因此,我假设您正在尝试为0.0fx生成一个随机值,并将y设置为z,这更有意义。首先,每个点有0.0f个组件,因此需要一个包含3个元素的数组。首先,让我们修复之前的代码:

100*3 = 300

好多了。现在我们需要为每个点生成一个随机的GLfloat dots_vert[300]; for (int i = 0; i < 300; ++i) { [...] } x valye,并将y设置为z,因为我们不需要它。您想在一个循环中一次完成所有组件,所以您希望循环以0.0f而不是3步进,所以再次让我们修复前面的代码:

1

现在,我们可以在一个循环中一起生成GLfloat dots_vert[300]; for (int i = 0; i < 300; i += 3) { [...] } xy。这是理解计算机图形工作原理的关键部分,特别是在OpenGL API的上下文中。 OpenGL使用坐标系,其中原点位于屏幕中间,z轴水平移动(正x指向右侧),x轴垂直移动(正{ {1}}朝上),y轴直接穿过屏幕(正y指向屏幕之外,指向您)。现在,这是非常重要的部分:zzx被裁剪为特定的值范围。超出此范围的任何内容都将被忽略。对于所有坐标,范围从yz。上面的以下任何内容都没有绘制。

因此,如果您想让-1.0f点位于屏幕内,而忽略了本练习范围之外的投影,则希望在屏幕上生成1.0f100xy范围,而不是像从-1.0f1.0f那样。您可以将-50.0f保留为50.0f,在这种情况下并不重要。这就是为什么您的大多数点都落在屏幕之外的原因:从这个角度来看,从统计学上讲,大约98%的点将落在剪辑空间之外,并且将被忽略。

所以最终这就是您想要的:

z

最后一个提醒:您执行0.0f时,是在告诉GPU绘制100点。每个点都是由您在GLfloat dots_vert[300]; for (int i = 0; i < 300; i += 3) { dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is x dots_vert[i+1] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is y dots_vert[i+2] = 0.0f; // this is z } 函数的glDrawArrays(GL_POINTS, 0, 100);参数中指定的许多组件组成的。在这种情况下,您想绘制size个点,每个点都由glVertexAttribPointer个组件组成,因此GPU期望有100个浮点数组。数字。少做任何事情都可能导致分割错误,甚至更糟的是无法定义的行为(这意味着可能发生任何事情),因此请密切注意您的操作并确保您确切知道要传递给GPU的数据类型。因为您可能最终会胡说八道,并且会被困在找出问题出在哪里。在这种情况下,您基本上根本不需要检查任何代码,因此很容易修复,但是当您最终得到相当数量的代码(最终您将最终)时,这样的错误可能意味着数小时甚至数天的浪费试图找到错误。

作为奖励,请随时忽略这一点:从技术上讲,一个点由3组成。该组件称为100*3 = 300,它的使用不在本练习的讨论范围之内,因此不必担心,只要记住,除非进行投影,否则应始终将其设置为4。 / p>

从技术上讲,您也可以这样做:

w

然后将1.0f的{​​{1}}参数设置为GLfloat dots_vert[400]; for (int i = 0; i < 400; i += 4) { dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is x dots_vert[i+1] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is y dots_vert[i+2] = 0.0f; // this is z dots_vert[i+3] = 1.0f; // this is w } 而不是size,结果应该完全相同。