Include three.js into wordpress theme - wordpress

So basically what I am trying to achieve is simple:
I want to use three.js with my current custom wordpress theme.
Unfortunately I can't seem to find any information on how to do so.
I enqueue all my scripts via functions.php, I guess that is the default approach.
Since three.js has to be loaded with "type=module" I can not get it to work properly, and it seems as if it has to be done in another way. Should the import statements take place in my themes header? I always think that it is bad practice... And how can I then write my three.js code into an external js file?
Can someone please help me out?

Since three.js has to be loaded with "type=module"
That is actually not true. three.js provides an ESM (three.module.js) and two UMD builds (three.js and three.min.js). Including the minified UMD build in your wordpress theme should solve the issue. The following lives example uses this build file:
let camera, scene, renderer;
let mesh;
init();
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
camera.position.z = 1;
scene = new THREE.Scene();
const geometry = new THREE.BoxGeometry( 0.2, 0.2, 0.2 );
const material = new THREE.MeshNormalMaterial();
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animation );
document.body.appendChild( renderer.domElement );
}
function animation( time ) {
mesh.rotation.x = time / 2000;
mesh.rotation.y = time / 1000;
renderer.render( scene, camera );
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.130.1/build/three.min.js"></script>

Related

Aframe fire raycaster on drop event

I'm trying to drop an object into a 3D scene from a React UI.
I can capture the drop data/ position etc, I'm now trying to use this in a RayCaster to determine what 3D entity has been dropped onto.
const handleDragStop = (e) => {
console.log(e)
const scene = document.getElementById('scene');
const raycaster:any = scene.getAttribute("raycaster");
const camera = AFRAME.scenes[0].camera;
console.log(raycaster)
console.log(AFRAME.scenes[0])
const mouse = new window.THREE.Vector2();
mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.children );
console.log(intersects)
};
The Aframe version of RayCaster does not seem to to have the raycaster.setFromCamera() function, it's not recognised as a function.
How do I fire a raycaster from a drop event?
EDIT
I can get it working with a new Raycaster
const raycaster = new window.THREE.Raycaster();
The new question is, how do I get this raycaster to use the same objects as the existing one?
Thanks
To access the THREE raycaster you have to do the following on an entity with the raycaster component:
entityEl.components.raycaster.raycaster.setFromCamera(..);
Make sure you are in the latest A-Frame release

A-Frame. Zoom on wheel scroll

I've come through the official docs but wasn't able to locate information about how possibility of zooming in/out panorama images, is it supported in the A-Frame or maybe there is a workaround to read about implementing some of three.js on top of it?
This might be a cleaner way in 2018.
I limited the zoom of the Aframe camera 1-5 so it doesn't get too messy.I just tested this and its working greatly.Hope it helps others.
window.addEventListener("mousewheel", event => {
const delta = Math.sign(event.wheelDelta);
//getting the mouse wheel change (120 or -120 and normalizing it to 1 or -1)
var mycam=document.getElementById('cam').getAttribute('camera');
var finalZoom=document.getElementById('cam').getAttribute('camera').zoom+delta;
//limiting the zoom so it doesnt zoom too much in or out
if(finalZoom<1)
finalZoom=1;
if(finalZoom>5)
finalZoom=5;
mycam.zoom=finalZoom;
//setting the camera element
document.getElementById('cam').setAttribute('camera',mycam);
});
You could either:
Scale an <a-sphere> up or down when detecting the mouse wheel event
zoom in or out the camera, like documented here
This article might be helpful, as it covers using the mousewheel event on multiple browsers.
I think scaling may screw up Your setup, or be a resource waste, so I'd go with 2.
Sandy's answer helped me. I want to contribute an answer which shows the full code and enables smoother zooming (increments of 0.1):
<script>
window.addEventListener("wheel", (event) => {
// small increments for smoother zooming
const delta = event.wheelDelta / 120 / 10;
var mycam = document.getElementById("cam").getAttribute("camera");
var finalZoom =
document.getElementById("cam").getAttribute("camera").zoom + delta;
// limiting the zoom
if (finalZoom < 0.5) finalZoom = 0.5;
if (finalZoom > 2) finalZoom = 2;
mycam.zoom = finalZoom;
document.getElementById("cam").setAttribute("camera", mycam);
});
</script>
<a-scene>
<a-entity
id="cam"
camera="zoom: 1"
look-controls="reverseMouseDrag: true"
></a-entity>
<!-- my pano image stuff -->
<a-assets>
<img id="skyTexture" crossorigin="anonymous" />
</a-assets>
<a-sky src="#skyTexture"></a-sky>
</a-scene>
This is what I put together to do it. Check the initial vrZoom variable.
For me, what I struggled the most, was to understand the way you set a parameter that's inside a component. You have to call it like this: element.setAttribute('componentName', 'parameterName', 'value') and in my case cam.setAttribute('camera', 'zoom', vrZoom)
Here's my script all together. It would be possible to create a component with this, such as look-controls.
var mousewheelevt=(/Firefox/i.test(navigator.userAgent))? "DOMMouseScroll" : "mousewheel";
if (document.attachEvent)
document.attachEvent("on"+mousewheelevt, function(e){scroller(e)});
else if (document.addEventListener)
document.addEventListener(mousewheelevt, function(e){scroller(e)},false);
var vrZoom = 4; // My initial zoom after animation
var cam = document.querySelector('#mainCam');
function scroller(evt)
{
//Guess the delta.
var delta = 0;
if (!evt) evt = window.event;
if (evt.wheelDelta) {
delta = evt.wheelDelta/120;
} else if (evt.detail) {
delta = -evt.detail/3;
}
if (evt.preventDefault) evt.preventDefault();
evt.returnValue = false;
//Actual Zooming.
vrZoom += delta * 0.1
vrZoom = Math.min(Math.max(vrZoom, 1), 8); // clamp between 1 and 8
cam.setAttribute('camera', 'zoom', vrZoom)
}
I struggled quite a bit with getting this to work for an embedded a-frame, especially because the scene would become skewed upon dynamically adjusting the camera's zoom setting. This is a bug with a-frame. Here are the two ways I found to reset the scene upon setting the zoom level.
AFRAME.scenes[0].resize();
Or ...
let scene = document.querySelector('a-scene');
scene.camera.aspect = scene.clientWidth / scene.clientHeight;
scene.camera.updateProjectionMatrix();

Can you reflect geometry (not textures) in three.js?

I have found many examples of three.js reflecting images, but is at all possible to reflect lines, triangles and shapes? I want to create a mirror pyramid that reflects lines.
For example: http://www.gus.graphics/buffer.html >This page has lots of lines.
I want to reflect them onto a 3d shape that sits in the middle.
For example: http://www.gus.graphics/ball1.html > This page has a mirror ball.
These are the sort of lines of code I am looking at. Not sure if it's even possible.
var textureCube = THREE.ImageUtils.loadTextureCube( urls );
var material = new THREE.MeshBasicMaterial( { color: 0xffffff, envMap: textureCube } )
shader.uniforms[ "tCube" ].value = textureCube;
At the moment that code above is taking in a bunch of images "urls", but as you probably know by now I want to reflect the geometry in the first link I provided.
You can take a look at THREE.CubeCamera. It creates 6 cameras that render to a WebGLRenderTargetCube and then use it as envMap. An example would be:
//Create cube camera
var cubeCamera = new THREE.CubeCamera( 1, 100000, 128 );
scene.add( cubeCamera );
//Create material and mesh
var chromeMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: cubeCamera.renderTarget } );
var car = new Mesh( carGeometry, chromeMaterial );
scene.add( car );
//Update the render target cube
car.setVisible( false );
cubeCamera.position.copy( car.position );
cubeCamera.updateCubeMap( renderer, scene );
//Render the scene
car.setVisible( true );
renderer.render( scene, camera );
See this: http://threejs.org/docs/#Reference/Cameras/CubeCamera
There are also examples usage here:
http://threejs.org/examples/#webgl_materials_cubemap_dynamic
http://threejs.org/examples/#webgl_materials_cubemap_dynamic2

Mirror reflection quirks in ThreeJS

(Disclaimer: first post on SO. I've searched SO and elsewhere for an answer to this, but while mirrors and reflections do come up, I haven't found anything related to my particular issue.)
Problematic Mirror
This is my first scene in ThreeJS and most of it is based on the official examples (super helpful!). As you can see, for whatever reason the mirror reflection is black/fragmented from most angles, so it only displays a proper reflection under a very narrow range. (Explore other angles to see what I'm talking about.)
Relevant code:
// MIRROR
verticalMirror = new THREE.Mirror( renderer, camera, { clipBias: 0.003, textureWidth: 1024, textureHeight: 1024, color:0x889999 } );
var verticalMirrorMesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 300, 300 ), verticalMirror.material );
verticalMirrorMesh.add( verticalMirror );
verticalMirrorMesh.position.y = 100;
verticalMirrorMesh.position.z = -500;
scene.add( verticalMirrorMesh );
And in the render function:
function render()
{
renderer.render( scene, camera );
verticalMirror.renderWithMirror( verticalMirror );
}
I've tried messing with the texture settings and the clipbias to no avail, and the whole code is mostly based on The ThreeJS reference example for Mirror.
Any and all help would be greatly appreciated - thank you!
Thanks WestLangley, verticalMirror.render() saved the day! Mirror reflects beautifully now. I'll avoid renderWithMirror until I get a better idea of what it does.
Much appreciated.

Changing three.js background to transparent or other color

I've been trying to change what seems to be the default background color of my canvas from black to transparent / any other color - but no luck.
My HTML:
<canvas id="canvasColor">
My CSS:
<style type="text/css">
#canvasColor {
z-index: 998;
opacity:1;
background: red;
}
</style>
As you can see in the following online example I have some animation appended to the canvas, so cant just do a opacity: 0; on the id.
Live preview:
http://devsgs.com/preview/test/particle/
Any ideas how to overwrite the default black?
I came across this when I started using three.js as well. It's actually a javascript issue. You currently have:
renderer.setClearColorHex( 0x000000, 1 );
in your threejs init function. Change it to:
renderer.setClearColorHex( 0xffffff, 1 );
Update: Thanks to HdN8 for the updated solution:
renderer.setClearColor( 0xffffff, 0);
Update #2: As pointed out by WestLangley in another, similar question - you must now use the below code when creating a new WebGLRenderer instance in conjunction with the setClearColor() function:
var renderer = new THREE.WebGLRenderer({ alpha: true });
Update #3: Mr.doob points out that since r78 you can alternatively use the code below to set your scene's background colour:
var scene = new THREE.Scene(); // initialising the scene
scene.background = new THREE.Color( 0xff0000 );
A full answer: (Tested with r71)
To set a background color use:
renderer.setClearColor( 0xffffff ); // white background - replace ffffff with any hex color
If you want a transparent background you will have to enable alpha in your renderer first:
renderer = new THREE.WebGLRenderer( { alpha: true } ); // init like this
renderer.setClearColor( 0xffffff, 0 ); // second param is opacity, 0 => transparent
View the docs for more info.
For transparency, this is also mandatory: renderer = new THREE.WebGLRenderer( { alpha: true } ) via Transparent background with three.js
In 2020 using r115 it works very good with this:
const renderer = new THREE.WebGLRenderer({ alpha: true });
const scene = new THREE.Scene();
scene.background = null;
I found that when I created a scene via the three.js editor, I not only had to use the correct answer's code (above), to set up the renderer with an alpha value and the clear color, I had to go into the app.json file and find the "Scene" Object's "background" attribute and set it to:
"background: null".
The export from Three.js editor had it originally set to "background": 0
Set renderer clear colour
With the below code
renderer.setClearColor( 0x000000, 1 );
I'd also like to add that if using the three.js editor don't forget to set the background colour to clear as well in the index.html.
background-color:#00000000

Resources