ref: 1bc7f0b665afa19c97314f8e4606407d4ead470f
dir: /shaders.inc/
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; LightSource *l; 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; } lightc = getscenecolor(sp->su->camera->scene, pos, sp->v->n); sp->v->c = Vec3(0,0,0); for(l = sp->su->camera->scene->lights.next; l != &sp->su->camera->scene->lights; l = l->next){ lightdir = normvec3(subpt3(l->p, pos)); 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); /* reflect */ spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess); specular = mulpt3(lightc, spec*Ks); specular = modulapt3(specular, m.specular); sp->v->c = addpt3(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->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; LightSource *l; 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; /* 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)); } 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); 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); lightc = getscenecolor(sp->su->camera->scene, pos, n); c = Vec3(0,0,0); for(l = sp->su->camera->scene->lights.next; l != &sp->su->camera->scene->lights; l = l->next){ lightdir = normvec3(subpt3(l->p, pos)); ambient = mulpt3(lightc, Ka); ambient = modulapt3(ambient, m.diffuse); Kd = max(0, dotvec3(n, lightdir)); diffuse = mulpt3(lightc, Kd); diffuse = modulapt3(diffuse, m.diffuse); lookdir = normvec3(subpt3(sp->su->camera->p, pos)); lightdir = qrotate(lightdir, n, PI); /* reflect */ spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess); specular = mulpt3(lightc, spec*Ks); specular = modulapt3(specular, m.specular); c = addpt3(c, addpt3(ambient, addpt3(diffuse, specular))); } c.a = m.diffuse.a; n.w = 1; sp->toraster(sp, "normals", &n); specular.a = 1; sp->toraster(sp, "specular", &specular); 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; LightSource *l; 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; /* 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)); } 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); 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); lightc = getscenecolor(sp->su->camera->scene, pos, n); c = Vec3(0,0,0); for(l = sp->su->camera->scene->lights.next; l != &sp->su->camera->scene->lights; l = l->next){ lightdir = normvec3(subpt3(l->p, pos)); ambient = mulpt3(lightc, Ka); ambient = modulapt3(ambient, m.diffuse); Kd = max(0, dotvec3(n, lightdir)); diffuse = mulpt3(lightc, Kd); diffuse = modulapt3(diffuse, m.diffuse); lookdir = normvec3(subpt3(sp->su->camera->p, pos)); lightdir = normvec3(addpt3(lookdir, lightdir)); /* half vector */ spec = pow(max(0, dotvec3(lookdir, lightdir)), m.shininess); specular = mulpt3(lightc, spec*Ks); specular = modulapt3(specular, m.specular); c = addpt3(c, addpt3(ambient, addpt3(diffuse, specular))); } c.a = m.diffuse.a; n.w = 1; sp->toraster(sp, "normals", &n); specular.a = 1; sp->toraster(sp, "specular", &specular); return c; } Point3 toonvshader(Shaderparams *sp) { Point3 pos, lightdir; LightSource *l; double intens; sp->v->n = model2world(sp->su->entity, sp->v->n); pos = model2world(sp->su->entity, sp->v->p); intens = 0; for(l = sp->su->camera->scene->lights.next; l != &sp->su->camera->scene->lights; l = l->next){ lightdir = normvec3(subpt3(l->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->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); /* wireframe version */ enum { THICKNESS = 8 }; Point2 p01, p12, p20; double d01, d12, d20, d; Point2 p, v, r; p01 = subpt2(t.p1, t.p0); p12 = subpt2(t.p2, t.p1); p20 = subpt2(t.p0, t.p2); p = Pt2(sp->p.x, sp->p.y, 1); r = subpt2(t.p0, p); v = Vec2(p01.y, -p01.x); d01 = fabs(dotvec2(v, r)); r = subpt2(t.p1, p); v = Vec2(p12.y, -p12.x); d12 = fabs(dotvec2(v, r)); r = subpt2(t.p2, p); v = Vec2(p20.y, -p20.x); d20 = fabs(dotvec2(v, r)); d = min(d01, min(d12, d20)); if(d > THICKNESS) return Vec3(0,0,0); return Pt3(bc.x, bc.y, bc.z, 1); } Color circleshader(Shaderparams *sp) { Vertexattr *va; Point2 uv; double r, d, time; uv = Pt2(sp->p.x,sp->p.y,1); uv.x /= Dx(sp->su->fb->r); uv.y /= Dy(sp->su->fb->r); va = sp->getuniform(sp, "time"); time = va == nil? 0: va->n; // r = 0.3; r = 0.3*fabs(sin(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) { Vertexattr *va; Point2 uv; double y, pct, time; 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 */ va = sp->getuniform(sp, "time"); time = va == nil? 0: va->n; // y = step(0.5, uv.x); // y = pow(uv.x, 5); // y = sin(uv.x); y = sin(uv.x*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; }