Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Normalize bone weights #185 #187

Merged
merged 7 commits into from
May 23, 2018
Merged

Conversation

akulagrawal
Copy link
Contributor

Solved issue #185 by normalizing bone weights vector.

@emackey
Copy link
Member

emackey commented May 20, 2018

Very cool, thanks @akulagrawal. Can you add some protection for divide-by-zero on norm?

@emackey emackey requested a review from lasalvavida May 20, 2018 12:44
@@ -1620,6 +1620,15 @@ bool COLLADA2GLTF::Writer::writeController(const COLLADAFW::Controller* controll
std::tie(type, joints, weights) = _skinData[skinControllerDataId];
int numberOfComponents = GLTF::Accessor::getNumberOfComponents(type);

float norm = 0.0;
for(int i = 0; i < weights.size(); i++) {
norm = norm + ( (*weights[i]) * (*weights[i]) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normalization should be linear, not quadratic. The spec hasn't been updated on that yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh cool I will change that to linear. @emackey sure, will do that.

Copy link
Contributor

@lasalvavida lasalvavida left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @akulagrawal, thanks for the contribution! Just one small thing from me, please use size_t for your iterator instead of int. Otherwise, once the normalization is changed to linear this should be good to merge.

@akulagrawal
Copy link
Contributor Author

@lasalvavida I have updated everything. Please have a look now.

@@ -1620,6 +1620,33 @@ bool COLLADA2GLTF::Writer::writeController(const COLLADAFW::Controller* controll
std::tie(type, joints, weights) = _skinData[skinControllerDataId];
int numberOfComponents = GLTF::Accessor::getNumberOfComponents(type);

float maxweight = 0.0, minweight = 0.0;
if (weights.size() > 0) {
Copy link
Contributor

@lasalvavida lasalvavida May 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is redundant with the for loop below it and can probably be removed unless I'm missing something.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see why you did this; you can start the loop from 1 though so you don't do a redundant max/min on the first element.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, if this condition is not imposed, if in some case, weights.size() = 0, we will still end up trying to access 1st element of weights vector. But since there is no element in the weights vector, it would result in segmentation fault. A solution to this problem is to assign constant values to maxweight and minweight initially which are equal to the upper and lower bound of float datatype. But the current solution seemed to be more robust to me.

minweight = std::min(minweight, *weights[i]);
}
if (maxweight == minweight) {
if (maxweight == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to do this here. If max and min are both equal to zero, then that means all of the weights are already zero.

@lasalvavida
Copy link
Contributor

lasalvavida commented May 20, 2018

edit: Apologies, hold on a second while I edit this, it wasn't quite correct; it's been a while since I looked at this code

@lasalvavida
Copy link
Contributor

lasalvavida commented May 20, 2018

The gist of my original comment was correct, but wasn't as clear as I think it could have been. Here goes again.

weights is a vector of float arrays that we get from OpenCOLLADA containing numberOfComponents floating point weights. Take a look at how we iterate on weights a little further down.

We want to normalize each set of weights independently. Currently this code does normalization on the first weight in each set across all sets.

Does that make sense?

@lasalvavida
Copy link
Contributor

For example, weights[0] could be [0.5, 0.5, 0.5, 0.5] which we would normalize to [0.25, 0.25, 0.25, 0.25]. Then move on to weights[1] and so on.

@akulagrawal
Copy link
Contributor Author

Oh yes! my bad. I just went with the literal meaning. Yeah I had a look at the code following the edit and
now realize the issue. Also, thanks for the explanation. Will update it soon

@akulagrawal
Copy link
Contributor Author

akulagrawal commented May 21, 2018

Strange to find that sublime doesn't apply proper indentation. Indentation is fine in sublime but incorrect in reality.

@akulagrawal
Copy link
Contributor Author

@lasalvavida @lexaknyazev @emackey please review it once more. Hope it's fine now

@lasalvavida
Copy link
Contributor

Good work @akulagrawal! The code changes here look fine to me; I would just like for this to be tested on the CesiumMan COLLADA model rendered with log depth enabled to make sure that the issue is resolved.

I should be able to take care of that this evening if no one does it before then.

@lasalvavida
Copy link
Contributor

Tested in Cesium and can confirm that this resolves the issue, thanks @akulagrawal!

@lasalvavida lasalvavida merged commit aaf3971 into KhronosGroup:master May 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants