How to reverse the direction of applying texture in the object CylinderGeometry?
var obj = new THREE.Mesh(
new THREE.CylinderGeometry(20, 15, 1, 20),
new THREE.MeshLambertMaterial({color: 0x000000}) //the material is later changed to the correct
);
Thank you in advance for your help :)
This function works:
var invertTextureOnCylinderGeometry = function(obj) {
var faceVertexes = obj.geometry.faceVertexUvs[0];
var faceVertexesLength = faceVertexes.length;
var divisionT = 1 / (faceVertexesLength * 0.25);
faceVertexes.map(function(face, index) {
if (index < 0.5*faceVertexesLength) {
var thisIndexDivision = [
Math.floor(index/2) * divisionT,
Math.ceil((index+divisionT)/2) * divisionT
];
if (index % 2) {
face[0].set(1, thisIndexDivision[0]);
face[1].set(1, thisIndexDivision[1]);
face[2].set(0, thisIndexDivision[1]);
} else {
face[0].set(0, thisIndexDivision[0]);
face[1].set(1, thisIndexDivision[0]);
face[2].set(0, thisIndexDivision[1]);
}
}
});
obj.geometry.uvsNeedUpdate = true;
};
Related
How can I pause/stop the vehicle moving entity (to stop the vehicle from the moving) by calling another function? Cannot seem to use viewModel.pauseViewModel.command();. Appreciate if anyone can demonstrate how to provide a pause & continue for moving entity.
function togglesimulation() {
Cesium.Math.setRandomNumberSeed(3);
var start = Cesium.JulianDate.fromDate(new Date(2021, 6, 29, 16));
var stop = Cesium.JulianDate.addSeconds(start, 300, new Cesium.JulianDate);
//Make sure viewer is at the desired time.
var clock = new Cesium.Clock();
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.CLAMPED; // stop at the end
viewer.clock.multiplier = clockmultiplier;
viewer.clock.shouldAnimate = true;
var position = new Cesium.SampledPositionProperty();
var time = Cesium.JulianDate.addSeconds(start, 120, new Cesium.JulianDate());
var timeStepInSeconds = 5;
var newPositions = mergedgeom1;
for (var i = 0; i < newPositions.length; i++) {
var poss = Cesium.Cartesian3.fromDegrees(parseFloat(newPositions[i][0]), parseFloat(newPositions[i][1])); //height
var time = Cesium.JulianDate.addSeconds(start, i * timeStepInSeconds, new Cesium.JulianDate());
position.addSample(time, poss);
}
var entity = viewer.entities.add({
availability: new Cesium.TimeIntervalCollection([
new Cesium.TimeInterval({
start: start,
stop: stop,
}),
]),
model: {
uri: "../asset/vehicle/CesiumMilkTruck/CesiumMilkTruck.glb",
minimumPixelSize: 64,
},
viewFrom: new Cesium.Cartesian3(-100.0, 0.0, 100.0),
position: position,
orientation: new Cesium.VelocityOrientationProperty(position),
});
viewer.trackedEntity = entity;
var scene = viewer.scene;
}
Pause the clock with:
viewer.clock.shouldAnimate = false;
You can un-pause later with:
viewer.clock.shouldAnimate = true;
I would like to be able to overlay a html iframe on top of an augmented reality marker, however I cannot get the CSS3DRenderer to show the same result as the WebGLRenderer and I'm not sure where I'm going wrong.
The WebGL renders perfectly, with the mesh following the marker and it's all magic, the CSS3DRenderer however centers the iframe in the middle of the video, inversed and unscaled, and it rotates in the opposite direction.
Thanks to three.js and artoolkit, here is some test code using video input and both renderers.
new Promise(function(resolve,reject) {
var source = document.createElement('video');
source.autoplay = true;
source.playsinline = true;
source.controls = false;
source.loop = true;
source.onplay = function(event) {
resolve(source);
}
source.src = 'data/output_4.ogg';
document.body.appendChild(source);
}).then(function(source) {
var scene = new THREE.Scene();
var camera = new THREE.Camera();
camera.matrixAutoUpdate = false;
scene.add(camera);
var material = new THREE.MeshNormalMaterial({
transparent : true,
opacity : 0.5,
side : THREE.DoubleSide
});
var geometry = new THREE.PlaneGeometry(1,1);
var mesh = new THREE.Mesh(geometry,material);
// mesh.matrixAutoUpdate = false;
scene.add(mesh);
var renderer = new THREE.WebGLRenderer({
antialias : true,
alpha : true
});
renderer.setSize(source.videoWidth,source.videoHeight);
renderer.setClearColor(new THREE.Color('lightgrey'),0);
document.body.appendChild(renderer.domElement);
/*\
cssRenderer
\*/
var cssRenderer = new THREE.CSS3DRenderer();
cssRenderer.setSize(source.videoWidth,source.videoHeight);
var cssScene = new THREE.Scene();
var iframe = document.createElement("iframe");
iframe.src = "/data/index.html";
iframe.style.background = "rgb(0,0,0)";
var iframe3D = new THREE.CSS3DObject(iframe);
// iframe3D.matrixAutoUpdate = false;
cssScene.add(iframe3D);
document.body.appendChild(cssRenderer.domElement);
/*\
arController
\*/
var cameraParameters = new ARCameraParam();
var arController = null;
cameraParameters.onload = function() {
arController = new ARController(source.videoWidth,source.videoHeight,cameraParameters);
arController.addEventListener("getMarker",function(event) {
var modelViewMatrix = new THREE.Matrix4().fromArray(event.data.matrix);
camera.matrix.getInverse(modelViewMatrix);
// mesh.matrix.copy(modelViewMatrix);
// iframe3D.matrix.copy(modelViewMatrix);
});
var cameraViewMatrix = new THREE.Matrix4().fromArray(arController.getCameraMatrix());
camera.projectionMatrix.copy(cameraViewMatrix);
}
cameraParameters.load("data/camera_para.dat");
/*\
animate
\*/
requestAnimationFrame(function animate() {
requestAnimationFrame(animate);
if (!arController) {
return;
}
arController.process(source);
renderer.render(scene,camera);
cssRenderer.render(cssScene,camera);
});
});
I had hoped that rotating the camera instead of the object would provide a solution, alas. It's as if I was missing out some matrix transformation that needs to be applied.
Perhaps there was something with the fov parameters of the camera, or maybe the transform matrix was getting overwritten, but anyway I couldn't locate the problem. So here's an alternative that doesn't use CSS3DRenderer, or THREE.js.
Essentially we can use the coordinates from the marker data itself to create a projection matrix. Many, many thanks to this post which provided most of the code I needed.
function adjugate(m) { // Compute the adjugate of m
return [
m[4]*m[8]-m[7]*m[5],m[7]*m[2]-m[1]*m[8],m[1]*m[5]-m[4]*m[2],
m[6]*m[5]-m[3]*m[8],m[0]*m[8]-m[6]*m[2],m[3]*m[2]-m[0]*m[5],
m[3]*m[7]-m[6]*m[4],m[6]*m[1]-m[0]*m[7],m[0]*m[4]-m[3]*m[1]
];
}
function multiply(a,b) { // multiply two matrices
a = [
a[0],a[3],a[6],
a[1],a[4],a[7],
a[2],a[5],a[8]
];
b = [
b[0],b[3],b[6],
b[1],b[4],b[7],
b[2],b[5],b[8]
];
var m = Array(9);
for (var i = 0; i != 3; ++i) {
for (var j = 0; j != 3; ++j) {
var mij = 0;
for (var k = 0; k != 3; ++k) {
mij += a[3*i + k]*b[3*k + j];
}
m[3*i + j] = mij;
}
}
return [
m[0],m[3],m[6],
m[1],m[4],m[7],
m[2],m[5],m[8]
];
}
function apply(m,v) { // multiply matrix and vector
return [
m[0]*v[0] + m[3]*v[1] + m[6]*v[2],
m[1]*v[0] + m[4]*v[1] + m[7]*v[2],
m[2]*v[0] + m[5]*v[1] + m[8]*v[2]
];
}
//
var iframe = document.createElement("iframe");
iframe.src = "data/index.html";
iframe.style.position = "absolute";
iframe.style.left = "0";
iframe.style.top = "0";
iframe.style.transformOrigin = "0 0";
document.querySelector("main").appendChild(iframe);
var s = [
0,0,1,
iframe.offsetWidth,0,1,
0,iframe.offsetHeight,1
];
var v = apply(adjugate(s),[iframe.offsetWidth,iframe.offsetHeight,1]);
s = multiply(s,[
v[0], 0, 0,
0, v[1], 0,
0, 0, v[2]
]);
arController.addEventListener("getMarker",function(event) {
if (event.data.marker.id === marker) {
var d = [
event.data.marker.vertex[(4 - event.data.marker.dir) % 4][0],event.data.marker.vertex[(4 - event.data.marker.dir) % 4][1],1,
event.data.marker.vertex[(5 - event.data.marker.dir) % 4][0],event.data.marker.vertex[(5 - event.data.marker.dir) % 4][1],1,
event.data.marker.vertex[(7 - event.data.marker.dir) % 4][0],event.data.marker.vertex[(7 - event.data.marker.dir) % 4][1],1
];
var v = apply(adjugate(d),[event.data.marker.vertex[(6 - event.data.marker.dir) % 4][0],event.data.marker.vertex[(6 - event.data.marker.dir) % 4][1],1]);
d = multiply(d,[
v[0],0,0,
0,v[1],0,
0,0,v[2]
]);
var t = multiply(d,adjugate(s));
for (i = 0; i < 9; ++i) {
t[i] = t[i] / t[8];
t[i] = Math.abs(t[i]) < Number.EPSILON ? 0 : t[i];
}
t = [
t[0],t[1],0,t[2],
t[3],t[4],0,t[5],
0,0,1,0,
t[6],t[7],0,t[8]
];
iframe.style.transform = "matrix3d(" + t.join(", ") + ")";
} else {
// mesh.visible = false;
}
});
Might be an answer 4 years overdue, but it might be useful for somebody.
I've created an alternative solution.
You can check it here: https://github.com/jonathanneels/QrA
In essence;
QrA uses tilt-js to simulate 3D-effects (parallax) and AR.js a-box as the startobject.
The iframe gets pushed by the tilt.js functions and the AR cube's .position, .scale and .rotation is used as reference.
Enjoy!
Picking and objects code is one of the most popular:
function Picking(event) {
var raycaster = new THREE.Raycaster();
event.preventDefault();
mouse.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mouse.y = -(event.clientY / renderer.domElement.clientHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(objects);
if (intersects.length > 0) {
if (INTERSECTED != intersects[0].object) {
}
} else {
INTERSECTED = null;
}
}
The description: in scene are two objects - cube and sphere. Sphere is first to camera and cube is second. The Sphere has ID1 and cube ID2. Picking is working.
The problem: after deleting the sphere (scene.remove(sphere)); Picking is giving the ID1, so, it seems like sphere is invisible. What is the problam?
The picture of the example: Picture
This code is not giving the result:
for (i = sphere.children.length - 1; i >= 0 ; i--) {
object = sphere.children[i];
object.geometry.remove;
object.material.remove;
object.geometry.dispose();
object.material.dispose();
scene.remove(object);
sphere.remove(object);
}
or
recur(sphere);
for (var i in objects) {
objects[i].geometry.remove;
objects[i].material.remove;
objects[i].geometry.dispose();
objects[i].material.dispose();
scene.remove(objects[i]);
sphere.remove(objects[i]);
}
function recur(obj) {
if (obj instanceof THREE.Mesh) {
objects.push(obj);
}
for (var i in obj.children) {
recur(obj.children[i]);
}
}
The code that add objects:
var ObjLoader = new THREE.ObjectLoader();
var ii;
var group = new THREE.Object3D();
var oldModel = scene.getObjectByName('group');
if (oldModel !== undefined) { scene.remove(oldModel); }
ObjLoader.load("path/model.json", addModelToScene);
group.name = "group";
scene.add(group);
function addModelToScene(model) {
recur(model);
for (var i in objects) {
objects[i].castShadow = true;
objects[i].receiveShadow = true;
}
model.name = "ModelName";
group.add(model)
}
So, The .json model consists of some objects (1..n);
This .json model is added into group.
With picking the side of the cube (may be material) is selectable, but not removable. but the position can be changed.
Thank you.
Change your picking logic a little, store all your objects into array when creating them:
/*var objects = [];
var group = new THREE.Object3D();
create your mesh add to array*/
objects.push(MyMesh);
/*now we have a reference all the time in objects[0] , objects[1]*/
objects[0].displose(); check syntax been a while*/
customMaterial = new THREE.ShaderMaterial(
{
uniforms: customUniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
//wireframe: true,
side: THREE.FrontSide
} );
function ground (){
var map = new THREE.PlaneGeometry(1024,1024, 128, 128);//Use planebufferGeo
map.dynamic = true;
_terrain = new THREE.Mesh( map, customMaterial );
_terrain.material.needsUpdate = true;
_terrain.geometry.dynamic = true;
_terrain.geometry.vertexColors = true;
_terrain.material.uvsNeedUpdate = true;
_terrain.geometry.normalsNeedUpdate = true;
_terrain.rotation.x = -Math.PI / 2;
objects.push(_terrain);
scene.add(_terrain );
}
So I used this in a situation where it was a picking game type, I used an array to store the mesh and i could manipulate the vertices / faces etc edit the array to make changes.
It was an easier way to compare things and check data.
function animate() {
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(objects);
if ( intersects.length > 0 ) {
var faceIndex = intersects[0].faceIndex;
var obj = intersects[0].object;
var geom = obj.geometry;
//etc
I have a HTML page that has Javascript in it (see below).
Within the HTML page there is a HTML code line that calls a Javascript function.
This works exactly as it should and looks like this :
hour
This code line calls from the last part of the below Javascript.
I wish to replace this code line with a button. How can I do this ?
Thank you
ps the Javascript is for use with dygraph and I did not write it. I know little about Javascript. I'm simply looking to replace the above single line of html with a button that does the same job or produce a button through other minimalistic change.
$(document).ready(function () {
var r = [ ];
var base_time = Date.parse("2014/03/05");
var num = 24 * 0.25 * 365;
for (var i = 0; i < num; i++) {
r.push([
new Date(base_time + i * 3600 * 1000),
i + 50 * (i % 60), // line
i * (num - i) * 4.0 / num // parabola
]);
}
var orig_range = [
r[0][0].valueOf(),
r[r.length - 1][0].valueOf()
];
// NEW CODE INSERTED - STARTS
var one_month_previous = new Date();
one_month_previous.setMonth(one_month_previous.getMonth() - 1);
var one_week_previous = new Date();
one_week_previous.setDate(one_week_previous.getDate()-7);
var three_days_previous = new Date();
three_days_previous.setDate(three_days_previous.getDate()-3);
var one_days_previous = new Date();
one_days_previous.setDate(one_days_previous.getDate()-1);
var twelve_hours_previous = new Date();
twelve_hours_previous.setHours(twelve_hours_previous.getHours() - 12);
// NEW CODE INSERTED - ENDS
g = new Dygraph(
document.getElementById("graphdiv3"),
"show_csv.php",
{
// NEW CODE INSERTED - STARTS
// dateWindow: [ Date.parse(one_month_previous) ,
// Date.parse(new Date()) ],
dateWindow: [
Date.parse(one_week_previous),
Date.parse(new Date())
],
// dateWindow: [ Date.parse(three_days_previous) ,
// Date.parse(new Date()) ],
// dateWindow: [ Date.parse(one_days_previous) ,
// Date.parse(new Date()) ],
// dateWindow: [ Date.parse(twelve_hours_previous) ,
// Date.parse(new Date()) ],
// dateWindow: [ Date.parse("2014/03/01 12:00:00"),
// Date.parse("2014/03/31 12:00:00") ],
// NEW CODE INSERTED - ENDS
title: 'Temperature(°C) vs Time',
rollPeriod: 1,
showRoller: true,
xlabel: 'Time',
ylabel: 'Temperature (°C)',
legend: 'always',
labelsKMB: 'true',
labelsSeparateLines: 'true',
colors: [
"rgb(51,204,204)",
"#00DD55",
"rgb(255,100,100)",
"rgba(50,50,200,0.4)"
]
}
);
var desired_range = null;
function approach_range() {
if (!desired_range) return;
// go halfway there
var range = g.xAxisRange();
if (Math.abs(desired_range[0] - range[0]) < 60 &&
Math.abs(desired_range[1] - range[1]) < 60) {
g.updateOptions({dateWindow: desired_range});
// (do not set another timeout.)
} else {
var new_range;
new_range = [
0.5 * (desired_range[0] + range[0]),
0.5 * (desired_range[1] + range[1])
];
g.updateOptions({dateWindow: new_range});
animate();
}
}
function animate() {
setTimeout(approach_range, 50);
}
var zoom = function(res) {
var w = g.xAxisRange();
desired_range = [ w[0], w[0] + res * 1000 ];
animate();
}
var reset = function() {
desired_range = orig_range;
animate();
}
var pan = function(dir) {
var w = g.xAxisRange();
var scale = w[1] - w[0];
var amount = scale * 0.25 * dir;
desired_range = [
w[0] + amount,
w[1] + amount
];
animate();
}
document.getElementById('hour').onclick = function() { zoom(3600); };
document.getElementById('day').onclick = function() { zoom(86400); };
document.getElementById('week').onclick = function() { zoom(604800); };
document.getElementById('month').onclick = function() { zoom(30 * 86400); };
document.getElementById('full').onclick = function() { reset(); };
document.getElementById('left').onclick = function() { pan(-1); };
document.getElementById('right').onclick = function() { pan(+1); };
});
if you want that the link looks like a button, then you can style the link with css that he looks like a button.
http://www.usabilitypost.com/2012/01/10/pressed-button-state-with-css3/
Just style it your way now!=)
(IE optimized:)
not sure if this is right tho.
<a href="#">
<button id="hour">Hour</button>
</a>
Normal button
<button id="hour">Hour</button>
form method:
<form action="#">
<input type="submit" value="submit">
</form>
Dude encapsulate the javascript inside a function first
//
function foo()
{
$(document).ready(function () {
var r = [ ];
var base_time = Date.parse("2014/03/05");
var num = 24 * 0.25 * 365;
for (var i = 0; i < num; i++) {
r.push([ new Date(base_time + i * 3600 * 1000),
i + 50 * (i % 60), // line
i * (num - i) * 4.0 / num // parabola
]);
}
var orig_range = [ r[0][0].valueOf(), r[r.length - 1][0].valueOf() ];
// NEW CODE INSERTED - STARTS
var one_month_previous = new Date();
one_month_previous.setMonth(one_month_previous.getMonth() - 1);
var one_week_previous = new Date();
one_week_previous.setDate(one_week_previous.getDate()-7);
var three_days_previous = new Date();
three_days_previous.setDate(three_days_previous.getDate()-3);
var one_days_previous = new Date();
one_days_previous.setDate(one_days_previous.getDate()-1);
var twelve_hours_previous = new Date();
twelve_hours_previous.setHours(twelve_hours_previous.getHours() - 12);
// NEW CODE INSERTED - ENDS
g = new Dygraph(
document.getElementById("graphdiv3"),
"show_csv.php",
{
// NEW CODE INSERTED - STARTS
// dateWindow: [ Date.parse(one_month_previous) ,
// Date.parse(new Date()) ],
dateWindow: [ Date.parse(one_week_previous) ,
Date.parse(new Date()) ],
// dateWindow: [ Date.parse(three_days_previous) ,
// Date.parse(new Date()) ],
// dateWindow: [ Date.parse(one_days_previous) ,
// Date.parse(new Date()) ],
// dateWindow: [ Date.parse(twelve_hours_previous) ,
// Date.parse(new Date()) ],
// dateWindow: [ Date.parse("2014/03/01 12:00:00"),
// Date.parse("2014/03/31 12:00:00") ],
// NEW CODE INSERTED - ENDS
title: 'Temperature(°C) vs Time',
rollPeriod: 1,
showRoller: true,
xlabel: 'Time',
ylabel: 'Temperature (°C)',
legend: 'always',
labelsKMB: 'true',
labelsSeparateLines: 'true',
colors: [
"rgb(51,204,204)",
"#00DD55",
"rgb(255,100,100)",
"rgba(50,50,200,0.4)"]
}
);
var desired_range = null;
function approach_range() {
if (!desired_range) return;
// go halfway there
var range = g.xAxisRange();
if (Math.abs(desired_range[0] - range[0]) < 60 &&
Math.abs(desired_range[1] - range[1]) < 60) {
g.updateOptions({dateWindow: desired_range});
// (do not set another timeout.)
} else {
var new_range;
new_range = [0.5 * (desired_range[0] + range[0]),
0.5 * (desired_range[1] + range[1])];
g.updateOptions({dateWindow: new_range});
animate();
}
}
function animate() {
setTimeout(approach_range, 50);
}
var zoom = function(res) {
var w = g.xAxisRange();
desired_range = [ w[0], w[0] + res * 1000 ];
animate();
}
var reset = function() {
desired_range = orig_range;
animate();
}
var pan = function(dir) {
var w = g.xAxisRange();
var scale = w[1] - w[0];
var amount = scale * 0.25 * dir;
desired_range = [ w[0] + amount, w[1] + amount ];
animate();
}
document.getElementById('hour').onclick = function() { zoom(3600); };
document.getElementById('day').onclick = function() { zoom(86400); };
document.getElementById('week').onclick = function() { zoom(604800); };
document.getElementById('month').onclick = function() { zoom(30 * 86400); };
document.getElementById('full').onclick = function() { reset(); };
document.getElementById('left').onclick = function() { pan(-1); };
document.getElementById('right').onclick = function() { pan(+1); };
}
);
}
//]]>
</script>
Now, call the function from the button
<button id="hour" onClick="foo()">Hour</button>
Edit: And for the document.ready() not being safe:
Is it safe to call $(document).ready() from inside a function?
Edit: Guys you are right, and i'm really sorry, I didn't see the whole question before answering.
user1062153 There is no need to do the extra work in javascript, you just have to give the id to the element you are using. Just add the
<button id="hour">Hour</button>
as Xatenev said. That should work fine..
I'm using Three.js on an app, currently I'm having issues with the object picking. Some objects are not getting intersected by the rays, but only on certain camera rotations. I'm trying to debug the code and to draw the ray.
I'm using this methods in my code(canvas is a namespace for the Three objects):
C.getXY = function(e) {
var click = {};
click.x = ( e.clientX / window.innerWidth ) * 2 - 1;
click.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
return click;
};
C.doPicking = function(e) {
var picked = false;
if (canvas.boundingBox !== null) {
canvas.scene.remove(canvas.boundingBox);
}
var projector = new THREE.Projector(), click = C.getXY(e);
var ray = projector.pickingRay(new THREE.Vector3(click.x, click.y, 0), canvas.camera);
ray.linePrecision = 0.00000000000000001;
ray.precision = 0.00000000000000001;
var intersects = ray.intersectObjects(canvas.scene.children);
if (intersects.length > 0) {
var i = 0;
var ids = [];
while (i < intersects.length) {
if (intersects[i].object.visible) {
//Object is picked
}
++i;
}
}
};
My question is...are other points to consider in the debuging process?
Ooops...forgot to add mesh.geometry.computeFaceNormals(); before adding the meshes to the scene. Now the picking is working normally.