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) 2017-2018 Francois Beaune, 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 // appleseed.renderer headers. 30 #include "renderer/api/object.h" 31 #include "renderer/api/project.h" 32 #include "renderer/api/rendering.h" 33 #include "renderer/api/scene.h" 34 #include "renderer/api/types.h" 35 36 // todo: fix. 37 #include "renderer/kernel/shading/shadingray.h" 38 39 // appleseed.foundation headers. 40 #include "foundation/math/ray.h" 41 #include "foundation/math/scalar.h" 42 #include "foundation/math/vector.h" 43 #include "foundation/utility/api/specializedapiarrays.h" 44 #include "foundation/utility/containers/dictionary.h" 45 #include "foundation/utility/job/iabortswitch.h" 46 #include "foundation/utility/searchpaths.h" 47 #include "foundation/utility/string.h" 48 49 // appleseed.main headers. 50 #include "main/dllvisibility.h" 51 52 // Standard headers. 53 #include <algorithm> 54 #include <cmath> 55 56 namespace asf = foundation; 57 namespace asr = renderer; 58 59 namespace 60 { 61 // 62 // A sphere object. 63 // 64 // The sphere is assumed to be centered at the origin. 65 // 66 67 const char* Model = "example_sphere_object"; 68 69 class SphereObject 70 : public asr::ProceduralObject 71 { 72 public: 73 // Constructor. SphereObject(const char * name,const asr::ParamArray & params)74 SphereObject( 75 const char* name, 76 const asr::ParamArray& params) 77 : asr::ProceduralObject(name, params) 78 { 79 } 80 81 // Delete this instance. release()82 void release() override 83 { 84 delete this; 85 } 86 87 // Return a string identifying this object model. get_model() const88 const char* get_model() const override 89 { 90 return Model; 91 } 92 93 // This method is called once before rendering each frame. 94 // Returns true on success, false otherwise. on_frame_begin(const asr::Project & project,const asr::BaseGroup * parent,asr::OnFrameBeginRecorder & recorder,asf::IAbortSwitch * abort_switch)95 bool on_frame_begin( 96 const asr::Project& project, 97 const asr::BaseGroup* parent, 98 asr::OnFrameBeginRecorder& recorder, 99 asf::IAbortSwitch* abort_switch) override 100 { 101 if (!asr::ProceduralObject::on_frame_begin(project, parent, recorder, abort_switch)) 102 return false; 103 104 m_radius = get_uncached_radius(); 105 m_rcp_radius = 1.0 / m_radius; 106 107 return true; 108 } 109 110 // Compute the local space bounding box of the object over the shutter interval. compute_local_bbox() const111 asr::GAABB3 compute_local_bbox() const override 112 { 113 const auto r = static_cast<asr::GScalar>(get_uncached_radius()); 114 return asr::GAABB3(asr::GVector3(-r), asr::GVector3(r)); 115 } 116 117 // Access materials slots. get_material_slot_count() const118 size_t get_material_slot_count() const override 119 { 120 return 1; 121 } get_material_slot(const size_t index) const122 const char* get_material_slot(const size_t index) const override 123 { 124 return "default"; 125 } 126 127 // Compute the intersection between a ray expressed in object space and 128 // the surface of this object and return detailed intersection results. intersect(const asr::ShadingRay & ray,IntersectionResult & result) const129 void intersect( 130 const asr::ShadingRay& ray, 131 IntersectionResult& result) const override 132 { 133 const double Epsilon = 1.0e-6; 134 135 const double a = asf::dot(ray.m_org, ray.m_dir); 136 const double b = asf::square(a) - dot(ray.m_org, ray.m_org) + asf::square(m_radius); 137 138 if (b < 0.0) 139 { 140 result.m_hit = false; 141 return; 142 } 143 144 const double c = std::sqrt(b); 145 146 double t = -a - c; 147 if (t < std::max(ray.m_tmin, Epsilon) || t >= ray.m_tmax) 148 { 149 t = -a + c; 150 if (t < std::max(ray.m_tmin, Epsilon) || t >= ray.m_tmax) 151 { 152 result.m_hit = false; 153 return; 154 } 155 } 156 157 result.m_hit = true; 158 result.m_distance = t; 159 160 const asf::Vector3d n = asf::normalize(ray.point_at(t)); 161 result.m_geometric_normal = n; 162 result.m_shading_normal = n; 163 164 const asf::Vector3f p(ray.point_at(t) * m_rcp_radius); 165 result.m_uv[0] = std::acos(p.y) * asf::RcpPi<float>(); 166 result.m_uv[1] = std::atan2(-p.z, p.x) * asf::RcpTwoPi<float>(); 167 168 result.m_material_slot = 0; 169 } 170 171 // Compute the intersection between a ray expressed in object space and 172 // the surface of this object and simply return whether there was a hit. intersect(const asr::ShadingRay & ray) const173 bool intersect( 174 const asr::ShadingRay& ray) const override 175 { 176 const double Epsilon = 1.0e-6; 177 178 const double a = asf::dot(ray.m_org, ray.m_dir); 179 const double b = asf::square(a) - dot(ray.m_org, ray.m_org) + asf::square(m_radius); 180 181 if (b < 0.0) 182 return false; 183 184 const double c = std::sqrt(b); 185 186 const double t1 = -a - c; 187 if (t1 >= std::max(ray.m_tmin, Epsilon) && t1 < ray.m_tmax) 188 return true; 189 190 const double t2 = -a + c; 191 if (t2 >= std::max(ray.m_tmin, Epsilon) && t2 < ray.m_tmax) 192 return true; 193 194 return false; 195 } 196 197 private: 198 double m_radius; 199 double m_rcp_radius; 200 get_uncached_radius() const201 double get_uncached_radius() const 202 { 203 return m_params.get_optional<double>("radius"); 204 } 205 }; 206 207 208 // 209 // Factory for the new object model. 210 // 211 212 class SphereObjectFactory 213 : public asr::IObjectFactory 214 { 215 public: 216 // Delete this instance. release()217 void release() override 218 { 219 delete this; 220 } 221 222 // Return a string identifying this object model. get_model() const223 const char* get_model() const override 224 { 225 return Model; 226 } 227 228 // Return metadata for this object model. get_model_metadata() const229 asf::Dictionary get_model_metadata() const override 230 { 231 return 232 asf::Dictionary() 233 .insert("name", Model) 234 .insert("label", "Sphere Object"); 235 } 236 237 // Return metadata for the inputs of this object model. get_input_metadata() const238 asf::DictionaryArray get_input_metadata() const override 239 { 240 asf::DictionaryArray metadata; 241 242 metadata.push_back( 243 asf::Dictionary() 244 .insert("name", "radius") 245 .insert("label", "Radius") 246 .insert("type", "numeric") 247 .insert("min", 248 asf::Dictionary() 249 .insert("value", "0.0") 250 .insert("type", "hard")) 251 .insert("max", 252 asf::Dictionary() 253 .insert("value", "10.0") 254 .insert("type", "soft")) 255 .insert("use", "optional") 256 .insert("default", "1.0")); 257 258 return metadata; 259 } 260 261 // Create a new single empty object. create(const char * name,const asr::ParamArray & params) const262 asf::auto_release_ptr<asr::Object> create( 263 const char* name, 264 const asr::ParamArray& params) const override 265 { 266 return asf::auto_release_ptr<asr::Object>(new SphereObject(name, params)); 267 } 268 269 // Create objects, potentially from external assets. create(const char * name,const asr::ParamArray & params,const asf::SearchPaths & search_paths,const bool omit_loading_assets,asr::ObjectArray & objects) const270 bool create( 271 const char* name, 272 const asr::ParamArray& params, 273 const asf::SearchPaths& search_paths, 274 const bool omit_loading_assets, 275 asr::ObjectArray& objects) const override 276 { 277 objects.push_back(create(name, params).release()); 278 return true; 279 } 280 }; 281 } 282 283 284 // 285 // Plugin entry point. 286 // 287 288 extern "C" 289 { appleseed_create_object_factory()290 APPLESEED_DLL_EXPORT asr::IObjectFactory* appleseed_create_object_factory() 291 { 292 return new SphereObjectFactory(); 293 } 294 } 295