장면 의 데이터 구조: Node & Entity

15340 단어 entity
Scene 에 대해 알 고 싶다 면 데이터 구 조 를 알 아 보 는 것 이 필수 적 이다.Scene 에는 노드 가 있 는데 하 나 는 트 리 구조 로 장면 의 모든 노드 의 현재 상태 (위치 크기 조정 등 데이터 기준 이 있 음) 를 저장 합 니 다.다른 하 나 는 Entity 로 Node 에 연결 되 고 이런 방식 으로 장면 의 내용 디자인 을 유연 하 게 한다.
 
Node:
1. 구조
Node::Node(const String& name)
		:
		mParent(0),   //  
		mNeedParentUpdate(false),  //    true,          
		mNeedChildUpdate(false),  //    true,         (  )
		mParentNotified(false),  // true       
        mQueuedForUpdate(false),  // true           
		mName(name),
		mOrientation(Quaternion::IDENTITY), //        ,          
		mPosition(Vector3::ZERO), //          
		mScale(Vector3::UNIT_SCALE), //     
        mInheritOrientation(true), // true       
		mInheritScale(true),  //       
		mDerivedOrientation(Quaternion::IDENTITY),  // Derived               
		mDerivedPosition(Vector3::ZERO), // ,                
		mDerivedScale(Vector3::UNIT_SCALE),
		mInitialPosition(Vector3::ZERO), // Initial        ,          。
		mInitialOrientation(Quaternion::IDENTITY),
		mInitialScale(Vector3::UNIT_SCALE),
		mCachedTransformOutOfDate(true), //      
		mListener(0), 
		mDebug(0)

    {
        needUpdate();
    }

 
2. create Child: 아 이 를 만 들 었 습 니 다. 자신 이 아버지 이 고 부자 관계 도 맺 었 습 니 다.
Node* Node::createChild(const String& name, const Vector3& inTranslate, const Quaternion& inRotate)
    {
        Node* newNode = createChildImpl(name);
        newNode->translate(inTranslate);
        newNode->rotate(inRotate);
        this->addChild(newNode);
        return newNode;
    }

 create ChildImpl 은 가상 함수 로 하위 클래스 에서 연구 합 니 다.translate 라 는 이름 이 좀 아 프 네요. 위 치 를 정 했 는데.rotate 회전 과 크기 조정.
 
translate :
void Node::translate(const Vector3& d, TransformSpace relativeTo)
    {
        switch(relativeTo)
        {
        case TS_LOCAL:
            // position is relative to parent so transform downwards
            mPosition += mOrientation * d;
        	break;
        case TS_WORLD:
            // position is relative to parent so transform upwards
            if (mParent)
            {
                mPosition += (mParent->_getDerivedOrientation().Inverse() * d)
                    / mParent->_getDerivedScale();
            }
            else
            {
                mPosition += d;
            }
        	break;
        case TS_PARENT:
            mPosition += d;
            break;
        }
        needUpdate();
    }

 처음부터 끝까지 위치 가 바 뀌 는 것 만 봤 어 요. mPosition. 
 
rotate:
rotate(Vector3::UNIT_Y, angle, relativeTo); //  

void Node::rotate(const Vector3& axis, const Radian& angle, TransformSpace relativeTo)
    {
        Quaternion q;
        q.FromAngleAxis(angle,axis);
        rotate(q, relativeTo);
    }

    void Node::rotate(const Quaternion& q, TransformSpace relativeTo)
    {
		// Normalise quaternion to avoid drift
		Quaternion qnorm = q;
		qnorm.normalise();

        switch(relativeTo)
        {
        case TS_PARENT:
            // Rotations are normally relative to local axes, transform up
            mOrientation = qnorm * mOrientation;
            break;
        case TS_WORLD:
            // Rotations are normally relative to local axes, transform up
            mOrientation = mOrientation * _getDerivedOrientation().Inverse()
                * qnorm * _getDerivedOrientation();
            break;
        case TS_LOCAL:
            // Note the order of the mult, i.e. q comes after
            mOrientation = mOrientation * qnorm;
            break;
        }
        needUpdate();
    }

 밑 에 있 는 본질 이 수학 적 계산 인지 4 원 수 를 통 해 축 을 정 하 는 것 입 니 다. 여기 에는 세 가지 유형의 선택 이 있 습 니 다. LOCAL (자신 에 게), PARENT (아버지 에 게), WORLD (상대 세계) 가 회전 합 니 다.Vector3::UNIT_Z 는 어떤 축 을 따라 가 는 지 지정 합 니 다.
 
3. Update: 여기까지 쓰 면 EMF 가 생각 납 니 다. 사실은 모든 인터페이스 요 소 는 비슷 한 표현 을 가지 고 있 습 니 다. 다른 것 은 바 텀 실현 에 사용 되 는 사람 이 누구 입 니까?
void Node::needUpdate(bool forceParentUpdate)
    {
        mNeedParentUpdate = true;
		mNeedChildUpdate = true;
        mCachedTransformOutOfDate = true;
        // Make sure we're not root and parent hasn't been notified before
        if (mParent && (!mParentNotified || forceParentUpdate))
        {
            mParent->requestUpdate(this, forceParentUpdate);
			mParentNotified = true ;
        }
        // all children will be updated
        mChildrenToUpdate.clear();
    }

void Node::requestUpdate(Node* child, bool forceParentUpdate)
    {
        // If we're already going to update everything this doesn't matter
        if (mNeedChildUpdate)
        {
            return;
        }
        mChildrenToUpdate.insert(child);
        // Request selective update of me, if we didn't do it before
        if (mParent && (!mParentNotified || forceParentUpdate))
		{
            mParent->requestUpdate(this, forceParentUpdate);
			mParentNotified = true ;
		}
 }

여기에 붙 인 두 가지 방법 은 노드 에 업데이트 가 필요 하 다 는 것 을 알려 주 었 을 뿐 최종 적 으로 업데이트 해 야 할 노드 는 모두 mChildren ToUpdate 에 저장 되 어 있 습 니 다.
 
_update:
void Node::_update(bool updateChildren, bool parentHasChanged)
    {
		// always clear information about parent notification
		mParentNotified = false;

        // See if we should process everyone
        if (mNeedParentUpdate || parentHasChanged)
        {
            // Update transforms from parent
            _updateFromParent();   //             ,         
		}

        if(updateChildren)
        {
            if (mNeedChildUpdate || parentHasChanged)
            {
                ChildNodeMap::iterator it, itend;
                itend = mChildren.end();
                for (it = mChildren.begin(); it != itend; ++it)
                {
                    Node* child = it->second;
                    child->_update(true, true);
                }
            }
            else
            {
                // Just update selected children
                ChildUpdateSet::iterator it, itend;
                itend = mChildrenToUpdate.end();
                for(it = mChildrenToUpdate.begin(); it != itend; ++it)
                {
                    Node* child = *it;
                    child->_update(true, false);
                }

            }

            mChildrenToUpdate.clear();
            mNeedChildUpdate = false;
        }
    }

 
 이런 재 귀적 인 방식 으로 업 데 이 트 를 하면 효율 이 높 지 않 을 것 이다. 특히 하나의 노드 만 있 는 상황 에서 다 중 스 레 드 도 할 수 없다.ogre 는 효율 을 생각해 야 합 니 다. 적어도 하나의 노드 가 아 닌 list 를 따라 가 봐 야 합 니 다.
 
updateFromParent:
void Node::updateFromParentImpl(void) const
    {
        if (mParent)
        {
            // Update orientation
            const Quaternion& parentOrientation = mParent->_getDerivedOrientation();
            if (mInheritOrientation)
            {
                // Combine orientation with that of parent
                mDerivedOrientation = parentOrientation * mOrientation;
            }
			else
            {
                // No inheritance
                mDerivedOrientation = mOrientation;
            }

            // Update scale
            const Vector3& parentScale = mParent->_getDerivedScale();
            if (mInheritScale)
            {
                // Scale own position by parent scale, NB just combine
                // as equivalent axes, no shearing
                mDerivedScale = parentScale * mScale;
            }
            else
            {
                // No inheritance
                mDerivedScale = mScale;
            }

            // Change position vector based on parent's orientation & scale
            mDerivedPosition = parentOrientation * (parentScale * mPosition);

            // Add altered position vector to parents
            mDerivedPosition += mParent->_getDerivedPosition();
        }
        else
        {
            // Root node, no parent
            mDerivedOrientation = mOrientation;
            mDerivedPosition = mPosition;
            mDerivedScale = mScale;
        }

		mCachedTransformOutOfDate = true;
		mNeedParentUpdate = false;

    }

 Derived 를 접두사 로 하 는 세 개의 노드 위 치 를 설명 하 는 필드 를 업데이트 합 니 다.
 
SceneNode:
Node 의 계승, 장면 의 진실 한 결점, 각종 Object 가 그 위 에 걸 립 니 다.
1. Axis Aligned Box: 노드 의 경계, 충돌 검 측 이 필요 하기 때문에 업데이트 할 때 업데이트 해 야 합 니 다.
void SceneNode::_updateBounds(void)
    {
        // Reset bounds first
        mWorldAABB.setNull();

        // Update bounds from own attached objects         objects    
        ObjectMap::iterator i;
        for (i = mObjectsByName.begin(); i != mObjectsByName.end(); ++i)
        {
            // Merge world bounds of each object
            mWorldAABB.merge(i->second->getWorldBoundingBox(true));
        }

        // Merge with children           
        ChildNodeMap::iterator child;
        for (child = mChildren.begin(); child != mChildren.end(); ++child)
        {
            SceneNode* sceneChild = static_cast<SceneNode*>(child->second);
            mWorldAABB.merge(sceneChild->mWorldAABB);
        }

    }

 여 기 는 주로 mWorldAABB 의 크기 를 계산 하고 모든 연결 을 통 해 objects + ChildNode 합병 이 가장 큰 범 위 를 얻 었 습 니 다.
 
2. WireBounding Box: 선 상자 디 스 플레이 모드 라 는 디 스 플레이 모드 가 있 습 니 다. 바로 이 아버 지 는 Simple Renderable 로 렌 더 링 대상 을 볼 수 있 습 니 다.스스로 계산 하지 않 고 Axis Aligned Box 를 통 해 테 두 리 를 가 져 옵 니 다.
void SceneNode::_addBoundingBoxToQueue(RenderQueue* queue) {
		// Create a WireBoundingBox if needed.
		if (mWireBoundingBox == NULL) {
			mWireBoundingBox = OGRE_NEW WireBoundingBox();
		}
		mWireBoundingBox->setupBoundingBox(mWorldAABB);
		queue->addRenderable(mWireBoundingBox);
	}

 
3. autoTrack: 목 표를 자동 으로 추적 하고 모든 노드 에 SceneNode * mAutoTrackTarget 이 있 습 니 다.목표 노드 는 추적 할 수 있다. 이 능력 은 두 가지 효 과 를 실현 할 수 있다. 하 나 는 바로 캐릭터 이동 카메라 가 따라 움 직 이 는 것 이 고 또 하 나 는 캐릭터 가 아 기 를 데 리 고 다 니 는 것 이다.이 기능 은 주로 세 가지 방법 과 관련된다.autoTrack, lookAt, setDirection.
void SceneNode::setDirection(const Vector3& vec, TransformSpace relativeTo, 
        const Vector3& localDirectionVector)
    {
        // Do nothing if given a zero vector
        if (vec == Vector3::ZERO) return;

        // The direction we want the local direction point to
        Vector3 targetDir = vec.normalisedCopy();

        // Transform target direction to world space
        switch (relativeTo)
        {
        case TS_PARENT:
            if (mInheritOrientation)
            {
                if (mParent)
                {
                    targetDir = mParent->_getDerivedOrientation() * targetDir;
                }
            }
            break;
        case TS_LOCAL:
            targetDir = _getDerivedOrientation() * targetDir;
            break;
        case TS_WORLD:
            // default orientation
            break;
        }

        // Calculate target orientation relative to world space
        Quaternion targetOrientation;
        if( mYawFixed )
        {
            // Calculate the quaternion for rotate local Z to target direction
            Vector3 xVec = mYawFixedAxis.crossProduct(targetDir);
            xVec.normalise();
            Vector3 yVec = targetDir.crossProduct(xVec);
            yVec.normalise();
            Quaternion unitZToTarget = Quaternion(xVec, yVec, targetDir);

            if (localDirectionVector == Vector3::NEGATIVE_UNIT_Z)
            {
                // Specail case for avoid calculate 180 degree turn
                targetOrientation =
                    Quaternion(-unitZToTarget.y, -unitZToTarget.z, unitZToTarget.w, unitZToTarget.x);
            }
            else
            {
                // Calculate the quaternion for rotate local direction to target direction
                Quaternion localToUnitZ = localDirectionVector.getRotationTo(Vector3::UNIT_Z);
                targetOrientation = unitZToTarget * localToUnitZ;
            }
        }
        else
        {
            const Quaternion& currentOrient = _getDerivedOrientation();

            // Get current local direction relative to world space
            Vector3 currentDir = currentOrient * localDirectionVector;

            if ((currentDir+targetDir).squaredLength() < 0.00005f)
            {
                // Oops, a 180 degree turn (infinite possible rotation axes)
                // Default to yaw i.e. use current UP
                targetOrientation =
                    Quaternion(-currentOrient.y, -currentOrient.z, currentOrient.w, currentOrient.x);
            }
            else
            {
                // Derive shortest arc to new direction
                Quaternion rotQuat = currentDir.getRotationTo(targetDir);
                targetOrientation = rotQuat * currentOrient;
            }
        }

        // Set target orientation, transformed to parent space
        if (mParent && mInheritOrientation)
            setOrientation(mParent->_getDerivedOrientation().UnitInverse() * targetOrientation);
        else
            setOrientation(targetOrientation);
    }

 이것 은 setDirection 방법 으로 방향 을 바 꾸 는 것 입 니 다. 자동 추적 뿐만 아니 라 자신 이 방향 을 제어 하 는 데 도 이 방법 을 사용 합 니 다.
 
4. attachObject: 이것 은 반드시 말 해 야 합 니 다. 모든 Object 는 이 방법 을 통 해 노드 에 걸 려 있 습 니 다.최종 Object 는 ObjectMap mObjectsByName 에 저 장 됩 니 다.안 은 name 을 통 해 얻 을 수 있 습 니 다.
 
요약: 전체 장면 관리 에 있어 노드 는 그 중의 아주 작은 부분 일 뿐 노드 는 자원 과 관련 되 지 않 았 다.자원 과 관련 된 것 은 모두 Object 안에 있다.이 는 전체 장면 을 크 고 완전 하 게 묘 사 했 는데 실제 적 으로 렌 더 링 이 필요 한 대상 은 렌 더 링 대기 열 에 넣 을 것 이다.

좋은 웹페이지 즐겨찾기