diff options
author | Brecht Van Lommel <brecht@blender.org> | 2021-12-01 19:30:46 +0300 |
---|---|---|
committer | Brecht Van Lommel <brecht@blender.org> | 2021-12-16 22:54:04 +0300 |
commit | 35b1e9fc3acd6db565e7e54252a4a4152d8343d9 (patch) | |
tree | 8599df3b2be192d1fe19d30a8afb7e8d8729499e /intern/cycles/kernel/geom | |
parent | 2229179faa44e2c685b4eabd0c51d4c7d5c1f193 (diff) |
Cycles: pointcloud rendering
This add support for rendering of the point cloud object in Blender, as a native
geometry type in Cycles that is more memory and time efficient than instancing
sphere meshes. This can be useful for rendering sand, water splashes, particles,
motion graphics, etc.
Points are currently always rendered as spheres, with backface culling. More
shapes are likely to be added later, but this is the most important one and can
be customized with shaders.
For CPU rendering the Embree primitive is used, for GPU there is our own
intersection code. Motion blur is suppored. Volumes inside points are not
currently supported.
Implemented with help from:
* Kévin Dietrich: Alembic procedural integration
* Patrick Mourse: OptiX integration
* Josh Whelchel: update for cycles-x changes
Ref T92573
Differential Revision: https://developer.blender.org/D9887
Diffstat (limited to 'intern/cycles/kernel/geom')
-rw-r--r-- | intern/cycles/kernel/geom/geom.h | 3 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/motion_point.h | 74 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/point.h | 124 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/point_intersect.h | 133 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/primitive.h | 49 | ||||
-rw-r--r-- | intern/cycles/kernel/geom/shader_data.h | 7 |
6 files changed, 382 insertions, 8 deletions
diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h index 9d023375a35..efc296c8d39 100644 --- a/intern/cycles/kernel/geom/geom.h +++ b/intern/cycles/kernel/geom/geom.h @@ -29,6 +29,9 @@ #include "kernel/geom/motion_triangle_intersect.h" #include "kernel/geom/motion_triangle_shader.h" #include "kernel/geom/motion_curve.h" +#include "kernel/geom/motion_point.h" +#include "kernel/geom/point.h" +#include "kernel/geom/point_intersect.h" #include "kernel/geom/curve.h" #include "kernel/geom/curve_intersect.h" #include "kernel/geom/volume.h" diff --git a/intern/cycles/kernel/geom/motion_point.h b/intern/cycles/kernel/geom/motion_point.h new file mode 100644 index 00000000000..d7ffc80c045 --- /dev/null +++ b/intern/cycles/kernel/geom/motion_point.h @@ -0,0 +1,74 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* Motion Point Primitive + * + * These are stored as regular points, plus extra positions and radii at times + * other than the frame center. Computing the point at a given ray time is + * a matter of interpolation of the two steps between which the ray time lies. + * + * The extra points are stored as ATTR_STD_MOTION_VERTEX_POSITION. + */ + +#ifdef __POINTCLOUD__ + +ccl_device_inline float4 +motion_point_for_step(KernelGlobals kg, int offset, int numkeys, int numsteps, int step, int prim) +{ + if (step == numsteps) { + /* center step: regular key location */ + return kernel_tex_fetch(__points, prim); + } + else { + /* center step is not stored in this array */ + if (step > numsteps) + step--; + + offset += step * numkeys; + + return kernel_tex_fetch(__attributes_float4, offset + prim); + } +} + +/* return 2 point key locations */ +ccl_device_inline float4 motion_point(KernelGlobals kg, int object, int prim, float time) +{ + /* get motion info */ + int numsteps, numkeys; + object_motion_info(kg, object, &numsteps, NULL, &numkeys); + + /* figure out which steps we need to fetch and their interpolation factor */ + int maxstep = numsteps * 2; + int step = min((int)(time * maxstep), maxstep - 1); + float t = time * maxstep - step; + + /* find attribute */ + int offset = intersection_find_attribute(kg, object, ATTR_STD_MOTION_VERTEX_POSITION); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + + /* fetch key coordinates */ + float4 point = motion_point_for_step(kg, offset, numkeys, numsteps, step, prim); + float4 next_point = motion_point_for_step(kg, offset, numkeys, numsteps, step + 1, prim); + + /* interpolate between steps */ + return (1.0f - t) * point + t * next_point; +} + +#endif + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/point.h b/intern/cycles/kernel/geom/point.h new file mode 100644 index 00000000000..021135b76fb --- /dev/null +++ b/intern/cycles/kernel/geom/point.h @@ -0,0 +1,124 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* Point Primitive + * + * Point primitive for rendering point clouds. + */ + +#ifdef __POINTCLOUD__ + +/* Reading attributes on various point elements */ + +ccl_device float point_attribute_float(KernelGlobals kg, + ccl_private const ShaderData *sd, + const AttributeDescriptor desc, + ccl_private float *dx, + ccl_private float *dy) +{ +# ifdef __RAY_DIFFERENTIALS__ + if (dx) + *dx = 0.0f; + if (dy) + *dy = 0.0f; +# endif + + if (desc.element == ATTR_ELEMENT_VERTEX) { + return kernel_tex_fetch(__attributes_float, desc.offset + sd->prim); + } + else { + return 0.0f; + } +} + +ccl_device float2 point_attribute_float2( + KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float2 *dx, float2 *dy) +{ +# ifdef __RAY_DIFFERENTIALS__ + if (dx) + *dx = make_float2(0.0f, 0.0f); + if (dy) + *dy = make_float2(0.0f, 0.0f); +# endif + + if (desc.element == ATTR_ELEMENT_VERTEX) { + return kernel_tex_fetch(__attributes_float2, desc.offset + sd->prim); + } + else { + return make_float2(0.0f, 0.0f); + } +} + +ccl_device float3 point_attribute_float3( + KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy) +{ +# ifdef __RAY_DIFFERENTIALS__ + if (dx) + *dx = make_float3(0.0f, 0.0f, 0.0f); + if (dy) + *dy = make_float3(0.0f, 0.0f, 0.0f); +# endif + + if (desc.element == ATTR_ELEMENT_VERTEX) { + return float4_to_float3(kernel_tex_fetch(__attributes_float4, desc.offset + sd->prim)); + } + else { + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +ccl_device float4 point_attribute_float4( + KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float4 *dx, float4 *dy) +{ +# ifdef __RAY_DIFFERENTIALS__ + if (dx) + *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f); + if (dy) + *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f); +# endif + + if (desc.element == ATTR_ELEMENT_VERTEX) { + return kernel_tex_fetch(__attributes_float4, desc.offset + sd->prim); + } + else { + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } +} + +/* Point radius */ + +ccl_device float point_radius(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + if (sd->type & PRIMITIVE_ALL_POINT) { + return kernel_tex_fetch(__points, sd->prim).w; + } + + return 0.0f; +} + +/* Point location for motion pass, linear interpolation between keys and + * ignoring radius because we do the same for the motion keys */ + +ccl_device float3 point_motion_center_location(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + return float4_to_float3(kernel_tex_fetch(__points, sd->prim)); +} + +#endif /* __POINTCLOUD__ */ + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/point_intersect.h b/intern/cycles/kernel/geom/point_intersect.h new file mode 100644 index 00000000000..da0b31f9a8c --- /dev/null +++ b/intern/cycles/kernel/geom/point_intersect.h @@ -0,0 +1,133 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Based on Embree code, copyright 2009-2020 Intel Corporation. + */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* Point primitive intersection functions. */ + +#ifdef __POINTCLOUD__ + +ccl_device_forceinline bool point_intersect_test( + const float4 point, const float3 P, const float3 dir, const float tmax, float *t) +{ + const float3 center = float4_to_float3(point); + const float radius = point.w; + + const float rd2 = 1.0f / dot(dir, dir); + + const float3 c0 = center - P; + const float projC0 = dot(c0, dir) * rd2; + const float3 perp = c0 - projC0 * dir; + const float l2 = dot(perp, perp); + const float r2 = radius * radius; + if (!(l2 <= r2)) { + return false; + } + + const float td = sqrt((r2 - l2) * rd2); + const float t_front = projC0 - td; + const bool valid_front = (0.0f <= t_front) & (t_front <= tmax); + + /* Always backface culling for now. */ +# if 0 + const float t_back = projC0 + td; + const bool valid_back = (0.0f <= t_back) & (t_back <= tmax); + + /* check if there is a first hit */ + const bool valid_first = valid_front | valid_back; + if (!valid_first) { + return false; + } + + *t = (valid_front) ? t_front : t_back; + return true; +# else + if (!valid_front) { + return false; + } + *t = t_front; + return true; +# endif +} + +ccl_device_forceinline bool point_intersect(KernelGlobals kg, + ccl_private Intersection *isect, + const float3 P, + const float3 dir, + const float tmax, + const int object, + const int prim, + const float time, + const int type) +{ + const float4 point = (type & PRIMITIVE_ALL_MOTION) ? motion_point(kg, object, prim, time) : + kernel_tex_fetch(__points, prim); + + if (!point_intersect_test(point, P, dir, tmax, &isect->t)) { + return false; + } + + isect->prim = prim; + isect->object = object; + isect->type = type; + isect->u = 0.0f; + isect->v = 0.0f; + return true; +} + +ccl_device_inline void point_shader_setup(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private const Intersection *isect, + const Ray *ray) +{ + sd->shader = kernel_tex_fetch(__points_shader, isect->prim); + sd->P = ray->P + ray->D * isect->t; + + /* Texture coordinates, zero for now. */ +# ifdef __UV__ + sd->u = isect->u; + sd->v = isect->v; +# endif + + /* Computer point center for normal. */ + float3 center = float4_to_float3((isect->type & PRIMITIVE_ALL_MOTION) ? + motion_point(kg, sd->object, sd->prim, sd->time) : + kernel_tex_fetch(__points, sd->prim)); + + if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { + const Transform tfm = object_get_transform(kg, sd); + +# ifndef __KERNEL_OPTIX__ + center = transform_point(&tfm, center); +# endif + } + + /* Normal */ + sd->Ng = normalize(sd->P - center); + sd->N = sd->Ng; + +# ifdef __DPDU__ + /* dPdu/dPdv */ + sd->dPdu = make_float3(0.0f, 0.0f, 0.0f); + sd->dPdv = make_float3(0.0f, 0.0f, 0.0f); +# endif +} + +#endif + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/primitive.h b/intern/cycles/kernel/geom/primitive.h index 6d7b550d82f..9416385638c 100644 --- a/intern/cycles/kernel/geom/primitive.h +++ b/intern/cycles/kernel/geom/primitive.h @@ -48,6 +48,11 @@ ccl_device_inline float primitive_surface_attribute_float(KernelGlobals kg, return curve_attribute_float(kg, sd, desc, dx, dy); } #endif +#ifdef __POINTCLOUD__ + else if (sd->type & PRIMITIVE_ALL_POINT) { + return point_attribute_float(kg, sd, desc, dx, dy); + } +#endif else { if (dx) *dx = 0.0f; @@ -74,6 +79,11 @@ ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals kg, return curve_attribute_float2(kg, sd, desc, dx, dy); } #endif +#ifdef __POINTCLOUD__ + else if (sd->type & PRIMITIVE_ALL_POINT) { + return point_attribute_float2(kg, sd, desc, dx, dy); + } +#endif else { if (dx) *dx = make_float2(0.0f, 0.0f); @@ -100,6 +110,11 @@ ccl_device_inline float3 primitive_surface_attribute_float3(KernelGlobals kg, return curve_attribute_float3(kg, sd, desc, dx, dy); } #endif +#ifdef __POINTCLOUD__ + else if (sd->type & PRIMITIVE_ALL_POINT) { + return point_attribute_float3(kg, sd, desc, dx, dy); + } +#endif else { if (dx) *dx = make_float3(0.0f, 0.0f, 0.0f); @@ -126,6 +141,11 @@ ccl_device_forceinline float4 primitive_surface_attribute_float4(KernelGlobals k return curve_attribute_float4(kg, sd, desc, dx, dy); } #endif +#ifdef __POINTCLOUD__ + else if (sd->type & PRIMITIVE_ALL_POINT) { + return point_attribute_float4(kg, sd, desc, dx, dy); + } +#endif else { if (dx) *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f); @@ -225,8 +245,8 @@ ccl_device bool primitive_ptex(KernelGlobals kg, ccl_device float3 primitive_tangent(KernelGlobals kg, ccl_private ShaderData *sd) { -#ifdef __HAIR__ - if (sd->type & PRIMITIVE_ALL_CURVE) +#if defined(__HAIR__) || defined(__POINTCLOUD__) + if (sd->type & (PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_POINT)) # ifdef __DPDU__ return normalize(sd->dPdu); # else @@ -261,10 +281,21 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg, /* center position */ float3 center; -#ifdef __HAIR__ - bool is_curve_primitive = sd->type & PRIMITIVE_ALL_CURVE; - if (is_curve_primitive) { - center = curve_motion_center_location(kg, sd); +#if defined(__HAIR__) || defined(__POINTCLOUD__) + bool is_curve_or_point = sd->type & (PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_POINT); + if (is_curve_or_point) { + center = make_float3(0.0f, 0.0f, 0.0f); + + if (sd->type & PRIMITIVE_ALL_CURVE) { +# if defined(__HAIR__) + center = curve_motion_center_location(kg, sd); +# endif + } + else if (sd->type & PRIMITIVE_ALL_POINT) { +# if defined(__POINTCLOUD__) + center = point_motion_center_location(kg, sd); +# endif + } if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { object_position_transform(kg, sd, ¢er); @@ -272,7 +303,9 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg, } else #endif + { center = sd->P; + } float3 motion_pre = center, motion_post = center; @@ -284,8 +317,8 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg, int numverts, numkeys; object_motion_info(kg, sd->object, NULL, &numverts, &numkeys); -#ifdef __HAIR__ - if (is_curve_primitive) { +#if defined(__HAIR__) || defined(__POINTCLOUD__) + if (is_curve_or_point) { motion_pre = float4_to_float3(curve_attribute_float4(kg, sd, desc, NULL, NULL)); desc.offset += numkeys; motion_post = float4_to_float3(curve_attribute_float4(kg, sd, desc, NULL, NULL)); diff --git a/intern/cycles/kernel/geom/shader_data.h b/intern/cycles/kernel/geom/shader_data.h index 46bda2b656c..d3932545ef6 100644 --- a/intern/cycles/kernel/geom/shader_data.h +++ b/intern/cycles/kernel/geom/shader_data.h @@ -75,6 +75,13 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg, } else #endif +#ifdef __POINTCLOUD__ + if (sd->type & PRIMITIVE_ALL_POINT) { + /* point */ + point_shader_setup(kg, sd, isect, ray); + } + else +#endif if (sd->type & PRIMITIVE_TRIANGLE) { /* static triangle */ float3 Ng = triangle_normal(kg, sd); |