1 //
2 // Copyright 2019 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #include "pxr/imaging/hdSt/volumeShader.h"
25
26 #include "pxr/imaging/hdSt/tokens.h"
27 #include "pxr/imaging/hdSt/volume.h"
28 #include "pxr/imaging/hdSt/field.h"
29 #include "pxr/imaging/hdSt/resourceBinder.h"
30 #include "pxr/imaging/hdSt/textureObject.h"
31 #include "pxr/imaging/hdSt/textureHandle.h"
32 #include "pxr/imaging/hdSt/textureBinder.h"
33 #include "pxr/imaging/hdSt/materialParam.h"
34 #include "pxr/imaging/hdSt/resourceRegistry.h"
35 #include "pxr/imaging/hd/renderDelegate.h"
36 #include "pxr/imaging/hd/vtBufferSource.h"
37 #include "pxr/base/tf/staticTokens.h"
38
39 PXR_NAMESPACE_OPEN_SCOPE
40
41 TF_DEFINE_PRIVATE_TOKENS(
42 _tokens,
43 (stepSize)
44 (stepSizeLighting)
45
46 (sampleDistance)
47 (volumeBBoxInverseTransform)
48 (volumeBBoxLocalMin)
49 (volumeBBoxLocalMax)
50 );
51
52
HdSt_VolumeShader(HdRenderDelegate * const renderDelegate)53 HdSt_VolumeShader::HdSt_VolumeShader(HdRenderDelegate * const renderDelegate)
54 : _renderDelegate(renderDelegate),
55 _lastRenderSettingsVersion(0),
56 _stepSize(HdStVolume::defaultStepSize),
57 _stepSizeLighting(HdStVolume::defaultStepSizeLighting),
58 _fillsPointsBar(false)
59 {
60 }
61
62
63 HdSt_VolumeShader::~HdSt_VolumeShader() = default;
64
65 void
AddBindings(HdBindingRequestVector * const customBindings)66 HdSt_VolumeShader::AddBindings(HdBindingRequestVector * const customBindings)
67 {
68 HdSt_MaterialNetworkShader::AddBindings(customBindings);
69 customBindings->push_back(
70 HdBindingRequest(
71 HdBinding::UNIFORM,
72 _tokens->stepSize,
73 HdTypeFloat));
74 customBindings->push_back(
75 HdBindingRequest(
76 HdBinding::UNIFORM,
77 _tokens->stepSizeLighting,
78 HdTypeFloat));
79 }
80
81 void
BindResources(const int program,HdSt_ResourceBinder const & binder,HdRenderPassState const & state)82 HdSt_VolumeShader::BindResources(const int program,
83 HdSt_ResourceBinder const &binder,
84 HdRenderPassState const &state)
85 {
86 HdSt_MaterialNetworkShader::BindResources(program, binder, state);
87
88 const int currentRenderSettingsVersion =
89 _renderDelegate->GetRenderSettingsVersion();
90
91 if (_lastRenderSettingsVersion != currentRenderSettingsVersion) {
92 _lastRenderSettingsVersion = currentRenderSettingsVersion;
93 _stepSize = _renderDelegate->GetRenderSetting<float>(
94 HdStRenderSettingsTokens->volumeRaymarchingStepSize,
95 HdStVolume::defaultStepSize);
96 _stepSizeLighting = _renderDelegate->GetRenderSetting<float>(
97 HdStRenderSettingsTokens->volumeRaymarchingStepSizeLighting,
98 HdStVolume::defaultStepSizeLighting);
99 }
100
101 binder.BindUniformf(_tokens->stepSize, 1, &_stepSize);
102 binder.BindUniformf(_tokens->stepSizeLighting, 1, &_stepSizeLighting);
103 }
104
105 void
UnbindResources(const int program,HdSt_ResourceBinder const & binder,HdRenderPassState const & state)106 HdSt_VolumeShader::UnbindResources(const int program,
107 HdSt_ResourceBinder const &binder,
108 HdRenderPassState const &state)
109 {
110 HdSt_MaterialNetworkShader::UnbindResources(program, binder, state);
111 }
112
113 void
SetPointsBar(HdBufferArrayRangeSharedPtr const & pointsBar)114 HdSt_VolumeShader::SetPointsBar(HdBufferArrayRangeSharedPtr const &pointsBar)
115 {
116 _pointsBar = pointsBar;
117 }
118
119 void
SetFillsPointsBar(const bool fillsPointsBar)120 HdSt_VolumeShader::SetFillsPointsBar(const bool fillsPointsBar)
121 {
122 _fillsPointsBar = fillsPointsBar;
123 }
124
125 static
126 TfToken
_ConcatFallback(const TfToken & token)127 _ConcatFallback(const TfToken &token)
128 {
129 return TfToken(
130 token.GetString()
131 + HdSt_ResourceBindingSuffixTokens->fallback.GetString());
132 }
133
134 void
GetParamsAndBufferSpecsForBBoxAndSampleDistance(HdSt_MaterialParamVector * const params,HdBufferSpecVector * const specs)135 HdSt_VolumeShader::GetParamsAndBufferSpecsForBBoxAndSampleDistance(
136 HdSt_MaterialParamVector * const params,
137 HdBufferSpecVector * const specs)
138 {
139 {
140 params->emplace_back(
141 HdSt_MaterialParam::ParamTypeFallback,
142 _tokens->volumeBBoxInverseTransform,
143 VtValue(GfMatrix4d()));
144
145 static const TfToken sourceName(
146 _ConcatFallback(_tokens->volumeBBoxInverseTransform));
147 specs->emplace_back(
148 sourceName,
149 HdTupleType{HdTypeDoubleMat4, 1});
150 }
151
152 {
153 params->emplace_back(
154 HdSt_MaterialParam::ParamTypeFallback,
155 _tokens->volumeBBoxLocalMin,
156 VtValue(GfVec3d()));
157
158 static const TfToken sourceName(
159 _ConcatFallback(_tokens->volumeBBoxLocalMin));
160 specs->emplace_back(
161 sourceName,
162 HdTupleType{HdTypeDoubleVec3, 1});
163 }
164
165 {
166 params->emplace_back(
167 HdSt_MaterialParam::ParamTypeFallback,
168 _tokens->volumeBBoxLocalMax,
169 VtValue(GfVec3d()));
170
171 static const TfToken sourceName(
172 _ConcatFallback(_tokens->volumeBBoxLocalMax));
173 specs->emplace_back(
174 sourceName,
175 HdTupleType{HdTypeDoubleVec3, 1});
176 }
177
178 {
179 params->emplace_back(
180 HdSt_MaterialParam::ParamTypeFallback,
181 _tokens->sampleDistance,
182 VtValue(100000.0f));
183
184 static const TfToken sourceName(
185 _ConcatFallback(_tokens->sampleDistance));
186 specs->emplace_back(
187 sourceName,
188 HdTupleType{HdTypeFloat, 1});
189 }
190 }
191
192 void
GetBufferSourcesForBBoxAndSampleDistance(const std::pair<GfBBox3d,float> & bboxAndSampleDistance,HdBufferSourceSharedPtrVector * const sources)193 HdSt_VolumeShader::GetBufferSourcesForBBoxAndSampleDistance(
194 const std::pair<GfBBox3d, float> &bboxAndSampleDistance,
195 HdBufferSourceSharedPtrVector * const sources)
196 {
197 const GfBBox3d &bbox = bboxAndSampleDistance.first;
198 const GfRange3d &range = bbox.GetRange();
199
200 {
201 static const TfToken sourceName(
202 _ConcatFallback(_tokens->volumeBBoxInverseTransform));
203 sources->push_back(
204 std::make_shared<HdVtBufferSource>(
205 sourceName,
206 VtValue(bbox.GetInverseMatrix())));
207 }
208
209 {
210 static const TfToken sourceName(
211 _ConcatFallback(_tokens->volumeBBoxLocalMin));
212 sources->push_back(
213 std::make_shared<HdVtBufferSource>(
214 sourceName,
215 VtValue(GetSafeMin(range))));
216 }
217
218 {
219 static const TfToken sourceName(
220 _ConcatFallback(_tokens->volumeBBoxLocalMax));
221 sources->push_back(
222 std::make_shared<HdVtBufferSource>(
223 sourceName,
224 VtValue(GetSafeMax(range))));
225 }
226
227 {
228 const float sampleDistance = bboxAndSampleDistance.second;
229
230 static const TfToken sourceName(
231 _ConcatFallback(_tokens->sampleDistance));
232 sources->push_back(
233 std::make_shared<HdVtBufferSource>(
234 sourceName,
235 VtValue(sampleDistance)));
236 }
237 }
238
239 GfVec3d
GetSafeMin(const GfRange3d & range)240 HdSt_VolumeShader::GetSafeMin(const GfRange3d &range)
241 {
242 if (range.IsEmpty()) {
243 return GfVec3d(0.0, 0.0, 0.0);
244 }
245 return range.GetMin();
246 }
247
248 GfVec3d
GetSafeMax(const GfRange3d & range)249 HdSt_VolumeShader::GetSafeMax(const GfRange3d &range)
250 {
251 if (range.IsEmpty()) {
252 return GfVec3d(0.0, 0.0, 0.0);
253 }
254 return range.GetMax();
255 }
256
257 namespace {
258
259 // Square of length of a 3-vector
260 float
_SqrLengthThreeVector(const double * const v)261 _SqrLengthThreeVector(const double * const v)
262 {
263 return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
264 }
265
266 // Assuming the bounding box comes from a grid (range is the
267 // bounding box of active voxels and matrix the grid transform),
268 // compute the distance between samples.
269 //
270 // Note that this assumes that the bounding box transform is an
271 // affine transformation obtained by composing scales with rotation.
272 // (More generally, we would need to take the minimum of the singular
273 // values from the SVD of the 3x3-matrix).
274 float
_ComputeSampleDistance(const GfBBox3d & bbox)275 _ComputeSampleDistance(const GfBBox3d &bbox)
276 {
277 const GfMatrix4d &m = bbox.GetMatrix();
278
279 // Take minimum of lengths of images of the x-, y-, and z-vector.
280 return sqrt(
281 std::min({ _SqrLengthThreeVector(m[0]),
282 _SqrLengthThreeVector(m[1]),
283 _SqrLengthThreeVector(m[2]) }));
284 }
285
286 // Compute the bounding box and sample distance from all the fields in
287 // this volume.
288 std::pair<GfBBox3d, float>
_ComputeBBoxAndSampleDistance(const HdStShaderCode::NamedTextureHandleVector & textures)289 _ComputeBBoxAndSampleDistance(
290 const HdStShaderCode::NamedTextureHandleVector &textures)
291 {
292 // Computed by combining all bounding boxes.
293 GfBBox3d bbox;
294 // Computes as minimum of all sampling distances.
295 // (Initialized to large value rather than IEEE754-infinity which might
296 // not be converted to correctly to GLSL: if there is
297 // no texture, the ray marcher simply obtains a point outside the
298 // bounding box after one step and stops).
299 float sampleDistance = 1000000.0;
300
301 for (const HdStShaderCode::NamedTextureHandle &texture : textures) {
302 HdStTextureObjectSharedPtr const &textureObject =
303 texture.handle->GetTextureObject();
304
305 if (const HdStFieldTextureObject * const fieldTex =
306 dynamic_cast<HdStFieldTextureObject *>(
307 textureObject.get())) {
308 const GfBBox3d &fieldBbox = fieldTex->GetBoundingBox();
309 bbox =
310 GfBBox3d::Combine(bbox, fieldBbox);
311 sampleDistance =
312 std::min(sampleDistance, _ComputeSampleDistance(fieldBbox));
313 }
314 }
315
316 return { bbox, sampleDistance };
317 }
318
319 // Compute 8 vertices of a bounding box.
320
321 VtValue
_ComputePoints(const GfBBox3d & bbox)322 _ComputePoints(const GfBBox3d &bbox)
323 {
324 VtVec3fArray points(8);
325
326 size_t i = 0;
327
328 const GfMatrix4d &transform = bbox.GetMatrix();
329 const GfRange3d &range = bbox.GetRange();
330
331 // Use vertices of a cube shrunk to point for empty bounding box
332 // (to avoid min and max being large floating point numbers).
333 const GfVec3d min = HdSt_VolumeShader::GetSafeMin(range);
334 const GfVec3d max = HdSt_VolumeShader::GetSafeMax(range);
335
336 for (const double x : { min[0], max[0] }) {
337 for (const double y : { min[1], max[1] }) {
338 for (const double z : { min[2], max[2] }) {
339 points[i] = GfVec3f(transform.Transform(GfVec3d(x, y, z)));
340 i++;
341 }
342 }
343 }
344
345 return VtValue(points);
346 }
347
348 } // end anonymous namespace
349
350 void
AddResourcesFromTextures(ResourceContext & ctx) const351 HdSt_VolumeShader::AddResourcesFromTextures(ResourceContext &ctx) const
352 {
353 HdBufferSourceSharedPtrVector shaderBarSources;
354
355 // Fills in sampling transforms for textures.
356 HdSt_TextureBinder::ComputeBufferSources(
357 GetNamedTextureHandles(), &shaderBarSources);
358
359 if (_fillsPointsBar) {
360 // Compute volume bounding box from field bounding boxes
361 const std::pair<GfBBox3d, float> bboxAndSampleDistance =
362 _ComputeBBoxAndSampleDistance(GetNamedTextureHandles());
363
364 const GfBBox3d &bbox = bboxAndSampleDistance.first;
365
366 // Use as points
367 ctx.AddSource(
368 _pointsBar,
369 std::make_shared<HdVtBufferSource>(
370 HdTokens->points,
371 _ComputePoints(bbox)));
372
373 // And let the shader know for raymarching bounds.
374 GetBufferSourcesForBBoxAndSampleDistance(
375 bboxAndSampleDistance, &shaderBarSources);
376 }
377
378 if (!shaderBarSources.empty()) {
379 ctx.AddSources(GetShaderData(), std::move(shaderBarSources));
380 }
381 }
382
383 void
SetFieldDescriptors(const HdVolumeFieldDescriptorVector & fieldDescs)384 HdSt_VolumeShader::SetFieldDescriptors(
385 const HdVolumeFieldDescriptorVector & fieldDescs)
386 {
387 _fieldDescriptors = fieldDescs;
388 }
389
390 void
UpdateTextureHandles(HdSceneDelegate * const sceneDelegate)391 HdSt_VolumeShader::UpdateTextureHandles(
392 HdSceneDelegate * const sceneDelegate)
393 {
394 TRACE_FUNCTION();
395
396 HdStResourceRegistrySharedPtr const resourceRegistry =
397 std::static_pointer_cast<HdStResourceRegistry>(
398 sceneDelegate->GetRenderIndex().GetResourceRegistry());
399
400 NamedTextureHandleVector textureHandles = GetNamedTextureHandles();
401
402 if (!TF_VERIFY(textureHandles.size() == _fieldDescriptors.size())) {
403 return;
404 }
405
406 // Walk through the vector of named texture handles and field descriptors
407 // simultaneously.
408 for (size_t i = 0; i < textureHandles.size(); i++) {
409 // To allocate the texture and update it in the vector ...
410
411 // use field descriptor to find field prim, ...
412 const HdVolumeFieldDescriptor &fieldDesc = _fieldDescriptors[i];
413
414 const HdStField * const fieldPrim =
415 dynamic_cast<HdStField*>(
416 sceneDelegate->GetRenderIndex().GetBprim(
417 fieldDesc.fieldPrimType, fieldDesc.fieldId));
418
419 // ask field prim for texture information, ...
420 const HdStTextureIdentifier &textureId =
421 TF_VERIFY(fieldPrim) ?
422 fieldPrim->GetTextureIdentifier() : HdStTextureIdentifier();
423 const HdTextureType textureType = textureHandles[i].type;
424 const size_t textureMemory =
425 TF_VERIFY(fieldPrim) ?
426 fieldPrim->GetTextureMemory() : 0;
427 static const HdSamplerParameters samplerParams{
428 HdWrapBlack, HdWrapBlack, HdWrapBlack,
429 HdMinFilterLinear, HdMagFilterLinear };
430
431 // allocate texture handle and assign it.
432 textureHandles[i].handle =
433 resourceRegistry->AllocateTextureHandle(
434 textureId,
435 textureType,
436 samplerParams,
437 textureMemory,
438 shared_from_this());
439 }
440
441 // And update!
442 SetNamedTextureHandles(textureHandles);
443 }
444
445
446 PXR_NAMESPACE_CLOSE_SCOPE
447