制作着色器将 vertexArray 作为 canvas 而不是 window
Making shader takes vertexArray as canvas instead of the window
目前正在开发一个基于 SFML 的开源 GUI 库,但在着色器方面遇到了一些困难。到目前为止,我已经设法毫无问题地渲染着色器,但不是将着色器应用于当前对象,而是将其应用于整个 window,但仅在对象范围内可见。
这是我的简单代码:
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
const char *glsl = R"(
#version 330 core
uniform vec2 u_resolution;
void main() {
vec2 pos = gl_FragCoord.xy / u_resolution;
float radius = 0.4;
float d = distance(pos, vec2(0.5));
gl_FragColor = d <= radius ? vec4(pos.y,pos.y/2.,pos.y, 1.0) : vec4(d*0.8, d*0.8, d*0.8, 1.0);
//gl_FragColor = vec4(0.0, 0.5, 1.0, 1.0);
}
)";
const char *pos = R"(
// some default shader I've found
// adding #version 330 core will complain for outdated gl_Position variable..
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_FrontColor = gl_Color;
}
)";
int main() {
sf::RenderWindow window(sf::VideoMode(800, 600), "GLSL", sf::Style::Default);
// create a quad
sf::VertexArray quad(sf::Quads, 4);
// define it as a rectangle, located at (10, 10) and with size 100x100
quad[0].position = sf::Vector2f(100, 100);
quad[1].position = sf::Vector2f(410, 100);
quad[2].position = sf::Vector2f(410, 410);
quad[3].position = sf::Vector2f(100, 410);
sf::Shader shader;
// the following line is the same as shader.loadFromMemory(pos, glsl);
shader.loadFromMemory(glsl, sf::Shader::Fragment);
shader.setUniform("u_resolution", sf::Vector2f(800, 600));
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color(244,244,244));
window.draw(quad, &shader);
window.display();
}
return 0;
}
暂时不确定要做什么,但我想 pos
着色器应该会影响渲染的完成方式。谢谢!
只需要做一些小改动。我不确定在任何更现代的着色器版本中完成它的最佳方法是什么,但是如果您省略任何版本标记(即使用遗留代码),它很快就会改变:
首先,您的各个顶点(或更具体的渲染片段)不知道它们相对于正在绘制的四边形的位置。幸运的是,您可以为此滥用纹理坐标。例如,将左上角定义为 (0, 0)
,将右下角定义为 (1, 1)
。这样,它们的值将根据片段所在的位置从 0 到 1 变化。这基本上就是您现有的着色器代码计算为 pos
.
所以让我们从添加纹理坐标开始:
quad[0].position = sf::Vector2f(100, 100);
quad[0].texCoords = sf::Vector2f(0, 0);
quad[1].position = sf::Vector2f(410, 100);
quad[1].texCoords = sf::Vector2f(1, 0);
quad[2].position = sf::Vector2f(410, 410);
quad[2].texCoords = sf::Vector2f(1, 1);
quad[3].position = sf::Vector2f(100, 410);
quad[3].texCoords = sf::Vector2f(0, 1);
现在我们所要做的就是将纹理坐标分配给pos
(或者最好删除pos completely
)。为了简单起见,我将直接进行作业:
vec2 pos = gl_TexCoord[0].xy;
但是,这会导致着色器编译器报错,因为 gl_TexCoord
已被删除。因此,为了进行测试,我只是删除了预编译器行,我猜结果看起来就像你想的那样:
目前正在开发一个基于 SFML 的开源 GUI 库,但在着色器方面遇到了一些困难。到目前为止,我已经设法毫无问题地渲染着色器,但不是将着色器应用于当前对象,而是将其应用于整个 window,但仅在对象范围内可见。
这是我的简单代码:
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
const char *glsl = R"(
#version 330 core
uniform vec2 u_resolution;
void main() {
vec2 pos = gl_FragCoord.xy / u_resolution;
float radius = 0.4;
float d = distance(pos, vec2(0.5));
gl_FragColor = d <= radius ? vec4(pos.y,pos.y/2.,pos.y, 1.0) : vec4(d*0.8, d*0.8, d*0.8, 1.0);
//gl_FragColor = vec4(0.0, 0.5, 1.0, 1.0);
}
)";
const char *pos = R"(
// some default shader I've found
// adding #version 330 core will complain for outdated gl_Position variable..
void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
gl_FrontColor = gl_Color;
}
)";
int main() {
sf::RenderWindow window(sf::VideoMode(800, 600), "GLSL", sf::Style::Default);
// create a quad
sf::VertexArray quad(sf::Quads, 4);
// define it as a rectangle, located at (10, 10) and with size 100x100
quad[0].position = sf::Vector2f(100, 100);
quad[1].position = sf::Vector2f(410, 100);
quad[2].position = sf::Vector2f(410, 410);
quad[3].position = sf::Vector2f(100, 410);
sf::Shader shader;
// the following line is the same as shader.loadFromMemory(pos, glsl);
shader.loadFromMemory(glsl, sf::Shader::Fragment);
shader.setUniform("u_resolution", sf::Vector2f(800, 600));
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
}
window.clear(sf::Color(244,244,244));
window.draw(quad, &shader);
window.display();
}
return 0;
}
暂时不确定要做什么,但我想 pos
着色器应该会影响渲染的完成方式。谢谢!
只需要做一些小改动。我不确定在任何更现代的着色器版本中完成它的最佳方法是什么,但是如果您省略任何版本标记(即使用遗留代码),它很快就会改变:
首先,您的各个顶点(或更具体的渲染片段)不知道它们相对于正在绘制的四边形的位置。幸运的是,您可以为此滥用纹理坐标。例如,将左上角定义为 (0, 0)
,将右下角定义为 (1, 1)
。这样,它们的值将根据片段所在的位置从 0 到 1 变化。这基本上就是您现有的着色器代码计算为 pos
.
所以让我们从添加纹理坐标开始:
quad[0].position = sf::Vector2f(100, 100);
quad[0].texCoords = sf::Vector2f(0, 0);
quad[1].position = sf::Vector2f(410, 100);
quad[1].texCoords = sf::Vector2f(1, 0);
quad[2].position = sf::Vector2f(410, 410);
quad[2].texCoords = sf::Vector2f(1, 1);
quad[3].position = sf::Vector2f(100, 410);
quad[3].texCoords = sf::Vector2f(0, 1);
现在我们所要做的就是将纹理坐标分配给pos
(或者最好删除pos completely
)。为了简单起见,我将直接进行作业:
vec2 pos = gl_TexCoord[0].xy;
但是,这会导致着色器编译器报错,因为 gl_TexCoord
已被删除。因此,为了进行测试,我只是删除了预编译器行,我猜结果看起来就像你想的那样: