OSL_SHADEOP int osl_regex_impl (void *sg_, const char *subject_, void *results, int nresults, const char *pattern, int fullmatch) { ShaderGlobals *sg = (ShaderGlobals *)sg_; ShadingContext *ctx = sg->context; const std::string &subject (ustring::from_unique(subject_).string()); match_results<std::string::const_iterator> mresults; const regex ®ex (ctx->find_regex (USTR(pattern))); if (nresults > 0) { std::string::const_iterator start = subject.begin(); int res = fullmatch ? regex_match (subject, mresults, regex) : regex_search (subject, mresults, regex); int *m = (int *)results; for (int r = 0; r < nresults; ++r) { if (r/2 < (int)mresults.size()) { if ((r & 1) == 0) m[r] = mresults[r/2].first - start; else m[r] = mresults[r/2].second - start; } else { m[r] = USTR(pattern).length(); } } return res; } else { return fullmatch ? regex_match (subject, regex) : regex_search (subject, regex); } }
bool RendererServices::environment (ustring filename, TextureHandle *texture_handle, TexturePerthread *texture_thread_info, TextureOpt &options, ShaderGlobals *sg, const Vec3 &R, const Vec3 &dRdx, const Vec3 &dRdy, int nchannels, float *result, float *dresultds, float *dresultdt) { ShadingContext *context = sg->context; if (! texture_thread_info) texture_thread_info = context->texture_thread_info(); bool status; if (texture_handle) status = texturesys()->environment (texture_handle, texture_thread_info, options, R, dRdx, dRdy, nchannels, result, dresultds, dresultdt); else status = texturesys()->environment (filename, options, R, dRdx, dRdy, nchannels, result, dresultds, dresultdt); if (!status) { std::string err = texturesys()->geterror(); if (err.size() && sg) { sg->context->error ("[RendererServices::environment] %s", err); } } return status; }
OSL_SHADEOP void osl_luminance_dfdv (void *sg, void *out, void *c) { ShadingContext *ctx = (ShadingContext *)((ShaderGlobals *)sg)->context; ((float *)out)[0] = ctx->shadingsys().luminance (((const Color3 *)c)[0]); ((float *)out)[1] = ctx->shadingsys().luminance (((const Color3 *)c)[1]); ((float *)out)[2] = ctx->shadingsys().luminance (((const Color3 *)c)[2]); }
void DisneyLayeredBRDF::evaluate_inputs( const ShadingContext& shading_context, InputEvaluator& input_evaluator, const ShadingPoint& shading_point, const size_t offset) const { char* ptr = reinterpret_cast<char*>(input_evaluator.data()); DisneyBRDFInputValues* values = reinterpret_cast<DisneyBRDFInputValues*>(ptr + offset); memset(values, 0, sizeof(DisneyBRDFInputValues)); Color3d base_color(0.0); for (size_t i = 0, e = m_parent->get_layer_count(); i < e; ++i) { const DisneyMaterialLayer& layer = m_parent->get_layer(i, shading_context.get_thread_index()); layer.evaluate_expressions( shading_point, shading_context.get_oiio_texture_system(), base_color, *values); } // Colors in SeExpr are always in the sRGB color space. base_color = srgb_to_linear_rgb(base_color); values->m_base_color = Color3f(base_color); values->precompute_tint_color(); }
OSL_SHADEOP void osl_prepend_color_from (void *sg, void *c_, const char *from) { ShadingContext *ctx (((ShaderGlobals *)sg)->context); Color3 &c (*(Color3*)c_); c = ctx->shadingsys().to_rgb (USTR(from), c[0], c[1], c[2]); }
OSL_SHADEOP void osl_wavelength_color_vf (void *sg, void *out, float lambda) { ShadingContext *ctx = (ShadingContext *)((ShaderGlobals *)sg)->context; Color3 rgb = ctx->shadingsys().XYZ_to_RGB (wavelength_color_XYZ (lambda)); // constrain_rgb (rgb); rgb *= 1.0/2.52; // Empirical scale from lg to make all comps <= 1 // norm_rgb (rgb); clamp_zero (rgb); *(Color3 *)out = rgb; }
int Dictionary::get_document_index (ustring dictionaryname) { DocMap::iterator dm = m_document_map.find(dictionaryname); int dindex; if (dm == m_document_map.end()) { dindex = m_documents.size(); m_document_map[dictionaryname] = dindex; pugi::xml_document *doc = new pugi::xml_document; m_documents.push_back (doc); pugi::xml_parse_result parse_result; if (boost::ends_with (dictionaryname.string(), ".xml")) { // xml file -- read it parse_result = doc->load_file (dictionaryname.c_str()); } else { // load xml directly from the string parse_result = doc->load_buffer (dictionaryname.c_str(), dictionaryname.length()); } if (! parse_result) { m_context->error ("XML parsed with errors: %s, at offset %d", parse_result.description(), parse_result.offset); m_document_map[dictionaryname] = -1; return -1; } } else { dindex = dm->second; } DASSERT (dindex < (int)m_documents.size()); return dindex; }
void ShadingEngine::shade_environment( SamplingContext& sampling_context, const ShadingContext& shading_context, const ShadingPoint& shading_point, ShadingResult& shading_result) const { // Retrieve the environment shader of the scene. const EnvironmentShader* environment_shader = shading_point.get_scene().get_environment()->get_environment_shader(); if (environment_shader) { // There is an environment shader: execute it. InputEvaluator input_evaluator(shading_context.get_texture_cache()); const ShadingRay& ray = shading_point.get_ray(); const Vector3d direction = normalize(ray.m_dir); environment_shader->evaluate( input_evaluator, direction, shading_result); // Set environment shader AOV. shading_result.set_entity_aov(*environment_shader); } else { // No environment shader: shade as transparent black. shading_result.set_main_to_transparent_black_linear_rgba(); shading_result.set_aovs_to_transparent_black_linear_rgba(); } }
void do_compute_lighting( SamplingContext& sampling_context, const ShadingContext& shading_context, const ShadingPoint& shading_point, Spectrum& radiance, // output radiance, in W.sr^-1.m^-2 SpectrumStack& aovs) { PathVisitor path_visitor( m_params, m_light_sampler, sampling_context, shading_context, shading_point.get_scene(), radiance, aovs); PathTracer<PathVisitor, false> path_tracer( // false = not adjoint path_visitor, m_params.m_rr_min_path_length, m_params.m_max_path_length, shading_context.get_max_iterations()); const size_t path_length = path_tracer.trace( sampling_context, shading_context, shading_point); // Update statistics. ++m_path_count; m_path_length.insert(path_length); }
void PathVertex::compute_emitted_radiance( const ShadingContext& shading_context, TextureCache& texture_cache, Spectrum& radiance) const { assert(m_edf); // No radiance if we're too close to the light. if (m_shading_point->get_distance() < m_edf->get_light_near_start()) { radiance.set(0.0f); return; } if (const ShaderGroup* sg = get_material()->get_render_data().m_shader_group) shading_context.execute_osl_emission(*sg, *m_shading_point); // Evaluate the EDF inputs. InputEvaluator input_evaluator(texture_cache); m_edf->evaluate_inputs(input_evaluator, *m_shading_point); // Compute the emitted radiance. m_edf->evaluate( input_evaluator.data(), Vector3f(m_shading_point->get_geometric_normal()), Basis3f(m_shading_point->get_shading_basis()), Vector3f(m_outgoing.get_value()), radiance); }
ShadingContext *ShadingApi ::context(Gotham::AttributeMap &attr, const boost::shared_ptr<MaterialList> &materials, const boost::shared_ptr<TextureList> &textures) { ShadingContext *result = 0; result = new ShadingContext(); // give the materials to the ShadingContext result->setMaterials(materials); // give the textures to the ShadingContext result->setTextures(textures); return result; } // end context()
void evaluate_osl_background( const ShadingContext& shading_context, const Vector3f& local_outgoing, Spectrum& value) const { if (m_shader_group) shading_context.execute_osl_background(*m_shader_group, local_outgoing, value); else value.set(0.0f); }
void add_back_lighting( const InputValues& values, SamplingContext& sampling_context, const PixelContext& pixel_context, const ShadingContext& shading_context, const ShadingPoint& shading_point, Spectrum& radiance, SpectrumStack& aovs) const { const Vector3d& p = shading_point.get_point(); const Vector3d& n = shading_point.get_original_shading_normal(); const Vector3d& d = shading_point.get_ray().m_dir; // Construct a ray perpendicular to the other side of the surface. ShadingRay back_ray(shading_point.get_ray()); back_ray.m_tmax *= norm(d); back_ray.m_dir = dot(d, n) > 0.0 ? -n : n; back_ray.m_org = p - back_ray.m_tmax * back_ray.m_dir; ShadingPoint back_shading_point(shading_point); back_shading_point.set_ray(back_ray); Spectrum back_radiance(0.0f); SpectrumStack back_aovs(aovs.size(), 0.0f); // Compute back lighting. for (size_t i = 0; i < m_back_lighting_samples; ++i) { shading_context.get_lighting_engine()->compute_lighting( sampling_context, pixel_context, shading_context, back_shading_point, back_radiance, back_aovs); } // Apply translucency factor. back_radiance *= values.m_translucency; back_aovs *= values.m_translucency; // Divide by the number of samples. const float rcp_sample_count = 1.0f / static_cast<float>(m_back_lighting_samples); back_radiance *= rcp_sample_count; back_aovs *= rcp_sample_count; // Add back lighting contribution. radiance += back_radiance; aovs += back_aovs; }
int Dictionary::dict_find (ustring dictionaryname, ustring query) { int dindex = get_document_index (dictionaryname); if (dindex < 0) return dindex; ASSERT (dindex >= 0 && dindex < (int)m_documents.size()); Query q (dindex, 0, query); QueryMap::iterator qfound = m_cache.find (q); if (qfound != m_cache.end()) { return qfound->second.valueoffset; } pugi::xml_document *doc = m_documents[dindex]; // Query was not found. Do the expensive lookup and cache it pugi::xpath_node_set matches; try { matches = doc->select_nodes (query.c_str()); } catch (const pugi::xpath_exception& e) { m_context->error ("Invalid dict_find query '%s': %s", query.c_str(), e.what()); return 0; } if (matches.empty()) { m_cache[q] = QueryResult (false); // mark invalid return 0; // Not found } int firstmatch = (int) m_nodes.size(); int last = -1; for (int i = 0, e = (int)matches.size(); i < e; ++i) { m_nodes.push_back (Node (dindex, matches[i].node())); int nodeid = (int) m_nodes.size()-1; if (last < 0) { // If this is the first match, add a cache entry for it m_cache[q] = QueryResult (true /* it's a node */, nodeid); } else { // If this is a subsequent match, set the last match's 'next' m_nodes[last].next = nodeid; } last = nodeid; } return firstmatch; }
void apply_aerial_perspective( const InputValues& values, const ShadingContext& shading_context, const PixelContext& pixel_context, const ShadingPoint& shading_point, ShadingResult& shading_result) const { Spectrum sky_color; if (m_aerial_persp_mode == AerialPerspSkyColor) sky_color = values.m_aerial_persp_sky_color; else { // Retrieve the environment shader of the scene. const Scene& scene = shading_point.get_scene(); const EnvironmentShader* environment_shader = scene.get_environment()->get_environment_shader(); if (environment_shader) { // Execute the environment shader to obtain the sky color in the direction of the ray. InputEvaluator input_evaluator(shading_context.get_texture_cache()); const ShadingRay& ray = shading_point.get_ray(); const Vector3d direction = normalize(ray.m_dir); ShadingResult sky; environment_shader->evaluate( shading_context, pixel_context, input_evaluator, direction, sky); sky_color = sky.m_main.m_color; } else sky_color.set(0.0f); } // Compute the blend factor. const double d = shading_point.get_distance() * m_aerial_persp_rcp_distance; const double k = m_aerial_persp_intensity * exp(d); const double blend = min(k, 1.0); // Blend the shading result and the sky color. sky_color *= static_cast<float>(blend); shading_result.m_main.m_color *= static_cast<float>(1.0 - blend); shading_result.m_main.m_color += sky_color; }
int Dictionary::dict_find (int nodeID, ustring query) { if (nodeID <= 0 || nodeID >= (int)m_nodes.size()) return 0; // invalid node ID const Dictionary::Node &node (m_nodes[nodeID]); Query q (node.document, nodeID, query); QueryMap::iterator qfound = m_cache.find (q); if (qfound != m_cache.end()) { return qfound->second.valueoffset; } // Query was not found. Do the expensive lookup and cache it pugi::xpath_node_set matches; try { matches = node.node.select_nodes (query.c_str()); } catch (const pugi::xpath_exception& e) { m_context->error ("Invalid dict_find query '%s': %s", query.c_str(), e.what()); return 0; } if (matches.empty()) { m_cache[q] = QueryResult (false); // mark invalid return 0; // Not found } int firstmatch = (int) m_nodes.size(); int last = -1; for (int i = 0, e = (int)matches.size(); i < e; ++i) { m_nodes.push_back (Node (node.document, matches[i].node())); int nodeid = (int) m_nodes.size()-1; if (last < 0) { // If this is the first match, add a cache entry for it m_cache[q] = QueryResult (true /* it's a node */, nodeid); } else { // If this is a subsequent match, set the last match's 'next' m_nodes[last].next = nodeid; } last = nodeid; } return firstmatch; }
void compute_ibl_bsdf_sampling( SamplingContext& sampling_context, const ShadingContext& shading_context, const EnvironmentEDF& environment_edf, const ShadingPoint& shading_point, const Dual3d& outgoing, const BSDF& bsdf, const void* bsdf_data, const int bsdf_sampling_modes, const size_t bsdf_sample_count, const size_t env_sample_count, Spectrum& radiance) { assert(is_normalized(outgoing.get_value())); radiance.set(0.0f); for (size_t i = 0; i < bsdf_sample_count; ++i) { // Sample the BSDF. // todo: rendering will be incorrect if the BSDF value returned by the sample() method // includes the contribution of a specular component since these are explicitly rejected // afterward. We need a mechanism to indicate that we want the contribution of some of // the components only. BSDFSample sample(shading_point, outgoing); bsdf.sample( sampling_context, bsdf_data, false, // not adjoint true, // multiply by |cos(incoming, normal)| sample); // Filter scattering modes. if (!(bsdf_sampling_modes & sample.m_mode)) continue; // Discard occluded samples. const float transmission = shading_context.get_tracer().trace( shading_point, Vector3d(sample.m_incoming.get_value()), VisibilityFlags::ShadowRay); if (transmission == 0.0f) continue; // Evaluate the environment's EDF. InputEvaluator input_evaluator(shading_context.get_texture_cache()); Spectrum env_value; float env_prob; environment_edf.evaluate( shading_context, input_evaluator, sample.m_incoming.get_value(), env_value, env_prob); // Apply all weights, including MIS weight. if (sample.m_mode == ScatteringMode::Specular) env_value *= transmission; else { const float mis_weight = mis_power2( bsdf_sample_count * sample.m_probability, env_sample_count * env_prob); env_value *= transmission / sample.m_probability * mis_weight; } // Add the contribution of this sample to the illumination. env_value *= sample.m_value; radiance += env_value; } if (bsdf_sample_count > 1) radiance /= static_cast<float>(bsdf_sample_count); }
void DiagnosticSurfaceShader::evaluate( SamplingContext& sampling_context, const PixelContext& pixel_context, const ShadingContext& shading_context, const ShadingPoint& shading_point, ShadingResult& shading_result) const { switch (m_shading_mode) { case Color: { shading_result.set_main_to_opaque_pink_linear_rgba(); const Material* material = shading_point.get_material(); if (material) { const Material::RenderData& material_data = material->get_render_data(); #ifdef APPLESEED_WITH_OSL // Execute the OSL shader if there is one. if (material_data.m_shader_group) { shading_context.execute_osl_shading( *material_data.m_shader_group, shading_point); } #endif if (material_data.m_bsdf) { InputEvaluator input_evaluator(shading_context.get_texture_cache()); material_data.m_bsdf->evaluate_inputs( shading_context, input_evaluator, shading_point); const Vector3d direction = -normalize(shading_point.get_ray().m_dir); material_data.m_bsdf->evaluate( input_evaluator.data(), false, false, shading_point.get_geometric_normal(), shading_point.get_shading_basis(), direction, direction, ScatteringMode::All, shading_result.m_main.m_color); shading_result.m_color_space = ColorSpaceSpectral; } } } break; case Coverage: shading_result.set_main_to_linear_rgb(Color3f(1.0f)); break; case Barycentric: shading_result.set_main_to_linear_rgb( vector2_to_color(shading_point.get_bary())); break; case UV: shading_result.set_main_to_linear_rgb( uvs_to_color(shading_point.get_uv(0))); break; case Tangent: case Bitangent: case ShadingNormal: { #ifdef APPLESEED_WITH_OSL const Material* material = shading_point.get_material(); if (material) { const Material::RenderData& material_data = material->get_render_data(); // Execute the OSL shader if there is one. if (material_data.m_shader_group) { sampling_context.split_in_place(2, 1); shading_context.execute_osl_bump( *material_data.m_shader_group, shading_point, sampling_context.next_vector2<2>()); } } #endif const Vector3d v = m_shading_mode == ShadingNormal ? shading_point.get_shading_basis().get_normal() : m_shading_mode == Tangent ? shading_point.get_shading_basis().get_tangent_u() : shading_point.get_shading_basis().get_tangent_v(); shading_result.set_main_to_linear_rgb(vector3_to_color(v)); } break; case GeometricNormal: shading_result.set_main_to_linear_rgb( vector3_to_color(shading_point.get_geometric_normal())); break; case OriginalShadingNormal: shading_result.set_main_to_linear_rgb( vector3_to_color(shading_point.get_original_shading_normal())); break; case WorldSpacePosition: { const Vector3d& p = shading_point.get_point(); shading_result.set_main_to_linear_rgb( Color3f(Color3d(p.x, p.y, p.z))); } break; case Sides: shading_result.set_main_to_linear_rgb( shading_point.get_side() == ObjectInstance::FrontSide ? Color3f(0.0f, 0.0f, 1.0f) : Color3f(1.0f, 0.0f, 0.0f)); break; case Depth: shading_result.set_main_to_linear_rgb( Color3f(static_cast<float>(shading_point.get_distance()))); break; case ScreenSpaceWireframe: { // Initialize the shading result to the background color. shading_result.set_main_to_linear_rgba(Color4f(0.0f, 0.0f, 0.8f, 0.5f)); if (shading_point.is_triangle_primitive()) { // Film space thickness of the wires. const double SquareWireThickness = square(0.00025); // Retrieve the time, the scene and the camera. const double time = shading_point.get_time().m_absolute; const Scene& scene = shading_point.get_scene(); const Camera& camera = *scene.get_camera(); // Compute the film space coordinates of the intersection point. Vector2d point_ndc; camera.project_point(time, shading_point.get_point(), point_ndc); // Loop over the triangle edges. for (size_t i = 0; i < 3; ++i) { // Retrieve the end points of this edge. const size_t j = (i + 1) % 3; const Vector3d vi = shading_point.get_vertex(i); const Vector3d vj = shading_point.get_vertex(j); // Compute the film space coordinates of the edge's end points. Vector2d vi_ndc, vj_ndc; if (!camera.project_segment(time, vi, vj, vi_ndc, vj_ndc)) continue; // Compute the film space distance from the intersection point to the edge. const double d = square_distance_point_segment(point_ndc, vi_ndc, vj_ndc); // Shade with the wire's color if the hit point is close enough to the edge. if (d < SquareWireThickness) { shading_result.set_main_to_linear_rgba(Color4f(1.0f)); break; } } } else { assert(shading_point.is_curve_primitive()); // todo: implement. } } break; case WorldSpaceWireframe: { // Initialize the shading result to the background color. shading_result.set_main_to_linear_rgba(Color4f(0.0f, 0.0f, 0.8f, 0.5f)); if (shading_point.is_triangle_primitive()) { // World space thickness of the wires. const double SquareWireThickness = square(0.0015); // Retrieve the world space intersection point. const Vector3d& point = shading_point.get_point(); // Loop over the triangle edges. for (size_t i = 0; i < 3; ++i) { // Retrieve the end points of this edge. const size_t j = (i + 1) % 3; const Vector3d& vi = shading_point.get_vertex(i); const Vector3d& vj = shading_point.get_vertex(j); // Compute the world space distance from the intersection point to the edge. const double d = square_distance_point_segment(point, vi, vj); // Shade with the wire's color if the hit point is close enough to the edge. if (d < SquareWireThickness) { shading_result.set_main_to_linear_rgba(Color4f(1.0f)); break; } } } else { assert(shading_point.is_curve_primitive()); // todo: implement. } } break; case AmbientOcclusion: { // Compute the occlusion. const double occlusion = compute_ambient_occlusion( sampling_context, sample_hemisphere_uniform<double>, shading_context.get_intersector(), shading_point, m_ao_max_distance, m_ao_samples); // Return a gray scale value proportional to the accessibility. const float accessibility = static_cast<float>(1.0 - occlusion); shading_result.set_main_to_linear_rgb(Color3f(accessibility)); } break; case AssemblyInstances: shading_result.set_main_to_linear_rgb( integer_to_color(shading_point.get_assembly_instance().get_uid())); break; case ObjectInstances: shading_result.set_main_to_linear_rgb( integer_to_color(shading_point.get_object_instance().get_uid())); break; case Regions: { const uint32 h = mix_uint32( static_cast<uint32>(shading_point.get_object_instance().get_uid()), static_cast<uint32>(shading_point.get_region_index())); shading_result.set_main_to_linear_rgb(integer_to_color(h)); } break; case Primitives: { const uint32 h = mix_uint32( static_cast<uint32>(shading_point.get_object_instance().get_uid()), static_cast<uint32>(shading_point.get_region_index()), static_cast<uint32>(shading_point.get_primitive_index())); shading_result.set_main_to_linear_rgb(integer_to_color(h)); } break; case Materials: { const Material* material = shading_point.get_material(); if (material) shading_result.set_main_to_linear_rgb(integer_to_color(material->get_uid())); else shading_result.set_main_to_opaque_pink_linear_rgba(); } break; case RaySpread: { const ShadingRay& ray = shading_point.get_ray(); if (!ray.m_has_differentials) break; const Material* material = shading_point.get_material(); if (material) { const Material::RenderData& material_data = material->get_render_data(); #ifdef APPLESEED_WITH_OSL // Execute the OSL shader if there is one. if (material_data.m_shader_group) { shading_context.execute_osl_shading( *material_data.m_shader_group, shading_point); } #endif if (material_data.m_bsdf) { const Dual3d outgoing( -ray.m_dir, ray.m_dir - ray.m_rx.m_dir, ray.m_dir - ray.m_ry.m_dir); InputEvaluator input_evaluator(shading_context.get_texture_cache()); material_data.m_bsdf->evaluate_inputs( shading_context, input_evaluator, shading_point); const void* bsdf_data = input_evaluator.data(); BSDFSample sample(shading_point, outgoing); material_data.m_bsdf->sample( sampling_context, bsdf_data, false, false, sample); if (!sample.m_incoming.has_derivatives()) break; // The 3.0 factor is chosen so that ray spread from Lambertian BRDFs is approximately 1. const double spread = max( norm(sample.m_incoming.get_dx()), norm(sample.m_incoming.get_dy())) * 3.0; shading_result.set_main_to_linear_rgb( Color3f(static_cast<float>(spread))); } } } break; case FacingRatio: { const Vector3d& normal = shading_point.get_shading_normal(); const Vector3d& view = shading_point.get_ray().m_dir; const double facing = abs(dot(normal, view)); shading_result.set_main_to_linear_rgb( Color3f(static_cast<float>(facing))); } break; default: assert(false); shading_result.set_main_to_transparent_black_linear_rgba(); break; } }
void ShadingEngine::shade_hit_point( SamplingContext& sampling_context, const PixelContext& pixel_context, const ShadingContext& shading_context, const ShadingPoint& shading_point, ShadingResult& shading_result) const { // Retrieve the material of the intersected surface. const Material* material = shading_point.get_material(); // Compute the alpha channel of the main output. if (material && material->get_alpha_map()) { // There is an alpha map: evaluate it. material->get_alpha_map()->evaluate( shading_context.get_texture_cache(), shading_point.get_uv(0), shading_result.m_main.m_alpha); } else { // No alpha map: solid sample. shading_result.m_main.m_alpha = Alpha(1.0f); } #ifdef WITH_OSL if (material && material->get_osl_surface() && material->get_osl_surface()->has_transparency()) { Alpha a; shading_context.execute_osl_transparency( *material->get_osl_surface(), shading_point, a); shading_result.m_main.m_alpha *= a; } #endif if (shading_result.m_main.m_alpha[0] > 0.0f || material->shade_alpha_cutouts()) { // Use the diagnostic surface shader if there is one. const SurfaceShader* surface_shader = m_diagnostic_surface_shader.get(); if (surface_shader == 0) { if (material == 0) { // The intersected surface has no material: return solid pink. shading_result.set_main_to_opaque_pink_linear_rgba(); shading_result.set_aovs_to_transparent_black_linear_rgba(); return; } // Use the surface shader of the intersected surface. surface_shader = material->get_surface_shader(); if (surface_shader == 0) { // The intersected surface has no surface shader: return solid pink. shading_result.set_main_to_opaque_pink_linear_rgba(); shading_result.set_aovs_to_transparent_black_linear_rgba(); return; } } // Execute the surface shader. surface_shader->evaluate( sampling_context, pixel_context, shading_context, shading_point, shading_result); // Set AOVs. shading_result.set_entity_aov(shading_point.get_assembly()); shading_result.set_entity_aov(shading_point.get_assembly_instance()); shading_result.set_entity_aov(shading_point.get_object()); shading_result.set_entity_aov(shading_point.get_object_instance()); if (material) shading_result.set_entity_aov(*material); shading_result.set_entity_aov(*surface_shader); } else { // Alpha is zero: shade as transparent black. shading_result.set_main_to_transparent_black_linear_rgba(); shading_result.set_aovs_to_transparent_black_linear_rgba(); } }
int main (int argc, const char *argv[]) { // Create a new shading system. Timer timer; SimpleRenderer rend; shadingsys = ShadingSystem::create (&rend, NULL, &errhandler); shadingsys->attribute("lockgeom", 1); shadingsys->ShaderGroupBegin (); getargs (argc, argv); if (debug || verbose) errhandler.verbosity (ErrorHandler::VERBOSE); for (size_t i = 0; i < connections.size(); i += 4) { if (i+3 < connections.size()) { std::cout << "Connect " << connections[i] << "." << connections[i+1] << " to " << connections[i+2] << "." << connections[i+3] << "\n"; shadingsys->ConnectShaders (connections[i].c_str(), connections[i+1].c_str(), connections[i+2].c_str(), connections[i+3].c_str()); } } shadingsys->ShaderGroupEnd (); // getargs called 'add_shader' for each shader mentioned on the command // line. So now we should have a valid shading state. ShadingAttribStateRef shaderstate = shadingsys->state (); // Set up shader globals and a little test grid of points to shade. ShaderGlobals shaderglobals; memset(&shaderglobals, 0, sizeof(ShaderGlobals)); // Make a shader space that is translated one unit in x and rotated // 45deg about the z axis. OSL::Matrix44 Mshad; Mshad.translate (OSL::Vec3 (1.0, 0.0, 0.0)); Mshad.rotate (OSL::Vec3 (0.0, 0.0, M_PI_4)); // std::cout << "shader-to-common matrix: " << Mshad << "\n"; OSL::TransformationPtr Mshadptr (&Mshad); shaderglobals.shader2common = Mshadptr; // Make an object space that is translated one unit in y and rotated // 90deg about the z axis. OSL::Matrix44 Mobj; Mobj.translate (OSL::Vec3 (0.0, 1.0, 0.0)); Mobj.rotate (OSL::Vec3 (0.0, 0.0, M_PI_2)); // std::cout << "object-to-common matrix: " << Mobj << "\n"; OSL::TransformationPtr Mobjptr (&Mobj); shaderglobals.object2common = Mobjptr; // Make a 'myspace that is non-uniformly scaled OSL::Matrix44 Mmyspace; Mmyspace.scale (OSL::Vec3 (1.0, 2.0, 1.0)); // std::cout << "myspace-to-common matrix: " << Mmyspace << "\n"; rend.name_transform ("myspace", Mmyspace); shaderglobals.dudx = 1.0f / xres; shaderglobals.dvdy = 1.0f / yres; shaderglobals.raytype = ((ShadingSystemImpl *)shadingsys)->raytype_bit (ustring(raytype)); double setuptime = timer (); double runtime = 0; std::vector<float> pixel; if (outputfiles.size() != 0) std::cout << "\n"; // grab this once since we will be shading several points ShadingSystemImpl *ssi = (ShadingSystemImpl *)shadingsys; void* thread_info = ssi->create_thread_info(); for (int iter = 0; iter < iters; ++iter) { for (int y = 0, n = 0; y < yres; ++y) { for (int x = 0; x < xres; ++x, ++n) { shaderglobals.u = (xres == 1) ? 0.5f : (float) x / (xres - 1); shaderglobals.v = (yres == 1) ? 0.5f : (float) y / (yres - 1); shaderglobals.P = Vec3 (shaderglobals.u, shaderglobals.v, 1.0f); shaderglobals.dPdx = Vec3 (shaderglobals.dudx, shaderglobals.dudy, 0.0f); shaderglobals.dPdy = Vec3 (shaderglobals.dvdx, shaderglobals.dvdy, 0.0f); shaderglobals.N = Vec3 (0, 0, 1); shaderglobals.Ng = Vec3 (0, 0, 1); shaderglobals.dPdu = Vec3 (1.0f, 0.0f, 0.0f); shaderglobals.dPdv = Vec3 (0.0f, 1.0f, 0.0f); shaderglobals.surfacearea = 1; // Request a shading context, bind it, execute the shaders. // FIXME -- this will eventually be replaced with a public // ShadingSystem call that encapsulates it. ShadingContext *ctx = ssi->get_context (thread_info); timer.reset (); timer.start (); // run shader for this point ctx->execute (ShadUseSurface, *shaderstate, shaderglobals); runtime += timer (); if (iter == (iters - 1)) { // extract any output vars into images (on last iteration only) for (size_t i = 0; i < outputfiles.size(); ++i) { Symbol *sym = ctx->symbol (ShadUseSurface, ustring(outputvars[i])); if (! sym) { if (n == 0) { std::cout << "Output " << outputvars[i] << " not found, skipping.\n"; outputimgs.push_back(0); // invalid image } continue; } if (n == 0) std::cout << "Output " << outputvars[i] << " to " << outputfiles[i]<< "\n"; TypeDesc t = sym->typespec().simpletype(); TypeDesc tbase = TypeDesc ((TypeDesc::BASETYPE)t.basetype); TypeDesc outtypebase = tbase; if (dataformatname == "uint8") outtypebase = TypeDesc::UINT8; else if (dataformatname == "half") outtypebase = TypeDesc::HALF; else if (dataformatname == "float") outtypebase = TypeDesc::FLOAT; int nchans = t.numelements() * t.aggregate; pixel.resize (nchans); if (n == 0) { OIIO::ImageSpec spec (xres, yres, nchans, outtypebase); OIIO::ImageBuf* img = new OIIO::ImageBuf(outputfiles[i], spec); #if OPENIMAGEIO_VERSION >= 900 /* 0.9.0 */ OIIO::ImageBufAlgo::zero (*img); #else img->zero (); #endif outputimgs.push_back(img); } OIIO::convert_types (tbase, ctx->symbol_data (*sym, 0), TypeDesc::FLOAT, &pixel[0], nchans); outputimgs[i]->setpixel (x, y, &pixel[0]); } } ssi->release_context (ctx, thread_info); } } } ssi->destroy_thread_info(thread_info); if (outputfiles.size() == 0) std::cout << "\n"; // write any images to disk for (size_t i = 0; i < outputimgs.size(); ++i) { if (outputimgs[i]) { outputimgs[i]->save(); delete outputimgs[i]; } } if (debug || stats) { std::cout << "\n"; std::cout << "Setup: " << Strutil::timeintervalformat (setuptime,2) << "\n"; std::cout << "Run : " << Strutil::timeintervalformat (runtime,2) << "\n"; std::cout << "\n"; std::cout << shadingsys->getstats (5) << "\n"; } ShadingSystem::destroy (shadingsys); return EXIT_SUCCESS; }
void compute_ibl_bssrdf_sampling( SamplingContext& sampling_context, const ShadingContext& shading_context, const EnvironmentEDF& environment_edf, const BSSRDF& bssrdf, const void* bssrdf_data, const ShadingPoint& incoming_point, const ShadingPoint& outgoing_point, const Dual3d& outgoing, const size_t bssrdf_sample_count, const size_t env_sample_count, Spectrum& radiance) { assert(is_normalized(outgoing.get_value())); radiance.set(0.0f); sampling_context.split_in_place(2, bssrdf_sample_count); for (size_t i = 0; i < bssrdf_sample_count; ++i) { // Generate a uniform sample in [0,1)^2. const Vector2d s = sampling_context.next_vector2<2>(); // Sample the BSSRDF (hemisphere cosine). Vector3d incoming = sample_hemisphere_cosine(s); const double cos_in = incoming.y; const double bssrdf_prob = cos_in * RcpPi; incoming = incoming_point.get_shading_basis().transform_to_parent(incoming); if (incoming_point.get_side() == ObjectInstance::BackSide) incoming = -incoming; assert(is_normalized(incoming)); // Discard occluded samples. const double transmission = shading_context.get_tracer().trace( incoming_point, incoming, VisibilityFlags::ShadowRay); if (transmission == 0.0) continue; // Evaluate the BSSRDF. Spectrum bssrdf_value; bssrdf.evaluate( bssrdf_data, outgoing_point, outgoing.get_value(), incoming_point, incoming, bssrdf_value); // Evaluate the environment's EDF. InputEvaluator input_evaluator(shading_context.get_texture_cache()); Spectrum env_value; double env_prob; environment_edf.evaluate( shading_context, input_evaluator, incoming, env_value, env_prob); // Compute MIS weight. const double mis_weight = mis_power2( bssrdf_sample_count * bssrdf_prob, env_sample_count * env_prob); // Add the contribution of this sample to the illumination. env_value *= static_cast<float>(transmission * cos_in / bssrdf_prob * mis_weight); env_value *= bssrdf_value; radiance += env_value; } if (bssrdf_sample_count > 1) radiance /= static_cast<float>(bssrdf_sample_count); }
void compute_ibl_environment_sampling( SamplingContext& sampling_context, const ShadingContext& shading_context, const EnvironmentEDF& environment_edf, const BSSRDF& bssrdf, const void* bssrdf_data, const ShadingPoint& incoming_point, const ShadingPoint& outgoing_point, const Dual3d& outgoing, const size_t bssrdf_sample_count, const size_t env_sample_count, Spectrum& radiance) { assert(is_normalized(outgoing.get_value())); const Basis3d& shading_basis = incoming_point.get_shading_basis(); radiance.set(0.0f); sampling_context.split_in_place(2, env_sample_count); for (size_t i = 0; i < env_sample_count; ++i) { // Generate a uniform sample in [0,1)^2. const Vector2d s = sampling_context.next_vector2<2>(); // Sample the environment. InputEvaluator input_evaluator(shading_context.get_texture_cache()); Vector3d incoming; Spectrum env_value; double env_prob; environment_edf.sample( shading_context, input_evaluator, s, incoming, env_value, env_prob); // Cull samples behind the shading surface. assert(is_normalized(incoming)); const double cos_in = dot(incoming, shading_basis.get_normal()); if (cos_in <= 0.0) continue; // Discard occluded samples. const double transmission = shading_context.get_tracer().trace( incoming_point, incoming, VisibilityFlags::ShadowRay); if (transmission == 0.0) continue; // Evaluate the BSSRDF. Spectrum bssrdf_value; bssrdf.evaluate( bssrdf_data, outgoing_point, outgoing.get_value(), incoming_point, incoming, bssrdf_value); // Compute MIS weight. const double bssrdf_prob = cos_in * RcpPi; const double mis_weight = mis_power2( env_sample_count * env_prob, bssrdf_sample_count * bssrdf_prob); // Add the contribution of this sample to the illumination. env_value *= static_cast<float>(transmission * cos_in / env_prob * mis_weight); env_value *= bssrdf_value; radiance += env_value; } if (env_sample_count > 1) radiance /= static_cast<float>(env_sample_count); }
OSL_SHADEOP void osl_blackbody_vf (void *sg, void *out, float temp) { ShadingContext *ctx = (ShadingContext *)((ShaderGlobals *)sg)->context; *(Color3 *)out = ctx->shadingsys().blackbody_rgb (temp); }
void compute_ibl_environment_sampling( SamplingContext& sampling_context, const ShadingContext& shading_context, const EnvironmentEDF& environment_edf, const ShadingPoint& shading_point, const Vector3d& outgoing, const BSDF& bsdf, const void* bsdf_data, const int env_sampling_modes, const size_t bsdf_sample_count, const size_t env_sample_count, Spectrum& radiance) { assert(is_normalized(outgoing)); const Vector3d& geometric_normal = shading_point.get_geometric_normal(); const Basis3d& shading_basis = shading_point.get_shading_basis(); radiance.set(0.0f); // todo: if we had a way to know that a BSDF is purely specular, we could // immediately return black here since there will be no contribution from // such a BSDF. sampling_context.split_in_place(2, env_sample_count); for (size_t i = 0; i < env_sample_count; ++i) { // Generate a uniform sample in [0,1)^2. const Vector2d s = sampling_context.next_vector2<2>(); // Sample the environment. InputEvaluator input_evaluator(shading_context.get_texture_cache()); Vector3d incoming; Spectrum env_value; double env_prob; environment_edf.sample( input_evaluator, s, incoming, env_value, env_prob); // Cull samples behind the shading surface. assert(is_normalized(incoming)); const double cos_in = dot(incoming, shading_basis.get_normal()); if (cos_in < 0.0) continue; // Discard occluded samples. const double transmission = shading_context.get_tracer().trace( shading_point, incoming, ShadingRay::ShadowRay); if (transmission == 0.0) continue; // Evaluate the BSDF. Spectrum bsdf_value; const double bsdf_prob = bsdf.evaluate( bsdf_data, false, // not adjoint true, // multiply by |cos(incoming, normal)| geometric_normal, shading_basis, outgoing, incoming, env_sampling_modes, bsdf_value); if (bsdf_prob == 0.0) continue; // Compute MIS weight. const double mis_weight = mis_power2( env_sample_count * env_prob, bsdf_sample_count * bsdf_prob); // Add the contribution of this sample to the illumination. env_value *= static_cast<float>(transmission / env_prob * mis_weight); env_value *= bsdf_value; radiance += env_value; } if (env_sample_count > 1) radiance /= static_cast<float>(env_sample_count); }
OSL_SHADEOP void osl_incr_layers_executed (ShaderGlobals *sg) { ShadingContext *ctx = (ShadingContext *)sg->context; ctx->incr_layers_executed (); }
void compute_ibl_bsdf_sampling( SamplingContext& sampling_context, const ShadingContext& shading_context, const EnvironmentEDF& environment_edf, const ShadingPoint& shading_point, const Vector3d& outgoing, const BSDF& bsdf, const void* bsdf_data, const int bsdf_sampling_modes, const size_t bsdf_sample_count, const size_t env_sample_count, Spectrum& radiance) { assert(is_normalized(outgoing)); const Vector3d& geometric_normal = shading_point.get_geometric_normal(); const Basis3d& shading_basis = shading_point.get_shading_basis(); radiance.set(0.0f); for (size_t i = 0; i < bsdf_sample_count; ++i) { // Sample the BSDF. // todo: rendering will be incorrect if the BSDF value returned by the sample() method // includes the contribution of a specular component since these are explicitly rejected // afterward. We need a mechanism to indicate that we want the contribution of some of // the components only. Vector3d incoming; Spectrum bsdf_value; double bsdf_prob; const BSDF::Mode bsdf_mode = bsdf.sample( sampling_context, bsdf_data, false, // not adjoint true, // multiply by |cos(incoming, normal)| geometric_normal, shading_basis, outgoing, incoming, bsdf_value, bsdf_prob); // Filter scattering modes. if (!(bsdf_sampling_modes & bsdf_mode)) return; // Discard occluded samples. const double transmission = shading_context.get_tracer().trace( shading_point, incoming, ShadingRay::ShadowRay); if (transmission == 0.0) continue; // Evaluate the environment's EDF. InputEvaluator input_evaluator(shading_context.get_texture_cache()); Spectrum env_value; double env_prob; environment_edf.evaluate( input_evaluator, incoming, env_value, env_prob); // Apply all weights, including MIS weight. if (bsdf_mode == BSDF::Specular) env_value *= static_cast<float>(transmission); else { const double mis_weight = mis_power2( bsdf_sample_count * bsdf_prob, env_sample_count * env_prob); env_value *= static_cast<float>(transmission / bsdf_prob * mis_weight); } // Add the contribution of this sample to the illumination. env_value *= bsdf_value; radiance += env_value; } if (bsdf_sample_count > 1) radiance /= static_cast<float>(bsdf_sample_count); }