# Changeset View

Changeset View

# Standalone View

Standalone View

# intern/cycles/kernel/kernel_subsurface.h

Show All 14 Lines | |||||

15 | */ | 15 | */ | ||

16 | 16 | | |||

17 | CCL_NAMESPACE_BEGIN | 17 | CCL_NAMESPACE_BEGIN | ||

18 | 18 | | |||

19 | /* BSSRDF using disk based importance sampling. | 19 | /* BSSRDF using disk based importance sampling. | ||

20 | * | 20 | * | ||

21 | * BSSRDF Importance Sampling, SIGGRAPH 2013 | 21 | * BSSRDF Importance Sampling, SIGGRAPH 2013 | ||

22 | * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf | 22 | * http://library.imageworks.com/pdfs/imageworks-library-BSSRDF-sampling.pdf | ||

23 | * | | |||

24 | */ | 23 | */ | ||

25 | 24 | | |||

26 | ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd, | 25 | ccl_device_inline float3 subsurface_scatter_eval(ShaderData *sd, | ||

27 | const ShaderClosure *sc, | 26 | const ShaderClosure *sc, | ||

28 | float disk_r, | 27 | float disk_r, | ||

29 | float r, | 28 | float r, | ||

30 | bool all) | 29 | bool all) | ||

31 | { | 30 | { | ||

32 | /* this is the veach one-sample model with balance heuristic, some pdf | 31 | /* this is the veach one-sample model with balance heuristic, some pdf | ||

33 | * factors drop out when using balance heuristic weighting */ | 32 | * factors drop out when using balance heuristic weighting */ | ||

34 | float3 eval_sum = make_float3(0.0f, 0.0f, 0.0f); | 33 | float3 eval_sum = make_float3(0.0f, 0.0f, 0.0f); | ||

35 | float pdf_sum = 0.0f; | 34 | float pdf_sum = 0.0f; | ||

36 | float sample_weight_inv = 0.0f; | 35 | float sample_weight_inv = 0.0f; | ||

37 | 36 | | |||

38 | if(!all) { | 37 | if(!all) { | ||

39 | float sample_weight_sum = 0.0f; | 38 | float sample_weight_sum = 0.0f; | ||

40 | 39 | | |||

41 | for(int i = 0; i < sd->num_closure; i++) { | 40 | for(int i = 0; i < sd->num_closure; i++) { | ||

42 | sc = &sd->closure[i]; | 41 | sc = &sd->closure[i]; | ||

43 | 42 | | |||

44 | if(CLOSURE_IS_BSSRDF(sc->type)) { | 43 | if(CLOSURE_IS_DISK_BSSRDF(sc->type)) { | ||

45 | sample_weight_sum += sc->sample_weight; | 44 | sample_weight_sum += sc->sample_weight; | ||

46 | } | 45 | } | ||

47 | } | 46 | } | ||

48 | 47 | | |||

49 | sample_weight_inv = 1.0f/sample_weight_sum; | 48 | sample_weight_inv = 1.0f/sample_weight_sum; | ||

50 | } | 49 | } | ||

51 | 50 | | |||

52 | for(int i = 0; i < sd->num_closure; i++) { | 51 | for(int i = 0; i < sd->num_closure; i++) { | ||

53 | sc = &sd->closure[i]; | 52 | sc = &sd->closure[i]; | ||

54 | 53 | | |||

55 | if(CLOSURE_IS_BSSRDF(sc->type)) { | 54 | if(CLOSURE_IS_DISK_BSSRDF(sc->type)) { | ||

56 | /* in case of branched path integrate we sample all bssrdf's once, | 55 | /* in case of branched path integrate we sample all bssrdf's once, | ||

57 | * for path trace we pick one, so adjust pdf for that */ | 56 | * for path trace we pick one, so adjust pdf for that */ | ||

58 | float sample_weight = (all)? 1.0f: sc->sample_weight * sample_weight_inv; | 57 | float sample_weight = (all)? 1.0f: sc->sample_weight * sample_weight_inv; | ||

59 | 58 | | |||

60 | /* compute pdf */ | 59 | /* compute pdf */ | ||

61 | float3 eval = bssrdf_eval(sc, r); | 60 | float3 eval = bssrdf_eval(sc, r); | ||

62 | float pdf = bssrdf_pdf(sc, disk_r); | 61 | float pdf = bssrdf_pdf(sc, disk_r); | ||

63 | 62 | | |||

Show All 11 Lines | 73 | { | |||

75 | sd->flag &= ~SD_CLOSURE_FLAGS; | 74 | sd->flag &= ~SD_CLOSURE_FLAGS; | ||

76 | sd->num_closure = 0; | 75 | sd->num_closure = 0; | ||

77 | sd->num_closure_left = kernel_data.integrator.max_closures; | 76 | sd->num_closure_left = kernel_data.integrator.max_closures; | ||

78 | 77 | | |||

79 | if(hit) { | 78 | if(hit) { | ||

80 | Bssrdf *bssrdf = (Bssrdf *)sc; | 79 | Bssrdf *bssrdf = (Bssrdf *)sc; | ||

81 | #ifdef __PRINCIPLED__ | 80 | #ifdef __PRINCIPLED__ | ||

82 | if(bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID) { | 81 | if(bssrdf->type == CLOSURE_BSSRDF_PRINCIPLED_ID) { | ||

83 | PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), weight); | 82 | PrincipledDiffuseBsdf *bsdf = (PrincipledDiffuseBsdf*)bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), weight); | ||

sergey: Brace on the next line. | |||||

84 | 83 | | |||

85 | if(bsdf) { | 84 | if(bsdf) { | ||

86 | bsdf->N = N; | 85 | bsdf->N = N; | ||

87 | bsdf->roughness = bssrdf->roughness; | 86 | bsdf->roughness = bssrdf->roughness; | ||

88 | sd->flag |= bsdf_principled_diffuse_setup(bsdf); | 87 | sd->flag |= bsdf_principled_diffuse_setup(bsdf); | ||

89 | 88 | | |||

90 | /* replace CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID with this special ID so render passes | 89 | /* replace CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID with this special ID so render passes | ||

91 | * can recognize it as not being a regular Disney principled diffuse closure */ | 90 | * can recognize it as not being a regular Disney principled diffuse closure */ | ||

▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Line(s) | 156 | if(texture_blur > 0.0f) { | |||

161 | *eval *= safe_divide_color(in_color, out_color); | 160 | *eval *= safe_divide_color(in_color, out_color); | ||

162 | } | 161 | } | ||

163 | } | 162 | } | ||

164 | } | 163 | } | ||

165 | 164 | | |||

166 | /* Subsurface scattering step, from a point on the surface to other | 165 | /* Subsurface scattering step, from a point on the surface to other | ||

167 | * nearby points on the same object. | 166 | * nearby points on the same object. | ||

168 | */ | 167 | */ | ||

169 | ccl_device_inline int subsurface_scatter_multi_intersect( | 168 | ccl_device_inline int subsurface_scatter_disk( | ||

170 | KernelGlobals *kg, | 169 | KernelGlobals *kg, | ||

171 | LocalIntersection *ss_isect, | 170 | LocalIntersection *ss_isect, | ||

172 | ShaderData *sd, | 171 | ShaderData *sd, | ||

173 | const ShaderClosure *sc, | 172 | const ShaderClosure *sc, | ||

174 | uint *lcg_state, | 173 | uint *lcg_state, | ||

175 | float disk_u, | 174 | float disk_u, | ||

176 | float disk_v, | 175 | float disk_v, | ||

177 | bool all) | 176 | bool all) | ||

▲ Show 20 Lines • Show All 250 Lines • ▼ Show 20 Line(s) | 405 | #endif | |||

428 | /* optionally blur colors and bump mapping */ | 427 | /* optionally blur colors and bump mapping */ | ||

429 | float3 N = sd->N; | 428 | float3 N = sd->N; | ||

430 | subsurface_color_bump_blur(kg, sd, state, &eval, &N); | 429 | subsurface_color_bump_blur(kg, sd, state, &eval, &N); | ||

431 | 430 | | |||

432 | /* setup diffuse bsdf */ | 431 | /* setup diffuse bsdf */ | ||

433 | subsurface_scatter_setup_diffuse_bsdf(kg, sd, sc, eval, (ss_isect.num_hits > 0), N); | 432 | subsurface_scatter_setup_diffuse_bsdf(kg, sd, sc, eval, (ss_isect.num_hits > 0), N); | ||

434 | } | 433 | } | ||

435 | 434 | | |||

435 | /* Random walk subsurface scattering. | ||||

436 | * | ||||

437 | * "Practical and Controllable Subsurface Scattering for Production Path | ||||

438 | * Tracing". Matt Jen-Yuan Chiang, Peter Kutz, Brent Burley. SIGGRAPH 2016. */ | ||||

439 | | ||||

440 | ccl_device void subsurface_random_walk_remap( | ||||

441 | const float A, | ||||

442 | const float d, | ||||

443 | float *sigma_t, | ||||

444 | float *sigma_s) | ||||

445 | { | ||||

446 | /* Compute attenuation and scattering coefficients from albedo. */ | ||||

447 | const float a = 1.0f - expf(A * (-5.09406f + A * (2.61188f - A * 4.31805f))); | ||||

448 | const float s = 1.9f - A + 3.5f * sqr(A - 0.8f); | ||||

449 | | ||||

450 | *sigma_t = 1.0f / fmaxf(d * s, 1e-16f); | ||||

451 | *sigma_s = *sigma_t * a; | ||||

452 | } | ||||

453 | | ||||

454 | ccl_device void subsurface_random_walk_coefficients( | ||||

455 | const ShaderClosure *sc, | ||||

456 | float3 *sigma_t, | ||||

457 | float3 *sigma_s, | ||||

458 | float3 *weight) | ||||

459 | { | ||||

460 | const Bssrdf *bssrdf = (const Bssrdf*)sc; | ||||

461 | const float3 A = bssrdf->albedo; | ||||

462 | const float3 d = bssrdf->radius; | ||||

463 | float sigma_t_x, sigma_t_y, sigma_t_z; | ||||

464 | float sigma_s_x, sigma_s_y, sigma_s_z; | ||||

465 | | ||||

466 | subsurface_random_walk_remap(A.x, d.x, &sigma_t_x, &sigma_s_x); | ||||

467 | subsurface_random_walk_remap(A.y, d.y, &sigma_t_y, &sigma_s_y); | ||||

468 | subsurface_random_walk_remap(A.z, d.z, &sigma_t_z, &sigma_s_z); | ||||

469 | | ||||

470 | *sigma_t = make_float3(sigma_t_x, sigma_t_y, sigma_t_z); | ||||

471 | *sigma_s = make_float3(sigma_s_x, sigma_s_y, sigma_s_z); | ||||

472 | | ||||

473 | /* Closure mixing and Fresnel weights separate from albedo. */ | ||||

474 | *weight = safe_divide_color(bssrdf->weight, A); | ||||

475 | } | ||||

476 | | ||||

477 | ccl_device_noinline bool subsurface_random_walk( | ||||

478 | KernelGlobals *kg, | ||||

479 | LocalIntersection *ss_isect, | ||||

480 | ShaderData *sd, | ||||

481 | ccl_addr_space PathState *state, | ||||

482 | const ShaderClosure *sc, | ||||

483 | const float bssrdf_u, | ||||

484 | const float bssrdf_v) | ||||

485 | { | ||||

486 | /* Sample diffuse surface scatter into the object. */ | ||||

487 | float3 D; | ||||

488 | float pdf; | ||||

489 | sample_cos_hemisphere(-sd->N, bssrdf_u, bssrdf_v, &D, &pdf); | ||||

490 | if(dot(-sd->Ng, D) <= 0.0f) { | ||||

491 | return 0; | ||||

492 | } | ||||

493 | | ||||

494 | /* Convert subsurface to volume coefficients. */ | ||||

495 | float3 sigma_t, sigma_s; | ||||

496 | float3 throughput = make_float3(1.0f, 1.0f, 1.0f); | ||||

497 | subsurface_random_walk_coefficients(sc, &sigma_t, &sigma_s, &throughput); | ||||

498 | | ||||

499 | /* Setup ray. */ | ||||

500 | #ifdef __SPLIT_KERNEL__ | ||||

501 | Ray ray_object = ss_isect->ray; | ||||

502 | Ray *ray = &ray_object; | ||||

503 | #else | ||||

504 | Ray *ray = &ss_isect->ray; | ||||

505 | #endif | ||||

506 | ray->P = ray_offset(sd->P, -sd->Ng); | ||||

507 | ray->D = D; | ||||

508 | ray->t = FLT_MAX; | ||||

509 | ray->time = sd->time; | ||||

510 | | ||||

511 | /* Modify state for RNGs, decorrelated from other paths. */ | ||||

512 | uint prev_rng_offset = state->rng_offset; | ||||

513 | uint prev_rng_hash = state->rng_hash; | ||||

514 | state->rng_hash = cmj_hash(state->rng_hash + state->rng_offset, 0xdeadbeef); | ||||

515 | | ||||

516 | /* Random walk until we hit the surface again. */ | ||||

517 | bool hit = false; | ||||

518 | | ||||

519 | for(int bounce = 0; bounce < BSSRDF_MAX_BOUNCES; bounce++) { | ||||

520 | /* Advance random number offset. */ | ||||

521 | state->rng_offset += PRNG_BOUNCE_NUM; | ||||

522 | | ||||

523 | if(bounce > 0) { | ||||

524 | /* Sample scattering direction. */ | ||||

525 | const float anisotropy = 0.0f; | ||||

526 | float scatter_u, scatter_v; | ||||

527 | path_state_rng_2D(kg, state, PRNG_BSDF_U, &scatter_u, &scatter_v); | ||||

528 | ray->D = henyey_greenstrein_sample(ray->D, anisotropy, scatter_u, scatter_v, NULL); | ||||

529 | } | ||||

530 | | ||||

531 | /* Sample color channel, use MIS with balance heuristic. */ | ||||

532 | float rphase = path_state_rng_1D(kg, state, PRNG_PHASE_CHANNEL); | ||||

533 | float3 albedo = safe_divide_color(sigma_s, sigma_t); | ||||

534 | float3 channel_pdf; | ||||

535 | int channel = kernel_volume_sample_channel(albedo, throughput, rphase, &channel_pdf); | ||||

536 | | ||||

537 | /* Distance sampling. */ | ||||

538 | float rdist = path_state_rng_1D(kg, state, PRNG_SCATTER_DISTANCE); | ||||

539 | float sample_sigma_t = kernel_volume_channel_get(sigma_t, channel); | ||||

540 | float t = -logf(1.0f - rdist)/sample_sigma_t; | ||||

541 | | ||||

542 | ray->t = t; | ||||

543 | scene_intersect_local(kg, *ray, ss_isect, sd->object, NULL, 1); | ||||

544 | hit = (ss_isect->num_hits > 0); | ||||

545 | | ||||

546 | if(hit) { | ||||

547 | /* Compute world space distance to surface hit. */ | ||||

548 | float3 D = ray->D; | ||||

549 | object_inverse_dir_transform(kg, sd, &D); | ||||

550 | D = normalize(D) * ss_isect->hits[0].t; | ||||

551 | object_dir_transform(kg, sd, &D); | ||||

552 | t = len(D); | ||||

553 | } | ||||

554 | | ||||

555 | /* Advance to new scatter location. */ | ||||

556 | ray->P += t * ray->D; | ||||

557 | | ||||

558 | /* Update throughput. */ | ||||

559 | float3 transmittance = volume_color_transmittance(sigma_t, t); | ||||

560 | float pdf = dot(channel_pdf, (hit)? transmittance: sigma_t * transmittance); | ||||

561 | throughput *= ((hit)? transmittance: sigma_s * transmittance) / pdf; | ||||

562 | | ||||

563 | if(hit) { | ||||

564 | /* If we hit the surface, we are done. */ | ||||

565 | break; | ||||

566 | } | ||||

567 | | ||||

568 | /* Russian roulette. */ | ||||

569 | float terminate = path_state_rng_1D(kg, state, PRNG_TERMINATE); | ||||

570 | float probability = min(max3(fabs(throughput)), 1.0f); | ||||

571 | if(terminate >= probability) { | ||||

572 | break; | ||||

573 | } | ||||

574 | throughput /= probability; | ||||

575 | } | ||||

576 | | ||||

577 | kernel_assert(isfinite_safe(throughput.x) && | ||||

578 | isfinite_safe(throughput.y) && | ||||

579 | isfinite_safe(throughput.z)); | ||||

580 | | ||||

581 | state->rng_offset = prev_rng_offset; | ||||

582 | state->rng_hash = prev_rng_hash; | ||||

583 | | ||||

584 | /* Return number of hits in ss_isect. */ | ||||

585 | if(!hit) { | ||||

586 | return 0; | ||||

587 | } | ||||

588 | | ||||

589 | /* TODO: gain back performance lost from merging with disk BSSRDF. We | ||||

590 | * only need to return on hit so this indirect ray push/pop overhead | ||||

591 | * is not actually needed, but it does keep the code simpler. */ | ||||

592 | ss_isect->weight[0] = throughput; | ||||

593 | #ifdef __SPLIT_KERNEL__ | ||||

594 | ss_isect->ray = *ray; | ||||

595 | #endif | ||||

596 | | ||||

597 | return 1; | ||||

598 | } | ||||

599 | | ||||

600 | ccl_device_inline int subsurface_scatter_multi_intersect( | ||||

601 | KernelGlobals *kg, | ||||

602 | LocalIntersection *ss_isect, | ||||

603 | ShaderData *sd, | ||||

604 | ccl_addr_space PathState *state, | ||||

605 | const ShaderClosure *sc, | ||||

606 | uint *lcg_state, | ||||

607 | float bssrdf_u, | ||||

608 | float bssrdf_v, | ||||

609 | bool all) | ||||

610 | { | ||||

611 | if(CLOSURE_IS_DISK_BSSRDF(sc->type)) { | ||||

612 | return subsurface_scatter_disk(kg, | ||||

613 | ss_isect, | ||||

614 | sd, | ||||

615 | sc, | ||||

616 | lcg_state, | ||||

617 | bssrdf_u, | ||||

618 | bssrdf_v, | ||||

619 | all); | ||||

620 | } | ||||

621 | else { | ||||

622 | return subsurface_random_walk(kg, | ||||

623 | ss_isect, | ||||

624 | sd, | ||||

625 | state, | ||||

626 | sc, | ||||

627 | bssrdf_u, | ||||

628 | bssrdf_v); | ||||

629 | } | ||||

630 | } | ||||

631 | | ||||

436 | CCL_NAMESPACE_END | 632 | CCL_NAMESPACE_END | ||

437 | 633 | |

Brace on the next line.