three.js : Pass text instead of particles into particle cloud - javascript

I have a forked three.js codepen experiment that has square particles floating around.
But i'm trying to modify it such that i can pass text (geometry?) into it, replacing the square particles, somewhat like a word / tag cloud. Is this possible?
Link to current codepen:
https://codepen.io/farisk/pen/pWQGxB
Heres what i wish to achieve:
I'm currently not sure where to start.
I was thinking of somehow using a text geometry
var loader = new THREE.FontLoader();
let font = loader.parse(fontJSON);
var geometry = new THREE.TextGeometry("hello", {font: font, size: 120, height: 10, material: 0});
But someone mentioned that this is not the right way? I'm pretty new to three.js / html canvas so any help is appreciated.

Passing in geometry per particle is usually not possible in particle systems because the fact that its the same geometry for each particle is what makes these systems efficient.
To achieve the effect that you are looking for there are basically two options:
Render all texts into a single sprite texture and provide texture coordinates for each particle such that each particle renders the correct text. (Only two dimensional rendering of the text and not scalable for a large amount of texts) See this example.
Make each text object it's own geometry and render them without a particle system. (You loose the performance gain of particle systems)
If you really just want to achieve a tag cloud you could also just use pure JavaScript and transform the position of the text elements according to some calculated 3D positions.

Related

three.js CameraHelper rotates faster than PerspectiveCamera

I have a THREE.PerspectiveCamera to which I add a THREE.CameraHelper.
cameraLocal = new THREE.PerspectiveCamera(70, 1, 20, 120);
scene.add(cameraLocal);
cameraLocalHelper = new THREE.CameraHelper(cameraLocal);
cameraLocal.add(cameraLocalHelper);
However when I rotate the camera,
cameraLocal.rotateX(0.1);
the CameraHelper rotates by a larger amount than the camera.
I've made a
demo that shows this.
Initially, cameraLocal can't see the help lines drawn by the CameraHelper. However, if cameraLocal is rotated either way about the x-axis, the help lines come into view, I'm supposing on account of the CameraHelper rotating by a different amount.
Could anyone point out what I'm doing wrong here?
I'm using the build of three.js from 5-Aug-2019.
CameraHelper needs to be added directly to the scene.
Do not try to add it as a child of the camera itself.
three.js r.107

Threejs skybox out of range

I am writing a 3d game in javascript with threejs. I made a skybox, and it works, but if I make my cameras near and far distances too small it doesn't show.
I understand why this happens, the camera attached to my player doesn't see as far as the skybox. If I make my cameras "near" and "far" attributes large enough (corresponding to the size of my game map) I can make it so that my skybox is always within range, but I don't want that, since I don't want the camera to see all the objects that far away.
Any ideas of how to force the camera to see the skybox but still have a small "far" attribute so as to no see all the objects in the world?
Any help would be greatly appreciated.
There’s scene.background, which can be set to a CubeTexture.
Just want to add an example, because someone might find it useful here:
var loader = new THREE.CubeTextureLoader();
loader.load([
'./img/sky/galaxy-X.jpg', './img/sky/galaxy+X.jpg',
'./img/sky/galaxy-Y.jpg', './img/sky/galaxy+Y.jpg',
'./img/sky/galaxy-Z.jpg', './img/sky/galaxy+Z.jpg'
] , function(texture)
{
scene.background = texture;
});

Shift the rendered output in 2d space

Consider this simple example of a cube centered on the origin of the world. Since the camera is looking directly at it, the resulting rendered image shows the cube in the middle of the rendered 2D image and only its front face is visible. I'd like to have control over that cube's placement. I.e. I'd like to shift the rendered output up and to the left by some amount. That way, I can for example shift everything by half of the canvas's width and height and have the cube centered on the top left corner of the rendered output.
To be clear: I don't want to move the camera nor the object in the 3D world (nor the canvas). I just want the rendered result itself to shift, and I'd like to define this shift in 2D screen units rather than in 3D space. It entails that after the said shift, the sides of the cube will still not be visible — only the front face as it is currently. It also entails that if I shift the output to the left, some geometry that's on the right side of the view but previously out of the frame would now shift into view and get rendered.
In some 3D software I've encountered the ability to do this by modifying the camera's X and Y "center shift". Maybe in three.js I'd have to do it by applying a transformation to the camera or to the renderer? I'm not familiar enough with the library to know where to dig.
There's no relevant code to share, but StackOverflow won't let me submit this question without some code ;)
You offset of the camera using a pattern like so:
var fullWidth = window.innerWidth;
var fullHeight = window.innerHeight;
var xPixels = 600;
var yPixels = 200;
camera.setViewOffset ( fullWidth, fullHeight, xPixels, yPixels, fullWidth, fullHeight );
To undo it, call
camera.clearViewOffset();
See the docs for more info about this method and multi-monitor setups. It works for OrthographicCamera, too.
three.js r.84
Why don't you just use canvas translate?
Just do something like this:
// adjust for camera
ctx.translate(-this.camera.x, -this.camera.y);
// render scene here
// end of camera view
ctx.translate(this.camera.x, this.camera.y);

Three.JS: How to make textures overlap each other?

TL;DR: How do i make textures appear bigger than the faces they are attached to, with a fading effect, so that all textures overlap each other?
-
Learning three.js by trying to recreate the Game Warzone 2100. :)
I'm loading a default texture for the ground with:
var texture = THREE.ImageUtils.loadTexture('tile-53.png'); // Specify file
texture.wrapS = texture.wrapT = THREE.RepeatWrapping; // Make the texture repeat
texture.repeat.set(map_width, map_height); // Repeat for every face
texture.anisotropy = 100; // Disable anisoptropy
At the moment it looks like this. Now compare it to this.
Warzone 2100 finally started looking good with the new renderer especially because they made the textures show bigger than the faces and overlap each other, making the sharp borders vanish. Is it possible to reach the same effect with three.js and if so, how would i go there?
Texture is something that is attached to it's geometry in the first place (speaking about 3D), so to make just the texture itself overlap other textures is not quite possible. You can perfectly make your geometries overlap each other, though.
For your textures looking "bigger", try looking here.

Canvas - Fill a rectangle in all areas that are fully transparent

I'm writing a simple 2D game engine using the HTML5 canvas. I've come to adding a lighting engine. Each light source has a radius value and an intensity value (0-1, eg 1 would be very bright). There's also an ambient light value that is used to light everything else in the world that isn't near a light source (0-1, eg 0.1 would be moonlight). The process of lighting is done on a separate canvas above the main canvas:
For each light source, a radial gradient is drawn at that position with the same radius as the light source. The gradient is given two stops: the center is black with an alpha of 1-intensity of the light and the end/edge is black with alpha of 1-ambient light value. That all works fine.
This is where it goes wrong :/ I need to fill the whole canvas with black with and alpha of 1-ambient light value and at the moment I do this by setting the context.globalCompositeOperation to source-out then fillRecting the whole canvas.
My code for this stuff is:
var amb = 'rgba(0,0,0,' + (1-f.ambientLight) + ')';
for(i in f.entities) {
var e = f.entities[i], p = f.toScreenPoint(e.position.x, e.position.y), radius = e.light.radius;
if(radius > 0) {
var g = cxLighting.createRadialGradient(p.x, p.y, 0, p.x, p.y, radius);
g.addColorStop(0, 'rgba(0,0,0,' + (1-e.light.intensity) + ')');
g.addColorStop(1, amb);
cxLighting.fillStyle = g;
cxLighting.beginPath();
cxLighting.arc(p.x, p.y, radius, 0, Math.PI*2, true);
cxLighting.closePath();
cxLighting.fill();
}
}
//Ambient light
cxLighting.globalCompositeOperation = 'source-out';
cxLighting.fillStyle = amb;
cxLighting.fillRect(0, 0, f.width, f.height);
cxLighting.globalCompositeOperation = 'source-over';
However instead of getting what I wan't out of the engine (left) I get a kind of reversed gradient (right). I think this is because when I draw the rectangle with the source-out composite operation it affects the colours of the gradient itself because they are semi-transparent.
Is there a way to do this differently or better? Using clipping maybe, or drawing the rect over everything first?
Also, I modified the Mozila Dev Centre's example on composting to replicate what I need to do and none of the composite modes seemed to work, check that out if it would help.
Thanks very much, any answer would be great :)
One trivial way would be to use imageData but that would be painfully slow. It's an option, but not a good one for a game engine.
Another way would be to think of the ambient light and the light-source as if they were one path. That would make it very easy to do:
http://jsfiddle.net/HADky/
Or see it with an image behind: http://jsfiddle.net/HADky/10/
The thing you're taking advantage of here is the fact that any intersection of a path on canvas is always only unioned and never compounded. So you're using a single gradient brush to draw the whole thing.
But it gets a bit trickier than that if there's more than one light-source. I'm not too sure how to cover that in an efficient way, especially if you plan for two light-sources to intersect.
What you should probably do instead is devise an alpha channel instead of this overlay thing, but I can't currently think of a good way to get it to work. I'll revisit this if I think of anything else.
EDIT: Hey! So I've done a bit of thinking and came up with a good solution.
What you need to do is draw a sort of alpha channel, where the dark spots mark the places where you want light to be. So if you had three light sources it would look like this:
Then you want to set the fill style to your ambient color and set the globalCompositeOperation to xor and xor the whole thing.
ctx.fillStyle = amb;
ctx.globalCompositeOperation = 'xor';
ctx.fillRect(0,0,500,500);
That will leave you with the "opposite" image except the transparent parts will be correctly ambient:
Here's a working example of the code:
http://jsfiddle.net/a2Age/
Extra optimization: You can actually achieve the effect without using any paths at all, by simply drawing the exact same radial gradients onto rects instead of circular paths:
http://jsfiddle.net/a2Age/2/
Hope that helps!
Just an idea, but since you're getting the opposite effect you're going for from your gradient, have you tried reversing the gradient?

Categories

Resources