Example #1
0
glm::dvec4 StdCoating::indirectBrdf(
    std::vector<Raycast>& raycasts,
    const RayHitReport& report,
    const Raycast& incidentRay) const
{
    // Emission
    glm::dvec4 emission = glm::dvec4(0.0);

    // Report's shorthands
    const glm::dvec3& pos = report.position;
    const glm::dvec3& tex = report.texCoord;
    const glm::dvec3& wallNormal = report.normal;
    const glm::dvec3& reflectOrig = report.reflectionOrigin;
    const glm::dvec3& refractOrig = report.refractionOrigin;
    const Material& currMaterial = *report.currMaterial;
    const Material& nextMaterial = *report.nextMaterial;
    const glm::dvec3& incident = incidentRay.direction;

    // StdCoating properties
    double rough = roughness(tex);
    double pRIdx = paintRefractiveIndex(tex);
    double entropy = Raycast::getEntropy(rough);
    glm::dvec4 paintFrag = paintColor(tex);
    glm::dvec3 pColor = glm::dvec3(paintFrag);
    double pOpa = paintFrag.a;

    // Leaved material properties
    double lRIdx = currMaterial.refractiveIndex(pos);

    // Entered material properties
    double eOpa = nextMaterial.opacity(pos);
    double eCond = nextMaterial.conductivity(pos);
    double eRIdx = nextMaterial.refractiveIndex(pos);
    glm::dvec3 eColor = nextMaterial.color(pos);


    // Reflection
    glm::dvec3 reflectNormal = getMicrofacetNormal(
                                   wallNormal, incident, rough);

    // Fresnel reflection
    double paintReflectRatio = computeReflexionRatio(
                                   lRIdx, pRIdx, incident, reflectNormal);


    glm::dvec4 reflectSample(0.0);
    glm::dvec4 diffuseSample(0.0);
    glm::dvec4 refractSample(0.0);


    // Paint
    if(pOpa > 0.0)
    {
        double paintReflectWeight = pOpa * paintReflectRatio;
        reflectSample += glm::dvec4(paintReflectWeight);

        double paintDiffWeight = pOpa * (1 - paintReflectRatio);
        diffuseSample += glm::dvec4(pColor * paintDiffWeight, paintDiffWeight);
    }

    if(pOpa < 1.0)
    {
        // Metal reflection
        double metalWeight = (1 - pOpa) * eCond;
        if(metalWeight > 0.0)
        {
            reflectSample += glm::dvec4(eColor * metalWeight, metalWeight);
        }

        if(eCond < 1.0)
        {
            // Insulator reflection
            double insulProb = (1 - pOpa) * (1 - eCond);
            double matReflectRatio = computeReflexionRatio(
                                         lRIdx, eRIdx, incident, reflectNormal);

            double insulReflectWeight = insulProb * matReflectRatio;
            reflectSample += glm::dvec4(insulReflectWeight);

            // Fully opaque insulator
            if(eOpa >= 1.0)
            {
                double matDiffWeight = insulProb * (1 - matReflectRatio);
                diffuseSample += glm::dvec4(eColor * matDiffWeight, matDiffWeight);
            }
            // Refraction
            else
            {
                double paintRefract = pOpa * (1 - paintReflectRatio);
                double insulRefract = insulProb * (1 - matReflectRatio);
                double refractWeight = paintRefract + insulRefract;
                glm::dvec3 refractColor = glm::mix(color::white, pColor, pOpa);
                refractSample += glm::dvec4(refractColor * refractWeight, refractWeight);
            }
        }
    }


    // Refraction
    if(refractSample.w > 0.0)
    {
        glm::dvec3 refractDir = computeRefraction(
                                    lRIdx, eRIdx, incident, reflectNormal);
        if(glm::dot(refractDir, wallNormal) < 0.0)
        {
            raycasts.push_back(Raycast(
                                   entropy,
                                   refractSample,
                                   refractOrig,
                                   refractDir));
        }
        else
        {
            reflectSample += refractSample;
        }
    }

    // Diffuse
    if(diffuseSample.w > 0.0)
    {
        if(rough < 1.0)
        {
            glm::dvec3 diffuseNormal = getMicrofacetNormal(
                                           wallNormal, incident, 1.0); // Fully diffusive

            glm::dvec3 diffuseDir = glm::reflect(
                                        incident, diffuseNormal);

            raycasts.push_back(Raycast(
                                   Raycast::FULLY_DIFFUSE,
                                   diffuseSample,
                                   reflectOrig,
                                   diffuseDir));
        }
        else
        {
            reflectSample += diffuseSample;
        }
    }

    // Reflection
    if(reflectSample.w > 0.0)
    {
        glm::dvec3 reflectDir = glm::reflect(
                                    incident, reflectNormal);

        raycasts.push_back(Raycast(
                               entropy,
                               reflectSample,
                               reflectOrig,
                               reflectDir));
    }

    // No emission
    return emission;
}
Example #2
0
/*! loads an .a2mtl material file
 *  @param filename the materials filename
 */
void a2ematerial::load_material(const string& filename_) {
	filename = filename_;
	
	// read mat data
	if(!file_io::file_to_buffer(filename, buffer)) return;
	const string mat_data = buffer.str();
	
	// check if we have a xml (mat) file
	if(mat_data.length() < 5 || mat_data.substr(0, 5) != "<?xml") {
		log_error("invalid a2e-material file %s!", filename);
		return;
	}
	
	xmlDoc* doc = xmlReadMemory(mat_data.c_str(), (int)mat_data.size(), nullptr, (const char*)"UTF-8", 0);
	xmlNode* root = xmlDocGetRootElement(doc);
	
	size_t object_count = 0;
	size_t object_id = 0;
	a2ematerial::material* cur_material = nullptr;
	xmlNode* cur_node = nullptr;
	stack<xmlNode*> node_stack;
	node_stack.push(root);
	while(!node_stack.empty()) {
		cur_node = node_stack.top();
		node_stack.pop();

		if(cur_node->next != nullptr) node_stack.push(cur_node->next);

		if(cur_node->type == XML_ELEMENT_NODE) {
			xmlElement* cur_elem = (xmlElement*)cur_node;
			string node_name = (const char*)cur_elem->name;

			if(cur_node->children != nullptr) node_stack.push(cur_node->children);

			if(node_name == "a2e_material") {
				size_t version = x->get_attribute<size_t>(cur_elem->attributes, "version");
				if(version != A2E_MATERIAL_VERSION) {
					log_error("wrong version %u in material %s - should be %u!", version, filename, A2E_MATERIAL_VERSION);
					return;
				}
				
				object_count = x->get_attribute<size_t>(cur_elem->attributes, "object_count");
			}
			else if(node_name == "material") {
				// get material info
				size_t id = x->get_attribute<size_t>(cur_elem->attributes, "id");
				string type = x->get_attribute<string>(cur_elem->attributes, "type");
				string model = x->get_attribute<string>(cur_elem->attributes, "model");
				
				// create material
				materials.push_back(*new material());
				cur_material = &materials.back();
				cur_material->id = (ssize_t)id;
				cur_material->mat_type = (type == "diffuse" ? MATERIAL_TYPE::DIFFUSE :
										  (type == "parallax" ? MATERIAL_TYPE::PARALLAX : MATERIAL_TYPE::NONE));
				cur_material->lm_type = (model == "phong" ? LIGHTING_MODEL::PHONG :
										 (model == "ashikhmin_shirley" ? LIGHTING_MODEL::ASHIKHMIN_SHIRLEY : LIGHTING_MODEL::NONE));
				
				switch(cur_material->mat_type) {
					case MATERIAL_TYPE::DIFFUSE:
						cur_material->mat = new diffuse_material();
						((diffuse_material*)cur_material->mat)->diffuse_texture = dummy_texture;
						((diffuse_material*)cur_material->mat)->specular_texture = default_specular;
						((diffuse_material*)cur_material->mat)->reflectance_texture = default_specular;
						break;
					case MATERIAL_TYPE::PARALLAX:
						cur_material->mat = new parallax_material();
						((parallax_material*)cur_material->mat)->diffuse_texture = dummy_texture;
						((parallax_material*)cur_material->mat)->specular_texture = default_specular;
						((parallax_material*)cur_material->mat)->reflectance_texture = default_specular;
						((parallax_material*)cur_material->mat)->height_texture = dummy_texture;
						((parallax_material*)cur_material->mat)->normal_texture = dummy_texture;
						break;
					case MATERIAL_TYPE::NONE:
						cur_material->mat = new material_object();
						break;
				}
				
				switch(cur_material->lm_type) {
					case LIGHTING_MODEL::PHONG:
						cur_material->model = new phong_model();
						break;
					case LIGHTING_MODEL::ASHIKHMIN_SHIRLEY:
						cur_material->model = new ashikhmin_shirley_model();
						break;
					case LIGHTING_MODEL::NONE:
						log_error("unknown lighting model type \"%s\" (%d)!",
								  model, cur_material->lm_type);
						return;
				}
				
				// get material data
				for(xmlNode* material_node = cur_node->children; material_node; material_node = material_node->next) {
					xmlElement* material_elem = (xmlElement*)material_node;
					string material_name = (const char*)material_elem->name;
					if(material_name == "texture") {
						string texture_filename = x->get_attribute<string>(material_elem->attributes, "file");
						string texture_type_str = x->get_attribute<string>(material_elem->attributes, "type");
						
						TEXTURE_TYPE texture_type = (TEXTURE_TYPE)0;
						if(texture_type_str == "diffuse") texture_type = TEXTURE_TYPE::DIFFUSE;
						else if(texture_type_str == "specular") texture_type = TEXTURE_TYPE::SPECULAR;
						else if(texture_type_str == "reflectance") texture_type = TEXTURE_TYPE::REFLECTANCE;
						else if(texture_type_str == "height") texture_type = TEXTURE_TYPE::HEIGHT;
						else if(texture_type_str == "normal") texture_type = TEXTURE_TYPE::NORMAL;
						else if(texture_type_str == "anisotropic") texture_type = TEXTURE_TYPE::ANISOTROPIC;
						else {
							log_error("unknown texture type %s!", texture_type_str.c_str());
							return;
						}
						
						// type/mat/model checking
						switch(cur_material->mat_type) {
							case MATERIAL_TYPE::DIFFUSE:
								if(texture_type == TEXTURE_TYPE::HEIGHT ||
								   texture_type == TEXTURE_TYPE::NORMAL) {
									log_error("invalid texture type/tag \"%s\" for diffuse material!",
											 texture_type_str.c_str());
									continue;
								}
								break;
							case MATERIAL_TYPE::PARALLAX: // everything allowed for parallax-mapping
							case MATERIAL_TYPE::NONE: break;
						}
						
						switch(cur_material->lm_type) {
							case LIGHTING_MODEL::PHONG:
								if(texture_type == TEXTURE_TYPE::ANISOTROPIC) {
									log_error("invalid texture type/tag \"%s\" for phong material (anisotropic type is not allowed)!",
											 texture_type_str.c_str());
									continue;
								}
								break;
							case LIGHTING_MODEL::ASHIKHMIN_SHIRLEY:
							case LIGHTING_MODEL::NONE: break;
						}
						
						// get filtering and wrapping modes (if they are specified)
						GLenum wrap_s = GL_REPEAT, wrap_t = GL_REPEAT; // default values
						TEXTURE_FILTERING filtering = TEXTURE_FILTERING::AUTOMATIC;
						
						for(unsigned int i = 0; i < 2; i++) {
							const char* wrap_mode = (i == 0 ? "wrap_s" : "wrap_t");
							GLenum& wrap_ref = (i == 0 ? wrap_s : wrap_t);
							if(x->is_attribute(material_elem->attributes, wrap_mode)) {
								string wrap_str = x->get_attribute<string>(material_elem->attributes, wrap_mode);
								
								if(wrap_str == "clamp_to_edge") wrap_ref = GL_CLAMP_TO_EDGE;
								else if(wrap_str == "repeat") wrap_ref = GL_REPEAT;
								else if(wrap_str == "mirrored_repeat") wrap_ref = GL_MIRRORED_REPEAT;
								else {
									log_error("unknown wrap mode \"%s\" for %s!", wrap_str.c_str(), wrap_mode);
								}
							}
						}
						
						if(x->is_attribute(material_elem->attributes, "filtering")) {
							string filtering_str = x->get_attribute<string>(material_elem->attributes, "filtering");
							
							if(filtering_str == "automatic") filtering = TEXTURE_FILTERING::AUTOMATIC;
							else if(filtering_str == "point") filtering = TEXTURE_FILTERING::POINT;
							else if(filtering_str == "linear") filtering = TEXTURE_FILTERING::LINEAR;
							else if(filtering_str == "bilinear") filtering = TEXTURE_FILTERING::BILINEAR;
							else if(filtering_str == "trilinear") filtering = TEXTURE_FILTERING::TRILINEAR;
							else {
								log_error("unknown filtering mode \"%s\"!", filtering_str.c_str());
							}
						}
						
						a2e_texture tex = t->add_texture(floor::data_path(texture_filename.c_str()), filtering, engine::get_anisotropic(), (GLint)wrap_s, (GLint)wrap_t);
						switch(texture_type) {
							case TEXTURE_TYPE::DIFFUSE: ((diffuse_material*)cur_material->mat)->diffuse_texture = tex; break;
							case TEXTURE_TYPE::SPECULAR: ((diffuse_material*)cur_material->mat)->specular_texture = tex; break;
							case TEXTURE_TYPE::REFLECTANCE: ((diffuse_material*)cur_material->mat)->reflectance_texture = tex; break;
							case TEXTURE_TYPE::HEIGHT: ((parallax_material*)cur_material->mat)->height_texture = tex; break;
							case TEXTURE_TYPE::NORMAL: ((parallax_material*)cur_material->mat)->normal_texture = tex; break;
							case TEXTURE_TYPE::ANISOTROPIC:
								if(cur_material->lm_type == LIGHTING_MODEL::ASHIKHMIN_SHIRLEY) {
									((ashikhmin_shirley_model*)cur_material->model)->anisotropic_texture = tex;
								}
								break;
						}
					}
					// ashikhmin/shirley only
					else if(material_name == "ashikhmin_shirley" ||
							material_name == "const_isotropic" ||
							material_name == "const_anisotropic") {
						if(cur_material->lm_type != LIGHTING_MODEL::ASHIKHMIN_SHIRLEY) {
							log_error("<%s> is an ashikhmin/shirley lighting-model only tag!", material_name.c_str());
							continue;
						}
						
						if(material_name == "ashikhmin_shirley") {
							// no attributes atm
						}
						else if(material_name == "const_anisotropic") {
							float2 roughness(1.0f);
							string roughness_str = x->get_attribute<string>(material_elem->attributes, "roughness");
							vector<string> roughness_arr = core::tokenize(roughness_str, ',');
							
							if(roughness_arr.size() < 2 ||
							   roughness_arr[0].length() == 0 ||
							   roughness_arr[1].length() == 0) {
								log_error("invalid anisotropic roughness value \"%s\"!", roughness_str.c_str());
								return;
							}
							
							if(cur_material->lm_type == LIGHTING_MODEL::ASHIKHMIN_SHIRLEY) {
								ashikhmin_shirley_model* as_model = (ashikhmin_shirley_model*)cur_material->model;
								as_model->anisotropic_roughness.set(stof(roughness_arr[0]), stof(roughness_arr[1]));
							}
							else {
								log_error("invalid lighting model type for \"const_anisotropic\"!");
								return;
							}
						}
					}
					// parallax mapping only
					else if(material_name == "pom") {
						if(cur_material->mat_type != MATERIAL_TYPE::PARALLAX) {
							log_error("<pom> is a parallax-mapping only tag!");
							continue;
						}
						
						((parallax_material*)cur_material->mat)->parallax_occlusion = (x->get_attribute<string>(material_elem->attributes, "value") == "true" ? true : false);
					}
				}
			}
			else if(node_name == "object") {
				size_t material_id = x->get_attribute<size_t>(cur_elem->attributes, "material_id");
				const material* mat = nullptr;
				try {
					mat = &get_material(material_id);
				}
				catch(...) {
					log_error("invalid object mapping for object #%d!", object_id);
					
					if(object_id == 0) return; // no default possible, abort
					
					// set to default and continue
					mat = mapping[0]->mat;
				}
				
				bool blending = false;
				if(x->is_attribute(cur_elem->attributes, "blending")) {
					blending = x->get_attribute<bool>(cur_elem->attributes, "blending");
				}
				
				mapping[object_id] = new object_mapping((material*)mat, blending);
				
				object_id++;
			}
		}
	}
	
	if(object_id == 0) {
		log_error("at least one object mapping is required!");
		return;
	}
	
	if(object_count < mapping.size()) {
		log_error("less object mappings specified than required by object count!");
		return;
	}
	
	xmlFreeDoc(doc);
	xmlCleanupParser();
}
Example #3
0
glm::dvec4 StdCoating::directBrdf(
    const LightCast& lightCast,
    const RayHitReport& report,
    const Raycast& eyeRay) const
{
    glm::dvec4 sampleSum = glm::dvec4(0.0);

    // Report's shorthands
    const glm::dvec3& pos = report.position;
    const glm::dvec3& tex = report.texCoord;
    const glm::dvec3& incident = lightCast.raycast.direction;

    // StdCoating properties
    double rough = roughness(tex);
    double entropy = Raycast::getEntropy(rough);
    double pRIdx = paintRefractiveIndex(tex);
    glm::dvec4 paintFrag = paintColor(tex);
    double pOpa = paintFrag.a;

    // Material properties
    double lRIdx = report.currMaterial->refractiveIndex(pos);
    double eRIdx = report.nextMaterial->refractiveIndex(pos);
    double eCond = report.nextMaterial->conductivity(pos);
    double eOpa = report.nextMaterial->opacity(pos);

    // Geometry
    glm::dvec3 wallNormal = report.normal;
    glm::dvec3 outDir = -eyeRay.direction;
    double inDotNorm = -glm::dot(incident, wallNormal);
    double outDotNorm = glm::dot(outDir, wallNormal);
    bool isTransmission = outDotNorm < 0.0;

    // Microfacet
    glm::dvec3 halfVec = glm::normalize(outDir - incident);
    wallNormal = glm::normalize(glm::mix(wallNormal, halfVec, rough));

    // Fresnel reflection
    double paintReflectRatio = computeReflexionRatio(
                                   lRIdx, pRIdx, incident, wallNormal);
    double matReflectRatio = computeReflexionRatio(
                                 lRIdx, eRIdx, incident, wallNormal);


    if(!isTransmission)
    {
        glm::dvec3 eColor = report.nextMaterial->color(pos);
        double diffuseLightSize = lightCast.diffuseSize(
                                      lightCast, eyeRay, Raycast::FULLY_DIFFUSE);

        double totalDiffScatt = (eOpa >= 1.0 ? 1.0 : 0.0);

        double metalProb = (1 - pOpa) * eCond;
        double insulProb = (1 - pOpa) * (1 - eCond);
        double matDiffProb = insulProb * totalDiffScatt * (1 - matReflectRatio);
        double diffuseProb = pOpa * (1 - paintReflectRatio) + matDiffProb;
        double fresnelProb = pOpa * paintReflectRatio + insulProb * matReflectRatio;
        double reflectProb = fresnelProb + metalProb;

        double diffuseIntens = inDotNorm * diffuseLightSize;

        if(diffuseProb > 0.0)
        {
            double diffuseWeight = diffuseProb * diffuseIntens;

            glm::dvec3 pColor = glm::dvec3(paintFrag);
            glm::dvec3 diffuseColor = glm::mix(pColor, eColor, matDiffProb / diffuseProb);
            glm::dvec4 diffSample(diffuseColor * diffuseWeight, diffuseWeight);
            sampleSum += diffSample;
        }

        if(reflectProb > 0.0 && rough > 0.0)
        {
            double reflectLightSize = lightCast.diffuseSize(
                                          lightCast, eyeRay, entropy);

            glm::dvec3 reflection = glm::reflect(incident, wallNormal);
            double outDotReflect = glm::max(glm::dot(outDir, reflection), 0.0);
            double reflectPower = cellar::fast_pow(outDotReflect, 1 / rough);
            double reflectIntens = reflectPower * reflectLightSize;
            reflectIntens = glm::mix(reflectIntens, diffuseIntens, rough);
            double reflectWeight = reflectProb * reflectIntens;

            glm::dvec3 reflectColor = glm::mix(color::white, eColor, metalProb / reflectProb);
            glm::dvec4 reflectSample(reflectColor * reflectWeight, reflectWeight);
            sampleSum += reflectSample;
        }
    }
    else if(rough > 0.0 && eOpa < 1.0)
    {
        double insulProb = (1 - pOpa) * (1 - eCond);

        if(insulProb > 0.0)
        {
            double reflectLightSize = lightCast.diffuseSize(
                                          lightCast, eyeRay, entropy);

            glm::dvec3 refraction = computeRefraction(lRIdx, eRIdx, incident, wallNormal);
            double refractDotOut = glm::max(glm::dot(refraction, outDir), 0.0);
            double refractPower = cellar::fast_pow(refractDotOut, 1 / rough);
            refractPower = glm::mix(refractPower, inDotNorm, rough);

            double paintRefract = pOpa * (1 - paintReflectRatio);
            double insulRefract = insulProb * (1 - matReflectRatio);
            double refractProb = (paintRefract + insulRefract) * refractPower * reflectLightSize;

            glm::dvec4 refractSample(refractProb);
            sampleSum += refractSample;
        }
    }

    return sampleSum;
}