File: CarPaint.ispc

package info (click to toggle)
ospray 3.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,048 kB
  • sloc: cpp: 80,569; ansic: 951; sh: 805; makefile: 170; python: 69
file content (374 lines) | stat: -rw-r--r-- 11,634 bytes parent folder | download | duplicates (2)
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
// Copyright 2009 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "CarPaint.ih"

#include "common/Ray.ih"
#include "render/Material.ih"
#include "render/bsdfs/Conductor.ih"
#include "render/bsdfs/DielectricLayer.ih"
#include "render/bsdfs/Lambert.ih"
#include "render/bsdfs/MicrofacetConductor.ih"
#include "render/bsdfs/MicrofacetDielectricLayer.ih"
#include "render/bsdfs/OrenNayar.ih"
#include "render/bsdfs/PassthroughLayer.ih"
#include "render/shaders/Flakes.ih"
#include "texture/TextureParam.ih"
// c++ shared
#include "CarPaintShared.h"

///////////////////////////////////////////////////////////////////////////////
// Implementation

OSPRAY_BEGIN_ISPC_NAMESPACE

struct CarPaint_BSDF
{
  BSDF root;
  MicrofacetDielectricLayer dielectricLayer;
  int flakeMask;
  MicrofacetConductor conductor;
  OrenNayar baseDiffuse;
};

SYCL_EXTERNAL const varying BSDF *uniform CarPaint_getBSDF(
    const uniform Material *uniform super,
    uniform ShadingContext *uniform ctx,
    const DifferentialGeometry &dg,
    const Ray &ray,
    const Medium &,
    const uniform FeatureFlagsHandler &)
{
  const uniform CarPaint *uniform self = (const uniform CarPaint *uniform)super;

  varying linear3f *uniform frame = LinearSpace3f_create(ctx,
      makeShadingFrame(dg, self->normalMap, self->normalRot, self->normal));

  // Allocate memory and initialize material BSDF
  varying CarPaint_BSDF *uniform bsdf = (varying CarPaint_BSDF * uniform)
      ShadingContext_alloc(ctx, sizeof(CarPaint_BSDF));

  const float flakeDensity =
      clamp(self->flakeDensity * get1f(self->flakeDensityMap, dg, 1.f));
  int flakeMask = 0;
  varying linear3f *uniform flakeFrame = NULL;

  varying BSDF *varying substrate = NULL;

  // metallic flakes in the clear coat layer
  if (flakeDensity > EPS) {
    const float flakeScale =
        max(self->flakeScale * get1f(self->flakeScaleMap, dg, 1.f), 0.f);
    const float flakeSpread =
        max(self->flakeSpread * get1f(self->flakeSpreadMap, dg, 1.f), 0.f);
    const float flakeJitter =
        clamp(self->flakeJitter * get1f(self->flakeJitterMap, dg, 1.f));

    Flakes flakes;
    flakes.scale = flakeScale;
    flakes.density = flakeDensity;
    flakes.spread = flakeSpread;
    flakes.jitter = flakeJitter;

    const vec3f flakeN = Flakes_eval(flakes, dg.P, flakeMask);
    if (flakeMask) {
      flakeFrame = LinearSpace3f_create(ctx, makeShadingFrame(dg, flakeN));

      Fresnel *uniform flakeFresnel;
      if (self->useFlakeColor) {
        const vec3f r = clamp(
            self->flakeColor * get3f(self->flakeColorMap, dg, make_vec3f(1.f)));
        const vec3f g = make_vec3f(1.f);
        flakeFresnel = FresnelSchlick_create(ctx, r, g);
      } else {
        // flakes are made of aluminum
        const uniform vec3f flakeEta =
            make_vec3f(1.69700277f, 0.879832864f, 0.5301736f);
        const uniform vec3f flakeK =
            make_vec3f(9.30200672f, 6.27604008f, 4.89433956f);
        flakeFresnel = FresnelConductorRGBUniform_create(ctx, flakeEta, flakeK);
      }

      if (self->flakeRoughness < EPS)
        Conductor_Constructor((varying Conductor * uniform) & bsdf->conductor,
            flakeFrame,
            flakeFresnel);
      else
        MicrofacetConductor_Constructor(&bsdf->conductor,
            super->microfacetAlbedoTables,
            flakeFrame,
            flakeFresnel,
            max(self->flakeRoughness * get1f(self->flakeRoughnessMap, dg, 1.f),
                0.f),
            0.f);

      substrate = &bsdf->conductor.super;
    }
  }

  // base diffuse layer
  if (!flakeMask) {
    const vec3f baseColor =
        clamp(self->baseColor * get3f(self->baseColorMap, dg, make_vec3f(1.f))
            * make_vec3f(dg.color));

    if (self->roughness < EPS)
      Lambert_Constructor(
          (varying BSDF * uniform) & bsdf->baseDiffuse, frame, baseColor);
    else
      OrenNayar_Constructor(&bsdf->baseDiffuse,
          frame,
          baseColor,
          max(self->roughness * get1f(self->roughnessMap, dg, 1.f), 0.f));

    substrate = &bsdf->baseDiffuse.super;
  }
  bsdf->flakeMask = flakeMask;

  // clear coat layer
  if ((self->coat > EPS)
      && (abs(self->coatIor - 1.f) > EPS || valid(self->coatIorMap))) {
    const float coat = max(self->coat * get1f(self->coatMap, dg, 1.f), 0.f);
    float coatIor = self->coatIor * get1f(self->coatIorMap, dg, 1.f);
    if (coatIor < 1.f)
      coatIor = rcp(coatIor);
    coatIor = clamp(coatIor, 1.f, 3.f); // clamp to common range due to LUTs

    // compute the final coat color
    const vec3f coatColor =
        clamp(self->coatColor * get3f(self->coatColorMap, dg, make_vec3f(1.f)));
    vec3f coatFinalColor = coatColor;
    if (flakeMask) {
      const float flipflopFalloff = clamp(
          self->flipflopFalloff * get1f(self->flipflopFalloffMap, dg, 1.f));
      if (flipflopFalloff < 1.f - EPS) {
        // pearlescent flakes
        const vec3f flipflopColor = clamp(self->flipflopColor
            * get3f(self->flipflopColorMap, dg, make_vec3f(1.f)));
        const float cosThetaO = max(-dot(ray.dir, flakeFrame->vz), 0.f);
        const float weight = pow(1.f - cosThetaO,
            rcp(1.f - flipflopFalloff)); // use Schlick for the blending weight
        coatFinalColor = lerp(weight, coatColor, flipflopColor);
      }
    }

    const float coatThickness =
        max(self->coatThickness * get1f(self->coatThicknessMap, dg, 1.f), 0.f);
    varying linear3f *uniform coatFrame = LinearSpace3f_create(ctx,
        makeShadingFrame(
            dg, self->coatNormalMap, self->coatNormalRot, self->coatNormal));

    if (self->coatRoughness < EPS) {
      DielectricLayer_Constructor(
          (varying DielectricLayer * uniform) & bsdf->dielectricLayer,
          coatFrame,
          substrate,
          rcp(coatIor),
          coatFinalColor,
          coatThickness,
          coat);
    } else {
      MicrofacetDielectricLayer_Constructor(&bsdf->dielectricLayer,
          super->microfacetAlbedoTables,
          coatFrame,
          substrate,
          rcp(coatIor),
          coatFinalColor,
          coatThickness,
          max(self->coatRoughness * get1f(self->coatRoughnessMap, dg, 1.f),
              0.f),
          0.f,
          coat);
    }
  } else {
    PassthroughLayer_Constructor(
        (varying PassthroughLayer * uniform) & bsdf->dielectricLayer,
        substrate);
  }

  bsdf->root = bsdf->dielectricLayer.super;
  bsdf->root.bsdfType = BSDF_TYPE_CARPAINT;
  return &bsdf->root;
}

// Conductor BSDF

inline BSDF_EvalRes ConductorBSDF_eval(
    const varying MicrofacetConductor *uniform self,
    const vec3f &wo,
    const vec3f &wi)
{
  if (self->super.bsdfType == BSDF_TYPE_MICROFACET_CONDUCTOR)
    return MicrofacetConductor_eval(self, wo, wi);
  else
    return make_BSDF_EvalRes_zero();
}

inline BSDF_SampleRes ConductorBSDF_sample(
    const varying MicrofacetConductor *uniform self,
    const vec3f &wo,
    const vec2f &s,
    float ss)
{
  if (self->super.bsdfType == BSDF_TYPE_MICROFACET_CONDUCTOR)
    return MicrofacetConductor_sample(self, wo, s, ss);
  else
    return Conductor_sample(&self->super, wo, s, ss);
}

// Diffuse BSDF

inline BSDF_EvalRes DiffuseBSDF_eval(
    const varying OrenNayar *uniform self, const vec3f &wo, const vec3f &wi)
{
  if (self->super.bsdfType == BSDF_TYPE_OREN_NAYAR)
    return OrenNayar_eval(&self->super, wo, wi);
  else
    return Lambert_eval(&self->super, wo, wi);
}

inline BSDF_SampleRes DiffuseBSDF_sample(const varying OrenNayar *uniform self,
    const vec3f &wo,
    const vec2f &s,
    float ss)
{
  if (self->super.bsdfType == BSDF_TYPE_OREN_NAYAR)
    return OrenNayar_sample(&self->super, wo, s, ss);
  else
    return Lambert_sample(&self->super, wo, s, ss);
}

// Base layer BSDF

__noinline BSDF_EvalRes BaseBSDF_eval(
    const varying CarPaint_BSDF *uniform self, const vec3f &wo, const vec3f &wi)
{
  if (self->flakeMask) {
    return ConductorBSDF_eval(&self->conductor, wo, wi);
  } else {
    return DiffuseBSDF_eval(&self->baseDiffuse, wo, wi);
  }
}

__noinline BSDF_SampleRes BaseBSDF_sample(
    const varying CarPaint_BSDF *uniform self,
    const vec3f &wo,
    const vec2f &s,
    float ss)
{
  if (self->flakeMask) {
    return ConductorBSDF_sample(&self->conductor, wo, s, ss);
  } else {
    return DiffuseBSDF_sample(&self->baseDiffuse, wo, s, ss);
  }
}

// DielectricLayer BSDF

inline BSDF_EvalRes DielectricLayerBSDF_eval(
    const varying CarPaint_BSDF *uniform self, const vec3f &wo, const vec3f &wi)
{
  BSDFScatteringType scatteringType = (self->flakeMask)
      ? self->conductor.super.scatteringType
      : self->baseDiffuse.super.scatteringType;

  DIELECTRICLAYER_EVAL(
      self->dielectricLayer, scatteringType, self, BaseBSDF_eval);
  return DIELECTRICLAYER_EVAL_GET();
}

inline BSDF_SampleRes DielectricLayerBSDF_sample(
    const varying CarPaint_BSDF *uniform self,
    const vec3f &wo,
    const vec2f &s,
    float ss)
{
  BSDFScatteringType scatteringType = (self->flakeMask)
      ? self->conductor.super.scatteringType
      : self->baseDiffuse.super.scatteringType;

  DIELECTRICLAYER_SAMPLE(
      self->dielectricLayer, scatteringType, self, BaseBSDF_sample);
  return DIELECTRICLAYER_SAMPLE_GET();
}

// MicrofacetDielectricLayer BSDF

inline BSDF_EvalRes MicrofacetDielectricLayerBSDF_eval(
    const varying CarPaint_BSDF *uniform self, const vec3f &wo, const vec3f &wi)
{
  BSDFScatteringType scatteringType = (self->flakeMask)
      ? self->conductor.super.scatteringType
      : self->baseDiffuse.super.scatteringType;

  MICROFACETDIELECTRICLAYER_EVAL(
      self->dielectricLayer, scatteringType, self, BaseBSDF_eval);
  return MICROFACETDIELECTRICLAYER_EVAL_GET();
}

inline BSDF_SampleRes MicrofacetDielectricLayerBSDF_sample(
    const varying CarPaint_BSDF *uniform self,
    const vec3f &wo,
    const vec2f &s,
    float ss)
{
  BSDFScatteringType scatteringType = (self->flakeMask)
      ? self->conductor.super.scatteringType
      : self->baseDiffuse.super.scatteringType;

  MICROFACETDIELECTRICLAYER_SAMPLE(self->dielectricLayer,
      scatteringType,
      self,
      BaseBSDF_eval,
      BaseBSDF_sample);
  return MICROFACETDIELECTRICLAYER_SAMPLE_GET();
}

// CarPaint BSDF

SYCL_EXTERNAL BSDF_EvalRes CarPaint_BSDF_eval(
    const varying BSDF *uniform super, const vec3f &wo, const vec3f &wi)
{
  const varying CarPaint_BSDF *uniform self =
      (const varying CarPaint_BSDF *uniform)super;

  // Skip dielectric layer if no clear coat
  if (self->dielectricLayer.weight < EPS)
    return BaseBSDF_eval(self, wo, wi);

  if (self->dielectricLayer.super.bsdfType
      == BSDF_TYPE_MICROFACET_DIELECTRIC_LAYER)
    return MicrofacetDielectricLayerBSDF_eval(self, wo, wi);
  else
    return DielectricLayerBSDF_eval(self, wo, wi);
}

SYCL_EXTERNAL BSDF_SampleRes CarPaint_BSDF_sample(
    const varying BSDF *uniform super,
    const vec3f &wo,
    const vec2f &s,
    float ss)
{
  const varying CarPaint_BSDF *uniform self =
      (const varying CarPaint_BSDF *uniform)super;

  // Skip dielectric layer if no clear coat
  if (self->dielectricLayer.weight < EPS)
    return BaseBSDF_sample(self, wo, s, ss);

  if (self->dielectricLayer.super.bsdfType
      == BSDF_TYPE_MICROFACET_DIELECTRIC_LAYER)
    return MicrofacetDielectricLayerBSDF_sample(self, wo, s, ss);
  else
    return DielectricLayerBSDF_sample(self, wo, s, ss);
}

///////////////////////////////////////////////////////////////////////////////
// External API

export void *uniform CarPaint_getBSDF_addr()
{
  return (void *uniform)CarPaint_getBSDF;
}

OSPRAY_END_ISPC_NAMESPACE