Verified Commit 60aabbb0 authored by insert's avatar insert

First Commit.

parents
/target
Cargo.lock
[package]
name = "shader-generator"
version = "0.1.0"
authors = ["Paul Makles <[email protected]>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1.0.104", features = ["derive"] }
tera = "1.1.0"
use shader_generator::{ ShaderOptions, generate_vertex_shader, generate_fragment_shader };
fn main() {
println!("{}", generate_fragment_shader(ShaderOptions::new()));
}
use tera::Context;
use serde::Serialize;
#[macro_export]
macro_rules! include_render {
($data: expr, $ctx: expr) => {Tera::one_off(include_str!($data), &$ctx, false).unwrap()};
}
#[macro_export]
macro_rules! push_render {
($str: expr, $data: expr, $ctx: expr) => {$str.push_str(&include_render!($data, $ctx))};
}
#[derive(Serialize)]
pub enum RenderType {
Colour,
Texture,
}
#[derive(Serialize)]
pub struct LightingOptions {
pub specular: RenderType,
pub shadows: bool,
pub point_lights: usize,
}
#[derive(Serialize)]
pub struct ShaderOptions {
pub diffuse: RenderType,
pub lighting: Option<LightingOptions>,
}
impl ShaderOptions {
pub fn new() -> ShaderOptions {
ShaderOptions {
diffuse: RenderType::Colour,
lighting: Some(LightingOptions {
specular: RenderType::Colour,
shadows: true,
point_lights: 4,
}),
}
}
pub fn to_context(&self) -> Context {
Context::from_serialize(self).unwrap()
}
}
#version 330 core
in vec3 fPos;
in vec3 fNormal;
{% if diffuse == "Colour" %}
in vec4 fColor;
{% else %}
in vec2 fUV;
{% endif %}
struct Material {
{% if diffuse == "Colour" %} vec3 {% else %} sampler2D {% endif %} diffuse;
{% if lighting.specular == "Colour" %} vec3 {% else %} sampler2D {% endif %} specular;
float shininess;
};
uniform Material material;
{{ inject_header }}
out vec4 color;
void main() {
vec4 diffuse =
{% if diffuse == "Colour" %} fColor * vec4(material.diffuse, 1.0)
{% else %} texture(material.diffuse, fUV) {% endif %};
{% if lighting %}
vec4 specular =
{% if lighting.specular == "Colour" %} vec4(material.specular, 1.0)
{% else %} texture(material.specular, fUV) {% endif %};
{% endif %}
color =
{% if lighting %}
lighting(diffuse, specular)
{% else %}
diffuse
{% endif %}
;
}
float calc_spec(vec3 viewDir, vec3 lightDir, vec3 normal) {
float spec;
if (material.shininess > 0) {
{% if graphics.blinn %}
vec3 halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normal, halfwayDir), 0.0), material.shininess * 2.0);
{% else %}
vec3 reflectDir = reflect(-lightDir, normal);
spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
{% endif %}
} else {
spec = 0;
}
return spec;
}
vec4 directional_light(vec3 viewDir, vec4 mat_diffuse, vec4 mat_specular) {
vec4 ambient = vec4(directionalLight.ambient, 1.0) * mat_diffuse;
vec3 norm = normalize(fNormal);
vec3 lightDir = normalize(-directionalLight.direction);
float diff = max(dot(norm, lightDir), 0.0);
vec4 diffuse = vec4(directionalLight.diffuse, 1.0) * (diff * mat_diffuse);
vec4 specular;
if (material.shininess > 0) {
vec3 reflectDir = reflect(-lightDir, norm);
float spec = calc_spec(viewDir, lightDir, norm);
specular = vec4(directionalLight.specular, 1.0) * (spec * mat_specular);
} else {
specular = vec4(0.0);
}
return (ambient +
{% if lighting.shadows %}(1.0 - directional_shadow()) * {% endif %}
(diffuse + specular));
}
vec4 point_light(PointLight light, vec3 viewDir, vec4 mat_diffuse, vec4 mat_specular) {
vec3 norm = normalize(fNormal);
vec3 lightDir = normalize(light.position - fPos);
float diff = max(dot(norm, lightDir), 0.0);
float spec = calc_spec(viewDir, lightDir, norm);
float distance = length(light.position - fPos);
float attenuation = 1.0 / (light.constant + light.linear * distance +
light.quadratic * (distance * distance));
vec4 ambient = vec4(light.ambient, 1.0) * mat_diffuse;
vec4 diffuse = vec4(light.diffuse, 1.0) * diff * mat_diffuse;
vec4 specular = vec4(light.specular, 1.0) * spec * mat_specular;
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return (ambient + diffuse + specular);
}
vec4 lighting(vec4 diffuse, vec4 specular) {
vec3 viewDir = normalize(viewPos - fPos);
vec4 result = directional_light(viewDir, diffuse, specular);
for (int i=0;i<NR_POINT_LIGHTS&&i<activePointLights;i++)
result += point_light(pointLights[i], viewDir, diffuse, specular);
return result;
}
\ No newline at end of file
in vec4 fPosLightSpace;
uniform sampler2D shadowMap;
float directional_shadow() {
vec3 projCoords = fPosLightSpace.xyz / fPosLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
if (projCoords.z > 1.0) {
return 0.0;
}
float closestDepth = texture(shadowMap, projCoords.xy).r;
float currentDepth = projCoords.z;
vec3 norm = normalize(fNormal);
float bias = max(0.05 * (1.0 - dot(norm, directionalLight.direction)), 0.005);
// ? PCF, make optional
{% if graphics.pcf %}
float shadow = 0.0;
vec2 texelSize = 1.0 / textureSize(shadowMap, 0);
for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r;
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
}
}
shadow /= 9.0;
{% else %}
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
{% endif %}
return shadow;
}
\ No newline at end of file
uniform vec3 viewPos;
struct DirectionalLight {
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform DirectionalLight directionalLight;
struct PointLight {
vec3 position;
float constant;
float linear;
float quadratic;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
#define NR_POINT_LIGHTS {{ lighting.point_lights }}
uniform PointLight pointLights[NR_POINT_LIGHTS];
uniform int activePointLights;
\ No newline at end of file
use tera::Tera;
use super::{ ShaderOptions, include_render, push_render };
pub fn generate_fragment_shader(options: ShaderOptions) -> String {
let mut ctx = options.to_context();
let header = {
let mut header = "".to_string();
if let Some(lighting) = options.lighting {
push_render!(header, "lighting/uniforms.glsl", ctx);
if lighting.shadows {
push_render!(header, "lighting/shadows.glsl", ctx);
}
push_render!(header, "lighting/header.glsl", ctx);
}
header
};
ctx.insert("inject_header", &header);
include_render!("common.glsl", ctx)
}
pub mod common;
pub mod fragment;
pub mod vertex;
pub use common::*;
pub use fragment::*;
pub use vertex::*;
#version 330 core
layout (location = 0) in vec3 vPos;
layout (location = 2) in vec3 vNormal;
uniform mat4 model;
uniform mat4 mvp;
out vec3 fPos;
out vec3 fNormal;
{% if diffuse == "Colour" %}
layout (location = 1) in vec4 vColour;
out vec4 fColour;
{% else %}
layout (location = 1) in vec2 vUV;
out vec2 fUV;
{% endif %}
{{ inject_header }}
void main() {
vec4 pos = vec4(vPos, 1.0);
gl_Position = mvp * pos;
fPos = vec3(model * pos);
fNormal = mat3(transpose(inverse(model))) * vNormal;
{% if diffuse == "Colour" %}
fColor = vColor;
{% else %}
fUV = vUV;
{% endif %}
{{ inject_main }}
}
uniform mat4 lightSpaceMatrix;
out vec4 fPosLightSpace;
\ No newline at end of file
fPosLightSpace = lightSpaceMatrix * vec4(fPos, 1.0);
\ No newline at end of file
use tera::Tera;
use super::{ ShaderOptions, include_render, push_render };
pub fn generate_vertex_shader(options: ShaderOptions) -> String {
let mut ctx = options.to_context();
let header = {
let mut header = "".to_string();
if let Some(_) = options.lighting {
push_render!(header, "lighting/header.glsl", ctx);
}
header
};
let main = {
let mut main = "".to_string();
if let Some(_) = options.lighting {
push_render!(main, "lighting/main.glsl", ctx);
}
main
};
ctx.insert("inject_header", &header);
ctx.insert("inject_main", &main);
include_render!("common.glsl", ctx)
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment