1
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2019 Esteban Tovagliari, The appleseedhq Organization
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 //
28
29 // interface header.
30 #include "rectangleobject.h"
31
32 // appleseed.renderer headers.
33 #include "renderer/kernel/shading/shadingray.h"
34
35 // appleseed.foundation headers.
36 #include "foundation/math/intersection/rayparallelogram.h"
37 #include "foundation/math/ray.h"
38 #include "foundation/math/scalar.h"
39 #include "foundation/math/vector.h"
40 #include "foundation/platform/compiler.h"
41 #include "foundation/utility/api/specializedapiarrays.h"
42 #include "foundation/utility/containers/dictionary.h"
43 #include "foundation/utility/job/iabortswitch.h"
44 #include "foundation/utility/searchpaths.h"
45 #include "foundation/utility/string.h"
46
47 using namespace foundation;
48
49 namespace renderer
50 {
51
52 //
53 // RectangleObject class implementation.
54 //
55
56 namespace
57 {
58 const char* Model = "rectangle_object";
59 }
60
61 struct RectangleObject::Impl
62 {
63 Vector3d m_corner;
64 Vector3d m_normal;
65 Vector3d m_x;
66 Vector3d m_y;
67 bool m_skip_intersection;
68 };
69
RectangleObject(const char * name,const ParamArray & params)70 RectangleObject::RectangleObject(
71 const char* name,
72 const ParamArray& params)
73 : ProceduralObject(name, params)
74 , impl(new Impl())
75 {
76 }
77
release()78 void RectangleObject::release()
79 {
80 delete this;
81 }
82
get_model() const83 const char* RectangleObject::get_model() const
84 {
85 return Model;
86 }
87
on_frame_begin(const Project & project,const BaseGroup * parent,OnFrameBeginRecorder & recorder,IAbortSwitch * abort_switch)88 bool RectangleObject::on_frame_begin(
89 const Project& project,
90 const BaseGroup* parent,
91 OnFrameBeginRecorder& recorder,
92 IAbortSwitch* abort_switch)
93 {
94 if (!ProceduralObject::on_frame_begin(project, parent, recorder, abort_switch))
95 return false;
96
97 const double width = get_uncached_width();
98 const double height = get_uncached_height();
99
100 const double half_width = width * 0.5;
101 const double half_height = height * 0.5;
102
103 impl->m_x = Vector3d(width, 0.0, 0.0);
104 impl->m_y = Vector3d(0.0, 0.0, -height);
105
106 impl->m_corner = Vector3d(-half_width, 0.0, half_height);
107 impl->m_normal = Vector3d(0.0, 1.0, 0.0);
108
109 impl->m_skip_intersection = (half_width == 0.0f || half_height == 0.0f);
110
111 return true;
112 }
113
compute_local_bbox() const114 GAABB3 RectangleObject::compute_local_bbox() const
115 {
116 const float width = static_cast<float>(get_uncached_width());
117 const float height = static_cast<float>(get_uncached_height());
118
119 const GVector3 pmax(width * 0.5f, 0.0f, height * 0.5f);
120 const GVector3 pmin(-pmax.x, 0.0f, -pmax.z);
121
122 GAABB3 bbox(pmin, pmax);
123 return bbox;
124 }
125
get_material_slot_count() const126 size_t RectangleObject::get_material_slot_count() const
127 {
128 return 1;
129 }
130
get_material_slot(const size_t index) const131 const char* RectangleObject::get_material_slot(const size_t index) const
132 {
133 return "default";
134 }
135
get_uncached_width() const136 double RectangleObject::get_uncached_width() const
137 {
138 return m_params.get_optional<double>("width", 1.0);
139 }
140
get_uncached_height() const141 double RectangleObject::get_uncached_height() const
142 {
143 return m_params.get_optional<double>("height", 1.0);
144 }
145
get_origin_and_axes(Vector3d & origin,Vector3d & x,Vector3d & y,Vector3d & n) const146 void RectangleObject::get_origin_and_axes(
147 Vector3d& origin,
148 Vector3d& x,
149 Vector3d& y,
150 Vector3d& n) const
151 {
152 const double width = get_uncached_width();
153 const double height = get_uncached_height();
154
155 origin = Vector3d(-width * 0.5, 0.0, height * 0.5);
156 x = Vector3d(width, 0.0, 0.0);
157 y = Vector3d(0.0, 0.0, -height);
158 n = Vector3d(0.0, 1.0, 0.0);
159 }
160
intersect(const ShadingRay & ray,IntersectionResult & result) const161 void RectangleObject::intersect(
162 const ShadingRay& ray,
163 IntersectionResult& result) const
164 {
165 if APPLESEED_UNLIKELY(impl->m_skip_intersection)
166 {
167 result.m_hit = false;
168 return;
169 }
170
171 double u, v;
172
173 result.m_hit = intersect_parallelogram(
174 ray,
175 impl->m_corner,
176 impl->m_x,
177 impl->m_y,
178 impl->m_normal,
179 result.m_distance,
180 u,
181 v);
182
183 if (result.m_hit)
184 {
185 result.m_geometric_normal = impl->m_normal;
186 result.m_shading_normal = impl->m_normal;
187
188 result.m_uv[0] = static_cast<float>(u);
189 result.m_uv[1] = static_cast<float>(v);
190 result.m_material_slot = 0;
191 }
192 }
193
intersect(const ShadingRay & ray) const194 bool RectangleObject::intersect(const ShadingRay& ray) const
195 {
196 if APPLESEED_UNLIKELY(impl->m_skip_intersection)
197 return false;
198
199 return intersect_parallelogram(
200 ray,
201 impl->m_corner,
202 impl->m_x,
203 impl->m_y,
204 impl->m_normal);
205 }
206
207
208 //
209 // RectangleObjectFactory class implementation.
210 //
211
release()212 void RectangleObjectFactory::release()
213 {
214 delete this;
215 }
216
get_model() const217 const char* RectangleObjectFactory::get_model() const
218 {
219 return Model;
220 }
221
get_model_metadata() const222 Dictionary RectangleObjectFactory::get_model_metadata() const
223 {
224 return
225 Dictionary()
226 .insert("name", Model)
227 .insert("label", "Rectangle Object");
228 }
229
get_input_metadata() const230 DictionaryArray RectangleObjectFactory::get_input_metadata() const
231 {
232 DictionaryArray metadata;
233
234 metadata.push_back(
235 Dictionary()
236 .insert("name", "width")
237 .insert("label", "Width")
238 .insert("type", "numeric")
239 .insert("min",
240 Dictionary()
241 .insert("value", "0.0")
242 .insert("type", "hard"))
243 .insert("max",
244 Dictionary()
245 .insert("value", "10.0")
246 .insert("type", "soft"))
247 .insert("use", "optional")
248 .insert("default", "1.0"));
249
250 metadata.push_back(
251 Dictionary()
252 .insert("name", "height")
253 .insert("label", "Height")
254 .insert("type", "numeric")
255 .insert("min",
256 Dictionary()
257 .insert("value", "0.0")
258 .insert("type", "hard"))
259 .insert("max",
260 Dictionary()
261 .insert("value", "10.0")
262 .insert("type", "soft"))
263 .insert("use", "optional")
264 .insert("default", "1.0"));
265
266 return metadata;
267 }
268
create(const char * name,const ParamArray & params) const269 auto_release_ptr<Object> RectangleObjectFactory::create(
270 const char* name,
271 const ParamArray& params) const
272 {
273 return auto_release_ptr<Object>(new RectangleObject(name, params));
274 }
275
create(const char * name,const ParamArray & params,const SearchPaths & search_paths,const bool omit_loading_assets,ObjectArray & objects) const276 bool RectangleObjectFactory::create(
277 const char* name,
278 const ParamArray& params,
279 const SearchPaths& search_paths,
280 const bool omit_loading_assets,
281 ObjectArray& objects) const
282 {
283 objects.push_back(create(name, params).release());
284 return true;
285 }
286
287 } // namespace renderer
288