示例#1
0
void ParticleSystem::spawnFace
   (const FaceScatter&  faceScatter, 
    const ParseOBJ&     parseObj, 
    const Color4&       color, 
    const Matrix4&      transform, 
    int                 materialIndex) {

    const Color4unorm8 c(color.pow(1.0f / SmokeVolumeSet::PARTICLE_GAMMA));

    Random rnd(10000, false);
    m_particle.resize(0);
    m_physicsData.resize(0);
    AABox bounds;

    for (ParseOBJ::GroupTable::Iterator git = parseObj.groupTable.begin(); git.isValid(); ++git) {
        const shared_ptr<ParseOBJ::Group>& group = git->value;
        for (ParseOBJ::MeshTable::Iterator mit = group->meshTable.begin(); mit.isValid(); ++mit) {
            const shared_ptr<ParseOBJ::Mesh>& mesh = mit->value;
            for (int f = 0; f < mesh->faceArray.size(); ++f) {
                if (rnd.uniform() <= faceScatter.particlesPerFace) {
                    const ParseOBJ::Face& face = mesh->faceArray[f];
                    Particle& particle = m_particle.next();
                    PhysicsData& physicsData = m_physicsData.next();

                    // Use the average vertex as the position
                    Point3 vrt[10];
                    particle.position = Point3::zero();
                    for (int v = 0; v < face.size(); ++v) {
                        vrt[v] = (transform * Vector4(parseObj.vertexArray[face[v].vertex], 1.0f)).xyz();
                        particle.position += vrt[v];
                    }
                    particle.position /= float(face.size());

                    const Vector3& normal = (vrt[1] - vrt[0]).cross(vrt[2] - vrt[0]).direction();
                    particle.position += faceScatter.explodeDistance * normal;

                    particle.normal = normal;
                    particle.materialIndex = materialIndex;
                    particle.color    = c;
                    particle.angle    = rnd.uniform(0.0f, 2.0f) * pif(); 
                    particle.radius   = min(faceScatter.maxRadius, faceScatter.radiusScaleFactor * pow((particle.position - vrt[0]).length(), faceScatter.radiusExponent));
                    particle.emissive = 0;
                    physicsData.angularVelocity = rnd.uniform(-1.0f, 1.0f) * (360.0f * units::degrees()) / (20.0f * units::seconds());
                    bounds.merge(particle.position);
                }
            }  // face
        } // mesh
    } // group

    // Center
    if (faceScatter.moveCenterToOrigin) {
        const Vector3& offset = -bounds.center();
        for (int i = 0; i < m_particle.size(); ++i) {
            m_particle[i].position += offset;
        }

        m_lastObjectSpaceAABoxBounds = bounds + offset;
    } else {
        m_lastObjectSpaceAABoxBounds = bounds;
    }
}
示例#2
0
void ArticulatedViewer::onInit(const String& filename) {
    ArticulatedModel::clearCache();
    Texture::clearCache();

    m_filename = filename;

    m_selectedPart   = NULL;
    m_selectedMesh   = NULL;
    m_selectedTriangleIndex = -1;
    m_numFaces       = 0;
    m_numVertices    = 0;
    m_shadowMapDirty = true;

    UniversalMaterial::clearCache();
    
    const RealTime start = System::time();
    if (toLower(FilePath::ext(filename)) == "any") {

        if ((toLower(FilePath::ext(FilePath::base(filename))) == "material") ||
            (toLower(FilePath::ext(FilePath::base(filename))) == "universalmaterial")) {

            // Assume that this is an .UniversalMaterial.Any file. Load a square and apply the material
            Any any(Any::TABLE, "ArticulatedModel::Specification");
            any["filename"] = "model/crate/crate4xtex.obj";
            any["stripMaterials"] = true;
            any["preprocess"] = Any(Any::ARRAY);

            Any arg(Any::ARRAY, "setMaterial");
            arg.append(Any(Any::ARRAY, "all"));
            arg.append(Any::fromFile(filename));
            any["preprocess"].append(arg);

            Any arg2(Any::ARRAY, "setTwoSided");
            arg2.append(Any(Any::ARRAY, "all"));
            arg2.append(true);
            any["preprocess"].append(arg2);

            m_model = ArticulatedModel::create(ArticulatedModel::Specification(any));
        } else {

            // Assume that this is an .ArticulatedModel.Any file
            Any any;
            any.load(filename);

            m_model = ArticulatedModel::create(ArticulatedModel::Specification(any));
        }
    } else {
        m_model = ArticulatedModel::fromFile(filename);
    }
    debugPrintf("%s loaded in %f seconds\n", filename.c_str(), System::time() - start);


    Array<shared_ptr<Surface> > arrayModel;
    if (m_model->usesSkeletalAnimation()) {
        Array<G3D::String> animationNames;
        m_model->getAnimationNames(animationNames);
        // TODO: Add support for selecting animations.
        m_model->getAnimation(animationNames[0], m_animation); 
        m_animation.getCurrentPose(0.0f, m_pose);
    } 
    
    m_model->pose(arrayModel, CFrame(), m_pose);

    m_model->countTrianglesAndVertices(m_numFaces, m_numVertices);
    
    m_scale = 1;
    m_offset = Vector3::zero();
    bool overwrite = true;
    
    // Find the size of the bounding box of the entire model
    AABox bounds;
    if (arrayModel.size() > 0) {
        
        for (int x = 0; x < arrayModel.size(); ++x) {		
            
            //merges the bounding boxes of all the seperate parts into the bounding box of the entire object
            AABox temp;
            CFrame cframe;
            arrayModel[x]->getCoordinateFrame(cframe);
            arrayModel[x]->getObjectSpaceBoundingBox(temp);
            Box partBounds = cframe.toWorldSpace(temp);
            
            // Some models have screwed up bounding boxes
            if (partBounds.extent().isFinite()) {
                if (overwrite) {
                    partBounds.getBounds(bounds);
                    overwrite = false;
                } else {
                    partBounds.getBounds(temp);
                    bounds.merge(temp);
                }
            }
        }
        
        if (overwrite) {
            // We never found a part with a finite bounding box
            bounds = AABox(Vector3::zero());
        }
        
        Vector3 extent = bounds.extent();
        Vector3 center = bounds.center();
        
        // Scale to X units
        float scale = 1.0f / max(extent.x, max(extent.y, extent.z));
        
        if (scale <= 0) {
            scale = 1;
        }

        if (! isFinite(scale)) {
            scale = 1;
        }

        m_scale = scale;
        scale *= VIEW_SIZE;
        m_offset = -scale * center;
        

        if (! center.isFinite()) {
            center = Vector3();
        }

        // Transform parts in-place
        m_model->scaleWholeModel(scale);

        ArticulatedModel::CleanGeometrySettings csg;
        // Merging vertices is slow and topology hasn't changed at all, so preclude vertex merging
        csg.allowVertexMerging = false; 
        m_model->cleanGeometry(csg);
    }

    // Get the newly transformed animation
    if (m_model->usesSkeletalAnimation()) {
        Array<String> animationNames;
        m_model->getAnimationNames(animationNames);
        // TODO: Add support for selecting animations.
        m_model->getAnimation(animationNames[0], m_animation); 
        m_animation.getCurrentPose(0.0f, m_pose);
    } 

    // saveGeometry();
}
示例#3
0
void ShadowMap::computeMatrices
(const shared_ptr<Light>& light, 
 AABox          sceneBounds,
 CFrame&        lightFrame,
 Projection&    lightProjection,
 Matrix4&       lightProjectionMatrix,
 float          lightProjX,
 float          lightProjY,
 float          lightProjNearMin,
 float          lightProjFarMax,
 float          intensityCutoff) {

    if (! sceneBounds.isFinite() || sceneBounds.isEmpty()) {
        // Produce some reasonable bounds
        sceneBounds = AABox(Point3(-20, -20, -20), Point3(20, 20, 20));
    }

    lightFrame = light->frame();

    if (light->type() == Light::Type::DIRECTIONAL) {
        Point3 center = sceneBounds.center();
        if (! center.isFinite()) {
            center = Point3::zero();
        }
        // Move directional light away from the scene.  It must be far enough to see all objects
        lightFrame.translation = -lightFrame.lookVector() * 
            min(1e6f, max(sceneBounds.extent().length() / 2.0f, lightProjNearMin, 30.0f)) + center;
    }

    const CFrame& f = lightFrame;

    float lightProjNear = finf();
    float lightProjFar  = 0.0f;

    // TODO: for a spot light, only consider objects this light can see

    // Find nearest and farthest corners of the scene bounding box
    for (int c = 0; c < 8; ++c) {
        const Vector3&  v        = sceneBounds.corner(c);
        const float     distance = -f.pointToObjectSpace(v).z;

        lightProjNear  = min(lightProjNear, distance);
        lightProjFar   = max(lightProjFar, distance);
    }
    
    // Don't let the near get too close to the source, and obey
    // the specified hint.
    lightProjNear = max(lightProjNearMin, lightProjNear);

    // Don't bother tracking shadows past the effective radius
    lightProjFar = min(light->effectSphere(intensityCutoff).radius, lightProjFar);
    lightProjFar = max(lightProjNear + 0.1f, min(lightProjFarMax, lightProjFar));

    debugAssert(lightProjNear < lightProjFar);

    if (light->type() != Light::Type::DIRECTIONAL) {
        // TODO: Square spot

        // Spot light; we can set the lightProj bounds intelligently

        alwaysAssertM(light->spotHalfAngle() <= halfPi(), "Spot light with shadow map and greater than 180-degree bounds");

        // The cutoff is half the angle of extent (See the Red Book, page 193)
        const float angle = light->spotHalfAngle();

        lightProjX = tan(angle) * lightProjNear;
      
        // Symmetric in x and y
        lightProjY = lightProjX;

        lightProjectionMatrix = 
            Matrix4::perspectiveProjection
            (-lightProjX, lightProjX, -lightProjY, 
             lightProjY, lightProjNear, lightProjFar);

    } else if (light->type() == Light::Type::DIRECTIONAL) {
        // Directional light

        // Construct a projection and view matrix for the camera so we can 
        // render the scene from the light's point of view
        //
        // Since we're working with a directional light, 
        // we want to make the center of projection for the shadow map
        // be in the direction of the light but at a finite distance 
        // to preserve z precision.
        
        lightProjectionMatrix = 
            Matrix4::orthogonalProjection
            (-lightProjX, lightProjX, -lightProjY, 
             lightProjY, lightProjNear, lightProjFar);

    } else {
        // Omni light.  Nothing good can happen here, but at least we
        // generate something

        lightProjectionMatrix =
            Matrix4::perspectiveProjection
            (-lightProjX, lightProjX, -lightProjY, 
             lightProjY, lightProjNear, lightProjFar);
    }

    float fov = atan2(lightProjX, lightProjNear) * 2.0f;
    lightProjection.setFieldOfView(fov, FOVDirection::HORIZONTAL);
    lightProjection.setNearPlaneZ(-lightProjNear);
    lightProjection.setFarPlaneZ(-lightProjFar);
}
示例#4
0
RayGridIterator::RayGridIterator
(Ray                    ray, 
 const Vector3int32&    numCells, 
 const Vector3&         cellSize,
 const Point3&          gridOrigin,
 const Point3int32&     gridOriginIndex) :
    m_numCells(numCells),
    m_enterDistance(0.0f),
    m_ray(ray), 
    m_cellSize(cellSize),
    m_insideGrid(true) {
    
    if (gridOrigin.nonZero()) {
        // Change to the grid's reference frame
        ray = Ray::fromOriginAndDirection(ray.origin() - gridOrigin, ray.direction());
    }

    //////////////////////////////////////////////////////////////////////
    // See if the ray begins inside the box
    const AABox gridBounds(Vector3::zero(), Vector3(numCells) * cellSize);

    bool startsOutside = false;
    bool inside = false;
    Point3 startLocation = ray.origin();

    const bool passesThroughGrid =
        CollisionDetection::rayAABox
        (ray, Vector3(1,1,1) / ray.direction(),
         gridBounds, gridBounds.center(),
         square(gridBounds.extent().length() * 0.5f),
         startLocation,
         inside);

    if (! inside) {
        if (passesThroughGrid) {
            // Back up slightly so that we immediately hit the
            // start location.  The precision here is tricky--if
            // the ray strikes at a very glancing angle, we need
            // to move a large distance along the ray to enter the
            // grid.  If the ray strikes head on, we only need to
            // move a small distance.
            m_enterDistance = (ray.origin() - startLocation).length() - 0.0001f;
            startLocation = ray.origin() + ray.direction() * m_enterDistance;
            startsOutside = true;
        } else {
            // The ray never hits the grid
            m_insideGrid = false;
        }
    }

    //////////////////////////////////////////////////////////////////////
    // Find the per-iteration variables
    for (int a = 0; a < 3; ++a) {
        m_index[a]  = floor(startLocation[a] / cellSize[a]);
        m_tDelta[a] = cellSize[a] / abs(ray.direction()[a]);

        m_step[a]   = sign(ray.direction()[a]);

        // Distance to the edge fo the cell along the ray direction
        float d = startLocation[a] - m_index[a] * cellSize[a];
        if (m_step[a] > 0) {
            // Measure from the other edge
            d = cellSize[a] - d;

            // Exit on the high side
            m_boundaryIndex[a] = m_numCells[a];
        } else {
            // Exit on the low side (or never)
            m_boundaryIndex[a] = -1;
        }
        debugAssert(d >= 0 && d <= cellSize[a]);

        if (ray.direction()[a] != 0) {
            m_exitDistance[a] = d / abs(ray.direction()[a]) + m_enterDistance;
        } else {
            // Ray is parallel to this partition axis.
            // Avoid dividing by zero, which could be NaN if d == 0
            m_exitDistance[a] = inf();
        }
    }

    if (gridOriginIndex.nonZero()) {
        // Offset the grid coordinates
        m_boundaryIndex += gridOriginIndex;
        m_index += gridOriginIndex;
    }


    if (startsOutside) {
        // Let the increment operator bring us into the first cell
        // so that the starting axis is initialized correctly.
        ++(*this);
    }
}