我试图在OpenGL中绘制这个模式:
为此,我创建了如下模式:
vector< vector<DataPoint> > datas;
float Intensitytemp=0;
float xPos=0, yPos=0, angleInRadians=0;
for (float theta = 0.0f; theta < 4096; theta += 1.f)
{
vector<DataPoint> temp;
angleInRadians = 2 * M_PI*theta / 4096;
for (float r = 0; r < 4096; r += 1.f)
{
xPos = cos(angleInRadians)*r / 4096;
yPos = sin(angleInRadians)*r / 4096;
Intensitytemp = ((float)((int)r % 256)) / 255;
DataPoint dt;
dt.x = xPos;
dt.y = yPos;
dt.Int = Intensitytemp;
temp.push_back(dt);
}
datas.push_back(temp);
}
我正在绘制模式:
glBegin(GL_POINTS);
for (int x = 0; x < 4096; x++)
for (int y = 0; y < 4096; y++)
{
xPos = datas[x][y].x;
yPos = datas[x][y].y;
Intensitytemp = datas[x][y].Int;
glColor4f(0.0f, Intensitytemp, 0.0f, 1.0f);
glVertex3f(xPos, yPos, 0.0f);
}
glEnd();
如果我在glBegin()-glEnd()
块中创建数据,它的工作速度会更快。但在这两种情况下,我相信更好的方法是在GLSL中做所有事情。我不了解现代OpenGL背后的逻辑。
我试图创建顶点缓冲区数组和颜色数组,但无法使其工作。问题不在于将阵列传输到图形卡。我在阵列中获得了堆栈溢出。 这是另一个主题的问题但是我想知道是否可以在完全GLSL代码(那些在.vert文件中)中完成此任务而无需将这些巨大的数组转移到图形卡。
答案 0 :(得分:2)
渲染四边形覆盖屏幕
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLint id;
glUseProgram(prog_id);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glColor3f(1,1,1);
glVertex2f(-1.0,-1.0);
glVertex2f(-1.0,+1.0);
glVertex2f(+1.0,+1.0);
glVertex2f(+1.0,-1.0);
glEnd();
glUseProgram(0);
glFlush();
SwapBuffers(hdc);
另请参阅See complete GL+GLSL+VAO/VBO C++ example了解如何让 GLSL 正常工作(即使是新的东西)
不要忘记将GL视图设置为方形区域!
将顶点坐标传递给片段
不需要矩阵...... pos
在<-1.0,1.0>
范围内,这对片段来说很合适。
// Vertex
varying vec2 pos;
void main()
{
pos=gl_Vertex.xy;
gl_Position=gl_Vertex;
}
片段计算距中间(0,0)
的距离并计算最终颜色
// Fragment
varying vec2 pos;
void main()
{
vec4 c=vec4(0.0,0.0,0.0,1.0);
float r=length(pos); // radius = distance to (0,0)
if (r<=1.0) // inside disc?
{
r=16.0*r; // your range 16=4096/256
c.g=r-floor(r); // use only the fractional part ... %256
}
gl_FragColor=c;
}
结果如下:
GLSL如何运作
您可以将片段着色器作为多边形填充的颜色计算引擎来处理。它的工作原理如下:
GL 原语由 GL 调用传递给顶点着色器,后者负责常量的转换和预计算。来自oldstyle GL 的每个glVertex
来电都会调用顶点着色器。
如果支持原语(在oldstyle GL 中由glBegin
设置)完全通过(如TRIANGLE,QUAD,...),则gfx卡会开始栅格化。这是通过 HW 内插器为每个要填充的“像素”调用片段着色器来完成的。由于“像素”包含更多数据,因此只是颜色,也可以放弃......它被称为片段。其唯一目的是计算它所代表的屏幕上像素的目标颜色。你不能只改变它的位置颜色。这是旧的 GL 和 GLSL 方法之间的最大区别。您无法仅更改对象的形状或位置(如何着色/着色),因此名称为着色器。因此,如果您需要生成特定的图案或效果,通常会渲染一些原始图像覆盖 GL 所涉及的区域,并通过主要片段着色器内的计算重新着色。
显然,顶点着色器在大多数情况下不会像片段着色器那样频繁调用,因此尽可能多地将计算移动到顶点着色器< / strong>提高绩效。
较新的 GLSL 版本也支持几何体和 tesselation着色器,但这本身就是一章,现在对您来说并不重要。 (你需要先习惯Vertex / Fragment)。
<强> [注释] 强>
这种简单着色器中的单if
不是一个大问题。主要的速度增加只是你传递单个四边形而不是4096x4096
点。 Shader代码直接由gfx HW 完全并行化。这就是为什么架构是如何...限制在着色器内部可以有效完成的一些功能,而不是标准的 CPU / MEM 架构。
<强> [EDIT1] 强>
你可以经常通过这样聪明的数学技巧来避免if
:
// Fragment
varying vec2 pos;
void main()
{
vec4 c=vec4(0.0,0.0,0.0,1.0);
float r=length(pos); // radius = distance to (0,0)
r*=max(1.0+floor(1.0-r),0.0); // if (r>1.0) r=0.0;
r*=16.0; // your range 16=4096/256
c.g=r-floor(r); // use only the fractional part ... %256
gl_FragColor=c;
}
答案 1 :(得分:0)
不,现在是着色器的工作方式。着色器重新定义了渲染管道的一部分。在管道固定的古老OpenGL中,GPU使用内置着色器例程来渲染您通过glBegin/glEnd
相关调用上传到它的基元。但是,对于以后的OpenGL版本,您可以编写自定义例程供GPU使用。 在这两种情况下,您需要发送着色器的数据才能使用。
首先,顶点着色器以顶点数据为基础。它采用顶点并对它们进行操作,一次应用各种变换(通过将顶点乘以模型 - 视图 - 投影矩阵)。对每个顶点完成此操作后,通过连接顶点所形成的区域将被分解为一个名为rasterization的过程中的坐标值(以及可以从顶点着色器传递到片段着色器的其他内容)。这些坐标(每个坐标代表屏幕上像素的位置)然后被发送到片段着色器,片段着色器对它们进行操作以设置颜色并应用任何光照计算。
现在,既然你想要绘制的是一个背后有一个公式的图案,你可以通过只发送4个顶点来为4096x4096平方着色,因为你希望产生相同的结果。
顶点着色器:
#version 150
in vec2 vertexPos;
out vec2 interpolatedVertexPos;
void main()
{
interpolatedVertexPos = vertexPos;
}
片段着色器:
#version 1.5
in vec2 interpolatedVertexPos;
out vec4 glFragColor;
void main()
{
const vec2 center = vec2(2048, 2048);
float distanceFromCenter = sqrt(pow((interpolatedVertexPos.x-center.x), 2) + pow((interpolatedVertexPos.y-center.y), 2));
if (distanceFromCenter > 2048){
discard;
}
float Intensitytemp = ((float)((int)distanceFromCenter % 256)) / 255;
glFragColor = vec4(0, Intensitytemp , 0, 1);
}
编辑:我想你也可以找到这个答案有用: OpenGL big projects, VAO-s and more