Hello everyone !
I’m looking for a way to activate a script when the camera is close to an object. I tested with getCameraPosition functions, but there is not enough documentation. Can you give some information ?
Cedric
Hello everyone !
I’m looking for a way to activate a script when the camera is close to an object. I tested with getCameraPosition functions, but there is not enough documentation. Can you give some information ?
Cedric
It is possibile, by using part of the API that has not been made official yet:
You could get your object data by using this function:
viewer.findNodesOfType('OBJECT TYPE NAME'))
OBJECT TYPE NAME refers to object name in editor:
Please use only object that are meshes directly (indicated by circle left to the name in the list) and not nodes that group meshes together (indicated by arrow left to the name in the list. Only by using meshes directly you can access their position.
Here is an example script that will:
<script>
var viewer = WALK.getViewer();
let meshCenter = null
function checkProximity() {
const cameraPosition = viewer.getCameraPosition();
const distance = cameraPosition.distanceTo(meshCenter);
if (distance < 2) {
// do something
}
requestAnimationFrame(checkProximity);
}
function onSceneLoadComplete() {
const nodes = viewer.findNodesOfType('Group61').pop();
const mesh = nodes.mesh;
meshCenter = mesh.geometry.boundingSphere.center;
requestAnimationFrame(checkProximity);
}
viewer.onSceneLoadComplete(onSceneLoadComplete);
</script>
Best
Thank you for that ! In your example, is there an activation of a script or an extension?
You could activate your script at the do something
part in the if
block.
However, this would fire the script each frame the camera is below certain distance.
We could add additional condition to check whether we should activate te script. We could reset the condition once we move away from the object.
The updated version of the script could look like this.
In the example I’m activating popup extension.
<script>
const viewer = WALK.getViewer();
const popupContent =
'<div style="font-size: 1.5em">' +
' <span style="font-size: 1.5em">Welcome</span>' +
" <hr/>" +
" Hello Visitor!" +
"</div>";
let meshCenter = null;
let cameraWithinDistance = false;
function showHtmlPopup() {
viewer.openPopup(popupContent, {
centerHorizontally: true,
centerVertically: true,
});
}
function checkProximity() {
const cameraPosition = viewer.getCameraPosition();
const distance = cameraPosition.distanceTo(meshCenter);
if (distance < 2 && !cameraWithinDistance) {
showHtmlPopup()
cameraWithinDistance = true;
}
if (distance >= 2) {
cameraWithinDistance = false;
}
requestAnimationFrame(checkProximity);
}
function onSceneLoadComplete() {
const nodes = viewer.findNodesOfType("Group61").pop();
const mesh = nodes.mesh;
meshCenter = mesh.geometry.boundingSphere.center;
requestAnimationFrame(checkProximity);
}
viewer.onSceneLoadComplete(onSceneLoadComplete);
</script>
in the top ! I’m testing this tonight
Good morning ! I just added this script in my body-end by modifying the NAME OF THE OBJECT TYPE but nothing happens…
An idea ?
Moreover, is it possible to activate an extension created from shapespark as a switch object?
THANKS !
Is there anything other than “meshCenter”?
This script should work, Bute there is one caveat that I did not anticipate. NAME OF THE OBJECT TYPE might refer to multiple objects. In this instance the script will return the last one of the found objects and we don’t have a way to determine which one this would be. We don’t have a way to filter objects by name in editor unfortunately so there is no reliable way to tell if there are multiple objects with the same name. Sorry for the confusion.
There are two solutions to this issue:
To lookup a point coordinates you can position camera in Viewer tab, and create new WALK view. The camera orientation will yield it’'s current position. (you can also click on “set current” to update coordinates)
To use a point coordinate in the script we can drop the mesh lookup nad pass the points parameters directly via new THREE.Vector3(X, Y, Z) object:
Here is updated script:
<script>
const viewer = WALK.getViewer();
const popupContent =
'<div style="font-size: 1.5em">' +
' <span style="font-size: 1.5em">Welcome</span>' +
" <hr/>" +
" Hello Visitor!" +
"</div>";
let meshCenter = new THREE.Vector3(1.383, -3.652, 0.744);
let cameraWithinDistance = false;
function showHtmlPopup() {
viewer.openPopup(popupContent, {
centerHorizontally: true,
centerVertically: true,
});
}
function checkProximity() {
const cameraPosition = viewer.getCameraPosition();
const distance = cameraPosition.distanceTo(meshCenter);
if (distance < 2 && !cameraWithinDistance) {
showHtmlPopup()
cameraWithinDistance = true;
}
if (distance >= 2) {
cameraWithinDistance = false;
}
requestAnimationFrame(checkProximity);
}
function onSceneLoadComplete() {
requestAnimationFrame(checkProximity);
}
viewer.onSceneLoadComplete(onSceneLoadComplete);
</script>
Let me know if this will work!
About the second part of your question:
It is possible to activate an extensions created from Shapespark editor.
You can get the extension by using viewer.getExtension('type', 'name')
and fire it up with trigger()
function.
In case of ‘switch objects’ the function should like this:
const extension = viewer.getExtension('SwitchObjects', '1');
extension.trigger();
if you would like to switch objects based on proximity you can modify the script I’ve provided:
This script will trigger switchObjects extension if camera is closer than 2 meters to the point specified and if the camera will move away the switchObjects extension is called again.
<script>
const viewer = WALK.getViewer();
let triggerPoint = new THREE.Vector3(1.383, -3.652, 0.744);
let extension = null;
let cameraWithinDistance = false;
function showHtmlPopup() {
viewer.openPopup(popupContent, {
centerHorizontally: true,
centerVertically: true,
});
}
function triggerExtension() {
extension.trigger()
}
function checkProximity() {
const cameraPosition = viewer.getCameraPosition();
const distance = cameraPosition.distanceTo(triggerPoint);
if (distance < 2 && !cameraWithinDistance) {
triggerExtension()
cameraWithinDistance = true;
}
if (distance >= 2 && cameraWithinDistance) {
triggerExtension()
cameraWithinDistance = false;
}
requestAnimationFrame(checkProximity);
}
function onSceneLoadComplete() {
extension = viewer.getExtension('SwitchObjects', '1');
requestAnimationFrame(checkProximity);
}
viewer.onSceneLoadComplete(onSceneLoadComplete);
</script>
Please look at my explanation how to use point instead of mesh in examples I’ve provided.
hello and thank you for your response!
My items are unique items so I shouldn’t have a problem. I’m going to try with the triangulation data you gave me because I placed this script in my body-end but it doesn’t work.
I did a test in a scene where I only put one cube
There is no camera orientation setting in the Viewer tab.
So I found the view position in the “scene.json” file and used it.
let meshCenter = new THREE.Vector3(-0.04766218254864165, -13.19379844758102, 1.7559728311134728);
let cameraWithinDistance = false;
function checkProximity() {
const cameraPosition = viewer.getCameraPosition();
const distance = cameraPosition.distanceTo(meshCenter);
viewer.setMaterialEditable(“SCREEN”);
var videoTexture = viewer.findMaterial(“SCREEN”).baseColorTexture;
if (distance < 2 && !cameraWithinDistance) {
if (videoTexture.isPlaying) {
videoTexture.pause();
} else {
videoTexture.play();
}
cameraWithinDistance = true;
viewer.requestFrame();
return true;
}
if (distance >= 2) {
cameraWithinDistance = false;
if (videoTexture.isPlaying) {
videoTexture.pause();
} else {
videoTexture.play();
}
viewer.requestFrame();
return true;
}
requestAnimationFrame(checkProximity);
}
function onSceneLoadComplete() {
requestAnimationFrame(checkProximity);
}
viewer.onSceneLoadComplete(onSceneLoadComplete);
The function to work only works once, I want to play it when the video stops, and I want it to stop when it’s playing
Can we get them to react every time they go to the area?This feature reacts only once when the user moves
Hi @heung_aile
I’m not sure if this is main issue, but it seems to me that in your code the second if-block is missing cameraWithinDistance
check.
if (distance < 2 && !cameraWithinDistance) {
triggerExtension()
cameraWithinDistance = true;
}
if (distance >= 2 && cameraWithinDistance) {
triggerExtension()
cameraWithinDistance = false;
}
This part of the code will trigger function once each time when camera moves within distance specified and when it leaves the distance specified. Without the second argument (&& cameraWithinDistance) the function declared in that block will be called continuously.
if (distance < 2 && !cameraWithinDistance) {
triggerExtension()
cameraWithinDistance = true;
}
if (distance >= 2) {
triggerExtension()
cameraWithinDistance = false;
}
it’s right??
I want to add various functions depending on the position.
let meshCenter = new THREE.Vector3(-11.740804869432607, -23.442055358814674, 2.0012483651156687);
let triggerPoint = new THREE.Vector3(-0.17461756312701143, -12.563396708711661, 2.0012483651156687);
let extension = null;
let extension2 = null;
let cameraWithinDistance = false;
function triggerExtension() {
extension.trigger();
}
function triggerExtension2() {
extension2.trigger();
}
function checkProximity() {
const cameraPosition = viewer.getCameraPosition();
const distance = cameraPosition.distanceTo(meshCenter);
const distance2 = cameraPosition.distanceTo(triggerPoint);
if (distance < 2 && !cameraWithinDistance) {
triggerExtension2();
cameraWithinDistance = true;
}
if (distance2 < 2 && !cameraWithinDistance) {
triggerExtension();
cameraWithinDistance = true;
}
if (distance2 >= 2 && cameraWithinDistance) {
triggerExtension();
cameraWithinDistance = false;
}
requestAnimationFrame(checkProximity);
}
function onSceneLoadComplete() {
extension = viewer.getExtension("VideoTextureControl", "1");
extension2 = viewer.getExtension("HtmlLabel", "1");
requestAnimationFrame(checkProximity);
}
viewer.onSceneLoadComplete(onSceneLoadComplete);
To use multiple functions you would need to duplicate both variables ‘distance’ and ‘cameraWithinDistance’.
for example:
so basically you would duplicate your code for each function that needs to be called:
if (distance1 < 2 && !cameraWithinDistance1) {
triggerExtension1()
cameraWithinDistance1 = true;
}
if (distance1 >= 2 && cameraWithinDistance1) {
triggerExtension1()
cameraWithinDistance1 = false;
}
if (distance2 < 2 && !cameraWithinDistance2) {
triggerExtension2()
cameraWithinDistance2 = true;
}
if (distance2 >= 2 && cameraWithinDistance2) {
triggerExtension2()
cameraWithinDistance2 = false;
}
Best!
It’s working well , thx
Good morning !
Both scripts work, one to activate an extension, the other to open a popup when approaching an object.
I tried to combine the two so that when I approach “Cube 1”, it activates an extension, without going through the coordinates of a point, but I can’t do it…
Can you help me ?
<script>
const viewer = WALK.getViewer();
let extension = null;
let cameraWithinDistance = false;
function triggerExtension() {
if (extension) {
extension.activate();
}
}
function checkProximity() {
const cameraPosition = viewer.getCameraPosition();
const nodes = viewer.findNodesOfType('Cube');
if (nodes.length > 0) {
const mesh = nodes[0].mesh;
const distance = cameraPosition.distanceTo(mesh.position);
if (distance < 2 && !cameraWithinDistance) {
cameraWithinDistance = true;
triggerExtension();
}
if (distance >= 2 && cameraWithinDistance) {
cameraWithinDistance = false;
}
}
requestAnimationFrame(checkProximity);
}
function onSceneLoadComplete() {
extension = viewer.getExtension('SwitchObjects', '1');
requestAnimationFrame(checkProximity);
}
viewer.onSceneLoadComplete(onSceneLoadComplete);
</script>