void Scene::createBulletTerrain() { Ogre::Terrain* baseTerrain = mTerrainGroup->getTerrain(0, 0); btHeightfieldTerrainShape* hfShape = new btHeightfieldTerrainShape( baseTerrain->getSize(), baseTerrain->getSize(), baseTerrain->getHeightData(), 1, 0, 0, 2, PHY_FLOAT, false); // Min and max height were set to 0 to force the terrain to be completely flat hfShape->setUseDiamondSubdivision(true); // This scale is based on the tutorial, but it may not be true... float metersBetweenVerts = baseTerrain->getWorldSize() / (baseTerrain->getSize() - 1); btVector3 scale(metersBetweenVerts, metersBetweenVerts, 1); hfShape->setLocalScaling(scale); hfShape->setUserPointer((void*) SU_Terrain); btCollisionObject* colObj = new btCollisionObject(); colObj->setCollisionShape(hfShape); colObj->setFriction(0.9); colObj->setRestitution(0.0); colObj->setCollisionFlags(colObj->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT); mSim->getCollisionWorld()->getDynamicsWorld()->addCollisionObject(colObj); mSim->getCollisionWorld()->addShape(hfShape); // Border planes const float px[4] = {-1, 1, 0, 0}; const float py[4] = { 0, 0,-1, 1}; for (int i = 0; i < 4; ++i) { btVector3 vpl(px[i], py[i], 0); btCollisionShape* shp = new btStaticPlaneShape(vpl, 0); shp->setUserPointer((void*) SU_Border); btTransform tr; tr.setIdentity(); tr.setOrigin(vpl * -0.5 * worldSize); btCollisionObject* col = new btCollisionObject(); col->setCollisionShape(shp); col->setWorldTransform(tr); col->setFriction(0.3); //+ col->setRestitution(0.0); col->setCollisionFlags(col->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT); mSim->getCollisionWorld()->getDynamicsWorld()->addCollisionObject(col); mSim->getCollisionWorld()->addShape(shp); } }
size_t generateVPLs(const Scene *scene, Random *random, size_t offset, size_t count, int maxDepth, bool prune, std::deque<VPL> &vpls) { if (maxDepth <= 1) return 0; static Sampler *sampler = NULL; if (!sampler) { Properties props("halton"); props.setInteger("scramble", 0); sampler = static_cast<Sampler *> (PluginManager::getInstance()-> createObject(MTS_CLASS(Sampler), props)); sampler->configure(); } const Sensor *sensor = scene->getSensor(); Float time = sensor->getShutterOpen() + 0.5f * sensor->getShutterOpenTime(); const Frame stdFrame(Vector(1,0,0), Vector(0,1,0), Vector(0,0,1)); while (vpls.size() < count) { sampler->setSampleIndex(++offset); PositionSamplingRecord pRec(time); DirectionSamplingRecord dRec; Spectrum weight = scene->sampleEmitterPosition(pRec, sampler->next2D()); size_t start = vpls.size(); /* Sample an emitted particle */ const Emitter *emitter = static_cast<const Emitter *>(pRec.object); if (!emitter->isEnvironmentEmitter() && emitter->needsDirectionSample()) { VPL lumVPL(EPointEmitterVPL, weight); lumVPL.its.p = pRec.p; lumVPL.its.shFrame = pRec.n.isZero() ? stdFrame : Frame(pRec.n); lumVPL.emitter = emitter; appendVPL(scene, random, lumVPL, prune, vpls); weight *= emitter->sampleDirection(dRec, pRec, sampler->next2D()); } else { /* Hack to get the proper information for directional VPLs */ DirectSamplingRecord diRec( scene->getKDTree()->getAABB().getCenter(), pRec.time); Spectrum weight2 = emitter->sampleDirect(diRec, sampler->next2D()) / scene->pdfEmitterDiscrete(emitter); if (weight2.isZero()) continue; VPL lumVPL(EDirectionalEmitterVPL, weight2); lumVPL.its.p = Point(0.0); lumVPL.its.shFrame = Frame(-diRec.d); lumVPL.emitter = emitter; appendVPL(scene, random, lumVPL, false, vpls); dRec.d = -diRec.d; Point2 offset = Warp::squareToUniformDiskConcentric(sampler->next2D()); Vector perpOffset = Frame(diRec.d).toWorld(Vector(offset.x, offset.y, 0)); BSphere geoBSphere = scene->getKDTree()->getAABB().getBSphere(); pRec.p = geoBSphere.center + (perpOffset - dRec.d) * geoBSphere.radius; weight = weight2 * M_PI * geoBSphere.radius * geoBSphere.radius; } int depth = 2; Ray ray(pRec.p, dRec.d, time); Intersection its; while (!weight.isZero() && (depth < maxDepth || maxDepth == -1)) { if (!scene->rayIntersect(ray, its)) break; const BSDF *bsdf = its.getBSDF(); BSDFSamplingRecord bRec(its, sampler, EImportance); Spectrum bsdfVal = bsdf->sample(bRec, sampler->next2D()); if (bsdfVal.isZero()) break; /* Assuming that BSDF importance sampling is perfect, the following should equal the maximum albedo over all spectral samples */ Float approxAlbedo = std::min((Float) 0.95f, bsdfVal.max()); if (sampler->next1D() > approxAlbedo) break; else weight /= approxAlbedo; VPL vpl(ESurfaceVPL, weight); vpl.its = its; if (BSDF::getMeasure(bRec.sampledType) == ESolidAngle) appendVPL(scene, random, vpl, prune, vpls); weight *= bsdfVal; Vector wi = -ray.d, wo = its.toWorld(bRec.wo); ray = Ray(its.p, wo, 0.0f); /* Prevent light leaks due to the use of shading normals -- [Veach, p. 158] */ Float wiDotGeoN = dot(its.geoFrame.n, wi), woDotGeoN = dot(its.geoFrame.n, wo); if (wiDotGeoN * Frame::cosTheta(bRec.wi) <= 0 || woDotGeoN * Frame::cosTheta(bRec.wo) <= 0) break; /* Disabled for now -- this increases VPL weights and accuracy is not really a big requirement */ #if 0 /* Adjoint BSDF for shading normals -- [Veach, p. 155] */ weight *= std::abs( (Frame::cosTheta(bRec.wi) * woDotGeoN)/ (Frame::cosTheta(bRec.wo) * wiDotGeoN)); #endif ++depth; } size_t end = vpls.size(); for (size_t i=start; i<end; ++i) vpls[i].emitterScale = 1.0f / (end - start); } return offset; }