Skip to content

Conversation

@JohnRodney
Copy link
Contributor

Description:
Adds the support for using a-animation components in order to animate colors. #733
Changes proposed:

  • Adds the detection of a color as an attribute
  • Adds a partialSetAttribute for color
  • Adds a conversion from rgb object to hex (maybe these belong in utils?)
  • Adds two unit tests for start and finish to ensure the color is properly tweened

…nent

*/
module.exports.isCoordinate = function (value) {
return regex.test(value);
return value[0] !== '#' && regex.test(value);
Copy link
Member

Choose a reason for hiding this comment

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

Color hexes were passing the regex test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes I'm not really a regex wizard so I wasn't sure how to adjust it to return false if a hex value was passed. Probably would be cleaner to adjust the regex initialization than check for a hash as index 0.

Copy link
Member

Choose a reason for hiding this comment

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

So coordinates will always have whitespaces in between the numbers. Colors won't. I see that the whitespace characters uses star (*) rather than (+) which will match even 0 whitespace characters. Need to change those to + to force at least 1 whitespace character.

BEFORE: /\s*(-?\d*\.{0,1}\d+)\s*(-?\d*\.{0,1}\d+)\s*(-?\d*\.{0,1}\d+)\s*/;
AFTER:: /\s*(-?\d*\.{0,1}\d+)\s+(-?\d*\.{0,1}\d+)\s+(-?\d*\.{0,1}\d+)\s*/;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This has been updated as well thanks for the help on the regex.

…d a new test that checks start inbetween and end for shorthand and capital from and to values
* @returns {string}
*/
function componentToHex (color) {
var hex = color.toString(16);
Copy link
Member

Choose a reason for hiding this comment

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

Should we check if color < 0 or > 255 and clamp it to 0-255?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dmarcos @ngokevin Hey this could be clamped in the function that calls this by doing a:
return Math.floor(Math.min(Math.abs(color), 1) * 255);
inside of the convertToIntegerColor() function. Would this be acceptable? Or would you prefer a separate clamp function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is also possibly unneeded as the value that is passed comes from a THREE.Color which is already tested to be within 0 and 1 from a hex value correct?

@JohnRodney
Copy link
Contributor Author

I think all feedback is resolved and I went through a refactor phase. It should be ready to squash the commits if everything else is approved.

@ngokevin
Copy link
Member

@dmarcos This looks pretty good. He made it not explicitly check for color, just let it fall through the if/else statements, saving about probably 50 LOC. I think even if we add more interpolation types, this should still hold.

getForCoordinateComponent();
} else if (['true', 'false'].indexOf(dataTo) !== -1) {
getForBoolean();
} else if (isNaN(dataTo)) {
Copy link
Member

Choose a reason for hiding this comment

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

Does this work for the following case? Can we add it to the tests?

<a-animation attribute="material.color" from="red" to="blue"></a-animation>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. I'll look at it in the morning.

Copy link
Member

Choose a reason for hiding this comment

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

It works.

from[attribute] = dataFrom;
}
from[attribute] = parseProperty(from[attribute], schema[componentPropName]);
to[attribute] = parseProperty(dataTo, schema[componentPropName]);
Copy link
Member

Choose a reason for hiding this comment

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

If our color property type parser converted to THREE.Color I think everything would work out of the box. But I'm not sure if that would break things.

@JohnRodney
Copy link
Contributor Author

@ngokevin @dmarcos Updated with a new approach to support both color and material.color. I feel better about this approach. Will add in some unit tests to ensure no regressions are introduced around the 'material.color' property.

var to = {};

if (attributeSplit.length === 2) {
if (attributeSplit.length === 2 && attributeSplit.indexOf('color') === -1) {
Copy link
Member

Choose a reason for hiding this comment

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

Note that material.color is only a single test case. Properties can be named anything and still be of type color. I'll try to help find a solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

are you saying something with a color property could be passed that did not contain the word color in it?

Copy link
Member

Choose a reason for hiding this comment

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

Yup. Anyone can create components with whatever schema they want. So I could do:

schema: {
  body: {type: 'color'}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok so exact matching the schema type should be safe here and then the rest should still work as far as the tweens are concerned. I'm using the passed attributes to set when there are more than one in attributeSplit

Copy link
Member

Choose a reason for hiding this comment

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

Ah, that's interesting. Seems like that might work. It's not ideal we need to special-case colors, but I'm feel okay with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right that will support both. And make all the test cases for color animation currently commited still work.

Then we would just have to figure out how to add el.components.material.schema.color.type = 'color' to the generated entity to test the cases of material.color or material.specular

Copy link
Member

Choose a reason for hiding this comment

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

You don't have to add anything. Just set the material component onto the entity.

el.setAttribute('material', 'shader: flat; color: #FFF');

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Now that I look at it I had tried that method earlier but it breaks 4 tests because I'm guessing in certain test cases the mapping doesn't exist so its not safe to check for it as the tests will try to call a property on an undefined object.

Copy link
Member

Choose a reason for hiding this comment

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

I'd ignore everything about mappings. That's part of what is currently not core code (e.g., <a-box>). Though it should be able to interpolate attributes that it detects are colors (e.g., color="#FFFFFF", but that doesn't require looking up schema.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright took your suggestion and pushed another version up with the fallback to isNaN and a isColor function that checks to make sure schemas are defined so that older tests don't fail with this introduction.

* Match the sceme type to color
* @return {bool} if the schema is of type color
*/
function isColor () {
Copy link
Member

Choose a reason for hiding this comment

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

You can clean this up a little bit:

function isColor () {
  var componentName = attributeSplit[0];
  var propertyName = attributeSplit[1];
  var component = el.components[componentName];
  var schema = component && component.schema;
  if (schema) { return schema[propertyName].type === 'color' }
  return true;
}
@JohnRodney
Copy link
Contributor Author

@dmarcos We all do here too haha.

@ngokevin I adjusted the requested changes. The only thing that may be missing I can think of now is a link to the example on the index page that is on localhost:9000 when you start the server. I'm guessing I should probably add this yes?


```html
<a-entity id="blushing-cube" geometry="primitive: box">
<a-animation attribute="color" begin="white" to="red" dur="1000"></a-animation>
Copy link
Member

Choose a reason for hiding this comment

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

Should be attribute="material.color"

begin="white" should be from="white"

@ngokevin
Copy link
Member

OK, that should be the last of it!

@JohnRodney
Copy link
Contributor Author

@ngokevin alright I updated the demo to a little more fancy of a demo. I also opened an issue because you can't use begin delays to stagger because they calculate the begin delay on a repeat meaning the "stagger" animation eventually gets out of sync.

This can be updated to remove the intervals once the bug is fixed there.

@ngokevin
Copy link
Member

Awesome! I'll merge this once I get to the office.

@JohnRodney
Copy link
Contributor Author

Cool once you give it one more look over and are ready let me know and I'll squash the commits

<a-animation attribute="color" dur="10000" from="#afafaf" to="#000000" repeat="indefinite">
</a-sky>

<a-entity position="4.5 1 -3" class="pulse" geometry="primitive: box; depth: 0.5; height: 1; width: 0.5" material="color: #5698Af">
Copy link
Member

@ngokevin ngokevin Apr 22, 2016

Choose a reason for hiding this comment

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

You can use mixins to clean up.

<a-assets>
  <a-mixin id="box" geometry="primitive: box..." material="..."></a-mixin>
  <a-mixin id="pulse" attribute="material.color" from="#fff" to="#5698Af" dur="1000" begin="pulse"></a-mixin>
</a-assets>

<a-entity mixin="box"><a-animation mixin="pulse"></a-animation></a-entity>
<a-entity mixin="box"><a-animation mixin="pulse"></a-animation></a-entity>
@JohnRodney
Copy link
Contributor Author

@ngokevin adjusted to mixins, new file structure and stats attribute.

<a-animation attribute="color" dur="10000" from="#afafaf" to="#000000" repeat="indefinite">
</a-sky>

<a-entity position="4.5 1 -3" class="pulse" mixin="box"><a-animation mixin="pulse"></a-animation></a-entity>
Copy link
Member

Choose a reason for hiding this comment

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

You don't need the class anymore because your selectorAll can be [mixin="box"]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@ngokevin ngokevin merged commit 29446e0 into aframevr:master Apr 22, 2016
@ngokevin
Copy link
Member

Thanks so much!!! That was a long process, but everything works, and your example is pretty cool and running at 60fps :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants