Previous topicNext topic

[ShaderToy] Copied a shader, but it doesn't work in Magic

Questions, comments, feedback, etc.
Post Reply
Jengamon
Posts: 4
Joined: Thu May 21, 2020 1:28 pm

[ShaderToy] Copied a shader, but it doesn't work in Magic

Post by Jengamon »

Hello!

I'm having a problem as stated in the title.

This is the shader: https://www.shadertoy.com/view/tsjfWW.

When I copy it to a file and run it, there simply is a completely black output. The module still has the "speed" parameter working, so there aren't any compile errors afaik.

The shader *is* quite a bit chonky though. Might that be a problem? (It does take ShaderToy 3 seconds to compile...)

EDIT:

I changed the code to measure ray trace depth (the shader is a raytracer), and somehow the geometry is there! It's something about lightScene that works in ShaderToy, but not in Magic...

Here's the relevant code (for the structs, reference the full shader):

Code: Select all

vec3 lightScene(Scene scene, SurfaceInteraction si, Ray r) {
  vec3 color = vec3(0.);
  vec3 p = r.o + r.d * si.d;
  Material mat = si.shape.mat;
  float reflected = mat.albedo / PI;
  for(int i = 0; i < scene.lightCount; i++) {
    Light l = scene.lights[i];
    Ray ra;
    ra.o = p + (si.n * scene.shadow_bias);
    switch(l.tag) {
      case 1:
        ra.d = normalize(l.point.p - ra.o);
        if(!intersectScene(scene, ra).isHit && si.isHit && dot(r.d, si.n) < 0.0) {
          color += dot(normalize(l.point.p - p), si.n) * (l.brightness / (4. * PI * dot(l.point.p - p, l.point.p - p))) * l.color * reflected * mat.color;
        }
        break;
      case 2:
        ra.d = normalize(l.point.p - ra.o);
        if(!intersectScene(scene, ra).isHit && si.isHit && dot(r.d, si.n) < 0.0) {
          color += dot(normalize(l.point.p - p), si.n) * l.brightness * l.color * reflected * mat.color;
        }
        break;
      case 3:
        ra.d = -l.dir.d;
        if(!intersectScene(scene, ra).isHit && si.isHit && dot(r.d, si.n) < 0.0) {
          color += dot(-l.dir.d, si.n) * l.brightness * l.color * reflected * mat.color;
        }
      case 0:
      default:
        break;
    }
  }

  return color;
}
EDIT:

- Did a little link switcheroo, so I can continue experimenting with raytracing
Magic
Site Admin
Posts: 3440
Joined: Wed Apr 09, 2014 9:28 pm

Re: [ShaderToy] Copied a shader, but it doesn't work in Magi

Post by Magic »

Did you check Magic's log file for compile errors?
Jengamon
Posts: 4
Joined: Thu May 21, 2020 1:28 pm

Re: [ShaderToy] Copied a shader, but it doesn't work in Magi

Post by Jengamon »

I did, there weren't any. The shader does compile, as I can render "lighting" based off of distance from camera. It just doesn't do the coloring from lightScene properly, while ShaderToy does.
Jengamon
Posts: 4
Joined: Thu May 21, 2020 1:28 pm

Re: [ShaderToy] Copied a shader, but it doesn't work in Magi

Post by Jengamon »

Figured out something. Apparently colors just work differently. Both videos are produced using the *exact* same shader code.

In ShaderToy: https://streamable.com/tpxl0z
In Magic: https://streamable.com/lyean8

The code (for reference):

Code: Select all

const float maxDist = 100.; // Maximum distance to trace a ray

#define PI 3.14159265359

// Generative palettes
const vec3 a = vec3(0.5);
const vec3 b = vec3(0.2, 0.5, 1.0);
const vec3 c = vec3(1.0, 0.4, 0.5);
const vec3 d = vec3(0.5);

vec3 palette(float t) {
  return a + b*cos(6.28318 * (c * t + d));
}

// Geomtru
struct Sphere {
  vec3 c;
  float r;
};

struct RidgePlane {
  vec3 n;
  vec3 o;
  float rh;
};

struct Material {
  vec3 color;
  float albedo;
};

struct Shape {
  Material mat;
  int tag; // Indicates which member to look at
  // Tag 0 [invalid]
  // Tag 1 [sphere]
  Sphere sphere;
  // Tag 2 [ridge plane]
  RidgePlane rplane;
};

struct Camera {
  vec3 origin;
  vec3 target;
  float fov;
};

struct Ray {
  vec3 o;
  vec3 d;
};

struct SurfaceInteraction {
  bool isHit;
  vec3 n;
  float d;
  vec3 dpdu, dpdv; // Dunno
  vec3 dndu, dndv; // Dunno
  Shape shape;
};

// Lighting
struct PointLight {
  vec3 p;
};

struct DirectionalLight {
  vec3 d;
};

struct Light {
  vec3 color;
  float brightness;
  int tag;
  // Tag 0 [invalid]
  // Tag 1 [point]
  PointLight point;
  // Tag 2 [point NO ISL] (just use the point member)
  // Tag 3 [directional]
  DirectionalLight dir;
};

struct Scene {
  Shape shapes[256]; // Support up to 256 shapes
  int shapeCount; // How many shapes were *actually* used?
  Light lights[256]; // Support up to 256 lights
  int lightCount; // How many lights were *actually* used?
  float shadow_bias;
};

// Functions
Shape Sphere_new(float x, float y, float z, float r) {
  Sphere sphere;
  sphere.c = vec3(x, y, z); sphere.r = r;
  Shape shape;
  shape.sphere = sphere;
  shape.tag = 1;

  return shape;
}

Shape RidgePlane_new(vec3 n, vec3 o, float rh) {
  RidgePlane rplane;
  rplane.n = n; rplane.o = o; rplane.rh = rh;
  Shape shape;
  shape.rplane = rplane;
  shape.tag = 2;

  return shape;
}

Light PointLight_new(vec3 point) {
  PointLight plight;
  plight.p = point;
  Light light;
  light.point = plight;
  light.tag = 1;

  return light;
}

Light DirectionalLight_new(vec3 dir) {
    DirectionalLight dlight;
    dlight.d = normalize(dir);
    Light light;
    light.dir = dlight;
    light.tag = 3;

    return light;
}

float hit_sphere(Sphere sphere, Ray r) {
  vec3 oc = r.o - sphere.c;
  float a = dot(r.d, r.d);
  float b = 2.0 * dot(oc, r.d);
  float c = dot(oc, oc) - sphere.r * sphere.r;
  float discriminant = b*b - 4.0 * a * c;
  if(discriminant < 0.) {
    return -1.0;
  } else {
    return (-b - sqrt(discriminant)) / (2.0 * a);
  }
}

float hit_plane(RidgePlane rplane, Ray r) {
  float denom = dot(r.d, rplane.n);
  if(denom > 0.0001) {
    vec3 p0l0 = rplane.o - r.o;
    float t = dot(p0l0, rplane.n) / denom;
    if(t > 0.0001)
      return t;
  }
  return -1.0;
}

SurfaceInteraction intersectScene(Scene scene, Ray r) {
  SurfaceInteraction si;

  float dist = maxDist; // The closest a shape has come

  for(int i = 0; i < scene.shapeCount; i++) {
    Shape s = scene.shapes[i];
    switch(s.tag)
    {
      case 1:
        if(hit_sphere(s.sphere, r) > 0.0 && hit_sphere(s.sphere, r) < dist) {
          // Populate the surface interaction
          dist = hit_sphere(s.sphere, r);
          si.isHit = true;
          si.n = normalize((r.o + r.d * dist) - s.sphere.c);
          si.shape = s;
          si.d = dist;
        }
        break;
      case 2:
        if(hit_plane(s.rplane, r) > 0.0 && hit_plane(s.rplane, r) < dist) {
          // Populate the surface interaction
          dist = hit_plane(s.rplane, r);
          si.isHit = true;
          // TODO Fake out the normal calc to make the ridges
          si.n = -s.rplane.n;
          si.shape = s;
          si.d = dist;
        }
        break;
      case 0:
      default:
        break;
    }
  }

  return si;
}

vec3 lightScene(Scene scene, SurfaceInteraction si, Ray r) {
  vec3 color = vec3(0.);
  vec3 p = r.o + r.d * si.d;
  Material mat = si.shape.mat;
  float reflected = mat.albedo / PI;
  for(int i = 0; i < scene.lightCount; i++) {
    Light l = scene.lights[i];
    Ray ra;
    ra.o = p + (si.n * scene.shadow_bias);
    switch(l.tag) {
      case 1:
        ra.d = normalize(l.point.p - ra.o);
        if(!intersectScene(scene, ra).isHit && si.isHit && dot(r.d, si.n) < 0.0) {
          color += dot(normalize(l.point.p - p), si.n) * (l.brightness / (4. * PI * dot(l.point.p - p, l.point.p - p))) * l.color * reflected * mat.color;
        }
        break;
      case 2:
        ra.d = normalize(l.point.p - ra.o);
        if(!intersectScene(scene, ra).isHit && si.isHit && dot(r.d, si.n) < 0.0) {
          color += dot(normalize(l.point.p - p), si.n) * l.brightness * l.color * reflected * mat.color;
        }
        break;
      case 3:
        ra.d = -l.dir.d;
        // if(!intersectScene(scene, ra).isHit && si.isHit && dot(r.d, si.n) < 0.0) {
          color += dot(-l.dir.d, si.n) * l.brightness * l.color * reflected * mat.color;
        // }
        break;
      case 0:
      default:
        break;
    }
  }

  return pow(color, vec3(0.7));
}

Scene buildScene() {
  Scene scene;
  scene.shapeCount = 2;
  scene.lightCount = 2;
  scene.shadow_bias = 0.01;

  // A sphere at (around) the origin with radius 5
  scene.shapes[0] = Sphere_new(3. * sin(iTime * 4.), cos(iTime) + 2.0, 0., 1.);
  scene.shapes[0].mat.color = palette(0.3 * sin(iTime / 2.) + 0.3);
  scene.shapes[0].mat.albedo = 5.0;
  //scene.shapes[0].mat.color = vec3(0., 1., 0.);
  //scene.shapes[1] = Sphere_new(0., -1000., 0., 1000.);
  //scene.shapes[1].mat.color = vec3(1.);
  // A ridged plane at the origin, pointing up, with some ridges
  scene.shapes[1] = RidgePlane_new(vec3(0., -1., 0.), vec3(0., 0., 0.), 2.);
  scene.shapes[1].mat.color = vec3(1.);
  scene.shapes[1].mat.albedo = 2.0;

  // A light that moves around
  scene.lights[0] = PointLight_new(vec3(2. * sin(iTime), 5., 5.));
  scene.lights[0].color = vec3(1.);
  scene.lights[0].brightness = 300.;
  // A directional light
  scene.lights[1] = DirectionalLight_new(vec3(0., -1., 0.));
  scene.lights[1].color = vec3(0.5, 0.4, 0.);
  scene.lights[1].brightness = 0.4;

  return scene;
}

vec3 lookAt(vec2 uv, Camera cam) {
  // Get the z axis same way as direction vector
  vec3 zAxis = normalize(cam.target - cam.origin);
  vec3 up = vec3(0., 1., 0.);

  // cross prd of 2 vec prod. 3 vec that is orthog to first 2
  // non-communicative so order matters
  vec3 xAxis = normalize(cross(up, zAxis));
  vec3 yAxis = normalize(cross(zAxis, xAxis));

  float fov = cam.fov;
  // scale unit v by ray origin
  // one for x one for y, no z vector, so just add it
  // then scale by fov
  vec3 dir = (normalize((uv.x * xAxis) + (uv.y * yAxis) + (zAxis * fov)));

  return dir;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from -1 to 1)
    vec2 uv = 2.0 * fragCoord/iResolution.xy - vec2(1.0);

    // Create the scene
    Scene scene = buildScene();

    // Create the camera object
    Camera camera;
    camera.origin = vec3(20. * sin(iTime / 2.), 10. * sin(iTime) + 12., 20. * cos(iTime / 2.));
    //camera.origin = vec3(0., 1., -5.);
    camera.target = vec3(0., 0., 0.);
    camera.fov = 2.;

    // Create Ray object
    Ray ray;
    ray.o = vec3(uv + camera.origin.xy, camera.origin.z + 1.);
    ray.d = lookAt(uv, camera);

    SurfaceInteraction si = intersectScene(scene, ray);

    // fragColor = vec4(mix(lightScene(scene, si, ray), 1.0 * (float)si.isHit - (vec3(si.d * (float)si.isHit) / maxDist), 0.2), 1.0);
    fragColor = vec4(lightScene(scene, si, ray), 1.0);
}

EDIT: How does one switch GPUs in Magic? My computer has 2, and ShaderToy uses 1 (integrated Intel) while Magic uses the other (an RTX 2070 Max-Q), so the comparison might be apples to oranges.
Jengamon
Posts: 4
Joined: Thu May 21, 2020 1:28 pm

Re: [ShaderToy] Copied a shader, but it doesn't work in Magi

Post by Jengamon »

I'm giving up on this shader, cuz it's too much trouble, when I rewrote it as a raymarcher instead of raytracer for much better results. Thank you for your help so far.
Magic
Site Admin
Posts: 3440
Joined: Wed Apr 09, 2014 9:28 pm

Re: [ShaderToy] Copied a shader, but it doesn't work in Magi

Post by Magic »

Yes, different GPUs have slightly different requirements. Magic will always try to auto-select the best GPU available. Your web browser probably uses the default GPU to save power.
Post Reply