diff --git a/examples/shader/Shader.cpp b/examples/shader/Shader.cpp index 82ad61cf..8a81fde3 100644 --- a/examples/shader/Shader.cpp +++ b/examples/shader/Shader.cpp @@ -258,6 +258,85 @@ private: }; +//////////////////////////////////////////////////////////// +// "Geometry" geometry shader example +//////////////////////////////////////////////////////////// +class Geometry : public Effect +{ +public: + + Geometry() : + Effect("geometry shader billboards"), + m_pointCloud(sf::Points, 10000) + { + } + + bool onLoad() + { + // Check if geometry shaders are supported + if (!sf::Shader::isGeometryAvailable()) + return false; + + // Move the points in the point cloud to random positions + for (std::size_t i = 0; i < 10000; i++) + { + // Spread the coordinates from -480 to +480 + // So they'll always fill the viewport at 800x600 + m_pointCloud[i].position.x = rand() % 960 - 480.f; + m_pointCloud[i].position.y = rand() % 960 - 480.f; + } + + // Load the texture + if (!m_logoTexture.loadFromFile("resources/logo.png")) + return false; + + // Load the shader + if (!m_shader.loadFromFile("resources/billboard.vert", "resources/billboard.geom", "resources/billboard.frag")) + return false; + m_shader.setUniform("texture", sf::Shader::CurrentTexture); + + // Set the render resolution (used for proper scaling) + m_shader.setUniform("resolution", sf::Vector2f(800, 600)); + + return true; + } + + void onUpdate(float time, float x, float y) + { + // Reset our transformation matrix + m_transform = sf::Transform::Identity; + // Move to the center of the window + m_transform.translate(400, 300); + // Rotate everything based on cursor position + m_transform.rotate(x * 360.f); + + // Adjust billboard size to scale between 25 and 75 + float size = 25 + std::abs(y) * 50; + + // Update the shader parameter + m_shader.setUniform("size", sf::Vector2f(size, size)); + } + + void onDraw(sf::RenderTarget& target, sf::RenderStates states) const + { + // Prepare the render state + states.shader = &m_shader; + states.texture = &m_logoTexture; + states.transform = m_transform; + + // Draw the point cloud + target.draw(m_pointCloud, states); + } + +private: + + sf::Texture m_logoTexture; + sf::Transform m_transform; + sf::Shader m_shader; + sf::VertexArray m_pointCloud; +}; + + //////////////////////////////////////////////////////////// /// Entry point of application /// @@ -283,6 +362,7 @@ int main() effects.push_back(new WaveBlur); effects.push_back(new StormBlink); effects.push_back(new Edge); + effects.push_back(new Geometry); std::size_t current = 0; // Initialize them diff --git a/examples/shader/resources/billboard.frag b/examples/shader/resources/billboard.frag new file mode 100644 index 00000000..3057f64b --- /dev/null +++ b/examples/shader/resources/billboard.frag @@ -0,0 +1,11 @@ +#version 150 + +uniform sampler2D texture; + +in vec2 tex_coord; + +void main() +{ + // Read and apply a color from the texture + gl_FragColor = texture2D(texture, tex_coord); +} diff --git a/examples/shader/resources/billboard.geom b/examples/shader/resources/billboard.geom new file mode 100644 index 00000000..2f47a1fa --- /dev/null +++ b/examples/shader/resources/billboard.geom @@ -0,0 +1,56 @@ +#version 150 + +// The render target's resolution (used for scaling) +uniform vec2 resolution; + +// The billboards' size +uniform vec2 size; + +// Input is the passed point cloud +layout (points) in; + +// The output will consist of triangle strips with four vertices each +layout (triangle_strip, max_vertices = 4) out; + +// Output texture coordinates +out vec2 tex_coord; + +// Main entry point +void main() +{ + // Caculate the half width/height of the billboards + vec2 half_size = size / 2.f; + + // Scale the size based on resolution (1 would be full width/height) + half_size /= resolution; + + // Iterate over all vertices + for (int i = 0; i < gl_in.length(); i++) + { + // Retrieve the passed vertex position + vec2 pos = gl_in[i].gl_Position.xy; + + // Bottom left vertex + gl_Position = vec4(pos - half_size, 0.f, 1.f); + tex_coord = vec2(1.f, 1.f); + EmitVertex(); + + // Bottom right vertex + gl_Position = vec4(pos.x + half_size.x, pos.y - half_size.y, 0.f, 1.f); + tex_coord = vec2(0.f, 1.f); + EmitVertex(); + + // Top left vertex + gl_Position = vec4(pos.x - half_size.x, pos.y + half_size.y, 0.f, 1.f); + tex_coord = vec2(1.f, 0.f); + EmitVertex(); + + // Top right vertex + gl_Position = vec4(pos + half_size, 0.f, 1.f); + tex_coord = vec2(0.f, 0.f); + EmitVertex(); + + // And finalize the primitive + EndPrimitive(); + } +} diff --git a/examples/shader/resources/billboard.vert b/examples/shader/resources/billboard.vert new file mode 100644 index 00000000..3a899052 --- /dev/null +++ b/examples/shader/resources/billboard.vert @@ -0,0 +1,5 @@ +void main() +{ + // Transform the vertex position + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; +} diff --git a/examples/shader/resources/logo.png b/examples/shader/resources/logo.png new file mode 100644 index 00000000..29ba0102 Binary files /dev/null and b/examples/shader/resources/logo.png differ