1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
/**
** sipp - SImple Polygon Processor
**
** A general 3d graphic package
**
** Copyright Equivalent Software HB 1992
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 1, or any later version.
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
** You can receive a copy of the GNU General Public License from the
** Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**/
/**
** strauss.c - Shading model designed by Paul S. Strauss
** Silicon Graphics Inc.
** Described in IEEE CG&A November 1990.
**
** Implemented for SIPP by Jonas Yngvesson
**/
#include <math.h>
#include <sipp.h>
#include <shaders.h>
#include <geometric.h>
/*
* Strauss describes, in his article, two functions that simulates
* fresnel reflection and geometric attenuation. These functions
* are dependent of an angle between 0 and pi/2 normalized to the
* range (0.0, 1.0). He also mentions that he uses versions of the
* functions that depend on the cosine of an angle instead (since
* that can be calculated with a dot product).
* These versions are not described in the article so I have empirically
* tried to recreate them. I don't know if this bears any resemblence
* to what he used, so any errors are my fault.
*
* What i did was only to change x in the functions to (1 - x) and modify
* the Kf and Kg constants slightly. The original values in the article
* was: Kf = 1.12, Kg = 1.02
*/
#define Kf 1.2 /* Factor used in approximation of fresnel reflection */
#define Kg 1.031 /* Factor used in approximation of geometric attenuation */
/*
* Function to simulate fresnel reflection.
*/
#define FR(x) ((1.0/((1.0-(x)-Kf)*(1.0-(x)-Kf))-1.0/(Kf*Kf))\
/(1.0/((1.0-Kf)*(1.0-Kf))-1.0/(Kf*Kf)))
/*
* Function to simulate geometric attenuation.
*/
#define GA(x) ((1.0/((1.0-Kg)*(1.0-Kg))-1.0/((1.0-(x)-Kg)*(1.0-(x)-Kg)))\
/(1.0/((1.0-Kg)*(1.0-Kg))-1.0/(Kg*Kg)))
void
strauss_shader(pos, normal, texture, view_vec, lights, sd, color, opacity)
Vector *pos;
Vector *normal;
Vector *texture;
Vector *view_vec;
Lightsource *lights;
Strauss_desc *sd;
Color *color;
Color *opacity;
{
Vector unit_normal; /* Normalized surface normal */
Vector highlight; /* Highlight vector */
double c_alpha; /* cos(angle between normal and lightvector) */
double c_beta; /* cos(angle between highlight & view_vec) */
double c_gamma; /* cos(angle between normal & view_vec) */
double rd; /* Diffuse reflectivity */
double rs; /* Specular reflectivity */
double rj; /* Adjusted specular reflectivity */
double rn; /* Specular reflectivity at normal incidence */
double h; /* Shininess exponent */
Vector qd; /* Diffuse reflection factor */
Vector qs; /* Specular reflection factor */
Vector light_dir; /* Direction to "current" light */
double light_factor; /* Fraction of light from "current" light */
Color col; /* Resulting color */
Lightsource *lp;
VecCopy(unit_normal, *normal);
vecnorm(&unit_normal);
c_gamma = VecDot(unit_normal, *view_vec);
col.red = col.grn = col.blu = 0.0;
rd = 1.0 - sd->smoothness * sd->smoothness * sd->smoothness;
for (lp = lights; lp != (Lightsource *)0; lp = lp->next) {
light_factor = light_eval(lp, pos, &light_dir);
c_alpha = VecDot(unit_normal, light_dir);
if (c_alpha >= 0) {
VecScalMul(highlight, 2 * c_alpha, unit_normal);
VecSub(highlight, highlight, light_dir);
c_beta = VecDot(highlight, *view_vec);
MakeVector(qd, sd->color.red, sd->color.grn, sd->color.blu);
VecScalMul(qd, (c_alpha * rd
* (1.0 - sd->metalness * sd->smoothness)), qd);
if (c_beta >= 0) {
h = 3 / (1.0 - sd->smoothness);
rn = 1.0 - rd;
rj = rn + (rn + 0.1) * FR(c_alpha) * GA(c_alpha) * GA(c_gamma);
if (rj > 1.0) {
rj = 1.0;
}
rs = exp(h * log(c_beta)) * rj;
MakeVector(qs,
sd->color.red - 1.0,
sd->color.grn - 1.0,
sd->color.blu - 1.0);
VecScalMul(qs, sd->metalness * (1.0 - FR(c_alpha)), qs);
qs.x += 1.0;
qs.y += 1.0;
qs.z += 1.0;
VecScalMul(qs, rs, qs);
VecAdd(qd, qd, qs);
}
/* VecScalMul(qd, lp->intensity, qd);*/
qd.x = lp->color.red * qd.x;
qd.y = lp->color.grn * qd.y;
qd.z = lp->color.blu * qd.z;
col.red += qd.x;
col.grn += qd.y;
col.blu += qd.z;
}
}
col.red += sd->ambient * rd * sd->color.red;
col.grn += sd->ambient * rd * sd->color.grn;
col.blu += sd->ambient * rd * sd->color.blu;
color->red = ((col.red > 1.0) ? 1.0 : col.red);
color->grn = ((col.grn > 1.0) ? 1.0 : col.grn);
color->blu = ((col.blu > 1.0) ? 1.0 : col.blu);
opacity->red = sd->opacity.red;
opacity->grn = sd->opacity.grn;
opacity->blu = sd->opacity.blu;
}
|