Browse Source

Use vertex array and geometry shader to render planets

master
Bergmann89 3 years ago
parent
commit
c5e70fb728
10 changed files with 172 additions and 69 deletions
  1. +3
    -4
      space-crush-app/resources/shader/planet/frag.glsl
  2. +44
    -0
      space-crush-app/resources/shader/planet/geom.glsl
  3. +9
    -0
      space-crush-app/resources/shader/planet/shared.glsl
  4. +7
    -8
      space-crush-app/resources/shader/planet/vert.glsl
  5. +1
    -2
      space-crush-app/resources/shader/ship/frag.glsl
  6. +1
    -1
      space-crush-app/resources/shader/ship/geom.glsl
  7. +3
    -2
      space-crush-app/resources/shader/ship/shared.glsl
  8. +100
    -50
      space-crush-app/src/render/planets.rs
  9. +1
    -1
      space-crush-app/src/render/ships.rs
  10. +3
    -1
      space-crush-common/src/components/planet.rs

+ 3
- 4
space-crush-app/resources/shader/planet/frag.glsl View File

@@ -14,15 +14,14 @@ const GlowArgs GLOW_ARGS = {

in FragmentData fragmentData;

uniform vec4 uGlowColor;
uniform sampler2D uTexture;

out vec4 outColor;

void main() {
float alpha = glow(GLOW_ARGS, fragmentData.texCoords - vec2(0.5), uGlobal.time);
vec4 glow = vec4(uGlowColor.rgb, uGlowColor.a * alpha);
vec4 tex = texture(uTexture, fragmentData.texCoords);
float alpha = glow(GLOW_ARGS, fragmentData.texCoords, uGlobal.time);
vec4 glow = vec4(fragmentData.color.rgb, fragmentData.color.a * alpha);
vec4 tex = texture(uTexture, 0.5 * GLOW_SIZE * fragmentData.texCoords + vec2(0.5));

outColor = tex * tex.a + glow * (1.0 - tex.a);
}

+ 44
- 0
space-crush-app/resources/shader/planet/geom.glsl View File

@@ -0,0 +1,44 @@
#version 450 core

#pragma include ./shared.glsl
#pragma include ../misc/camera.glsl

in VertexData vertexData[];

layout (points) in;
layout (triangle_strip, max_vertices = 4) out;

out FragmentData fragmentData;

void main() {
VertexData d = vertexData[0];

vec2 pos = d.pos;
float size = d.size * GLOW_SIZE;

mat4 m = uCamera.projection * uCamera.view * mat4(
vec4( size, 0.0, 0.0, 0.0),
vec4( 0.0, size, 0.0, 0.0),
vec4( 0.0, 0.0, 0.0, 0.0),
vec4(pos.x, pos.y, 0.0, 1.0));

fragmentData.color = d.color;

gl_Position = m * vec4(-1.0, -1.0, 0.0, 1.0);
fragmentData.texCoords = vec2(-1.0, 1.0);
EmitVertex();

gl_Position = m * vec4(-1.0, 1.0, 0.0, 1.0);
fragmentData.texCoords = vec2(-1.0, -1.0);
EmitVertex();

gl_Position = m * vec4( 1.0, -1.0, 0.0, 1.0);
fragmentData.texCoords = vec2( 1.0, 1.0);
EmitVertex();

gl_Position = m * vec4( 1.0, 1.0, 0.0, 1.0);
fragmentData.texCoords = vec2( 1.0, -1.0);
EmitVertex();

EndPrimitive();
}

+ 9
- 0
space-crush-app/resources/shader/planet/shared.glsl View File

@@ -1,3 +1,12 @@
struct FragmentData {
vec2 texCoords;
vec4 color;
};

struct VertexData {
vec2 pos;
float size;
vec4 color;
};

const float GLOW_SIZE = 2.0; // relative to planet size

+ 7
- 8
space-crush-app/resources/shader/planet/vert.glsl View File

@@ -3,15 +3,14 @@
#pragma include ./shared.glsl
#pragma include ../misc/camera.glsl

const float GLOW_SIZE_FACTOR = 2.00;
layout (location = 0) in vec2 inPosition;
layout (location = 1) in float inSize;
layout (location = 2) in vec4 inColor;

in vec3 inPosition;

uniform mat4 uModel;

out FragmentData fragmentData;
out VertexData vertexData;

void main() {
fragmentData.texCoords = inPosition.xy * GLOW_SIZE_FACTOR + vec2(0.5);
gl_Position = uCamera.projection * uCamera.view * uModel * vec4(2.0 * inPosition * GLOW_SIZE_FACTOR, 1.0);
vertexData.pos = inPosition;
vertexData.size = inSize;
vertexData.color = inColor;
}

+ 1
- 2
space-crush-app/resources/shader/ship/frag.glsl View File

@@ -4,7 +4,6 @@
#pragma include ../misc/glow.glsl
#pragma include ../misc/global.glsl

const float GLOW_ALPHA = 0.20;
const GlowArgs GLOW_ARGS = {
/* step0 */ 0.100,
/* step1 */ 0.900,
@@ -23,7 +22,7 @@ out vec4 outColor;
void main() {
float alpha = glow(GLOW_ARGS, fragmentData.texCoords, uGlobal.time);
vec4 glow = vec4(fragmentData.color.rgb, fragmentData.color.a * alpha * GLOW_ALPHA);
vec4 tex = texture(uTexture[textureId], fragmentData.texCoords / SHIP_SIZE + vec2(0.5));
vec4 tex = texture(uTexture[textureId], 0.5 * GLOW_SIZE * fragmentData.texCoords + vec2(0.5));

outColor = tex * tex.a + glow * (1.0 - tex.a);
}

+ 1
- 1
space-crush-app/resources/shader/ship/geom.glsl View File

@@ -15,7 +15,7 @@ void main() {
VertexData d = vertexData[0];

vec2 pos = d.pos;
vec2 dir = d.dir * QUAD_SIZE;
vec2 dir = d.dir * SHIP_SIZE * GLOW_SIZE;

mat4 m = uCamera.projection * uCamera.view * mat4(
vec4(dir.y, -dir.x, 0.0, 0.0),


+ 3
- 2
space-crush-app/resources/shader/ship/shared.glsl View File

@@ -10,5 +10,6 @@ struct VertexData {
int texture;
};

const float QUAD_SIZE = 150.00; // absolute
const float SHIP_SIZE = 0.50; // relative to QUAD_SIZE
const float SHIP_SIZE = 25.0; // absolute ship size
const float GLOW_SIZE = 4.0; // relative to ship size
const float GLOW_ALPHA = 0.5;

+ 100
- 50
space-crush-app/src/render/planets.rs View File

@@ -1,15 +1,18 @@
use std::mem::size_of;

use glc::{
matrix::Matrix4f,
buffer::{Buffer, Usage},
misc::{BindGuard, Bindable},
shader::{Program, Type, Uniform},
texture::Texture,
vector::Vector4f,
vector::{Vector2f, Vector4f},
vertex_array::{DataType, VertexArray},
};
use space_crush_common::{
components::{Planet, Player, PlayerOwned, Position},
misc::LogResult,
misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut},
};
use specs::{prelude::*, ReadExpect, ReadStorage, System, World};
use specs::{prelude::*, ReadStorage, System, World};

use crate::{
constants::{
@@ -17,52 +20,77 @@ use crate::{
UNIFORM_BUFFER_INDEX_UNIFORM,
},
misc::WorldHelper,
resources::Geometry,
Error,
};

pub struct Planets {
program: Program,
texture: Texture,
location_model: gl::GLint,
location_glow_color: gl::GLint,
vertex_array: VertexArray,
reader_id: ReaderId<ComponentEvent<Planet>>,
planet_count: usize,
}

#[repr(C, packed)]
struct VertexData {
pos: Vector2f,
size: gl::GLfloat,
color: Vector4f,
}

impl Planets {
pub fn new(world: &World) -> Result<Self, Error> {
pub fn new(world: &mut World) -> Result<Self, Error> {
WriteStorage::<Planet>::setup(world);

let program = world.load_program(vec![
(Type::Vertex, "resources/shader/planet/vert.glsl"),
(Type::Geometry, "resources/shader/planet/geom.glsl"),
(Type::Fragment, "resources/shader/planet/frag.glsl"),
])?;

program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?;
program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?;

let location_model = program.uniform_location("uModel")?;
let location_glow_color = program.uniform_location("uGlowColor")?;

program.bind();
program.uniform("uTexture", Uniform::Texture(0))?;
program.unbind();

let texture = world.load_texture("resources/textures/planet01.png")?;

const STRIDE: gl::GLsizei = size_of::<VertexData>() as gl::GLsizei;

const OFFSET_POS: gl::GLsizei = 0;
const OFFSET_SIZ: gl::GLsizei = OFFSET_POS + size_of::<Vector2f>() as gl::GLsizei;
const OFFSET_CLR: gl::GLsizei = OFFSET_SIZ + size_of::<gl::GLfloat>() as gl::GLsizei;

let vertex_array = VertexArray::builder()
.bind_buffer(Buffer::new()?)
.vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE, OFFSET_POS)?
.vertex_attrib_pointer(1, 1, DataType::Float, false, STRIDE, OFFSET_SIZ)?
.vertex_attrib_pointer(2, 4, DataType::Float, false, STRIDE, OFFSET_CLR)?
.build()?;

let reader_id = world
.system_data::<WriteStorage<Planet>>()
.register_event_reader();
let planet_count = 0;

Ok(Self {
program,
texture,
location_model,
location_glow_color,
vertex_array,
reader_id,
planet_count,
})
}
}

#[derive(SystemData)]
pub struct PlanetsData<'a> {
geometry: ReadExpect<'a, Geometry>,
position: ReadStorage<'a, Position>,
planet: ReadStorage<'a, Planet>,
positions: ReadStorage<'a, Position>,
planets: ReadStorage<'a, Planet>,
players: ReadStorage<'a, Player>,
owned: ReadStorage<'a, PlayerOwned>,
player: ReadStorage<'a, Player>,
}

impl<'a> System<'a> for Planets {
@@ -70,46 +98,68 @@ impl<'a> System<'a> for Planets {

fn run(&mut self, data: Self::SystemData) {
let PlanetsData {
geometry,
position,
planet,
positions,
planets,
players,
owned,
player,
} = data;

gl::enable(gl::BLEND);
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
/* handle events */
let mut need_update = false;
let events = planets.channel().read(&mut self.reader_id);
for event in events {
match event {
ComponentEvent::Inserted(_, _) => {
need_update = true;

self.planet_count += 1;
}
ComponentEvent::Removed(_, _) => {
need_update = true;

self.planet_count -= 1;
}
ComponentEvent::Modified(_, _) => {
unreachable!("Updates of the planet component should not be tracked!")
}
}
}

/* update vertex array */
let buffer = &mut self.vertex_array.buffers_mut()[0];
if need_update {
buffer
.buffer_size(
Usage::StaticDraw,
self.planet_count * size_of::<VertexData>(),
)
.panic("Unable to change buffer size for planet data");

let data = (&positions, &planets, owned.maybe());
let mut buffer = buffer
.map_mut::<VertexData>(true)
.panic("Unable to map buffer for planet data");

for (i, (position, _, owned)) in data.join().enumerate() {
let mut d = &mut buffer[i];

d.pos = *position.pos();
d.size = position.shape().circle().unwrap_or(PLANET_SIZE);
d.color = match owned.and_then(|owned| players.get(owned.owner())) {
Some(pv) => *pv.color(),
None => PLAYER_COLOR_DEFAULT,
};
}
}

/* render planets */
let _guard = BindGuard::new(&self.program);
let _guard = BindGuard::new(&self.vertex_array);
let _guard = BindGuard::new(&self.texture);

for (p, _, owned) in (&position, &planet, owned.maybe()).join() {
let p_x = p.pos().x;
let p_y = p.pos().y;
let s = p.shape().circle().unwrap_or(PLANET_SIZE);

let c = match owned.and_then(|owned| player.get(owned.owner())) {
Some(pv) => &pv.color(),
None => &PLAYER_COLOR_DEFAULT,
};

let m = Matrix4f::new(
Vector4f::new(s, 0.0, 0.0, 0.0),
Vector4f::new(0.0, s, 0.0, 0.0),
Vector4f::new(0.0, 0.0, s, 0.0),
Vector4f::new(p_x, p_y, 0.0, 1.0),
);

self.program
.uniform(self.location_glow_color, Uniform::Vector4f(&c))
.error("Error while updating glow color");
self.program
.uniform(self.location_model, Uniform::Matrix4f(&m))
.error("Error while updating model matrix");

geometry.render_quad();
}

gl::enable(gl::BLEND);
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
gl::draw_arrays(gl::POINTS, 0, self.planet_count as _);
gl::disable(gl::BLEND);
}
}

+ 1
- 1
space-crush-app/src/render/ships.rs View File

@@ -167,7 +167,7 @@ impl<'a> System<'a> for Ships {
let _guard = BindGuard::new(&self.texture_fighter);

gl::enable(gl::BLEND);
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
gl::blend_func(gl::SRC_ALPHA, gl::ONE);
gl::draw_arrays(gl::POINTS, 0, self.ship_count as _);
gl::disable(gl::BLEND);
}


+ 3
- 1
space-crush-common/src/components/planet.rs View File

@@ -1,9 +1,11 @@
use serde::{Deserialize, Serialize};
use specs::{Component, NullStorage};

use crate::misc::FlaggedStorage;

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Planet {}

impl Component for Planet {
type Storage = NullStorage<Self>;
type Storage = FlaggedStorage<Self, NullStorage<Self>>;
}

Loading…
Cancel
Save