diff options
-rw-r--r-- | med.c | 201 | ||||
-rw-r--r-- | shaders.inc | 421 | ||||
-rw-r--r-- | vis.c | 423 |
3 files changed, 425 insertions, 620 deletions
@@ -106,6 +106,8 @@ static int doprof; static int showhud; Color (*tsampler)(Texture*,Point2); +#include "shaders.inc" + static Point3 Vecquat(Quaternion q) { @@ -250,205 +252,6 @@ setupcompass(Compass *c, Rectangle r, Renderer *rctl) placecamera(c->cam, c->scn, camcfg.p, center, Vec3(0,1,0)); } -Point3 -gouraudvshader(Shaderparams *sp) -{ - static double Ka = 0.1; /* ambient factor */ - static double Ks = 0.5; /* specular factor */ - double Kd; /* diffuse factor */ - double spec; - Point3 pos, lightdir, lookdir; - Material m; - Color ambient, diffuse, specular, lightc; - - sp->v->n = model2world(sp->su->entity, sp->v->n); - sp->v->p = model2world(sp->su->entity, sp->v->p); - pos = sp->v->p; - - if(sp->v->mtl != nil) - m = *sp->v->mtl; - else{ - memset(&m, 0, sizeof m); - m.diffuse = sp->v->c; - m.specular = Pt3(1,1,1,1); - m.shininess = 1; - } - - lightdir = normvec3(subpt3(light.p, pos)); - lightc = getlightcolor(&light, lightdir); - - ambient = mulpt3(lightc, Ka); - ambient = modulapt3(ambient, m.diffuse); - - Kd = max(0, dotvec3(sp->v->n, lightdir)); - diffuse = mulpt3(lightc, Kd); - diffuse = modulapt3(diffuse, m.diffuse); - - lookdir = normvec3(subpt3(sp->su->camera->p, pos)); - lightdir = qrotate(lightdir, sp->v->n, PI); - spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess); - specular = mulpt3(lightc, spec*Ks); - specular = modulapt3(specular, m.specular); - - sp->v->c = addpt3(ambient, addpt3(diffuse, specular)); - sp->v->c.a = m.diffuse.a; - return world2clip(sp->su->camera, pos); -} - -Color -gouraudshader(Shaderparams *sp) -{ - Color tc; - - if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) - tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); - else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) - tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); - else - tc = Pt3(1,1,1,1); - - return modulapt3(sp->v->c, tc); -} - -Point3 -phongvshader(Shaderparams *sp) -{ - Point3 pos; - Color a, d, s; - double ss; - - sp->v->n = model2world(sp->su->entity, sp->v->n); - sp->v->p = model2world(sp->su->entity, sp->v->p); - pos = sp->v->p; - sp->setattr(sp, "pos", VAPoint, &pos); - if(sp->v->mtl != nil && sp->v->mtl->normalmap != nil && sp->v->uv.w != 0){ - sp->v->tangent = model2world(sp->su->entity, sp->v->tangent); - sp->setattr(sp, "tangent", VAPoint, &sp->v->tangent); - } - if(sp->v->mtl != nil){ - a = sp->v->mtl->ambient; - d = sp->v->mtl->diffuse; - s = sp->v->mtl->specular; - ss = sp->v->mtl->shininess; - sp->setattr(sp, "ambient", VAPoint, &a); - sp->setattr(sp, "diffuse", VAPoint, &d); - sp->setattr(sp, "specular", VAPoint, &s); - sp->setattr(sp, "shininess", VANumber, &ss); - } - return world2clip(sp->su->camera, pos); -} - -Color -phongshader(Shaderparams *sp) -{ - static double Ka = 0.1; /* ambient factor */ - static double Ks = 0.5; /* specular factor */ - double Kd; /* diffuse factor */ - double spec; - Color ambient, diffuse, specular, lightc, c; - Point3 pos, n, lightdir, lookdir; - Material m; - RFrame3 TBN; - Vertexattr *va; - - va = sp->getattr(sp, "pos"); - pos = va->p; - - va = sp->getattr(sp, "ambient"); - m.ambient = va != nil? va->p: Pt3(1,1,1,1); - va = sp->getattr(sp, "diffuse"); - m.diffuse = va != nil? va->p: sp->v->c; - va = sp->getattr(sp, "specular"); - m.specular = va != nil? va->p: Pt3(1,1,1,1); - va = sp->getattr(sp, "shininess"); - m.shininess = va != nil? va->n: 1; - - lightdir = normvec3(subpt3(light.p, pos)); - lightc = getlightcolor(&light, lightdir); - - /* normal mapping */ - va = sp->getattr(sp, "tangent"); - if(va == nil) - n = sp->v->n; - else{ - /* TODO implement this on the VS instead and apply Gram-Schmidt here */ - n = sampletexture(sp->v->mtl->normalmap, sp->v->uv, neartexsampler); - n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1))); - - TBN.p = Pt3(0,0,0,1); - TBN.bx = va->p; /* T */ - TBN.bz = sp->v->n; /* N */ - TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */ - - n = normvec3(invrframexform3(n, TBN)); - sp->v->n = n; - } - - if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) - m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); - else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) - m.diffuse = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); - - ambient = mulpt3(lightc, Ka); - ambient = modulapt3(ambient, m.diffuse); - - Kd = max(0, dotvec3(n, lightdir)); - diffuse = mulpt3(lightc, Kd); - diffuse = modulapt3(diffuse, m.diffuse); - - if(sp->v->mtl != nil && sp->v->mtl->specularmap != nil && sp->v->uv.w != 0) - m.specular = sampletexture(sp->v->mtl->specularmap, sp->v->uv, tsampler); - - lookdir = normvec3(subpt3(sp->su->camera->p, pos)); - lightdir = qrotate(lightdir, n, PI); - spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess); - specular = mulpt3(lightc, spec*Ks); - specular = modulapt3(specular, m.specular); - - c = addpt3(ambient, addpt3(diffuse, specular)); - c.a = m.diffuse.a; - return c; -} - -Point3 -identvshader(Shaderparams *sp) -{ - if(sp->v->mtl != nil) - sp->v->c = sp->v->mtl->diffuse; - return world2clip(sp->su->camera, model2world(sp->su->entity, sp->v->p)); -} - -Color -identshader(Shaderparams *sp) -{ - Color tc; - - if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) - tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); - else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) - tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); - else - tc = Pt3(1,1,1,1); - - return modulapt3(sp->v->c, tc); -} - -Shadertab shadertab[] = { - { "ident", identvshader, identshader }, - { "gouraud", gouraudvshader, gouraudshader }, - { "phong", phongvshader, phongshader }, -}; -Shadertab * -getshader(char *name) -{ - int i; - - for(i = 0; i < nelem(shadertab); i++) - if(strcmp(shadertab[i].name, name) == 0) - return &shadertab[i]; - return nil; -} - void zoomin(void) { diff --git a/shaders.inc b/shaders.inc new file mode 100644 index 0000000..0e0d0fe --- /dev/null +++ b/shaders.inc @@ -0,0 +1,421 @@ + +Point3 +gouraudvshader(Shaderparams *sp) +{ + static double Ka = 0.1; /* ambient factor */ + static double Ks = 0.5; /* specular factor */ + double Kd; /* diffuse factor */ + double spec; + Point3 pos, lightdir, lookdir; + Material m; + Color ambient, diffuse, specular, lightc; + + sp->v->n = model2world(sp->su->entity, sp->v->n); + sp->v->p = model2world(sp->su->entity, sp->v->p); + pos = sp->v->p; + + if(sp->v->mtl != nil) + m = *sp->v->mtl; + else{ + memset(&m, 0, sizeof m); + m.diffuse = sp->v->c; + m.specular = Pt3(1,1,1,1); + m.shininess = 1; + } + + lightdir = normvec3(subpt3(light.p, pos)); + lightc = getlightcolor(&light, lightdir); + + ambient = mulpt3(lightc, Ka); + ambient = modulapt3(ambient, m.diffuse); + + Kd = max(0, dotvec3(sp->v->n, lightdir)); + diffuse = mulpt3(lightc, Kd); + diffuse = modulapt3(diffuse, m.diffuse); + + lookdir = normvec3(subpt3(sp->su->camera->p, pos)); + lightdir = qrotate(lightdir, sp->v->n, PI); + spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess); + specular = mulpt3(lightc, spec*Ks); + specular = modulapt3(specular, m.specular); + + sp->v->c = addpt3(ambient, addpt3(diffuse, specular)); + sp->v->c.a = m.diffuse.a; + return world2clip(sp->su->camera, pos); +} + +Color +gouraudshader(Shaderparams *sp) +{ + Color tc; + + if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) + tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); + else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) + tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); + else + tc = Pt3(1,1,1,1); + + sp->v->n.w = 1; + sp->toraster(sp, "normals", &sp->v->n); + + return modulapt3(sp->v->c, tc); +} + +Point3 +phongvshader(Shaderparams *sp) +{ + Point3 pos; + Color a, d, s; + double ss; + + sp->v->n = model2world(sp->su->entity, sp->v->n); + sp->v->p = model2world(sp->su->entity, sp->v->p); + pos = sp->v->p; + sp->setattr(sp, "pos", VAPoint, &pos); + if(sp->v->mtl != nil && sp->v->mtl->normalmap != nil && sp->v->uv.w != 0){ + sp->v->tangent = model2world(sp->su->entity, sp->v->tangent); + sp->setattr(sp, "tangent", VAPoint, &sp->v->tangent); + } + if(sp->v->mtl != nil){ + a = sp->v->mtl->ambient; + d = sp->v->mtl->diffuse; + s = sp->v->mtl->specular; + ss = sp->v->mtl->shininess; + sp->setattr(sp, "ambient", VAPoint, &a); + sp->setattr(sp, "diffuse", VAPoint, &d); + sp->setattr(sp, "specular", VAPoint, &s); + sp->setattr(sp, "shininess", VANumber, &ss); + } + return world2clip(sp->su->camera, pos); +} + +Color +phongshader(Shaderparams *sp) +{ + static double Ka = 0.1; /* ambient factor */ + static double Ks = 0.5; /* specular factor */ + double Kd; /* diffuse factor */ + double spec; + Color ambient, diffuse, specular, lightc, c; + Point3 pos, n, lightdir, lookdir; + Material m; + RFrame3 TBN; + Vertexattr *va; + + va = sp->getattr(sp, "pos"); + pos = va->p; + + va = sp->getattr(sp, "ambient"); + m.ambient = va != nil? va->p: Pt3(1,1,1,1); + va = sp->getattr(sp, "diffuse"); + m.diffuse = va != nil? va->p: sp->v->c; + va = sp->getattr(sp, "specular"); + m.specular = va != nil? va->p: Pt3(1,1,1,1); + va = sp->getattr(sp, "shininess"); + m.shininess = va != nil? va->n: 1; + + lightdir = normvec3(subpt3(light.p, pos)); + lightc = getlightcolor(&light, lightdir); + + /* normal mapping */ + va = sp->getattr(sp, "tangent"); + if(va == nil) + n = sp->v->n; + else{ + /* TODO implement this on the VS instead and apply Gram-Schmidt here */ + n = sampletexture(sp->v->mtl->normalmap, sp->v->uv, neartexsampler); + n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1))); + + TBN.p = Pt3(0,0,0,1); + TBN.bx = va->p; /* T */ + TBN.bz = sp->v->n; /* N */ + TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */ + + n = normvec3(invrframexform3(n, TBN)); + sp->v->n = n; + } + + if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) + m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); + else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) + m.diffuse = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); + + ambient = mulpt3(lightc, Ka); + ambient = modulapt3(ambient, m.diffuse); + + Kd = max(0, dotvec3(n, lightdir)); + diffuse = mulpt3(lightc, Kd); + diffuse = modulapt3(diffuse, m.diffuse); + + if(sp->v->mtl != nil && sp->v->mtl->specularmap != nil && sp->v->uv.w != 0) + m.specular = sampletexture(sp->v->mtl->specularmap, sp->v->uv, tsampler); + + lookdir = normvec3(subpt3(sp->su->camera->p, pos)); + lightdir = qrotate(lightdir, n, PI); + spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess); + specular = mulpt3(lightc, spec*Ks); + specular = modulapt3(specular, m.specular); + + sp->v->n.w = 1; + sp->toraster(sp, "normals", &sp->v->n); + + c = addpt3(ambient, addpt3(diffuse, specular)); + c.a = m.diffuse.a; + return c; +} + +Color +blinnshader(Shaderparams *sp) +{ + static double Ka = 0.1; /* ambient factor */ + static double Ks = 0.5; /* specular factor */ + double Kd; /* diffuse factor */ + double spec; + Color ambient, diffuse, specular, lightc, c; + Point3 pos, n, lightdir, lookdir; + Material m; + RFrame3 TBN; + Vertexattr *va; + + va = sp->getattr(sp, "pos"); + pos = va->p; + + va = sp->getattr(sp, "ambient"); + m.ambient = va != nil? va->p: Pt3(1,1,1,1); + va = sp->getattr(sp, "diffuse"); + m.diffuse = va != nil? va->p: sp->v->c; + va = sp->getattr(sp, "specular"); + m.specular = va != nil? va->p: Pt3(1,1,1,1); + va = sp->getattr(sp, "shininess"); + m.shininess = va != nil? va->n: 1; + + lightdir = normvec3(subpt3(light.p, pos)); + lightc = getlightcolor(&light, lightdir); + + /* normal mapping */ + va = sp->getattr(sp, "tangent"); + if(va == nil) + n = sp->v->n; + else{ + /* TODO implement this on the VS instead and apply Gram-Schmidt here */ + n = sampletexture(sp->v->mtl->normalmap, sp->v->uv, neartexsampler); + n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1))); + + TBN.p = Pt3(0,0,0,1); + TBN.bx = va->p; /* T */ + TBN.bz = sp->v->n; /* N */ + TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */ + + n = normvec3(invrframexform3(n, TBN)); + sp->v->n = n; + } + + if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) + m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); + else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) + m.diffuse = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); + + ambient = mulpt3(lightc, Ka); + ambient = modulapt3(ambient, m.diffuse); + + Kd = max(0, dotvec3(n, lightdir)); + diffuse = mulpt3(lightc, Kd); + diffuse = modulapt3(diffuse, m.diffuse); + + if(sp->v->mtl != nil && sp->v->mtl->specularmap != nil && sp->v->uv.w != 0) + m.specular = sampletexture(sp->v->mtl->specularmap, sp->v->uv, tsampler); + + lookdir = normvec3(subpt3(sp->su->camera->p, pos)); + lightdir = normvec3(addpt3(lookdir, lightdir)); /* half vector */ + spec = pow(max(0, dotvec3(n, lightdir)), m.shininess); + specular = mulpt3(lightc, spec*Ks); + specular = modulapt3(specular, m.specular); + + sp->v->n.w = 1; + sp->toraster(sp, "normals", &sp->v->n); + + c = addpt3(ambient, addpt3(diffuse, specular)); + c.a = m.diffuse.a; + return c; +} + +Point3 +toonvshader(Shaderparams *sp) +{ + Point3 pos, lightdir; + double intens; + + sp->v->n = model2world(sp->su->entity, sp->v->n); + pos = model2world(sp->su->entity, sp->v->p); + lightdir = normvec3(subpt3(light.p, pos)); + intens = max(0, dotvec3(sp->v->n, lightdir)); + sp->setattr(sp, "intensity", VANumber, &intens); + if(sp->v->mtl != nil) + sp->v->c = sp->v->mtl->diffuse; + return world2clip(sp->su->camera, pos); +} + +Color +toonshader(Shaderparams *sp) +{ + Vertexattr *va; + double intens; + + va = sp->getattr(sp, "intensity"); + intens = va->n; + intens = intens > 0.85? 1: + intens > 0.60? 0.80: + intens > 0.45? 0.60: + intens > 0.30? 0.45: + intens > 0.15? 0.30: 0.15; + + sp->v->n.w = 1; + sp->toraster(sp, "normals", &sp->v->n); + + return Pt3(intens, 0.6*intens, 0, 1); +} + +Point3 +identvshader(Shaderparams *sp) +{ + if(sp->v->mtl != nil) + sp->v->c = sp->v->mtl->diffuse; + return world2clip(sp->su->camera, model2world(sp->su->entity, sp->v->p)); +} + +Color +identshader(Shaderparams *sp) +{ + Color tc; + + if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) + tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); + else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) + tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); + else + tc = Pt3(1,1,1,1); + + sp->v->n.w = 1; + sp->toraster(sp, "normals", &sp->v->n); + + return modulapt3(sp->v->c, tc); +} + +Point3 +ivshader(Shaderparams *sp) +{ + sp->v->n = model2world(sp->su->entity, sp->v->n); + sp->v->p = model2world(sp->su->entity, sp->v->p); + return world2clip(sp->su->camera, sp->v->p); +} + +Color +triangleshader(Shaderparams *sp) +{ + Triangle2 t; + Rectangle bbox; + Point3 bc; + + t.p0 = Pt2(240,200,1); + t.p1 = Pt2(400,40,1); + t.p2 = Pt2(240,40,1); + + bbox = Rect( + min(min(t.p0.x, t.p1.x), t.p2.x), min(min(t.p0.y, t.p1.y), t.p2.y), + max(max(t.p0.x, t.p1.x), t.p2.x), max(max(t.p0.y, t.p1.y), t.p2.y) + ); + if(!ptinrect(sp->p, bbox)) + return Vec3(0,0,0); + + bc = barycoords(t, Pt2(sp->p.x,sp->p.y,1)); + if(bc.x < 0 || bc.y < 0 || bc.z < 0) + return Vec3(0,0,0); + + return Pt3(bc.x, bc.y, bc.z, 1); +} + +Color +circleshader(Shaderparams *sp) +{ + Point2 uv; + double r, d; + + uv = Pt2(sp->p.x,sp->p.y,1); + uv.x /= Dx(sp->su->fb->r); + uv.y /= Dy(sp->su->fb->r); +// r = 0.3; + r = 0.3*fabs(sin(sp->su->uni_time/1e9)); + d = vec2len(subpt2(uv, Vec2(0.5,0.5))); + + if(d > r + r*0.05 || d < r - r*0.05) + return Vec3(0,0,0); + + return Pt3(uv.x, uv.y, 0, 1); +} + +/* some shaping functions from The Book of Shaders, Chapter 5 */ +Color +sfshader(Shaderparams *sp) +{ + Point2 uv; + double y, pct; + + uv = Pt2(sp->p.x,sp->p.y,1); + uv.x /= Dx(sp->su->fb->r); + uv.y /= Dy(sp->su->fb->r); + uv.y = 1 - uv.y; /* make [0 0] the bottom-left corner */ + +// y = step(0.5, uv.x); +// y = pow(uv.x, 5); +// y = sin(uv.x); + y = sin(uv.x*sp->su->uni_time/1e8)/2.0 + 0.5; +// y = smoothstep(0.1, 0.9, uv.x); + pct = smoothstep(y-0.02, y, uv.y) - smoothstep(y, y+0.02, uv.y); + + return Pt3(flerp(y, 0, pct), flerp(y, 1, pct), flerp(y, 0, pct), 1); +} + +Color +boxshader(Shaderparams *sp) +{ + Point2 uv, p; + Point2 r; + + uv = Pt2(sp->p.x,sp->p.y,1); + uv.x /= Dx(sp->su->fb->r); + uv.y /= Dy(sp->su->fb->r); + r = Vec2(0.2,0.4); + + p = Pt2(fabs(uv.x - 0.5), fabs(uv.y - 0.5), 1); + p = subpt2(p, r); + p.x = max(p.x, 0); + p.y = max(p.y, 0); + + if(vec2len(p) > 0) + return Vec3(0,0,0); + + return Pt3(uv.x, uv.y, smoothstep(0,1,uv.x+uv.y), 1); +} + +Shadertab shadertab[] = { + { "triangle", ivshader, triangleshader }, + { "circle", ivshader, circleshader }, + { "box", ivshader, boxshader }, + { "sf", ivshader, sfshader }, + { "toon", toonvshader, toonshader }, + { "ident", identvshader, identshader }, + { "gouraud", gouraudvshader, gouraudshader }, + { "phong", phongvshader, phongshader }, + { "blinn", phongvshader, blinnshader }, +}; +Shadertab * +getshader(char *name) +{ + int i; + + for(i = 0; i < nelem(shadertab); i++) + if(strcmp(shadertab[i].name, name) == 0) + return &shadertab[i]; + return nil; +} @@ -98,6 +98,8 @@ static int depthon; static int abuffon; Color (*tsampler)(Texture*,Point2); +#include "shaders.inc" + static Point3 Vecquat(Quaternion q) { @@ -110,427 +112,6 @@ Ptquat(Quaternion q, double w) return Pt3(q.i, q.j, q.k, w); } -Point3 -gouraudvshader(Shaderparams *sp) -{ - static double Ka = 0.1; /* ambient factor */ - static double Ks = 0.5; /* specular factor */ - double Kd; /* diffuse factor */ - double spec; - Point3 pos, lightdir, lookdir; - Material m; - Color ambient, diffuse, specular, lightc; - - sp->v->n = model2world(sp->su->entity, sp->v->n); - sp->v->p = model2world(sp->su->entity, sp->v->p); - pos = sp->v->p; - - if(sp->v->mtl != nil) - m = *sp->v->mtl; - else{ - memset(&m, 0, sizeof m); - m.diffuse = sp->v->c; - m.specular = Pt3(1,1,1,1); - m.shininess = 1; - } - - lightdir = normvec3(subpt3(light.p, pos)); - lightc = getlightcolor(&light, lightdir); - - ambient = mulpt3(lightc, Ka); - ambient = modulapt3(ambient, m.diffuse); - - Kd = max(0, dotvec3(sp->v->n, lightdir)); - diffuse = mulpt3(lightc, Kd); - diffuse = modulapt3(diffuse, m.diffuse); - - lookdir = normvec3(subpt3(sp->su->camera->p, pos)); - lightdir = qrotate(lightdir, sp->v->n, PI); - spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess); - specular = mulpt3(lightc, spec*Ks); - specular = modulapt3(specular, m.specular); - - sp->v->c = addpt3(ambient, addpt3(diffuse, specular)); - sp->v->c.a = m.diffuse.a; - return world2clip(sp->su->camera, pos); -} - -Color -gouraudshader(Shaderparams *sp) -{ - Color tc; - - if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) - tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); - else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) - tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); - else - tc = Pt3(1,1,1,1); - - sp->v->n.w = 1; - sp->toraster(sp, "normals", &sp->v->n); - - return modulapt3(sp->v->c, tc); -} - -Point3 -phongvshader(Shaderparams *sp) -{ - Point3 pos; - Color a, d, s; - double ss; - - sp->v->n = model2world(sp->su->entity, sp->v->n); - sp->v->p = model2world(sp->su->entity, sp->v->p); - pos = sp->v->p; - sp->setattr(sp, "pos", VAPoint, &pos); - if(sp->v->mtl != nil && sp->v->mtl->normalmap != nil && sp->v->uv.w != 0){ - sp->v->tangent = model2world(sp->su->entity, sp->v->tangent); - sp->setattr(sp, "tangent", VAPoint, &sp->v->tangent); - } - if(sp->v->mtl != nil){ - a = sp->v->mtl->ambient; - d = sp->v->mtl->diffuse; - s = sp->v->mtl->specular; - ss = sp->v->mtl->shininess; - sp->setattr(sp, "ambient", VAPoint, &a); - sp->setattr(sp, "diffuse", VAPoint, &d); - sp->setattr(sp, "specular", VAPoint, &s); - sp->setattr(sp, "shininess", VANumber, &ss); - } - return world2clip(sp->su->camera, pos); -} - -Color -phongshader(Shaderparams *sp) -{ - static double Ka = 0.1; /* ambient factor */ - static double Ks = 0.5; /* specular factor */ - double Kd; /* diffuse factor */ - double spec; - Color ambient, diffuse, specular, lightc, c; - Point3 pos, n, lightdir, lookdir; - Material m; - RFrame3 TBN; - Vertexattr *va; - - va = sp->getattr(sp, "pos"); - pos = va->p; - - va = sp->getattr(sp, "ambient"); - m.ambient = va != nil? va->p: Pt3(1,1,1,1); - va = sp->getattr(sp, "diffuse"); - m.diffuse = va != nil? va->p: sp->v->c; - va = sp->getattr(sp, "specular"); - m.specular = va != nil? va->p: Pt3(1,1,1,1); - va = sp->getattr(sp, "shininess"); - m.shininess = va != nil? va->n: 1; - - lightdir = normvec3(subpt3(light.p, pos)); - lightc = getlightcolor(&light, lightdir); - - /* normal mapping */ - va = sp->getattr(sp, "tangent"); - if(va == nil) - n = sp->v->n; - else{ - /* TODO implement this on the VS instead and apply Gram-Schmidt here */ - n = sampletexture(sp->v->mtl->normalmap, sp->v->uv, neartexsampler); - n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1))); - - TBN.p = Pt3(0,0,0,1); - TBN.bx = va->p; /* T */ - TBN.bz = sp->v->n; /* N */ - TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */ - - n = normvec3(invrframexform3(n, TBN)); - sp->v->n = n; - } - - if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) - m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); - else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) - m.diffuse = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); - - ambient = mulpt3(lightc, Ka); - ambient = modulapt3(ambient, m.diffuse); - - Kd = max(0, dotvec3(n, lightdir)); - diffuse = mulpt3(lightc, Kd); - diffuse = modulapt3(diffuse, m.diffuse); - - if(sp->v->mtl != nil && sp->v->mtl->specularmap != nil && sp->v->uv.w != 0) - m.specular = sampletexture(sp->v->mtl->specularmap, sp->v->uv, tsampler); - - lookdir = normvec3(subpt3(sp->su->camera->p, pos)); - lightdir = qrotate(lightdir, n, PI); - spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess); - specular = mulpt3(lightc, spec*Ks); - specular = modulapt3(specular, m.specular); - - sp->v->n.w = 1; - sp->toraster(sp, "normals", &sp->v->n); - - c = addpt3(ambient, addpt3(diffuse, specular)); - c.a = m.diffuse.a; - return c; -} - -Color -blinnshader(Shaderparams *sp) -{ - static double Ka = 0.1; /* ambient factor */ - static double Ks = 0.5; /* specular factor */ - double Kd; /* diffuse factor */ - double spec; - Color ambient, diffuse, specular, lightc, c; - Point3 pos, n, lightdir, lookdir; - Material m; - RFrame3 TBN; - Vertexattr *va; - - va = sp->getattr(sp, "pos"); - pos = va->p; - - va = sp->getattr(sp, "ambient"); - m.ambient = va != nil? va->p: Pt3(1,1,1,1); - va = sp->getattr(sp, "diffuse"); - m.diffuse = va != nil? va->p: sp->v->c; - va = sp->getattr(sp, "specular"); - m.specular = va != nil? va->p: Pt3(1,1,1,1); - va = sp->getattr(sp, "shininess"); - m.shininess = va != nil? va->n: 1; - - lightdir = normvec3(subpt3(light.p, pos)); - lightc = getlightcolor(&light, lightdir); - - /* normal mapping */ - va = sp->getattr(sp, "tangent"); - if(va == nil) - n = sp->v->n; - else{ - /* TODO implement this on the VS instead and apply Gram-Schmidt here */ - n = sampletexture(sp->v->mtl->normalmap, sp->v->uv, neartexsampler); - n = normvec3(subpt3(mulpt3(n, 2), Vec3(1,1,1))); - - TBN.p = Pt3(0,0,0,1); - TBN.bx = va->p; /* T */ - TBN.bz = sp->v->n; /* N */ - TBN.by = crossvec3(TBN.bz, TBN.bx); /* B */ - - n = normvec3(invrframexform3(n, TBN)); - sp->v->n = n; - } - - if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) - m.diffuse = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); - else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) - m.diffuse = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); - - ambient = mulpt3(lightc, Ka); - ambient = modulapt3(ambient, m.diffuse); - - Kd = max(0, dotvec3(n, lightdir)); - diffuse = mulpt3(lightc, Kd); - diffuse = modulapt3(diffuse, m.diffuse); - - if(sp->v->mtl != nil && sp->v->mtl->specularmap != nil && sp->v->uv.w != 0) - m.specular = sampletexture(sp->v->mtl->specularmap, sp->v->uv, tsampler); - - lookdir = normvec3(subpt3(sp->su->camera->p, pos)); - lightdir = normvec3(addpt3(lookdir, lightdir)); /* half vector */ - spec = pow(max(0, dotvec3(n, lightdir)), m.shininess); - specular = mulpt3(lightc, spec*Ks); - specular = modulapt3(specular, m.specular); - - sp->v->n.w = 1; - sp->toraster(sp, "normals", &sp->v->n); - - c = addpt3(ambient, addpt3(diffuse, specular)); - c.a = m.diffuse.a; - return c; -} - -Point3 -toonvshader(Shaderparams *sp) -{ - Point3 pos, lightdir; - double intens; - - sp->v->n = model2world(sp->su->entity, sp->v->n); - pos = model2world(sp->su->entity, sp->v->p); - lightdir = normvec3(subpt3(light.p, pos)); - intens = max(0, dotvec3(sp->v->n, lightdir)); - sp->setattr(sp, "intensity", VANumber, &intens); - if(sp->v->mtl != nil) - sp->v->c = sp->v->mtl->diffuse; - return world2clip(sp->su->camera, pos); -} - -Color -toonshader(Shaderparams *sp) -{ - Vertexattr *va; - double intens; - - va = sp->getattr(sp, "intensity"); - intens = va->n; - intens = intens > 0.85? 1: - intens > 0.60? 0.80: - intens > 0.45? 0.60: - intens > 0.30? 0.45: - intens > 0.15? 0.30: 0.15; - - sp->v->n.w = 1; - sp->toraster(sp, "normals", &sp->v->n); - - return Pt3(intens, 0.6*intens, 0, 1); -} - -Point3 -identvshader(Shaderparams *sp) -{ - if(sp->v->mtl != nil) - sp->v->c = sp->v->mtl->diffuse; - return world2clip(sp->su->camera, model2world(sp->su->entity, sp->v->p)); -} - -Color -identshader(Shaderparams *sp) -{ - Color tc; - - if(sp->su->entity->mdl->tex != nil && sp->v->uv.w != 0) - tc = sampletexture(sp->su->entity->mdl->tex, sp->v->uv, tsampler); - else if(sp->v->mtl != nil && sp->v->mtl->diffusemap != nil && sp->v->uv.w != 0) - tc = sampletexture(sp->v->mtl->diffusemap, sp->v->uv, tsampler); - else - tc = Pt3(1,1,1,1); - - sp->v->n.w = 1; - sp->toraster(sp, "normals", &sp->v->n); - - return modulapt3(sp->v->c, tc); -} - -Point3 -ivshader(Shaderparams *sp) -{ - sp->v->n = model2world(sp->su->entity, sp->v->n); - sp->v->p = model2world(sp->su->entity, sp->v->p); - return world2clip(sp->su->camera, sp->v->p); -} - -Color -triangleshader(Shaderparams *sp) -{ - Triangle2 t; - Rectangle bbox; - Point3 bc; - - t.p0 = Pt2(240,200,1); - t.p1 = Pt2(400,40,1); - t.p2 = Pt2(240,40,1); - - bbox = Rect( - min(min(t.p0.x, t.p1.x), t.p2.x), min(min(t.p0.y, t.p1.y), t.p2.y), - max(max(t.p0.x, t.p1.x), t.p2.x), max(max(t.p0.y, t.p1.y), t.p2.y) - ); - if(!ptinrect(sp->p, bbox)) - return Vec3(0,0,0); - - bc = barycoords(t, Pt2(sp->p.x,sp->p.y,1)); - if(bc.x < 0 || bc.y < 0 || bc.z < 0) - return Vec3(0,0,0); - - return Pt3(bc.x, bc.y, bc.z, 1); -} - -Color -circleshader(Shaderparams *sp) -{ - Point2 uv; - double r, d; - - uv = Pt2(sp->p.x,sp->p.y,1); - uv.x /= Dx(sp->su->fb->r); - uv.y /= Dy(sp->su->fb->r); -// r = 0.3; - r = 0.3*fabs(sin(sp->su->uni_time/1e9)); - d = vec2len(subpt2(uv, Vec2(0.5,0.5))); - - if(d > r + r*0.05 || d < r - r*0.05) - return Vec3(0,0,0); - - return Pt3(uv.x, uv.y, 0, 1); -} - -/* some shaping functions from The Book of Shaders, Chapter 5 */ -Color -sfshader(Shaderparams *sp) -{ - Point2 uv; - double y, pct; - - uv = Pt2(sp->p.x,sp->p.y,1); - uv.x /= Dx(sp->su->fb->r); - uv.y /= Dy(sp->su->fb->r); - uv.y = 1 - uv.y; /* make [0 0] the bottom-left corner */ - -// y = step(0.5, uv.x); -// y = pow(uv.x, 5); -// y = sin(uv.x); - y = sin(uv.x*sp->su->uni_time/1e8)/2.0 + 0.5; -// y = smoothstep(0.1, 0.9, uv.x); - pct = smoothstep(y-0.02, y, uv.y) - smoothstep(y, y+0.02, uv.y); - - return Pt3(flerp(y, 0, pct), flerp(y, 1, pct), flerp(y, 0, pct), 1); -} - -Color -boxshader(Shaderparams *sp) -{ - Point2 uv, p; - Point2 r; - - uv = Pt2(sp->p.x,sp->p.y,1); - uv.x /= Dx(sp->su->fb->r); - uv.y /= Dy(sp->su->fb->r); - r = Vec2(0.2,0.4); - - p = Pt2(fabs(uv.x - 0.5), fabs(uv.y - 0.5), 1); - p = subpt2(p, r); - p.x = max(p.x, 0); - p.y = max(p.y, 0); - - if(vec2len(p) > 0) - return Vec3(0,0,0); - - return Pt3(uv.x, uv.y, smoothstep(0,1,uv.x+uv.y), 1); -} - -Shadertab shadertab[] = { - { "triangle", ivshader, triangleshader }, - { "circle", ivshader, circleshader }, - { "box", ivshader, boxshader }, - { "sf", ivshader, sfshader }, - { "toon", toonvshader, toonshader }, - { "ident", identvshader, identshader }, - { "gouraud", gouraudvshader, gouraudshader }, - { "phong", phongvshader, phongshader }, - { "blinn", phongvshader, blinnshader }, -}; -Shadertab * -getshader(char *name) -{ - int i; - - for(i = 0; i < nelem(shadertab); i++) - if(strcmp(shadertab[i].name, name) == 0) - return &shadertab[i]; - return nil; -} - void zoomin(void) { |