Apply a texture to a UI.Graphic inherited Object - user-interface

I'm trying to display a mesh inside the Unity UI. My class inherits from UI.Graphic. I managed to make it work for my vertices and colors, but it seems I can't set a texture to the mesh. I tried different things but nothing worked :
Tried to set the material field on the CanvasRenderer
Tried to set the material field on the Graphic
The documentation on all this is very bad, and lots of code samples I found (mostly on how to set vertices) were out of date.
Here is the code where I set my vertices :
protected override void OnPopulateMesh(VertexHelper vh)
{
base.OnPopulateMesh(vh);
vh.Clear();
if( m_SkinData != null )
{
int j = 0;
foreach( SkinVertex vert in m_SkinData.m_Vertices )
{
float channel = j / (float)m_SkinData.m_Vertices.Count;
Color32 col = new Color(channel, channel, channel);
vh.AddVert(m_Vertice[j], col, m_uv[j]);
j++;
}
for( int i = 0; i < m_SkinData.m_Indices.Count; i += 3 )
{
vh.AddTriangle(m_SkinData.m_Indices[i], m_SkinData.m_Indices[i + 1], m_SkinData.m_Indices[i + 2]);
}
}
}
Here is the result :
and here is the Material with the diffuse set by code :
I'm sure I'm missing something obvious, but I can't find what.
[Edit] The exact same code is working if it inherits from UI.Image instead of UI.Graphic. It does not work if it inherits from UI.MaskableGraphic (Child of UI.Graphic, parent of UI.Image). I don't even have to set a sprite or whatever. It's really odd and I'd still like to understand why and what should be the correct way. But for the time being it's a workaround.[/Edit]

Related

Issue with TubeFilter when setting normals to polydata in vtk.js

I can set my own normals to a polydata (lines) in vtk.js, and it works fine. But when I try to use a TubeFilter with said polydata, it doesn't work; I can only generate the tube if I don't set the normals. The program doesn't run any code after calling tubeFilter.update().
I create my normals as so:
const numSegments = 1;
const normals = new Float32Array(3 * (numSegments + 1));
const normalArray = vtkDataArray.newInstance({
name: 'Normals',
values: normals,
numberOfComponents: 3,
});
for(let i=0; i<numSegments + 1; i++) {
normals[i*3+0] = 0;
normals[i*3+1] = 0;
normals[i*3+2] = 1;
}
And set it to the polydata as so:
polyData.getPointData().setNormals(normalArray);
I create the tube filter as so:
const tubeFilter = vtkTubeFilter.newInstance();
tubeFilter.setCapping(false);
tubeFilter.setNumberOfSides(50);
tubeFilter.setRadius(0.1);
tubeFilter.setInputData(polyData);
tubeFilter.setInputArrayToProcess(0, 'Scalars', 'PointData', 'Scalars');
tubeFilter.update(); // Program stops here
Why isn't it working? What am I doing wrong? What do I have to do to generate a tube with my own normals?
Here's the full code: index.js; it's a simplified version of this example.
Here's an image of the line with the tube generated when no normals are set (left) and only the line when normals are set (right), as the code stops after trying to generate the tube.
You can use SetDefaultNormal function of vtkTubeFilter class. Just use it like this and ignore creating vector normals and then put them into the line:
const tubeFilter = vtkTubeFilter.newInstance();
tubeFilter.setCapping(false);
tubeFilter.setNumberOfSides(50);
tubeFilter.setRadius(0.1);
tubeFilter.setInputData(polyData);
tubeFilter.useDefaultNormalOn();
tubeFilter.setDefaultNormal(0,0,1);
tubeFilter.setInputArrayToProcess(0, 'Scalars', 'PointData', 'Scalars');
tubeFilter.update(); // Program stops here

Unity3D: How do I improve my Idle animation (Y-axis)

Okay, I am almost finished with my 2d rpg click to move game. If you look at this video you will be able to see that when I click forward my player, once it gets to it's position, face the wrong direction rather than facing straight towards the players. To make myself more clearer, this is an image of the sprite sheet I am currently using, as you can see it has 8 directions. When you click here (in the game), my player would walk down and face this direction or this direction, rather than facing this direction (the normal/preferred position). This also happens when I click here (in the game) my player would walk up and face this direction or face this direction, rather than facing this direction. How can I make sure that my player face the right direction once it reached it's destination. Again this is only occurring within the Y-axis, so walking along the X-axis is fine.
private Animator anim;
public float speed = 15f;
private Vector3 target;
private bool touched;
private bool playerMovementRef;
void Start () {
target = transform.position;
anim = GetComponent<Animator> ();
}
void Update () {
if (Input.GetMouseButtonDown (0)) {
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = 10; // distance from the camera
target = Camera.main.ScreenToWorldPoint (mousePosition);
target.z = transform.position.z;
var movementDirection = (target - transform.position).normalized;
Vector3 animDirection = Vector3.zero;
if (movementDirection.sqrMagnitude > 0)
{
// Use >= to default to horizontal on both being equal
if (movementDirection.x > movementDirection.y)
animDirection.x = 1;
else
animDirection.y = 1;
anim.SetBool ("walking", true);
anim.SetFloat ("SpeedX", movementDirection.x);
anim.SetFloat ("SpeedY", movementDirection.y);
if (movementDirection.x < 0) {
anim.SetFloat ("LastMoveX", -1f);
} else if (movementDirection.x > 0) {
anim.SetFloat ("LastMoveX", 1f);
} else {
anim.SetFloat ("LastMoveX", 0f);
}
if (movementDirection.y > 0) {
anim.SetFloat ("LastMoveY", 1f);
} else if (movementDirection.y < 0) {
anim.SetFloat ("LastMoveY", -1f);
} else {
anim.SetFloat ("LastMoveY", 0f);
}
}
} else {
if (Mathf.Approximately (transform.position.x, target.x) && Mathf.Approximately (transform.position.y, target.y)) {
touched = false;
anim.SetBool ("walking", false);
} else {
transform.position = Vector3.MoveTowards (transform.position, target, speed * Time.deltaTime);
}
}
}
}
I'm just starting out with Unity, but hope I can help.
From the video you've posted I've noticed that the sprite is only 'wrong' when the oldPosition and newPosition click differs in the X component, e.g. when you would click straight down it would show the desired behavior and sprite.
Have you tried printing out the x and y values that your code is using to calculate which sprite it's setting?
At first I thought that maybe it's because the values you set in the Blend Tree were at -1, 1 etc, and due to normalizing you sometimes wound up with 0.9 for a certain value.
Can you maybe try debugging it with the animator window open, like you did at the end? Writing down the values and comparing them between Desired and Undesired behavior might tell you something more.
Sorry I don't have a concrete solution to your problem, but I hope this helps.
Edit for clarification:
Basically, what I'm recommending is to:
1) Print out the values you are getting when the behavior happens, an example of how to print these things out is by using LogFormat, for example:
Debug.LogFormat("X: {0}, Y: {1}", xPosition, yPosition);
Now, you will get the values printed out when it finishes moving.
2) Write down the values for when the moving finishes with the 'Wrong' sprite, and keep clicking to move until the 'Right' sprite shows up. Write down the values again.
3) Compare each values, and find the differences. Now deduce why the differences are as they are, using the values in conjunction with your blend trees.
4) Once you know why, go back through your code/blend trees and rewrite/fix it to work as you intended it to.

Is it possible to loop through a sprite group in three.js with a tween that ends in a different position for each sprite?

I'm confused.
I've made a group of 10 sprites and added them to a THREE.Object3D() called fireworkGroup. I have another Object3D called explode. The tween loops through the sprites changing them from their initial position to explode.position.
for ( var i = 0; i < fireworkGroup.children.length; i ++ )
{
explode.position.x =(Math.random() - 0.5)*4;
explode.position.y =4;
explode.position.z =2;
var tweenLaunch = new TWEEN.Tween(fireworkGroup.children[i].position).to(explode.position, 4000).easing( TWEEN.Easing.Quartic.In);
tweenLaunch.start();
}
The tween is moving all the sprites from their start position to the same end position. So I thought this might be because "tweenLaunch" is being overwritten with a different explode.position each time as the tween is rendered so I'm only seeing the last one created in the loop. When I refresh the page they do all move to a different position, consistent with the Math.random().
But then why do all the sprites move to the explode.position? If "tweenLaunch" is being overwritten then why is it not moving only the last sprite?
Is it possible to have a loop with a tween in it that also changes?
Many Thanks.
I've managed to work out what was wrong by reading around the subject on Stackoverflow questions and answers, looking at a great particle example by stemkoski then trial and error.
view-source:http://stemkoski.github.io/Three.js/Particles.html
I used console.log to look at explode.position that I was using as the second position in the tween. It wasn't holding the values I wanted (a different Math.random on each loop).
So I created fireworkAttributes:
fireworkAttributes = { startPosition: [], explodePosition: [], nextPosition: [] };
and then cloned the sprite position in the function that created the sprites using:
fireworkAttributes.explodePosition.push( sprite.position.clone() );
then looped it in it's own function:
for (var i = 0; i < fireworkGroup.children.length; i++)
{
fireworkAttributes.explodePosition[i].x = (Math.random() - 0.5)*4;
fireworkAttributes.explodePosition[i].y = 4;
fireworkAttributes.explodePosition[i].z = 2;
}
then changed the code in the original question to:
for ( var a = 0; a < fireworkGroup.children.length; a ++ )
{
//need to use this new object as tweening to fireworkAttributes.explodePosition[a] does not work
explodeSite.position = fireworkAttributes.explodePosition[a];
var tweenLaunch = new TWEEN.Tween(fireworkGroup.children[a].position).to(explodeSite.position, 4000).easing( TWEEN.Easing.Quartic.In);
tweenLaunch.start();
}
There may be a more elegant way to do this and I will be working to clean up the code where possible but this does work.

Three.js text mesh missing every other face/triangle

So I performed a simple operation where i generated a text mesh (of the word TEST), put it's vertices, normals and faces into a json object then had my server save it to an STL. The problem is that it seems to be missing every other face/triangle. It renders in the browser correctly but it looks like this whenever I export it to an STL. I'm not sure why.
My code for getting all the relevant info is simple so I don't see why it seems to be missing half the faces/triangles
// Pass in textMesh.geometry
function getTextMesh(geometry)
{
var mfaces = geometry.faces;
var mvertices = geometry.vertices;
var i;
var faces=[],
vertices=[],
normals=[];
for(i=0; i<mfaces.length; i++) {
var face = mfaces[i];
var normal = face.normal;
faces.push([face.a, face.b, face.c]);
normals.push([normal.x, normal.y, normal.z]);
}
for(i=0; i<mvertices.length; i++) {
var vertex = mvertices[i];
vertices.push([vertex.x, vertex.y, vertex.z]);
}
return {'faces':faces, 'vertices':vertices, 'normals':normals};
}
Bah, turns out the issue was that TextGeometry also used Face4 for faces. I had assumed it only used triangles (Face3). This was easily solved by calling
THREE.GeometryUtils.triangulateQuads(textGeo);
after creating the geometry for the text

Color Changing Sprites Cocos2d

I need my sprite to transition to one color to another and on and on... like blue tint then green then purple, but i cannot find any good actions for that and am wondering, should i use animations? or is there an incorporated action for this?
you can use CCTintTo action to change the color of the sprite
[sprite runAction:[CCTintTo actionWithDuration:2 red:255 green:0 blue:0]];
since i saw several questions about replacing pixel colours in sprites, and i did'nt see any good solution (all solution only tint the color, and none of them is able to change an array of colours without forcing you into creating multiple image layers which construct the final image you want, i.e: one layer for pans, other for show, other for shirt, another for hair colour... and it goes on - note that they do have their advantages like the ability to use accurate gradients)
my solution allows you to change array of colors, meaning you can have a single image with a known colors (you dont want any gradiants in this layer, only colours that you KNOW their values - PS this only applies to colors you intent to change, other pixels can have any colour you want)
if you need gradiants over the colours you change, create an additional image with only the shading and place it as a child of the sprite.
also be aware that i am super-new to cocos2d/x (3 days), and that this code is written for cocos2dx but can be ported to cocos2d easily.
also note that i didnt test it on android only on iOS, i am not sure how capable is android official gcc and how will it deal with the way i allocate _srcC and _dstC, but again, this is easily portable.
so here it goes:
cocos2d::CCSprite * spriteWithReplacedColors( const char * imgfilename, cocos2d::ccColor3B * srcColors, cocos2d::ccColor3B * dstColors, int numColors )
{
CCSprite *theSprite = NULL;
CCImage *theImage = new CCImage;
if( theImage->initWithImageFile( imgfilename ) )
{
//make a color array which is easier to work with
unsigned long _srcC [ numColors ];
unsigned long _dstC [ numColors ];
for( int c=0; c<numColors; c++ )
{
_srcC[c] = (srcColors[c].r << 0) | (srcColors[c].g << 8) | (srcColors[0].b << 16);
_dstC[c] = (dstColors[c].r << 0) | (dstColors[c].g << 8) | (dstColors[0].b << 16);
}
unsigned char * rawData = theImage->getData();
int width = theImage->getWidth();
int height = theImage->getHeight();
//replace the colors need replacing
unsigned int * b = (unsigned int *) rawData;
for( int pixel=0; pixel<width*height; pixel++ )
{
register unsigned int p = *b;
for( int c=0; c<numColors; c++ )
{
if( (p&0x00FFFFFF) == _srcC[c] )
{
*b = (p&0xFF000000) | _dstC[c];
break;
}
}
b++;
}
CCTexture2D *theTexture = new CCTexture2D();
if( theTexture->initWithData(rawData, kCCTexture2DPixelFormat_RGBA8888, width, height, CCSizeMake(width, height)) )
{
theSprite = CCSprite::spriteWithTexture(theTexture);
}
theTexture->release();
}
theImage->release();
return theSprite;
}
to use it just do the following:
ccColor3B src[] = { ccc3( 255,255,255 ), ccc3( 0, 0, 255 ) };
ccColor3B dst[] = { ccc3( 77,255,77 ), ccc3( 255, 0 0 ) };
//will change all whites to greens, and all blues to reds.
CCSprite * pSprite = spriteWithReplacedColors( "character_template.png", src, dst, sizeof(src)/sizeof(src[0]) );
of course if you need speed, you would create an extension for a sprite that create a pixel shader that does it hw accelerated at render time ;)
btw: this solution might cause some artefacts on the edges on some cases, so you can create a large image and scale it down, letting GL minimise the artefact.
you can also create "fix" layers with black outlines to hide the artefacts and place it on top etc.
also make sure you don't use these 'key' colors on the rest of the image you don't want the pixels changed.
also keep in mind that the fact that the alpha channel is not changed, and that if you use basic images with pure red/green/blue colors only, you can also optimize this function to eliminate all artefacts on edges automatically (and avoid in many cases, the need for an additional shade layer) and other cool stuff (multiplexing several images into a single bitmap - remember palette animation?)
enjoy ;)
In case someone wanted this for cocos2d-x here is the code:
somesprite->runAction(TintTo::create(float duration, Color3b &color));

Resources