From cdb4aca6643ebde7cfb7af332cb323ba2afacf15 Mon Sep 17 00:00:00 2001 From: rodri Date: Sat, 21 Sep 2024 11:44:08 +0000 Subject: put all the shaders in a single file. --- shaders.inc | 421 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 421 insertions(+) create mode 100644 shaders.inc (limited to 'shaders.inc') 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; +} -- cgit v1.2.3