File: strauss.c

package info (click to toggle)
sipp 3.1-2
  • links: PTS
  • area: main
  • in suites: potato, slink
  • size: 1,256 kB
  • ctags: 743
  • sloc: ansic: 8,534; makefile: 301; lex: 69; sh: 2
file content (166 lines) | stat: -rw-r--r-- 5,946 bytes parent folder | download | duplicates (4)
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;
}