The SVM attribute map is always generated and uses a simple linear search to lookup by an opaque ID, so can reuse that for OSL as well and simply use the attribute name hash as ID instead of generating a unique value separately. This works for both object and geometry attributes since the SVM attribute map already stores both. Simplifies code somewhat and reduces memory usage slightly. This patch was split from D15902. Differential Revision: https://developer.blender.org/D15918
665 lines
20 KiB
C
665 lines
20 KiB
C
/* SPDX-License-Identifier: Apache-2.0
|
|
* Copyright 2011-2022 Blender Foundation */
|
|
|
|
/* Functions for retrieving attributes on triangles produced from subdivision meshes */
|
|
|
|
#pragma once
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
/* UV coords of triangle within patch */
|
|
|
|
ccl_device_inline void subd_triangle_patch_uv(KernelGlobals kg,
|
|
ccl_private const ShaderData *sd,
|
|
float2 uv[3])
|
|
{
|
|
uint4 tri_vindex = kernel_data_fetch(tri_vindex, sd->prim);
|
|
|
|
uv[0] = kernel_data_fetch(tri_patch_uv, tri_vindex.x);
|
|
uv[1] = kernel_data_fetch(tri_patch_uv, tri_vindex.y);
|
|
uv[2] = kernel_data_fetch(tri_patch_uv, tri_vindex.z);
|
|
}
|
|
|
|
/* Vertex indices of patch */
|
|
|
|
ccl_device_inline uint4 subd_triangle_patch_indices(KernelGlobals kg, int patch)
|
|
{
|
|
uint4 indices;
|
|
|
|
indices.x = kernel_data_fetch(patches, patch + 0);
|
|
indices.y = kernel_data_fetch(patches, patch + 1);
|
|
indices.z = kernel_data_fetch(patches, patch + 2);
|
|
indices.w = kernel_data_fetch(patches, patch + 3);
|
|
|
|
return indices;
|
|
}
|
|
|
|
/* Originating face for patch */
|
|
|
|
ccl_device_inline uint subd_triangle_patch_face(KernelGlobals kg, int patch)
|
|
{
|
|
return kernel_data_fetch(patches, patch + 4);
|
|
}
|
|
|
|
/* Number of corners on originating face */
|
|
|
|
ccl_device_inline uint subd_triangle_patch_num_corners(KernelGlobals kg, int patch)
|
|
{
|
|
return kernel_data_fetch(patches, patch + 5) & 0xffff;
|
|
}
|
|
|
|
/* Indices of the four corners that are used by the patch */
|
|
|
|
ccl_device_inline void subd_triangle_patch_corners(KernelGlobals kg, int patch, int corners[4])
|
|
{
|
|
uint4 data;
|
|
|
|
data.x = kernel_data_fetch(patches, patch + 4);
|
|
data.y = kernel_data_fetch(patches, patch + 5);
|
|
data.z = kernel_data_fetch(patches, patch + 6);
|
|
data.w = kernel_data_fetch(patches, patch + 7);
|
|
|
|
int num_corners = data.y & 0xffff;
|
|
|
|
if (num_corners == 4) {
|
|
/* quad */
|
|
corners[0] = data.z;
|
|
corners[1] = data.z + 1;
|
|
corners[2] = data.z + 2;
|
|
corners[3] = data.z + 3;
|
|
}
|
|
else {
|
|
/* ngon */
|
|
int c = data.y >> 16;
|
|
|
|
corners[0] = data.z + c;
|
|
corners[1] = data.z + mod(c + 1, num_corners);
|
|
corners[2] = data.w;
|
|
corners[3] = data.z + mod(c - 1, num_corners);
|
|
}
|
|
}
|
|
|
|
/* Reading attributes on various subdivision triangle elements */
|
|
|
|
ccl_device_noinline float subd_triangle_attribute_float(KernelGlobals kg,
|
|
ccl_private const ShaderData *sd,
|
|
const AttributeDescriptor desc,
|
|
ccl_private float *dx,
|
|
ccl_private float *dy)
|
|
{
|
|
int patch = subd_triangle_patch(kg, sd->prim);
|
|
|
|
#ifdef __PATCH_EVAL__
|
|
if (desc.flags & ATTR_SUBDIVIDED) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
float2 dpdu = uv[1] - uv[0];
|
|
float2 dpdv = uv[2] - uv[0];
|
|
|
|
/* p is [s, t] */
|
|
float2 p = dpdu * sd->u + dpdv * sd->v + uv[0];
|
|
|
|
float a, dads, dadt;
|
|
a = patch_eval_float(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
|
|
|
|
# ifdef __RAY_DIFFERENTIALS__
|
|
if (dx || dy) {
|
|
float dsdu = dpdu.x;
|
|
float dtdu = dpdu.y;
|
|
float dsdv = dpdv.x;
|
|
float dtdv = dpdv.y;
|
|
|
|
if (dx) {
|
|
float dudx = sd->du.dx;
|
|
float dvdx = sd->dv.dx;
|
|
|
|
float dsdx = dsdu * dudx + dsdv * dvdx;
|
|
float dtdx = dtdu * dudx + dtdv * dvdx;
|
|
|
|
*dx = dads * dsdx + dadt * dtdx;
|
|
}
|
|
if (dy) {
|
|
float dudy = sd->du.dy;
|
|
float dvdy = sd->dv.dy;
|
|
|
|
float dsdy = dsdu * dudy + dsdv * dvdy;
|
|
float dtdy = dtdu * dudy + dtdv * dvdy;
|
|
|
|
*dy = dads * dsdy + dadt * dtdy;
|
|
}
|
|
}
|
|
# endif
|
|
|
|
return a;
|
|
}
|
|
else
|
|
#endif /* __PATCH_EVAL__ */
|
|
if (desc.element == ATTR_ELEMENT_FACE) {
|
|
if (dx)
|
|
*dx = 0.0f;
|
|
if (dy)
|
|
*dy = 0.0f;
|
|
|
|
return kernel_data_fetch(attributes_float, desc.offset + subd_triangle_patch_face(kg, patch));
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
uint4 v = subd_triangle_patch_indices(kg, patch);
|
|
|
|
float f0 = kernel_data_fetch(attributes_float, desc.offset + v.x);
|
|
float f1 = kernel_data_fetch(attributes_float, desc.offset + v.y);
|
|
float f2 = kernel_data_fetch(attributes_float, desc.offset + v.z);
|
|
float f3 = kernel_data_fetch(attributes_float, desc.offset + v.w);
|
|
|
|
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
|
|
f1 = (f1 + f0) * 0.5f;
|
|
f3 = (f3 + f0) * 0.5f;
|
|
}
|
|
|
|
float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
|
float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
|
float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
if (dx)
|
|
*dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a;
|
|
if (dy)
|
|
*dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a;
|
|
#endif
|
|
|
|
return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a;
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_CORNER) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
int corners[4];
|
|
subd_triangle_patch_corners(kg, patch, corners);
|
|
|
|
float f0 = kernel_data_fetch(attributes_float, corners[0] + desc.offset);
|
|
float f1 = kernel_data_fetch(attributes_float, corners[1] + desc.offset);
|
|
float f2 = kernel_data_fetch(attributes_float, corners[2] + desc.offset);
|
|
float f3 = kernel_data_fetch(attributes_float, corners[3] + desc.offset);
|
|
|
|
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
|
|
f1 = (f1 + f0) * 0.5f;
|
|
f3 = (f3 + f0) * 0.5f;
|
|
}
|
|
|
|
float a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
|
float b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
|
float c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
if (dx)
|
|
*dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a;
|
|
if (dy)
|
|
*dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a;
|
|
#endif
|
|
|
|
return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a;
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
|
|
if (dx)
|
|
*dx = 0.0f;
|
|
if (dy)
|
|
*dy = 0.0f;
|
|
|
|
return kernel_data_fetch(attributes_float, desc.offset);
|
|
}
|
|
else {
|
|
if (dx)
|
|
*dx = 0.0f;
|
|
if (dy)
|
|
*dy = 0.0f;
|
|
|
|
return 0.0f;
|
|
}
|
|
}
|
|
|
|
ccl_device_noinline float2 subd_triangle_attribute_float2(KernelGlobals kg,
|
|
ccl_private const ShaderData *sd,
|
|
const AttributeDescriptor desc,
|
|
ccl_private float2 *dx,
|
|
ccl_private float2 *dy)
|
|
{
|
|
int patch = subd_triangle_patch(kg, sd->prim);
|
|
|
|
#ifdef __PATCH_EVAL__
|
|
if (desc.flags & ATTR_SUBDIVIDED) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
float2 dpdu = uv[1] - uv[0];
|
|
float2 dpdv = uv[2] - uv[0];
|
|
|
|
/* p is [s, t] */
|
|
float2 p = dpdu * sd->u + dpdv * sd->v + uv[0];
|
|
|
|
float2 a, dads, dadt;
|
|
|
|
a = patch_eval_float2(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
|
|
|
|
# ifdef __RAY_DIFFERENTIALS__
|
|
if (dx || dy) {
|
|
float dsdu = dpdu.x;
|
|
float dtdu = dpdu.y;
|
|
float dsdv = dpdv.x;
|
|
float dtdv = dpdv.y;
|
|
|
|
if (dx) {
|
|
float dudx = sd->du.dx;
|
|
float dvdx = sd->dv.dx;
|
|
|
|
float dsdx = dsdu * dudx + dsdv * dvdx;
|
|
float dtdx = dtdu * dudx + dtdv * dvdx;
|
|
|
|
*dx = dads * dsdx + dadt * dtdx;
|
|
}
|
|
if (dy) {
|
|
float dudy = sd->du.dy;
|
|
float dvdy = sd->dv.dy;
|
|
|
|
float dsdy = dsdu * dudy + dsdv * dvdy;
|
|
float dtdy = dtdu * dudy + dtdv * dvdy;
|
|
|
|
*dy = dads * dsdy + dadt * dtdy;
|
|
}
|
|
}
|
|
# endif
|
|
|
|
return a;
|
|
}
|
|
else
|
|
#endif /* __PATCH_EVAL__ */
|
|
if (desc.element == ATTR_ELEMENT_FACE) {
|
|
if (dx)
|
|
*dx = make_float2(0.0f, 0.0f);
|
|
if (dy)
|
|
*dy = make_float2(0.0f, 0.0f);
|
|
|
|
return kernel_data_fetch(attributes_float2, desc.offset + subd_triangle_patch_face(kg, patch));
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
uint4 v = subd_triangle_patch_indices(kg, patch);
|
|
|
|
float2 f0 = kernel_data_fetch(attributes_float2, desc.offset + v.x);
|
|
float2 f1 = kernel_data_fetch(attributes_float2, desc.offset + v.y);
|
|
float2 f2 = kernel_data_fetch(attributes_float2, desc.offset + v.z);
|
|
float2 f3 = kernel_data_fetch(attributes_float2, desc.offset + v.w);
|
|
|
|
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
|
|
f1 = (f1 + f0) * 0.5f;
|
|
f3 = (f3 + f0) * 0.5f;
|
|
}
|
|
|
|
float2 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
|
float2 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
|
float2 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
if (dx)
|
|
*dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a;
|
|
if (dy)
|
|
*dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a;
|
|
#endif
|
|
|
|
return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a;
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_CORNER) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
int corners[4];
|
|
subd_triangle_patch_corners(kg, patch, corners);
|
|
|
|
float2 f0, f1, f2, f3;
|
|
|
|
f0 = kernel_data_fetch(attributes_float2, corners[0] + desc.offset);
|
|
f1 = kernel_data_fetch(attributes_float2, corners[1] + desc.offset);
|
|
f2 = kernel_data_fetch(attributes_float2, corners[2] + desc.offset);
|
|
f3 = kernel_data_fetch(attributes_float2, corners[3] + desc.offset);
|
|
|
|
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
|
|
f1 = (f1 + f0) * 0.5f;
|
|
f3 = (f3 + f0) * 0.5f;
|
|
}
|
|
|
|
float2 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
|
float2 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
|
float2 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
if (dx)
|
|
*dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a;
|
|
if (dy)
|
|
*dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a;
|
|
#endif
|
|
|
|
return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a;
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
|
|
if (dx)
|
|
*dx = make_float2(0.0f, 0.0f);
|
|
if (dy)
|
|
*dy = make_float2(0.0f, 0.0f);
|
|
|
|
return kernel_data_fetch(attributes_float2, desc.offset);
|
|
}
|
|
else {
|
|
if (dx)
|
|
*dx = make_float2(0.0f, 0.0f);
|
|
if (dy)
|
|
*dy = make_float2(0.0f, 0.0f);
|
|
|
|
return make_float2(0.0f, 0.0f);
|
|
}
|
|
}
|
|
|
|
ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg,
|
|
ccl_private const ShaderData *sd,
|
|
const AttributeDescriptor desc,
|
|
ccl_private float3 *dx,
|
|
ccl_private float3 *dy)
|
|
{
|
|
int patch = subd_triangle_patch(kg, sd->prim);
|
|
|
|
#ifdef __PATCH_EVAL__
|
|
if (desc.flags & ATTR_SUBDIVIDED) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
float2 dpdu = uv[1] - uv[0];
|
|
float2 dpdv = uv[2] - uv[0];
|
|
|
|
/* p is [s, t] */
|
|
float2 p = dpdu * sd->u + dpdv * sd->v + uv[0];
|
|
|
|
float3 a, dads, dadt;
|
|
a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
|
|
|
|
# ifdef __RAY_DIFFERENTIALS__
|
|
if (dx || dy) {
|
|
float dsdu = dpdu.x;
|
|
float dtdu = dpdu.y;
|
|
float dsdv = dpdv.x;
|
|
float dtdv = dpdv.y;
|
|
|
|
if (dx) {
|
|
float dudx = sd->du.dx;
|
|
float dvdx = sd->dv.dx;
|
|
|
|
float dsdx = dsdu * dudx + dsdv * dvdx;
|
|
float dtdx = dtdu * dudx + dtdv * dvdx;
|
|
|
|
*dx = dads * dsdx + dadt * dtdx;
|
|
}
|
|
if (dy) {
|
|
float dudy = sd->du.dy;
|
|
float dvdy = sd->dv.dy;
|
|
|
|
float dsdy = dsdu * dudy + dsdv * dvdy;
|
|
float dtdy = dtdu * dudy + dtdv * dvdy;
|
|
|
|
*dy = dads * dsdy + dadt * dtdy;
|
|
}
|
|
}
|
|
# endif
|
|
|
|
return a;
|
|
}
|
|
else
|
|
#endif /* __PATCH_EVAL__ */
|
|
if (desc.element == ATTR_ELEMENT_FACE) {
|
|
if (dx)
|
|
*dx = make_float3(0.0f, 0.0f, 0.0f);
|
|
if (dy)
|
|
*dy = make_float3(0.0f, 0.0f, 0.0f);
|
|
|
|
return kernel_data_fetch(attributes_float3, desc.offset + subd_triangle_patch_face(kg, patch));
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
uint4 v = subd_triangle_patch_indices(kg, patch);
|
|
|
|
float3 f0 = kernel_data_fetch(attributes_float3, desc.offset + v.x);
|
|
float3 f1 = kernel_data_fetch(attributes_float3, desc.offset + v.y);
|
|
float3 f2 = kernel_data_fetch(attributes_float3, desc.offset + v.z);
|
|
float3 f3 = kernel_data_fetch(attributes_float3, desc.offset + v.w);
|
|
|
|
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
|
|
f1 = (f1 + f0) * 0.5f;
|
|
f3 = (f3 + f0) * 0.5f;
|
|
}
|
|
|
|
float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
|
float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
|
float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
if (dx)
|
|
*dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a;
|
|
if (dy)
|
|
*dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a;
|
|
#endif
|
|
|
|
return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a;
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_CORNER) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
int corners[4];
|
|
subd_triangle_patch_corners(kg, patch, corners);
|
|
|
|
float3 f0, f1, f2, f3;
|
|
|
|
f0 = kernel_data_fetch(attributes_float3, corners[0] + desc.offset);
|
|
f1 = kernel_data_fetch(attributes_float3, corners[1] + desc.offset);
|
|
f2 = kernel_data_fetch(attributes_float3, corners[2] + desc.offset);
|
|
f3 = kernel_data_fetch(attributes_float3, corners[3] + desc.offset);
|
|
|
|
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
|
|
f1 = (f1 + f0) * 0.5f;
|
|
f3 = (f3 + f0) * 0.5f;
|
|
}
|
|
|
|
float3 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
|
float3 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
|
float3 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
if (dx)
|
|
*dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a;
|
|
if (dy)
|
|
*dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a;
|
|
#endif
|
|
|
|
return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a;
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
|
|
if (dx)
|
|
*dx = make_float3(0.0f, 0.0f, 0.0f);
|
|
if (dy)
|
|
*dy = make_float3(0.0f, 0.0f, 0.0f);
|
|
|
|
return kernel_data_fetch(attributes_float3, desc.offset);
|
|
}
|
|
else {
|
|
if (dx)
|
|
*dx = make_float3(0.0f, 0.0f, 0.0f);
|
|
if (dy)
|
|
*dy = make_float3(0.0f, 0.0f, 0.0f);
|
|
|
|
return make_float3(0.0f, 0.0f, 0.0f);
|
|
}
|
|
}
|
|
|
|
ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg,
|
|
ccl_private const ShaderData *sd,
|
|
const AttributeDescriptor desc,
|
|
ccl_private float4 *dx,
|
|
ccl_private float4 *dy)
|
|
{
|
|
int patch = subd_triangle_patch(kg, sd->prim);
|
|
|
|
#ifdef __PATCH_EVAL__
|
|
if (desc.flags & ATTR_SUBDIVIDED) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
float2 dpdu = uv[1] - uv[0];
|
|
float2 dpdv = uv[2] - uv[0];
|
|
|
|
/* p is [s, t] */
|
|
float2 p = dpdu * sd->u + dpdv * sd->v + uv[0];
|
|
|
|
float4 a, dads, dadt;
|
|
if (desc.type == NODE_ATTR_RGBA) {
|
|
a = patch_eval_uchar4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
|
|
}
|
|
else {
|
|
a = patch_eval_float4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
|
|
}
|
|
|
|
# ifdef __RAY_DIFFERENTIALS__
|
|
if (dx || dy) {
|
|
float dsdu = dpdu.x;
|
|
float dtdu = dpdu.y;
|
|
float dsdv = dpdv.x;
|
|
float dtdv = dpdv.y;
|
|
|
|
if (dx) {
|
|
float dudx = sd->du.dx;
|
|
float dvdx = sd->dv.dx;
|
|
|
|
float dsdx = dsdu * dudx + dsdv * dvdx;
|
|
float dtdx = dtdu * dudx + dtdv * dvdx;
|
|
|
|
*dx = dads * dsdx + dadt * dtdx;
|
|
}
|
|
if (dy) {
|
|
float dudy = sd->du.dy;
|
|
float dvdy = sd->dv.dy;
|
|
|
|
float dsdy = dsdu * dudy + dsdv * dvdy;
|
|
float dtdy = dtdu * dudy + dtdv * dvdy;
|
|
|
|
*dy = dads * dsdy + dadt * dtdy;
|
|
}
|
|
}
|
|
# endif
|
|
|
|
return a;
|
|
}
|
|
else
|
|
#endif /* __PATCH_EVAL__ */
|
|
if (desc.element == ATTR_ELEMENT_FACE) {
|
|
if (dx)
|
|
*dx = zero_float4();
|
|
if (dy)
|
|
*dy = zero_float4();
|
|
|
|
return kernel_data_fetch(attributes_float4, desc.offset + subd_triangle_patch_face(kg, patch));
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
uint4 v = subd_triangle_patch_indices(kg, patch);
|
|
|
|
float4 f0 = kernel_data_fetch(attributes_float4, desc.offset + v.x);
|
|
float4 f1 = kernel_data_fetch(attributes_float4, desc.offset + v.y);
|
|
float4 f2 = kernel_data_fetch(attributes_float4, desc.offset + v.z);
|
|
float4 f3 = kernel_data_fetch(attributes_float4, desc.offset + v.w);
|
|
|
|
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
|
|
f1 = (f1 + f0) * 0.5f;
|
|
f3 = (f3 + f0) * 0.5f;
|
|
}
|
|
|
|
float4 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
|
float4 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
|
float4 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
if (dx)
|
|
*dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a;
|
|
if (dy)
|
|
*dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a;
|
|
#endif
|
|
|
|
return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a;
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
|
|
float2 uv[3];
|
|
subd_triangle_patch_uv(kg, sd, uv);
|
|
|
|
int corners[4];
|
|
subd_triangle_patch_corners(kg, patch, corners);
|
|
|
|
float4 f0, f1, f2, f3;
|
|
|
|
if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
|
|
f0 = color_srgb_to_linear_v4(
|
|
color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, corners[0] + desc.offset)));
|
|
f1 = color_srgb_to_linear_v4(
|
|
color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, corners[1] + desc.offset)));
|
|
f2 = color_srgb_to_linear_v4(
|
|
color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, corners[2] + desc.offset)));
|
|
f3 = color_srgb_to_linear_v4(
|
|
color_uchar4_to_float4(kernel_data_fetch(attributes_uchar4, corners[3] + desc.offset)));
|
|
}
|
|
else {
|
|
f0 = kernel_data_fetch(attributes_float4, corners[0] + desc.offset);
|
|
f1 = kernel_data_fetch(attributes_float4, corners[1] + desc.offset);
|
|
f2 = kernel_data_fetch(attributes_float4, corners[2] + desc.offset);
|
|
f3 = kernel_data_fetch(attributes_float4, corners[3] + desc.offset);
|
|
}
|
|
|
|
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
|
|
f1 = (f1 + f0) * 0.5f;
|
|
f3 = (f3 + f0) * 0.5f;
|
|
}
|
|
|
|
float4 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
|
|
float4 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
|
|
float4 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
|
|
|
|
#ifdef __RAY_DIFFERENTIALS__
|
|
if (dx)
|
|
*dx = sd->du.dx * b + sd->dv.dx * c - (sd->du.dx + sd->dv.dx) * a;
|
|
if (dy)
|
|
*dy = sd->du.dy * b + sd->dv.dy * c - (sd->du.dy + sd->dv.dy) * a;
|
|
#endif
|
|
|
|
return sd->u * b + sd->v * c + (1.0f - sd->u - sd->v) * a;
|
|
}
|
|
else if (desc.element == ATTR_ELEMENT_OBJECT || desc.element == ATTR_ELEMENT_MESH) {
|
|
if (dx)
|
|
*dx = zero_float4();
|
|
if (dy)
|
|
*dy = zero_float4();
|
|
|
|
return kernel_data_fetch(attributes_float4, desc.offset);
|
|
}
|
|
else {
|
|
if (dx)
|
|
*dx = zero_float4();
|
|
if (dy)
|
|
*dy = zero_float4();
|
|
|
|
return zero_float4();
|
|
}
|
|
}
|
|
|
|
CCL_NAMESPACE_END
|