void lljoint_object::test<1>() { LLJoint lljoint; LLJoint* jnt = lljoint.getParent(); ensure("getParent() failed ", (NULL == jnt)); ensure("getRoot() failed ", (&lljoint == lljoint.getRoot())); }
//----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- void LLPolySkeletalDistortion::apply( ESex avatar_sex ) { F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); LLJoint* joint; joint_vec_map_t::iterator iter; for (iter = mJointScales.begin(); iter != mJointScales.end(); iter++) { joint = iter->first; LLVector3 newScale = joint->getScale(); LLVector3 scaleDelta = iter->second; newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta); joint->setScale(newScale); } for (iter = mJointOffsets.begin(); iter != mJointOffsets.end(); iter++) { joint = iter->first; LLVector3 newPosition = joint->getPosition(); LLVector3 positionDelta = iter->second; newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); joint->setPosition(newPosition); } if (mLastWeight != mCurWeight && !mIsAnimating) { mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1); } mLastWeight = mCurWeight; }
//----------------------------------------------------------------------------- // clampRotation() //----------------------------------------------------------------------------- void LLJoint::clampRotation(LLQuaternion old_rot, LLQuaternion new_rot) { LLVector3 main_axis(1.f, 0.f, 0.f); for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { LLJoint* joint = *iter; if (joint->isAnimatable()) { main_axis = joint->getPosition(); main_axis.normVec(); // only care about first animatable child break; } } // 2003.03.26 - This code was just using up cpu cycles. AB // LLVector3 old_axis = main_axis * old_rot; // LLVector3 new_axis = main_axis * new_rot; // for (S32 i = 0; i < mConstraintSilhouette.count() - 1; i++) // { // LLVector3 vert1 = mConstraintSilhouette[i]; // LLVector3 vert2 = mConstraintSilhouette[i + 1]; // figure out how to clamp rotation to line on 3-sphere // } }
void lljoint_object::test<9>() { LLJoint lljoint; LLVector3 vec3(2.3f,30.f,10.f); lljoint.setScale(vec3); LLVector3 scale = lljoint.getScale(); ensure("setScale()/getScale failed ", (vec3 == scale)); }
void lljoint_object::test<12>() { LLJoint lljoint; LLVector3 vec3(2.3f,30.f,10.f); lljoint.setSkinOffset(vec3); LLVector3 offset = lljoint.getSkinOffset(); ensure("1:setSkinOffset()/getSkinOffset() failed ", (vec3 == offset)); }
void lljoint_object::test<4>() { LLJoint parent; std::string str1 = "LLJoint", str2; parent.setName(str1); str2 = parent.getName(); ensure("setName() failed ", (str1 == str2)); }
void lljoint_object::test<5>() { LLJoint lljoint; LLVector3 vec3(2.3f,30.f,10.f); lljoint.setPosition(vec3); LLVector3 pos = lljoint.getPosition(); ensure("setPosition()/getPosition() failed ", (vec3 == pos)); }
// Local space means "parameter space". F32 LLPhysicsMotion::toLocal(const LLVector3 &world) { LLJoint *joint = mJointState->getJoint(); const LLQuaternion rotation_world = joint->getWorldRotation(); LLVector3 dir_world = mMotionDirectionVec * rotation_world; dir_world.normalize(); return world * dir_world; }
void lljoint_object::test<6>() { LLJoint lljoint; LLVector3 vec3(2.3f,30.f,10.f); lljoint.setWorldPosition(vec3); LLVector3 pos = lljoint.getWorldPosition(); ensure("1:setWorldPosition()/getWorldPosition() failed ", (vec3 == pos)); LLVector3 lastPos = lljoint.getLastWorldPosition(); ensure("2:getLastWorldPosition failed ", (vec3 == lastPos)); }
F32 LLPhysicsMotion::calculateVelocity_local() { const F32 world_to_model_scale = 100.0f; LLJoint *joint = mJointState->getJoint(); const LLVector3 position_world = joint->getWorldPosition(); const LLVector3 last_position_world = mPosition_world; const LLVector3 positionchange_world = (position_world-last_position_world) * world_to_model_scale; const LLVector3 velocity_world = positionchange_world; const F32 velocity_local = toLocal(velocity_world); return velocity_local; }
//----------------------------------------------------------------------------- // updateWorldMatrixParent() //----------------------------------------------------------------------------- void LLJoint::updateWorldMatrixParent() { if (mDirtyFlags & MATRIX_DIRTY) { LLJoint *parent = getParent(); if (parent) { parent->updateWorldMatrixParent(); } updateWorldMatrix(); } }
BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) { llassert(mInfo == NULL); if (info->mID < 0) return FALSE; mInfo = info; mID = info->mID; setWeight(getDefaultWeight(), FALSE ); LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter; for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++) { LLPolySkeletalBoneInfo *bone_info = &(*iter); LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName); if (!joint) { llwarns << "Joint " << bone_info->mBoneName << " not found." << llendl; continue; } if (mJointScales.find(joint) != mJointScales.end()) { llwarns << "Scale deformation already supplied for joint " << joint->getName() << "." << llendl; } // store it mJointScales[joint] = bone_info->mScaleDeformation; // apply to children that need to inherit it for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin(); iter != joint->mChildren.end(); ++iter) { LLViewerJoint* child_joint = (LLViewerJoint*)(*iter); if (child_joint->inheritScale()) { LLVector3 childDeformation = LLVector3(child_joint->getScale()); childDeformation.scaleVec(bone_info->mScaleDeformation); mJointScales[child_joint] = childDeformation; } } if (bone_info->mHasPositionDeformation) { if (mJointOffsets.find(joint) != mJointOffsets.end()) { llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl; } mJointOffsets[joint] = bone_info->mPositionDeformation; } } return TRUE; }
//-------------------------------------------------------------------- // removeAllChildren() //-------------------------------------------------------------------- void LLJoint::removeAllChildren() { for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end();) { child_list_t::iterator curiter = iter++; LLJoint* joint = *curiter; mChildren.erase(curiter); joint->mXform.setParent(NULL); joint->mParent = NULL; joint->touch(); } }
//----------------------------------------------------------------------------- // LLEyeMotion::onDeactivate() //----------------------------------------------------------------------------- void LLEyeMotion::onDeactivate() { LLJoint* joint = mLeftEyeState->getJoint(); if (joint) { joint->setRotation(LLQuaternion::DEFAULT); } joint = mRightEyeState->getJoint(); if (joint) { joint->setRotation(LLQuaternion::DEFAULT); } }
//----------------------------------------------------------------------------- // updateWorldPRSParent() //----------------------------------------------------------------------------- void LLJoint::updateWorldPRSParent() { if (mDirtyFlags & (ROTATION_DIRTY | POSITION_DIRTY)) { LLJoint *parent = getParent(); if (parent) { parent->updateWorldPRSParent(); } mXform.update(); mDirtyFlags &= ~(ROTATION_DIRTY | POSITION_DIRTY); } }
//----------------------------------------------------------------------------- // updateWorldMatrixChildren() //----------------------------------------------------------------------------- void LLJoint::updateWorldMatrixChildren() { if (!this->mUpdateXform) return; if (mDirtyFlags & MATRIX_DIRTY) { updateWorldMatrix(); } for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { LLJoint* joint = *iter; joint->updateWorldMatrixChildren(); } }
void showJointPosOverrides( const LLJoint& joint, const std::string& note, const std::string& av_info ) { std::ostringstream os; os << joint.m_posBeforeOverrides; joint.m_attachmentOverrides.showJointPosOverrides(os); LL_DEBUGS("Avatar") << av_info << " joint " << joint.getName() << " " << note << " " << os.str() << LL_ENDL; }
//----------------------------------------------------------------------------- // getJoint() //----------------------------------------------------------------------------- LLJoint *LLCharacter::getJoint( const std::string &name ) { LLJoint* joint = NULL; LLJoint *root = getRootJoint(); if (root) { joint = root->findJoint(name); } if (!joint) { llwarns << "Failed to find joint." << llendl; } return joint; }
//----------------------------------------------------------------------------- // clampRotation() //----------------------------------------------------------------------------- void LLJoint::clampRotation(LLQuaternion old_rot, LLQuaternion new_rot) { LLVector3 main_axis(1.f, 0.f, 0.f); for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { LLJoint* joint = *iter; if (joint->isAnimatable()) { main_axis = joint->getPosition(); main_axis.normVec(); // only care about first animatable child break; } } }
//----------------------------------------------------------------------------- // findJoint() //----------------------------------------------------------------------------- LLJoint *LLJoint::findJoint( const std::string &name ) { if (name == getName()) return this; for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { LLJoint* joint = *iter; LLJoint *found = joint->findJoint(name); if (found) { return found; } } return NULL; }
//----------------------------------------------------------------------------- // touch() // Sets all dirty flags for all children, recursively. //----------------------------------------------------------------------------- void LLJoint::touch(U32 flags) { if ((flags | mDirtyFlags) != mDirtyFlags) { sNumTouches++; mDirtyFlags |= flags; U32 child_flags = flags; if (flags & ROTATION_DIRTY) { child_flags |= POSITION_DIRTY; } for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { LLJoint* joint = *iter; joint->touch(child_flags); } } }
void LLPolySkeletalDistortion::apply( ESex avatar_sex ) { LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY); F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); LLJoint* joint; joint_vec_map_t::iterator iter; for (iter = mJointScales.begin(); iter != mJointScales.end(); iter++) { joint = iter->first; LLVector3 newScale = joint->getScale(); LLVector3 scaleDelta = iter->second; newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta); //An aspect of attached mesh objects (which contain joint offsets) that need to be cleaned up when detached // needed? // joint->storeScaleForReset( newScale ); joint->setScale(newScale); } for (iter = mJointOffsets.begin(); iter != mJointOffsets.end(); iter++) { joint = iter->first; LLVector3 newPosition = joint->getPosition(); LLVector3 positionDelta = iter->second; newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta); joint->setPosition(newPosition); } if (mLastWeight != mCurWeight && !mIsAnimating) { mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1); } mLastWeight = mCurWeight; }
// Return TRUE if character has to update visual params. BOOL LLPhysicsMotion::onUpdate(F32 time) { // static FILE *mFileWrite = fopen("c:\\temp\\avatar_data.txt","w"); if (!mParamDriver) return FALSE; if (!mLastTime) { mLastTime = time; return FALSE; } //////////////////////////////////////////////////////////////////////////////// // Get all parameters and settings // const F32 time_delta = time - mLastTime; // Don't update too frequently, to avoid precision errors from small time slices. if (time_delta <= .01) { return FALSE; } // If less than 1FPS, we don't want to be spending time updating physics at all. if (time_delta > 1.0) { mLastTime = time; return FALSE; } // Higher LOD is better. This controls the granularity // and frequency of updates for the motions. const F32 lod_factor = LLVOAvatar::sPhysicsLODFactor; if (lod_factor == 0) { return TRUE; } LLJoint *joint = mJointState->getJoint(); const F32 behavior_mass = getParamValue("Mass"); const F32 behavior_gravity = getParamValue("Gravity"); const F32 behavior_spring = getParamValue("Spring"); const F32 behavior_gain = getParamValue("Gain"); const F32 behavior_damping = getParamValue("Damping"); const F32 behavior_drag = getParamValue("Drag"); const BOOL physics_test = FALSE; // Enable this to simulate bouncing on all parts. F32 behavior_maxeffect = getParamValue("MaxEffect"); if (physics_test) behavior_maxeffect = 1.0f; // Normalize the param position to be from [0,1]. // We have to use normalized values because there may be more than one driven param, // and each of these driven params may have its own range. // This means we'll do all our calculations in normalized [0,1] local coordinates. const F32 position_user_local = (mParamDriver->getWeight() - mParamDriver->getMinWeight()) / (mParamDriver->getMaxWeight() - mParamDriver->getMinWeight()); // // End parameters and settings //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Calculate velocity and acceleration in parameter space. // //const F32 velocity_joint_local = calculateVelocity_local(time_iteration_step); const F32 velocity_joint_local = calculateVelocity_local(); const F32 acceleration_joint_local = calculateAcceleration_local(velocity_joint_local); // // End velocity and acceleration //////////////////////////////////////////////////////////////////////////////// BOOL update_visuals = FALSE; // Break up the physics into a bunch of iterations so that differing framerates will show // roughly the same behavior. for (F32 time_iteration = 0; time_iteration <= time_delta; time_iteration += TIME_ITERATION_STEP) { F32 time_iteration_step = TIME_ITERATION_STEP; if (time_iteration + TIME_ITERATION_STEP > time_delta) { time_iteration_step = time_delta-time_iteration; } // mPositon_local should be in normalized 0,1 range already. Just making sure... const F32 position_current_local = llclamp(mPosition_local, 0.0f, 1.0f); // If the effect is turned off then don't process unless we need one more update // to set the position to the default (i.e. user) position. if ((behavior_maxeffect == 0) && (position_current_local == position_user_local)) { return update_visuals; } //////////////////////////////////////////////////////////////////////////////// // Calculate the total force // // Spring force is a restoring force towards the original user-set breast position. // F = kx const F32 spring_length = position_current_local - position_user_local; const F32 force_spring = -spring_length * behavior_spring; // Acceleration is the force that comes from the change in velocity of the torso. // F = ma const F32 force_accel = behavior_gain * (acceleration_joint_local * behavior_mass); // Gravity always points downward in world space. // F = mg const LLVector3 gravity_world(0,0,1); const F32 force_gravity = (toLocal(gravity_world) * behavior_gravity * behavior_mass); // Damping is a restoring force that opposes the current velocity. // F = -kv const F32 force_damping = -behavior_damping * mVelocity_local; // Drag is a force imparted by velocity (intuitively it is similar to wind resistance) // F = .5kv^2 const F32 force_drag = .5*behavior_drag*velocity_joint_local*velocity_joint_local*llsgn(velocity_joint_local); const F32 force_net = (force_accel + force_gravity + force_spring + force_damping + force_drag); // // End total force //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Calculate new params // // Calculate the new acceleration based on the net force. // a = F/m const F32 acceleration_new_local = force_net / behavior_mass; static const F32 max_velocity = 100.0f; // magic number, used to be customizable. F32 velocity_new_local = mVelocity_local + acceleration_new_local*time_iteration_step; velocity_new_local = llclamp(velocity_new_local, -max_velocity, max_velocity); // Temporary debugging setting to cause all avatars to move, for profiling purposes. if (physics_test) { velocity_new_local = sin(time*4.0); } // Calculate the new parameters, or remain unchanged if max speed is 0. F32 position_new_local = position_current_local + velocity_new_local*time_iteration_step; if (behavior_maxeffect == 0) position_new_local = position_user_local; // Zero out the velocity if the param is being pushed beyond its limits. if ((position_new_local < 0 && velocity_new_local < 0) || (position_new_local > 1 && velocity_new_local > 0)) { velocity_new_local = 0; } // Check for NaN values. A NaN value is detected if the variables doesn't equal itself. // If NaN, then reset everything. if ((mPosition_local != mPosition_local) || (mVelocity_local != mVelocity_local) || (position_new_local != position_new_local)) { position_new_local = 0; mVelocity_local = 0; mVelocityJoint_local = 0; mAccelerationJoint_local = 0; mPosition_local = 0; mPosition_world = LLVector3(0,0,0); } const F32 position_new_local_clamped = llclamp(position_new_local, 0.0f, 1.0f); LLDriverParam *driver_param = dynamic_cast<LLDriverParam *>(mParamDriver); llassert_always(driver_param); if (driver_param) { // If this is one of our "hidden" driver params, then make sure it's // the default value. if ((driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE) && (driver_param->getGroup() != VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT)) { mCharacter->setVisualParamWeight(driver_param, 0, FALSE); } for (LLDriverParam::entry_list_t::iterator iter = driver_param->mDriven.begin(); iter != driver_param->mDriven.end(); ++iter) { LLDrivenEntry &entry = (*iter); LLViewerVisualParam *driven_param = entry.mParam; setParamValue(driven_param,position_new_local_clamped, behavior_maxeffect); } } // // End calculate new params //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Conditionally update the visual params // // Updating the visual params (i.e. what the user sees) is fairly expensive. // So only update if the params have changed enough, and also take into account // the graphics LOD settings. // For non-self, if the avatar is small enough visually, then don't update. const F32 area_for_max_settings = 0.0; const F32 area_for_min_settings = 1400.0; const F32 area_for_this_setting = area_for_max_settings + (area_for_min_settings-area_for_max_settings)*(1.0-lod_factor); const F32 pixel_area = (F32)sqrt(mCharacter->getPixelArea()); const BOOL is_self = (dynamic_cast<LLVOAvatar *>(mCharacter) != NULL && ((LLVOAvatar*)mCharacter)->isSelf()); if ((pixel_area > area_for_this_setting) || is_self) { const F32 position_diff_local = llabs(mPositionLastUpdate_local-position_new_local_clamped); const F32 min_delta = (1.0001f-lod_factor)*0.4f; if (llabs(position_diff_local) > min_delta) { update_visuals = TRUE; mPositionLastUpdate_local = position_new_local; } } // // End update visual params //////////////////////////////////////////////////////////////////////////////// mVelocity_local = velocity_new_local; mAccelerationJoint_local = acceleration_joint_local; mPosition_local = position_new_local; } mLastTime = time; mPosition_world = joint->getWorldPosition(); mVelocityJoint_local = velocity_joint_local; /* // Write out debugging info into a spreadsheet. if (mFileWrite != NULL && is_self) { fprintf(mFileWrite,"%f\t%f\t%f \t\t%f \t\t%f\t%f\t%f\t \t\t%f\t%f\t%f\t%f\t%f \t\t%f\t%f\t%f\n", position_new_local, velocity_new_local, acceleration_new_local, time_delta, mPosition_world[0], mPosition_world[1], mPosition_world[2], force_net, force_spring, force_accel, force_damping, force_drag, spring_length, velocity_joint_local, acceleration_joint_local ); } */ return update_visuals; }
void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) { if (avatar->isSelf() && !gAgent.needsRenderAvatar() || !gMeshRepo.meshRezEnabled()) { return; } stop_glerror(); for (U32 i = 0; i < mRiggedFace[type].size(); ++i) { LLFace* face = mRiggedFace[type][i]; LLDrawable* drawable = face->getDrawable(); if (!drawable) { continue; } LLVOVolume* vobj = drawable->getVOVolume(); if (!vobj) { continue; } LLVolume* volume = vobj->getVolume(); S32 te = face->getTEOffset(); if (!volume || volume->getNumVolumeFaces() <= te || !volume->isMeshAssetLoaded()) { continue; } LLUUID mesh_id = volume->getParams().getSculptID(); if (mesh_id.isNull()) { continue; } const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj); if (!skin) { continue; } stop_glerror(); const LLVolumeFace& vol_face = volume->getVolumeFace(te); updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face, vobj); stop_glerror(); U32 data_mask = LLFace::getRiggedDataMask(type); LLVertexBuffer* buff = face->getVertexBuffer(); if (buff) { if (sShaderLevel > 0) { //upload matrix palette to shader LLMatrix4 mat[64]; for (U32 i = 0; i < skin->mJointNames.size(); ++i) { LLJoint* joint = avatar->getJoint(skin->mJointNames[i]); if (joint) { mat[i] = skin->mInvBindMatrix[i]; mat[i] *= joint->getWorldMatrix(); } } stop_glerror(); LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette", skin->mJointNames.size(), FALSE, (GLfloat*) mat[0].mMatrix); stop_glerror(); } else { data_mask &= ~LLVertexBuffer::MAP_WEIGHT4; } buff->setBuffer(data_mask); U16 start = face->getGeomStart(); U16 end = start + face->getGeomCount()-1; S32 offset = face->getIndicesStart(); U32 count = face->getIndicesCount(); if (glow) { glColor4f(0,0,0,face->getTextureEntry()->getGlow()); } gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture()); if (normal_channel > -1) { LLDrawPoolBump::bindBumpMap(face, normal_channel); } if (face->mTextureMatrix) { glMatrixMode(GL_TEXTURE); glLoadMatrixf((F32*) face->mTextureMatrix->mMatrix); buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); } else { buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); } } } }
void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face, LLVOVolume* vobj) { LLVector4a* weight = vol_face.mWeights; if (!weight) { return; } LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer(); LLDrawable* drawable = face->getDrawable(); U32 data_mask = face->getRiggedVertexBufferDataMask(); if (buffer.isNull() || buffer->getTypeMask() != data_mask || buffer->getRequestedVerts() != vol_face.mNumVertices || buffer->getRequestedIndices() != vol_face.mNumIndices || (drawable && drawable->isState(LLDrawable::REBUILD_ALL))) { face->setGeomIndex(0); face->setIndicesIndex(0); if (buffer.isNull() || buffer->getTypeMask() != data_mask) { //make a new buffer if (sShaderLevel > 0) { buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB); } else { buffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB); } buffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true); } else { //resize existing buffer buffer->resizeBuffer(vol_face.mNumVertices, vol_face.mNumIndices); } face->setSize(vol_face.mNumVertices, vol_face.mNumIndices); face->setVertexBuffer(buffer); U16 offset = 0; LLMatrix4 mat_vert = skin->mBindShapeMatrix; glh::matrix4f m((F32*) mat_vert.mMatrix); m = m.inverse().transpose(); F32 mat3[] = { m.m[0], m.m[1], m.m[2], m.m[4], m.m[5], m.m[6], m.m[8], m.m[9], m.m[10] }; LLMatrix3 mat_normal(mat3); static LLCachedControl<bool> mesh_enable_deformer(gSavedSettings, "MeshEnableDeformer"); if (mesh_enable_deformer) { LLDeformedVolume* deformed_volume = vobj->getDeformedVolume(); deformed_volume->deform(volume, avatar, skin, face->getTEOffset()); face->getGeometryVolume(*deformed_volume, face->getTEOffset(), mat_vert, mat_normal, offset, true); } else { face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true); } } if (sShaderLevel <= 0 && face->mLastSkinTime < avatar->getLastSkinTime()) { //perform software vertex skinning for this face LLStrider<LLVector3> position; LLStrider<LLVector3> normal; bool has_normal = buffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); buffer->getVertexStrider(position); if (has_normal) { buffer->getNormalStrider(normal); } LLVector4a* pos = (LLVector4a*) position.get(); LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL; //build matrix palette LLMatrix4a mp[64]; LLMatrix4* mat = (LLMatrix4*) mp; for (U32 j = 0; j < skin->mJointNames.size(); ++j) { LLJoint* joint = avatar->getJoint(skin->mJointNames[j]); if (joint) { mat[j] = skin->mInvBindMatrix[j]; mat[j] *= joint->getWorldMatrix(); } } LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); for (U32 j = 0; j < buffer->getRequestedVerts(); ++j) { LLMatrix4a final_mat; final_mat.clear(); S32 idx[4]; LLVector4 wght; F32 scale = 0.f; for (U32 k = 0; k < 4; k++) { F32 w = weight[j][k]; idx[k] = llclamp((S32) floorf(w), 0, 63); wght[k] = w - floorf(w); scale += wght[k]; } wght *= 1.f/scale; for (U32 k = 0; k < 4; k++) { F32 w = wght[k]; LLMatrix4a src; src.setMul(mp[idx[k]], w); final_mat.add(src); } LLVector4a& v = vol_face.mPositions[j]; LLVector4a t; LLVector4a dst; bind_shape_matrix.affineTransform(v, t); final_mat.affineTransform(t, dst); pos[j] = dst; if (norm) { LLVector4a& n = vol_face.mNormals[j]; bind_shape_matrix.rotate(n, t); final_mat.rotate(t, dst); norm[j] = dst; } } } if (drawable && face->getTEOffset() == drawable->getNumFaces() - 1) { drawable->clearState(LLDrawable::REBUILD_ALL); } }
void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) { if ((avatar->isSelf() && !gAgent.needsRenderAvatar()) || !gMeshRepo.meshRezEnabled()) { return; } stop_glerror(); for (U32 i = 0; i < mRiggedFace[type].size(); ++i) { LLFace* face = mRiggedFace[type][i]; LLDrawable* drawable = face->getDrawable(); if (!drawable) { continue; } LLVOVolume* vobj = drawable->getVOVolume(); if (!vobj) { continue; } LLVolume* volume = vobj->getVolume(); S32 te = face->getTEOffset(); if (!volume || volume->getNumVolumeFaces() <= te || !volume->isMeshAssetLoaded()) { continue; } LLUUID mesh_id = volume->getParams().getSculptID(); if (mesh_id.isNull()) { continue; } const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id, vobj); if (!skin) { continue; } //stop_glerror(); //const LLVolumeFace& vol_face = volume->getVolumeFace(te); //updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face); //stop_glerror(); U32 data_mask = LLFace::getRiggedDataMask(type); LLVertexBuffer* buff = face->getVertexBuffer(); if (buff) { if (sShaderLevel > 0) { //upload matrix palette to shader LLMatrix4 mat[JOINT_COUNT]; U32 count = llmin((U32) skin->mJointNames.size(), (U32) JOINT_COUNT); for (U32 i = 0; i < count; ++i) { LLJoint* joint = avatar->getJoint(skin->mJointNames[i]); if(!joint) { joint = avatar->getJoint("mRoot"); } if (joint) { LLMatrix4a tmp; tmp.loadu((F32*)skin->mInvBindMatrix[i].mMatrix); tmp.setMul(joint->getWorldMatrix(),tmp); mat[i] = LLMatrix4(tmp.getF32ptr()); } } stop_glerror(); F32 mp[JOINT_COUNT*12]; for (U32 i = 0; i < count; ++i) { F32* m = (F32*) mat[i].mMatrix; U32 idx = i*12; mp[idx+0] = m[0]; mp[idx+1] = m[1]; mp[idx+2] = m[2]; mp[idx+3] = m[12]; mp[idx+4] = m[4]; mp[idx+5] = m[5]; mp[idx+6] = m[6]; mp[idx+7] = m[13]; mp[idx+8] = m[8]; mp[idx+9] = m[9]; mp[idx+10] = m[10]; mp[idx+11] = m[14]; } LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, count, FALSE, (GLfloat*) mp); LLDrawPoolAvatar::sVertexProgram->uniform1f(LLShaderMgr::AVATAR_MAX_WEIGHT, F32(count-1)); stop_glerror(); } else { data_mask &= ~LLVertexBuffer::MAP_WEIGHT4; } U16 start = face->getGeomStart(); U16 end = start + face->getGeomCount()-1; S32 offset = face->getIndicesStart(); U32 count = face->getIndicesCount(); /*if (glow) { gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow()); }*/ const LLTextureEntry* te = face->getTextureEntry(); LLMaterial* mat = te->getMaterialParams().get(); if (mat && is_deferred_render) { gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture(LLRender::DIFFUSE_MAP)); gGL.getTexUnit(normal_channel)->bind(face->getTexture(LLRender::NORMAL_MAP)); gGL.getTexUnit(specular_channel)->bind(face->getTexture(LLRender::SPECULAR_MAP)); LLColor4 col = mat->getSpecularLightColor(); F32 spec = llmax(0.0001f, mat->getSpecularLightExponent() / 255.f); F32 env = mat->getEnvironmentIntensity()/255.f; if (mat->getSpecularID().isNull()) { env = te->getShiny()*0.25f; col.set(env,env,env,0); spec = env; } BOOL fullbright = te->getFullbright(); sVertexProgram->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, fullbright ? 1.f : 0.f); sVertexProgram->uniform4f(LLShaderMgr::SPECULAR_COLOR, col.mV[0], col.mV[1], col.mV[2], spec); sVertexProgram->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env); if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) { sVertexProgram->setMinimumAlpha(mat->getAlphaMaskCutoff()/255.f); } else { sVertexProgram->setMinimumAlpha(0.004f); } for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) { LLViewerTexture* tex = face->getTexture(i); if (tex) { tex->addTextureStats(avatar->getPixelArea()); } } } else { gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture()); if(sVertexProgram) { if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) { sVertexProgram->setMinimumAlpha(mat->getAlphaMaskCutoff()/255.f); } else { sVertexProgram->setMinimumAlpha(0.004f); } } if (normal_channel > -1) { LLDrawPoolBump::bindBumpMap(face, normal_channel); } } if (face->mTextureMatrix && vobj->mTexAnimMode) { gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadMatrix(*face->mTextureMatrix); buff->setBuffer(data_mask); buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); gGL.loadIdentity(); gGL.matrixMode(LLRender::MM_MODELVIEW); } else { buff->setBuffer(data_mask); buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); } gPipeline.addTrianglesDrawn(count, LLRender::TRIANGLES); } } }