1d86ed7fbStbbdev /*
2*b15aabb3Stbbdev Copyright (c) 2005-2021 Intel Corporation
3d86ed7fbStbbdev
4d86ed7fbStbbdev Licensed under the Apache License, Version 2.0 (the "License");
5d86ed7fbStbbdev you may not use this file except in compliance with the License.
6d86ed7fbStbbdev You may obtain a copy of the License at
7d86ed7fbStbbdev
8d86ed7fbStbbdev http://www.apache.org/licenses/LICENSE-2.0
9d86ed7fbStbbdev
10d86ed7fbStbbdev Unless required by applicable law or agreed to in writing, software
11d86ed7fbStbbdev distributed under the License is distributed on an "AS IS" BASIS,
12d86ed7fbStbbdev WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d86ed7fbStbbdev See the License for the specific language governing permissions and
14d86ed7fbStbbdev limitations under the License.
15d86ed7fbStbbdev */
16d86ed7fbStbbdev
17d86ed7fbStbbdev /*
18d86ed7fbStbbdev The original source for this example is
19d86ed7fbStbbdev Copyright (c) 1994-2008 John E. Stone
20d86ed7fbStbbdev All rights reserved.
21d86ed7fbStbbdev
22d86ed7fbStbbdev Redistribution and use in source and binary forms, with or without
23d86ed7fbStbbdev modification, are permitted provided that the following conditions
24d86ed7fbStbbdev are met:
25d86ed7fbStbbdev 1. Redistributions of source code must retain the above copyright
26d86ed7fbStbbdev notice, this list of conditions and the following disclaimer.
27d86ed7fbStbbdev 2. Redistributions in binary form must reproduce the above copyright
28d86ed7fbStbbdev notice, this list of conditions and the following disclaimer in the
29d86ed7fbStbbdev documentation and/or other materials provided with the distribution.
30d86ed7fbStbbdev 3. The name of the author may not be used to endorse or promote products
31d86ed7fbStbbdev derived from this software without specific prior written permission.
32d86ed7fbStbbdev
33d86ed7fbStbbdev THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
34d86ed7fbStbbdev OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35d86ed7fbStbbdev WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36d86ed7fbStbbdev ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
37d86ed7fbStbbdev DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38d86ed7fbStbbdev DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39d86ed7fbStbbdev OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40d86ed7fbStbbdev HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41d86ed7fbStbbdev LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42d86ed7fbStbbdev OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43d86ed7fbStbbdev SUCH DAMAGE.
44d86ed7fbStbbdev */
45d86ed7fbStbbdev
46d86ed7fbStbbdev /*
47d86ed7fbStbbdev * shade.cpp - This file contains the functions that perform surface shading.
48d86ed7fbStbbdev */
49d86ed7fbStbbdev
50d86ed7fbStbbdev #include "machine.hpp"
51d86ed7fbStbbdev #include "types.hpp"
52d86ed7fbStbbdev #include "macros.hpp"
53d86ed7fbStbbdev #include "light.hpp"
54d86ed7fbStbbdev #include "intersect.hpp"
55d86ed7fbStbbdev #include "vector.hpp"
56d86ed7fbStbbdev #include "trace.hpp"
57d86ed7fbStbbdev #include "global.hpp"
58d86ed7fbStbbdev #include "shade.hpp"
59d86ed7fbStbbdev
reset_lights(void)60d86ed7fbStbbdev void reset_lights(void) {
61d86ed7fbStbbdev numlights = 0;
62d86ed7fbStbbdev }
63d86ed7fbStbbdev
add_light(point_light * li)64d86ed7fbStbbdev void add_light(point_light* li) {
65d86ed7fbStbbdev lightlist[numlights] = li;
66d86ed7fbStbbdev numlights++;
67d86ed7fbStbbdev }
68d86ed7fbStbbdev
shader(ray * incident)69d86ed7fbStbbdev color shader(ray* incident) {
70d86ed7fbStbbdev color col, diffuse, phongcol;
71d86ed7fbStbbdev vector N, L, hit;
72d86ed7fbStbbdev ray shadowray;
73d86ed7fbStbbdev flt inten, t, Llen;
74d86ed7fbStbbdev object* obj;
75d86ed7fbStbbdev int numints, i;
76d86ed7fbStbbdev point_light* li;
77d86ed7fbStbbdev
78d86ed7fbStbbdev numints = closest_intersection(&t, &obj, incident->intstruct);
79d86ed7fbStbbdev /* find the number of intersections */
80d86ed7fbStbbdev /* and return the closest one. */
81d86ed7fbStbbdev
82d86ed7fbStbbdev if (numints < 1) {
83d86ed7fbStbbdev /* if there weren't any object intersections then return the */
84d86ed7fbStbbdev /* background color for the pixel color. */
85d86ed7fbStbbdev return incident->scene->background;
86d86ed7fbStbbdev }
87d86ed7fbStbbdev
88d86ed7fbStbbdev if (obj->tex->islight) { /* if the current object is a light, then we */
89d86ed7fbStbbdev return obj->tex->col; /* will only use the objects ambient color */
90d86ed7fbStbbdev }
91d86ed7fbStbbdev
92d86ed7fbStbbdev RAYPNT(hit, (*incident), t) /* find the point of intersection from t */
93d86ed7fbStbbdev obj->methods->normal(obj, &hit, incident, &N); /* find the surface normal */
94d86ed7fbStbbdev
95d86ed7fbStbbdev /* execute the object's texture function */
96d86ed7fbStbbdev col = obj->tex->texfunc(&hit, obj->tex, incident);
97d86ed7fbStbbdev
98d86ed7fbStbbdev diffuse.r = 0.0;
99d86ed7fbStbbdev diffuse.g = 0.0;
100d86ed7fbStbbdev diffuse.b = 0.0;
101d86ed7fbStbbdev phongcol = diffuse;
102d86ed7fbStbbdev
103d86ed7fbStbbdev if ((obj->tex->diffuse > 0.0) || (obj->tex->phong > 0.0)) {
104d86ed7fbStbbdev for (i = 0; i < numlights; i++) { /* loop for light contributions */
105d86ed7fbStbbdev li = lightlist[i]; /* set li=to the current light */
106d86ed7fbStbbdev VSUB(li->ctr, hit, L) /* find the light vector */
107d86ed7fbStbbdev
108d86ed7fbStbbdev /* calculate the distance to the light from the hit point */
109d86ed7fbStbbdev Llen = sqrt(L.x * L.x + L.y * L.y + L.z * L.z) + EPSILON;
110d86ed7fbStbbdev
111d86ed7fbStbbdev L.x /= Llen; /* normalize the light direction vector */
112d86ed7fbStbbdev L.y /= Llen;
113d86ed7fbStbbdev L.z /= Llen;
114d86ed7fbStbbdev
115d86ed7fbStbbdev VDOT(inten, N, L) /* light intensity */
116d86ed7fbStbbdev
117d86ed7fbStbbdev /* add in diffuse lighting for this light if we're facing it */
118d86ed7fbStbbdev if (inten > 0.0) {
119d86ed7fbStbbdev /* test for a shadow */
120d86ed7fbStbbdev shadowray.intstruct = incident->intstruct;
121d86ed7fbStbbdev shadowray.flags = RT_RAY_SHADOW | RT_RAY_BOUNDED;
122d86ed7fbStbbdev incident->serial++;
123d86ed7fbStbbdev shadowray.serial = incident->serial;
124d86ed7fbStbbdev shadowray.mbox = incident->mbox;
125d86ed7fbStbbdev shadowray.o = hit;
126d86ed7fbStbbdev shadowray.d = L;
127d86ed7fbStbbdev shadowray.maxdist = Llen;
128d86ed7fbStbbdev shadowray.s = hit;
129d86ed7fbStbbdev shadowray.e = li->ctr;
130d86ed7fbStbbdev shadowray.scene = incident->scene;
131d86ed7fbStbbdev reset_intersection(incident->intstruct);
132d86ed7fbStbbdev intersect_objects(&shadowray);
133d86ed7fbStbbdev
134d86ed7fbStbbdev if (!shadow_intersection(incident->intstruct, Llen)) {
135d86ed7fbStbbdev /* XXX now that opacity is in the code, have to be more careful */
136d86ed7fbStbbdev ColorAddS(&diffuse, &li->tex->col, inten);
137d86ed7fbStbbdev
138d86ed7fbStbbdev /* phong type specular highlights */
139d86ed7fbStbbdev if (obj->tex->phong > 0.0) {
140d86ed7fbStbbdev flt phongval;
141d86ed7fbStbbdev phongval = shade_phong(incident, &hit, &N, &L, obj->tex->phongexp);
142d86ed7fbStbbdev if (obj->tex->phongtype)
143d86ed7fbStbbdev ColorAddS(&phongcol, &col, phongval);
144d86ed7fbStbbdev else
145d86ed7fbStbbdev ColorAddS(&phongcol, &(li->tex->col), phongval);
146d86ed7fbStbbdev }
147d86ed7fbStbbdev }
148d86ed7fbStbbdev }
149d86ed7fbStbbdev }
150d86ed7fbStbbdev }
151d86ed7fbStbbdev
152d86ed7fbStbbdev ColorScale(&diffuse, obj->tex->diffuse);
153d86ed7fbStbbdev
154d86ed7fbStbbdev col.r *= (diffuse.r + obj->tex->ambient); /* do a product of the */
155d86ed7fbStbbdev col.g *= (diffuse.g + obj->tex->ambient); /* diffuse intensity with */
156d86ed7fbStbbdev col.b *= (diffuse.b + obj->tex->ambient); /* object color + ambient */
157d86ed7fbStbbdev
158d86ed7fbStbbdev if (obj->tex->phong > 0.0) {
159d86ed7fbStbbdev ColorAccum(&col, &phongcol);
160d86ed7fbStbbdev }
161d86ed7fbStbbdev
162d86ed7fbStbbdev /* spawn reflection rays if necessary */
163d86ed7fbStbbdev /* note: this will overwrite the old intersection list */
164d86ed7fbStbbdev if (obj->tex->specular > 0.0) {
165d86ed7fbStbbdev color specol;
166d86ed7fbStbbdev specol = shade_reflection(incident, &hit, &N, obj->tex->specular);
167d86ed7fbStbbdev ColorAccum(&col, &specol);
168d86ed7fbStbbdev }
169d86ed7fbStbbdev
170d86ed7fbStbbdev /* spawn transmission rays / refraction */
171d86ed7fbStbbdev /* note: this will overwrite the old intersection list */
172d86ed7fbStbbdev if (obj->tex->opacity < 1.0) {
173d86ed7fbStbbdev color transcol;
174d86ed7fbStbbdev transcol = shade_transmission(incident, &hit, 1.0 - obj->tex->opacity);
175d86ed7fbStbbdev ColorAccum(&col, &transcol);
176d86ed7fbStbbdev }
177d86ed7fbStbbdev
178d86ed7fbStbbdev return col; /* return the color of the shaded pixel... */
179d86ed7fbStbbdev }
180d86ed7fbStbbdev
shade_reflection(ray * incident,vector * hit,vector * N,flt specular)181d86ed7fbStbbdev color shade_reflection(ray* incident, vector* hit, vector* N, flt specular) {
182d86ed7fbStbbdev ray specray;
183d86ed7fbStbbdev color col;
184d86ed7fbStbbdev vector R;
185d86ed7fbStbbdev
186d86ed7fbStbbdev VAddS(-2.0 * (incident->d.x * N->x + incident->d.y * N->y + incident->d.z * N->z),
187d86ed7fbStbbdev N,
188d86ed7fbStbbdev &incident->d,
189d86ed7fbStbbdev &R);
190d86ed7fbStbbdev
191d86ed7fbStbbdev specray.intstruct = incident->intstruct; /* what thread are we */
192d86ed7fbStbbdev specray.depth = incident->depth - 1; /* go up a level in recursion depth */
193d86ed7fbStbbdev specray.flags = RT_RAY_REGULAR; /* infinite ray, to start with */
194d86ed7fbStbbdev specray.serial = incident->serial + 1; /* next serial number */
195d86ed7fbStbbdev specray.mbox = incident->mbox;
196d86ed7fbStbbdev specray.o = *hit;
197d86ed7fbStbbdev specray.d = R; /* reflect incident ray about normal */
198d86ed7fbStbbdev specray.o = Raypnt(&specray, EPSILON); /* avoid numerical precision bugs */
199d86ed7fbStbbdev specray.maxdist = FHUGE; /* take any intersection */
200d86ed7fbStbbdev specray.scene = incident->scene; /* global scenedef info */
201d86ed7fbStbbdev col = trace(&specray); /* trace specular reflection ray */
202d86ed7fbStbbdev
203d86ed7fbStbbdev incident->serial = specray.serial; /* update the serial number */
204d86ed7fbStbbdev
205d86ed7fbStbbdev ColorScale(&col, specular);
206d86ed7fbStbbdev
207d86ed7fbStbbdev return col;
208d86ed7fbStbbdev }
209d86ed7fbStbbdev
shade_transmission(ray * incident,vector * hit,flt trans)210d86ed7fbStbbdev color shade_transmission(ray* incident, vector* hit, flt trans) {
211d86ed7fbStbbdev ray transray;
212d86ed7fbStbbdev color col;
213d86ed7fbStbbdev
214d86ed7fbStbbdev transray.intstruct = incident->intstruct; /* what thread are we */
215d86ed7fbStbbdev transray.depth = incident->depth - 1; /* go up a level in recursion depth */
216d86ed7fbStbbdev transray.flags = RT_RAY_REGULAR; /* infinite ray, to start with */
217d86ed7fbStbbdev transray.serial = incident->serial + 1; /* update serial number */
218d86ed7fbStbbdev transray.mbox = incident->mbox;
219d86ed7fbStbbdev transray.o = *hit;
220d86ed7fbStbbdev transray.d = incident->d; /* ray continues along incident path */
221d86ed7fbStbbdev transray.o = Raypnt(&transray, EPSILON); /* avoid numerical precision bugs */
222d86ed7fbStbbdev transray.maxdist = FHUGE; /* take any intersection */
223d86ed7fbStbbdev transray.scene = incident->scene; /* global scenedef info */
224d86ed7fbStbbdev col = trace(&transray); /* trace transmission ray */
225d86ed7fbStbbdev
226d86ed7fbStbbdev incident->serial = transray.serial;
227d86ed7fbStbbdev
228d86ed7fbStbbdev ColorScale(&col, trans);
229d86ed7fbStbbdev
230d86ed7fbStbbdev return col;
231d86ed7fbStbbdev }
232d86ed7fbStbbdev
shade_phong(ray * incident,vector * hit,vector * N,vector * L,flt specpower)233d86ed7fbStbbdev flt shade_phong(ray* incident, vector* hit, vector* N, vector* L, flt specpower) {
234d86ed7fbStbbdev vector H, V;
235d86ed7fbStbbdev flt inten;
236d86ed7fbStbbdev
237d86ed7fbStbbdev V = incident->d;
238d86ed7fbStbbdev VScale(&V, -1.0);
239d86ed7fbStbbdev VAdd(&V, L, &H);
240d86ed7fbStbbdev VScale(&H, 0.5);
241d86ed7fbStbbdev VNorm(&H);
242d86ed7fbStbbdev inten = VDot(N, &H);
243d86ed7fbStbbdev if (inten > 0.0)
244d86ed7fbStbbdev inten = pow(inten, specpower);
245d86ed7fbStbbdev else
246d86ed7fbStbbdev inten = 0.0;
247d86ed7fbStbbdev
248d86ed7fbStbbdev return inten;
249d86ed7fbStbbdev }
250