I'm using the following code, but can't get the animations to work with direction: alternate. The animations refuse to alternate but always start from their initial value.
<a-entity
gltf-model="models/u323/u323-2k1024.gltf"
position="-0.4 1.7 -1.7"
rotation="-2.7 0 0"
scale="1.2 1.2 1.2"
animation__position="property: position;
dir: alternate;
startEvents: click;
from: -0.4 1.7 -1.7;
to: -0.47272469351429525 2.3 -2;
dur: 2000"
animation__light="property: light.intensity;
dir: alternate;
startEvents: click;
from: 0;
to: 5;
dur: 2000"
>
try adding loop: 2, the second animation should be in the alternate direction:
animation__position="property: position;
dir: alternate;
startEvents: click;
from: -0.4 1.7 -1.7;
to: -0.47272469351429525 2.3 -2;
dur: 2000"
loop: 2
Related
https://glitch.com/edit/#!/copper-past-property?path=index.html%3A13%3A76
under picture's pivot position is center
i want to pivot position to bottom center like under image.
i update example. https://glitch.com/edit/#!/copper-past-property?path=viewport.js%3A127%3A39
I want to move and resize a shape relative to the bottom, just like a 3d object.
In general, the easiest way to add an offset / pivot is by using a parent-child relation:
insert your object inside any parent entity
set the parents position where want your object (plus the pivot position)
move the child in the opposite direction of where the pivot should be (so pivot * -1)
perform any operations on the parent entity
For example a box at 0 0.5 -3 with a pivot at 0 -0.5 0:
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<a-scene>
<!-- The sphere is the parent entity -->
<a-sphere position="0 0 -3" radius="0.1" color="blue"
animation="property: rotation; to: 360 0; loop: true; dur: 5000">
<!--- The original, but now off-centered box --->
<a-box position="0 0.5 0" material="wireframe:true; color: #aa00ff"></a-box>
</a-sphere>
<!--- axis --->
<a-box position="0 0 -3" scale="5 0.05 0.05" color="red"></a-box>
</a-scene>
Your case is quite specific, as you want a pivot for the TransformControls.
One way would be to apply a pivot where they are attached (viewport.js).
The entities could have a component defining a pivot point:
AFRAME.registerComponent("editor-config", {
schema: {
offset: {type: "vec3", default: {x: 0, y: 0, z: 0}}
},
init: function() {
// once the entity is loaded
this.el.addEventListener("loaded", evt => {
// save the offset within the THREE.Object3D
const mesh = this.el.getObject3D("mesh")
if (!mesh.userData) mesh.userData = {}
mesh.userData.editoroffset = this.data.offset
})
}
});
// <a-box position="-1 0.5 -3" editor-config="offset: 0 -0.5 0"></a-box>
Then when the TransformControls are attached - you can apply the pivot:
/*** setSelectEntity(entity) within viewport.js ***/
this.transformControls.attach(entity);
// reset the position
this.transformControls.position.multiplyScalar(0);
// if there is an offset to apply - use it
if (entity.userData && entity.userData.editoroffset)
this.transformControls.position.copy(entity.userData.editoroffset)
Check it out in this glitch
I'm using a-frame to create a scene with a box that moves according to a sine function, but the box doesn't show up inside the viewport.
I already tried to update the box position by changing the "position" attribute and resetting the box.object3D.position.
HTML file
<a-scene log="hello scene">
<a-assets>
<img id="boxTexture" src="https://i.imgur.com/mYmmbrp.jpg">
</a-assets>
<a-box src="#boxTexture" position="0 0 -5" rotation="0 45 45" scale="0.5 0.5 0.5">
<!-- <a-animation attribute="position" to="0 2.2 -5" direction="alternate" dur="2000"
repeat="indefinite"></a-animation> -->
<a-animation attribute="scale" begin="mouseenter" dur="300" to="2.3 2.3 2.3"></a-animation>
<a-animation attribute="scale" begin="mouseleave" dur="300" to="0.5 0.5 0.5"></a-animation>
<a-animation attribute="rotation" begin="click" dur="2000" to="360 405 45"></a-animation>
</a-box>
<a-camera>
<a-cursor></a-cursor>
</a-camera>
JavaScript file
// low frequency oscillator
function lfo(amp, freq, phase) {
var date = new Date();
var millis = 0.001 * date.getMilliseconds();
var value = amp * Math.sin(millis * freq + phase);
return value;
}
var boxes = document.querySelectorAll('a-box');
function moveBoxes() {
// loop through all the boxes in the document
for (var i = 0; i < boxes.length; i++) {
let x = lfo(1, 1, 0);
let y = lfo(1, 1, 0.2);
let z = lfo(1, 1, 0.7);
boxes[i].object3D.position.set(x, y, z);
//boxes[i].setAttribute("position", x+" "+y+" "+z);
}
}
I'd except to see the box either on center of the scene or at least at the upper-left corner, but it's neither.
The 2D viewport does not map to the 3D positions within the 3D scene.
The A-Frame mouse cursor maps mouse clicks to in-3D clicks. I'm not sure, but you might be able to use this sort of method to convert 2D X/Y coordinate to 3D coordinate at your specified distance: https://github.com/aframevr/aframe/blob/master/src/components/cursor.js#L213
But otherwise, I would just make something a child of the camera.
<a-entity camera>
<a-box move-sin-wave-or-whatever-animation position="0 0 -1"></a-box>
</a-entity>
Code: https://glitch.com/edit/#!/aframe-nyc?path=ballani.html:17:0
Demo: https://aframe-nyc.glitch.me/ballani.html
Description:
I am putting two bouncing balls next to each other Red (left) using kframe animation and Green (right) using the soon deprecating a-animation component
Problem:
Green switches to yellow on the way up, which is the intended behavior.
Red should switch to blue on the way up, but doesn't, what is wrong and how can I fix it?
It works if I use a hash color. I'll look into why a keyword color name doesn't work.
animation__switch="property: material.color; from: #F00; to: #0F0; dur: 1000; delay: 0; dir: alternate; easing: linear; loop: true; autoplay: true"
Note you can get more performant animations this way:
animation__switch="property: components.material.material.color; type: color; from: #F00; to: #0F0; dur: 1000; delay: 0; dir: alternate; easing: linear; loop: true; autoplay: true"
It is supposed to be a balloon going up, stoping when the window ends. I cannot understand why my ball eventually disappears... Somebody help me.... When I try to tune the gravity parameter or the accelereation one, it either starts moving crazy fast (and dissapears), or real slow (eventually dissapears too). I have the checkEdges(), method defined so that this does not happen. Obviously something is not right
Mover mover;
void setup(){
size(300,600);
background(255);
mover = new Mover();
}
void draw(){
background(255,50);
mover.applyForceWind();
mover.applyForceGravity();
mover.update();
mover.display();
mover.checkEdges();
}
class Mover {
PVector location;
PVector velocity;
PVector acceleration;
PVector gravity;
PVector wind;
Mover(){
location = new PVector(width/2,height*0.9);
velocity = new PVector(0,0);
acceleration = new PVector(0,-1);
}
void applyForceWind(){
PVector wind = new PVector(0.001,0);
acceleration.add(wind);
}
void applyForceGravity(){
PVector gravity = new PVector(0,0.1);
acceleration.add(gravity);
}
void update(){
velocity.add(acceleration);
location.add(velocity);
acceleration.mult(0);
}
void display(){
stroke(0);
fill(155);
ellipse(location.x,location.y,30,30);
}
void checkEdges(){
if ( location.x > width || location.x < 0){ velocity.x *= (-1);}
if ( location.y > height || location.y < 0){ velocity.y *=(-1);}
}
}
You had an extra close curly brace in your code, just FYI. The problem with the ball eventually getting "stuck" on the floor and disappearing is due to your checkEdges() code, as you suspected. To shed some light on the issue, try this code:
void checkEdges(){
if ( location.x > width || location.x < 0){ velocity.x *= (-1);}
if ( location.y > height || location.y < 0){
velocity.y *=(-1);
println("velocity: " + velocity.y + "; position: " + location.y);
}
}
And it will give something like this:
...
velocity: -2.3999999; position: 602.1
velocity: -2.3; position: 602.1
velocity: -2.2; position: 602.1
velocity: -2.1000001; position: 602.1
velocity: 2.0000002; position: 600.1
velocity: -2.1000001; position: 602.19995
velocity: 2.0000002; position: 600.19995
velocity: -2.1000001; position: 602.2999
velocity: 2.0000002; position: 600.2999
...
As you can see, the y-velocity at each successive "bounce" is slightly lower than the one before it, meaning that your system is bleeding energy. In particular, when the velocity becomes too low to get it back above the bottom of the screen (it goes below 2.1, which how far it has to go to get back up), it starts behaving erratically. Imagine it goes for a while, and then the next time it has to bounce, it only has a y velocity of -2. It's at y=602.1 > 600, so multiply y velocity by negative one. On the next iteration, it moves up 2 units, so y is now 600.1, but that is still off the screen so it inverts the velocity again! Here's a (crude) picture to illustrate the idea:
The red lines represent the iteration after the velocity was reversed. The length of each red line decreases as time goes on (the ball doesn't bounce quite as high), and eventually it doesn't actually get back above the barrier! At this point, it's still below the bottom of the screen, and so the inversion test still passes, so it turns the positive velocity negative, while it's still below the bottom of the screen.
There are a few ways to fix this:
Prevent the ball from losing energy as time goes on. This can be tricky to do. Here's a clue: if you swap the order of these two lines in your update() function, the ball will gain energy as time goes on! An interesting result.
location.add(velocity);
velocity.add(acceleration);
It doesn't make sense to allow the ball to go below the edge of the window anyway, so if it is there, then force it back up to the edge, ie insert this into your checkEdges() method:
location.y = height;
When I use the second bullet, I get a constant bounce response and no loss of speed as time goes on:
velocity: -3.5999987; position: 600.0
velocity: -3.5999987; position: 600.0
velocity: -3.5999987; position: 600.0
velocity: -3.5999987; position: 600.0
velocity: -3.5999987; position: 600.0
velocity: -3.5999987; position: 600.0
Also, a side note: there is no need to create new wind and gravity PVectors each time you call the methods. In fact, you even declared them as class variables anyways! Set their values in the constructor and then you can use them in your other methods.
Dude, acceleration is constant, but you're adding to it every iteration....
I searched for how to colorize an image (with the format svg or png ...).
I tried covering my image with a rectangle that fills the image, but as my image is not a rectangle it colorizes the whole rectangle and not just the image.
Is it possible to change image color with qml? Alternatively, is it possible to change the color on qt (with C++) with QPixmap then integrate the QPixmap on QML Item?
Thank you for your help. (If there is no solution, I will have to load a different image to the same basic image with different color.)
In Qt 5 (from 5.2) you may use ColorOverlay as follows:
import QtQuick 2.0
import QtGraphicalEffects 1.0
Item {
width: 300
height: 300
Image {
id: bug
source: "images/butterfly.png"
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
visible: false
}
ColorOverlay {
anchors.fill: bug
source: bug
color: "#ff0000" // make image like it lays under red glass
}
}
In Qt 6 module QtGraphicalEffects (which includes ColorOverlay) was removed because of licensing issues.
In Qt 6.1 GraphicalEffects is now available again, as #SCP3008 commented below
You can replace your image color using ShaderEffect.
ShaderEffect {
property variant src: yourImage
property real r: yourColor.r * yourColor.a
property real g: yourColor.g * yourColor.a
property real b: yourColor.b * yourColor.a
width: yourImage.width
height: yourImage.height
vertexShader: "
uniform highp mat4 qt_Matrix;
attribute highp vec4 qt_Vertex;
attribute highp vec2 qt_MultiTexCoord0;
varying highp vec2 coord;
void main() {
coord = qt_MultiTexCoord0;
gl_Position = qt_Matrix * qt_Vertex;
}
"
fragmentShader: "
varying highp vec2 coord;
uniform sampler2D src;
uniform lowp float r;
uniform lowp float g;
uniform lowp float b;
void main() {
lowp vec4 clr = texture2D(src, coord);
lowp float avg = (clr.r + clr.g + clr.b) / 3.;
gl_FragColor = vec4(r * avg, g * avg, b * avg, clr.a);
}
"
}
The above code turns your image into the grayscaled one and then applies your color.
You can also use Colorize
And the difference with ColorOverlay is:
Colorize can really change the color of a image with HSL, it is more suitable for me.
ColorOverlay is similar to what happens when a colorized glass is put on top of a grayscale image with RGBA.
import QtQuick 2.12
import QtGraphicalEffects 1.12
Item {
width: 300
height: 300
Image {
id: bug
source: "images/bug.jpg"
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
visible: false
}
Colorize {
anchors.fill: bug
source: bug
hue: 0.0
saturation: 0.5
lightness: -0.2
}
}
I also went looking for a non-QtGraphicalEffects solution and found a solution by using the icon property as follows:
icon.source - for setting the SVG image
icon.color - for changing the color of the SVG image
icon.width - for changing the width of the SVG image
icon.height - for changing the height of the SVG image
Some controls have the icon property such as Button, ItemDelegate and MenuItem.
In the following code, we implement AppIcon as a customized version of Button so that the only thing that remains is the icon rendering. We remove the button styling and the button size, it is clipped to just render the icon itself. Because we have customized the Button we can expose the clicked signal and the pressed property.
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
ColumnLayout {
anchors.centerIn: parent
AppIcon {
Layout.alignment: Qt.AlignHCenter
icon.source: "biking-32.svg"
icon.color: pressed ? "orange" : "red"
onClicked: status.text = "red clicked"
}
AppIcon {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 64
Layout.preferredHeight: 64
icon.source: "biking-32.svg"
icon.color: pressed ? "orange" : "blue"
onClicked: status.text = "blue clicked"
}
AppIcon {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: 96
Layout.preferredHeight: 96
icon.source: "biking-32.svg"
icon.color: pressed ? "orange" : "green"
onClicked: status.text = "green clicked"
}
Text {
id: status
text: "click on an image"
}
}
}
//AppIcon.qml
import QtQuick
import QtQuick.Controls
Item {
id: appIcon
implicitWidth: 32
implicitHeight: 32
property alias icon: btn.icon
property alias pressed: btn.pressed
signal clicked()
Button {
id: btn
anchors.centerIn: parent
background: Item { }
icon.width: parent.width
icon.height: parent.height
onClicked: appIcon.clicked()
}
}
//biking-32.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M16 5.5A2.5 2.5 0 1 1 18.5 8 2.498 2.498 0 0 1 16 5.5zm-1.042 19.02a1.545 1.545 0 0 0 1.021 1.688c.73.104 1.23-.25 1.452-1.211.034-.145 1.173-6.518 1.173-6.518l-3.979-2.146 2.823-4.087L19.498 15H24a1 1 0 0 0 0-2h-3.498l-2.434-3.27a1.63 1.63 0 0 0-.48-.551.995.995 0 0 0-.11-.083l-1.107-.765a1.685 1.685 0 0 0-2.194.595l-4.09 6.534a1 1 0 0 0 .367 1.408l5.114 2.8zM29.8 24.5a5.3 5.3 0 1 1-5.3-5.3 5.3 5.3 0 0 1 5.3 5.3zm-1.8 0a3.5 3.5 0 1 0-3.5 3.5 3.504 3.504 0 0 0 3.5-3.5zm-15.2 0a5.3 5.3 0 1 1-5.3-5.3 5.3 5.3 0 0 1 5.3 5.3zm-1.8 0A3.5 3.5 0 1 0 7.5 28a3.504 3.504 0 0 0 3.5-3.5z"/><path fill="none" d="M0 0h32v32H0z"/></svg>
You can Try it Online!