not-fl3 / macroquad

Cross-platform game engine in Rust.
Apache License 2.0
3.37k stars 323 forks source link

I need help with shaders #677

Open vada4367 opened 10 months ago

vada4367 commented 10 months ago

Hello, I’m translating through a translator, so most likely I can say something absurd. I wanted to write ray tracing in rust + glsl. I was able to draw a sphere something like this:

main.rs:


use macroquad::prelude::*;

#[macroquad::main("Ray Tracing")]
async fn main() {
    let texture = render_target(8, 8).texture;
    let material = load_material(
        ShaderSource::Glsl {
            vertex: include_str!("vert_shader.glsl"),
            fragment: include_str!("frag_shader.glsl"),
        },
        MaterialParams {
            uniforms: vec![
                ("screen_resolution".to_owned(), UniformType::Float2),
                ("fov".to_owned(), UniformType::Float1),
                ("u_sphere_pos".to_owned(), UniformType::Float3),
                ("u_sphere_radius".to_owned(), UniformType::Float1),
            ],
            ..Default::default()
        },
    )
    .unwrap();

    set_default_camera();
    loop {
        clear_background(WHITE);

        gl_use_material(&material);
        material.set_uniform("screen_resolution", (screen_width(), screen_height()));
        material.set_uniform("fov", 90f32);
        material.set_uniform("u_sphere_pos", (0f32, 0f32, 3f32));
        material.set_uniform("u_sphere_radius", 1f32);

        draw_texture(&texture, -1f32, -1f32, WHITE);
        gl_use_default_material();

        next_frame().await;
    }
}

vert_shader.glsl:


uniform vec2 screen_resolution;

attribute vec2 position;
varying vec2 uv;
varying vec2 sc_res;

void main() {
  gl_Position = vec4(position, 0.0, 1.0);
  uv = (position + 1.0) / 2.0;
  sc_res = screen_resolution;
}

frag_shader.glsl:


uniform float fov;
uniform vec3 u_sphere_pos;
uniform float u_sphere_radius;
varying vec2 uv;
varying vec2 sc_res;

struct Camera {
  vec3 position;
  vec3 direction;
  float fov;
};

struct Ray {
  vec3 origin;
  vec3 direction;
  vec3 color;
};

struct Sphere {
  vec3 position;
  float radius;
};

Ray ray_new(Camera camera) {
  Ray ray;
  ray.origin = camera.position;
  ray.direction = normalize(vec3((uv.x - 0.5) * sc_res.x, (uv.y - 0.5) * sc_res.y, sc_res.x / (2.0 * tan(camera.fov / 2.0))));
  ray.color = vec3(1.0);
  return ray;
}

float sphere(Ray ray, Sphere sphere) {
  vec3 oc = ray.origin - sphere.position;
  float a = dot(ray.direction, ray.direction);
  float b = dot(oc, ray.direction);
  float c = dot(oc, oc) - sphere.radius * sphere.radius;

  float discriminant = b * b - a * c;

  if (discriminant < 0.0) {
    return -1.0;
  } else {
    float t = (-b + sqrt(discriminant)) / a;
    return t;
  }
}

void main() {
  Camera camera;
  camera.position = vec3(0.0);
  camera.direction = vec3(0.0);
  camera.fov = fov;

  Ray ray = ray_new(camera);
  float min_t = -1.0;
  for (int i = 0; i < 1; i++) {
    Sphere sphere;
    sphere.position = u_sphere_pos;
    sphere.radius = u_sphere_radius;

    float t = sphere(ray, sphere);
    if (t > 0.0 && (t < min_t || min_t == -1.0)) {
      min_t = t;
    }
  }

  // float inter = ray.origin + ray.direction * t;

  if (min_t > 0.0) {
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
  } else {
    gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
  }
}

This code draws a sphere (just white circle, lol), but there is a problem. I don't know how to send a buffer or array to the shader. How can I edit my code to support a certain number of balls?

Thanks

NHodgesVFX commented 10 months ago

I don't think Uniform Arrays are implemented. So, you cant really do this easily.

vada4367 commented 10 months ago

How difficult is it to do this? I thought I saw Uniform Arrays in real "Shader" in miniquad

historydev commented 1 month ago

https://docs.rs/macroquad/latest/macroquad/prelude/struct.UniformDesc.html#method.array