Skip to content

Commit 5a8f7d5

Browse files
authored
More flexibility in pointcloud_search/get retrieval (#752)
In the default RendererServices implementation of retrieving data from point clouds via Partio, there had to be an exact match between the attribute type of the point cloud file (as understood by Partio) and the element type of the OSL array used to store the retrieved data. Because OSL doesn't support 2D arrays, that means that you could retrieve only data of the main non-array OSL types: int, float, 3-float (color, point, vector, normal etc.). But we had somebody create a point cloud that stored float[4] to store quaternions (don't ask), and then was unable to retrieve it from OSL, because there is no float[4] type. So the solution is that we are loosening the type matching tests. Simply stated, it's willing to match either a float or a float[n] in the point cloud, when retrieving into a float array in OSL. If it's a float[n], it will just pack them contiguously into the OSL array of floats, and it's up to the shader to know what's expected and to unpack and interpret it properly. An error will be reported if there is not enough room in the array provided.
1 parent 75b475c commit 5a8f7d5

3 files changed

Lines changed: 91 additions & 44 deletions

File tree

src/doc/languagespec.tex

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4337,6 +4337,15 @@ \section{Texture}
43374337
exist in memory, and that it will be initialized by reading a point
43384338
cloud from disk, if there is one matching the name.
43394339

4340+
Generally, the element type of the data arrays must match exactly the type
4341+
of the point data attribute, or else you will get a runtime error. But there
4342+
are two exceptions: (1) ``triple'' types (\color, \point, \vector, \normal)
4343+
are considered interchangeable; and (2) it is legal to retrieve {\cf float}
4344+
arrays (e.g., a point cloud attribute that is {\cf float[4]}) into a regular
4345+
array of {\cf float}, and the results will simply be concatenated into the
4346+
larger array (which must still be big enough, in total, to hold {\cf
4347+
maxpoints} of the data type in the file).
4348+
43404349
\noindent Example:
43414350

43424351
\begin{code}
@@ -4370,10 +4379,20 @@ \section{Texture}
43704379
int indices[10];
43714380
int n = pointcloud_search ("particles.ptc", P, r, 10,
43724381
"index", indices);
4373-
float temp[10];
4382+
float temp[10]; // presumed to be "float" attribute
4383+
float quaternions[40]; // presumed to be "float[4]" attribute
43744384
int ok = pointcloud_get ("particles.ptc", indices, n,
4375-
"temperature", temp);
4385+
"temperature", temp,
4386+
"quat", quaternions);
43764387
\end{code}
4388+
4389+
As with {\cf pointcloud_search}, the element type of the data array must
4390+
either be equivalent to the point cloud attribute being retrieved, or else
4391+
when retrieving {\cf float} arrays (e.g., a point cloud attribute
4392+
that is {\cf float[4]}) into a regular array of {\cf float}, and the
4393+
results will simply be concatenated into the larger array (which must
4394+
still be big enough, in total, to hold {\cf maxpoints} of the data type
4395+
in the file).
43774396
\apiend
43784397

43794398

src/liboslexec/constfold.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2594,10 +2594,6 @@ DECLFOLDER(constfold_pointcloud_search)
25942594
continue;
25952595
void *const_data = NULL;
25962596
TypeDesc const_valtype = value_types[i];
2597-
// How big should the constant arrays be? Shrink to the size of
2598-
// the results if they are much smaller.
2599-
if (count < const_valtype.arraylen/2 && const_valtype.arraylen > 8)
2600-
const_valtype.arraylen = count;
26012597
tmp.clear ();
26022598
tmp.resize (const_valtype.size(), 0);
26032599
const_data = &tmp[0];
@@ -2688,7 +2684,7 @@ DECLFOLDER(constfold_pointcloud_get)
26882684
int ok = rop.renderer()->pointcloud_get (rop.shaderglobals(), filename,
26892685
indices, count,
26902686
*(ustring *)Attr_name.data(),
2691-
valtype.elementtype(), &data[0]);
2687+
valtype, &data[0]);
26922688
rop.shadingsys().pointcloud_stats (0, 1, 0);
26932689

26942690
rop.turn_into_assign (op, rop.add_constant (TypeDesc::TypeInt, &ok),

src/liboslexec/pointcloud.cpp

Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -163,29 +163,67 @@ PartioType (TypeDesc t)
163163

164164

165165

166-
inline bool
167-
compatiblePartioType (Partio::ParticleAttribute *received, int expected)
166+
// Helper: number of base values
167+
inline int
168+
basevals (TypeDesc t)
168169
{
169-
return ((expected == Partio::VECTOR) &&
170-
(received->type == expected || received->type == Partio::FLOAT) &&
171-
received->count == 3) ||
172-
(received->type == expected && received->count == 1);
170+
return t.numelements() * int(t.aggregate);
173171
}
174172

175173

176174

177-
inline const char *
178-
partioTypeString(Partio::ParticleAttribute *ptype)
175+
bool
176+
compatiblePartioType (TypeDesc partio_type, TypeDesc osl_element_type)
177+
{
178+
// Matching types (treating all VEC3 aggregates as equivalent)...
179+
if (equivalent (partio_type, osl_element_type))
180+
return true;
181+
182+
// Consider arrays and aggregates as interchangeable, as long as the
183+
// totals are the same.
184+
if (partio_type.basetype == osl_element_type.basetype &&
185+
basevals(partio_type) == basevals(osl_element_type))
186+
return true;
187+
188+
// The Partio file may contain an array size that OSL can't exactly
189+
// represent, for example the partio type may be float[4], and the
190+
// OSL array will be float[] but the element type will be just float
191+
// because OSL doesn't permit multi-dimensional arrays.
192+
// Just allow it anyway and fill in the OSL array.
193+
if (TypeDesc::BASETYPE(partio_type.basetype) == osl_element_type)
194+
return true;
195+
196+
return false;
197+
}
198+
199+
200+
201+
TypeDesc
202+
TypeDescOfPartioType (const Partio::ParticleAttribute *ptype)
179203
{
204+
TypeDesc type; // default to UNKNOWN
180205
switch (ptype->type) {
181-
case Partio::INT: return "int";
182-
case Partio::FLOAT: return "float";
183-
case Partio::VECTOR: return "vector";
184-
default: return "none";
206+
case Partio::INT:
207+
type = TypeDesc::INT;
208+
if (ptype->count > 1)
209+
type.arraylen = ptype->count;
210+
break;
211+
case Partio::FLOAT:
212+
type = TypeDesc::FLOAT;
213+
if (ptype->count > 1)
214+
type.arraylen = ptype->count;
215+
break;
216+
case Partio::VECTOR:
217+
type = TypeDesc (TypeDesc::FLOAT, TypeDesc::VEC3, TypeDesc::NOSEMANTICS);
218+
if (ptype->count != 3)
219+
type = TypeDesc::UNKNOWN; // Must be 3: punt
220+
break;
221+
default:
222+
break; // Any other future types -- return UNKNOWN
185223
}
224+
return type;
186225
}
187226

188-
189227
#endif
190228

191229
} // anon namespace
@@ -308,50 +346,44 @@ RendererServices::pointcloud_get (ShaderGlobals *sg,
308346

309347
PointCloud *pc = PointCloud::get(filename);
310348
if (pc == NULL) { // The file failed to load
311-
sg->context->error ("pointcloud_get: could not open \"%s\"", filename.c_str());
349+
sg->context->error ("pointcloud_get: could not open \"%s\"", filename);
312350
return 0;
313351
}
314352

315353
const Partio::ParticlesData *cloud = pc->read_access();
316354
if (cloud == NULL) { // The file failed to load
317-
sg->context->error ("pointcloud_get: could not open \"%s\"", filename.c_str());
355+
sg->context->error ("pointcloud_get: could not open \"%s\"", filename);
318356
return 0;
319357
}
320358

321359
// lookup the ParticleAttribute pointer needed for a query
322360
Partio::ParticleAttribute *attr = pc->m_attributes[attr_name].get();
323361
if (! attr) {
324-
sg->context->error ("Accessing unexisting attribute %s in pointcloud \"%s\"", attr_name.c_str(), filename.c_str());
362+
sg->context->error ("Accessing unexisting attribute %s in pointcloud \"%s\"", attr_name, filename);
325363
return 0;
326364
}
327365

328-
// Now make sure that types are compatible
366+
// Type the partio file contains:
367+
TypeDesc partio_type = TypeDescOfPartioType (attr);
368+
// Type the OSL shader has provided in destination array:
329369
TypeDesc element_type = attr_type.elementtype ();
330-
int attr_partio_type = 0;
331-
332-
// Convert the OSL (OIIO) type to the equivalent Partio type
333-
if (element_type == TypeDesc::TypeFloat)
334-
attr_partio_type = Partio::FLOAT;
335-
else if (element_type == TypeDesc::TypeInt)
336-
attr_partio_type = Partio::INT;
337-
else if (element_type == TypeDesc::TypeColor || element_type == TypeDesc::TypePoint ||
338-
element_type == TypeDesc::TypeVector || element_type == TypeDesc::TypeNormal)
339-
attr_partio_type = Partio::VECTOR;
340-
else {
341-
// error ("Unsupported attribute type %s for pointcloud query in attribute %s",
342-
// element_type.c_str(), attr_name.c_str());
343-
return 0;
344-
}
345370

346371
// Finally check for some equivalent types like float3 and vector
347-
if (!compatiblePartioType(attr, attr_partio_type)) {
348-
sg->context->error ("Type of attribute \"%s\" : %s[%d] not compatible with OSL's %s in \"%s\" pointcloud",
349-
attr_name.c_str(), partioTypeString(attr), attr->count,
350-
element_type.c_str(), filename.c_str());
372+
if (!compatiblePartioType(partio_type, element_type)) {
373+
sg->context->error ("Type of attribute \"%s\" : %s not compatible with OSL's %s in \"%s\" pointcloud",
374+
attr_name, partio_type, element_type, filename);
351375
return 0;
352376
}
353377

354-
ASSERT (sizeof(size_t) == sizeof(Partio::ParticleIndex) &&
378+
// For safety, clamp the count to the most that will fit in the output
379+
int maxn = basevals(attr_type) / basevals(partio_type);
380+
if (maxn < count) {
381+
sg->context->error ("Point cloud attribute \"%s\" : %s with retrieval count %d will not fit in %s",
382+
attr_name, partio_type, count, attr_type);
383+
count = maxn;
384+
}
385+
386+
static_assert (sizeof(size_t) == sizeof(Partio::ParticleIndex),
355387
"Only will work if Partio ParticleIndex is the size of a size_t");
356388
// FIXME -- if anybody cares about an architecture in which that is not
357389
// the case, we can easily allocate local space to retrieve the indices,

0 commit comments

Comments
 (0)