How to scale a three.js sprite? - javascript

I am trying to display a sprite in three on javascript and make it bigger. I tried the following:
THREE.ImageUtils.crossOrigin = '';
var spriteMap = THREE.ImageUtils.loadTexture( "https://cdn.iconscout.com/icon/premium/png-256-thumb/airplane-1993284-1683707.png" );
var spriteMaterial = new THREE.SpriteMaterial( { map: spriteMap } );
var sprite = new THREE.Sprite( spriteMaterial );
sprite.width = 10;
sprite.height = 10;
scene.add( sprite );
and
THREE.ImageUtils.crossOrigin = '';
var spriteMap = THREE.ImageUtils.loadTexture( "https://cdn.iconscout.com/icon/premium/png-256-thumb/airplane-1993284-1683707.png" );
var spriteMaterial = new THREE.SpriteMaterial( { map: spriteMap } );
var sprite = new THREE.Sprite( spriteMaterial );
sprite.size = THREE.Vector3(10,10,10);
scene.add( sprite );
but the sprite was very very tiny in the middle of the browser window. I saw no error on the console.
What am I doing wrong?

Sprite.size does not exist. Try to modify Sprite.scale instead. Check out the following live example:
var camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 5;
scene = new THREE.Scene();
var loader = new THREE.TextureLoader();
var map = loader.load("https://cdn.iconscout.com/icon/premium/png-256-thumb/airplane-1993284-1683707.png");
var material = new THREE.SpriteMaterial({
map: map
});
var sprite = new THREE.Sprite(material);
sprite.scale.set( 5, 5, 1 );
scene.add(sprite);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
body {
margin: 0;
}
canvas {
display: block;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.119.1/build/three.js"></script>

If you want the scaling to happen based on the camera distance, you need to add a parameter to your material variable:
sizeAttenuation: false
Like this:
var material = new THREE.SpriteMaterial({
map: map,
sizeAttenuation: false});
This will make your sprite big when to camera is far away and smaller when the camera gets closer to it (based on the sprite.scale.set() values).

Related

Color based on .obj model

I want to set colors according to the height of my model, which is a .obj file. I want the colors to go from green to red, depending on the height, green for the minimum point, red for the maximum. This is my code currently:
loader.load(nombreMapa, function (object) {
loader.setMaterials(material);
escena.add(object);
object.position.y = -10;
if (object instanceof THREE.Object3D)
{
object.traverse (function (mesh)
{
if (! (mesh instanceof THREE.Mesh)) return;
mesh.material = new THREE.MeshNormalMaterial();
mesh.material.side = THREE.DoubleSide;
var geometry = new THREE.EdgesGeometry( mesh.geometry );
var material1 = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 1000 } );
var edges = new THREE.LineSegments( geometry, material1 );
mesh.add( edges );
});
}});
You can do this trick, using THREE.Box3() and .lerp() method of THREE.Color() for setting colors of each vertex in each child's mesh's geometry.
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 60, 250);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x404040);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, 60, 0);
controls.update();
var mat = new THREE.MeshBasicMaterial({
wireframe: true,
vertexColors: THREE.VertexColors
}); // the same material for all the children of the object
var loader = new THREE.OBJLoader();
loader.load('https://threejs.org/examples/models/obj/male02/male02.obj', function(obj) {
var size = new THREE.Vector3();
var box3 = new THREE.Box3().setFromObject(obj);
box3.getSize(size);
console.log(size);
var v3 = new THREE.Vector3(); // for re-use
var c = [
new THREE.Color(0x00ff00),
new THREE.Color(0xff0000)
];
var cTemp = new THREE.Color(); // for re-use
obj.traverse(child => {
if (child.isMesh) {
let colors = []; // array for color values of the current mesh's geometry
let pos = child.geometry.attributes.position;
for(let i = 0; i < pos.count; i++){
v3.fromBufferAttribute(pos, i);
obj.localToWorld(v3); // box3 is in world coords so we have to convert coortinates of the vertex from local to world
let a = (v3.y - box3.min.y) / size.y; // find the value in range 0..1
cTemp.copy(c[0]).lerp(c[1], a); // lerp the colors
colors.push(cTemp.r, cTemp.g, cTemp.b); // save values in the array
child.geometry.addAttribute("color", new THREE.BufferAttribute(new Float32Array(colors), 3)); // add a buffer attribute for colors
child.material = mat;
}
}
});
scene.add(obj);
})
renderer.setAnimationLoop(() => {
renderer.render(scene, camera)
});
body {
overflow: hidden;
margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script src="https://threejs.org/examples/js/loaders/OBJLoader.js"></script>
Also, take a look at this SO answer about other options of how to apply gradient.

three.js horizontal PlaneGeometry at x=0 y=0 z=0

Hi I have this code that draws the image below
window.onload = function()
{
// init renderer
var renderer=new THREE.WebGLRenderer();
canvas_width=side; canvas_height=side;
renderer.setSize(canvas_width,canvas_height);
document.body.appendChild(renderer.domElement);
// init scene and camera
var scene=new THREE.Scene();
var camera=new THREE.PerspectiveCamera(90,canvas_width/canvas_height,1,100);
camera.position.y=5;
camera.position.z=25;
var texture = new THREE.TextureLoader().load( 'arrow.png' );
var img = new THREE.MeshBasicMaterial( { map: texture } );
// mesh
mesh = new THREE.Mesh(new THREE.PlaneGeometry(25,25),img);
mesh.overdraw = true;
scene.add(mesh);
// a light
var light=new THREE.HemisphereLight(0xffffff,0x000000,1.5);
light.position.set(1,1,1);
scene.add(light);
// render
requestAnimationFrame(function animate(){
requestAnimationFrame(animate);
renderer.render(scene,camera);
})
}
but I want to draw the PlaneGeometry horizontally instead of vertically, not rotating it with mesh.rotation.x=THREE.Math.degToRad(-90);, to get this at x=0 y=0 z=0:
so that with
mesh.rotation.x=THREE.Math.degToRad(-90);
the arrow will pointing down
and with:
mesh.rotation.x=THREE.Math.degToRad(90);
the arrow will pointing up
can you help me?
You can do it, rotating the geometry with .rotateX():
// init renderer
var renderer = new THREE.WebGLRenderer();
canvas_width = window.innerWidth;
canvas_height = window.innerHeight;
renderer.setSize(canvas_width, canvas_height);
document.body.appendChild(renderer.domElement);
// init scene and camera
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(90, canvas_width / canvas_height, 1, 100);
camera.position.y = 5;
camera.position.z = 25;
var texture = new THREE.TextureLoader().load('https://threejs.org/examples/textures/uv_grid_opengl.jpg');
var img = new THREE.MeshBasicMaterial({
map: texture,
side: THREE.DoubleSide
});
// mesh
geom = new THREE.PlaneGeometry(25, 25);
geom.rotateX(-Math.PI * 0.5); // this is how you can do it
mesh = new THREE.Mesh(geom, img);
mesh.overdraw = true;
scene.add(mesh);
// a light
var light = new THREE.HemisphereLight(0xffffff, 0x000000, 1.5);
light.position.set(1, 1, 1);
scene.add(light);
// render
requestAnimationFrame(function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
})
body {
overflow: hidden;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>

square textures for circular particles in three.js

I'm having trouble rendering particles properly in three.js. I'm trying to follow this tutorial to set up particles. Unfortunately, while they're placed correctly and are displayed, they are clearly rectangular, rather than circular.
Here's the code for the material
var texture = new THREE.TextureLoader().load(
"textures/disc.png",
function(texture) {
var material = new THREE.PointsMaterial({
color: 0xFFFFFF,
size: 16,
map: texture,
transparent: true,
blending: THREE.AdditiveBlending,
});
particles = new THREE.Points( geometry, material );
});
and here's a pen with complete code.
I honestly have no idea why they're rendered like that, when it's working perfectly in the example in the tutorial.
The issue is the fog is being added to your particles. Set fog to false in the PointMaterial
var scene,
camera, fieldOfView, aspectRatio, nearPlane, farPlane, HEIGHT, WIDTH,
renderer, container;
function createScene() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0xf7d9aa, 100, 950)
aspectRatio = WIDTH / HEIGHT;
fieldOfView = 60;
nearPlane = 1;
farPlane = 10000;
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane
);
camera.position.x = 10;
camera.position.z = 290;
camera.position.y = 25;
renderer = new THREE.WebGLRenderer({
alpha: true,
antialias: true
});
renderer.setClearColor(new THREE.Color(0, 0, 0));
renderer.setSize(WIDTH, HEIGHT)
renderer.shadowMap.enabled = true;
container = document.getElementById('world');
container.appendChild(renderer.domElement);
window.addEventListener('resize', handleWindowResize, false);
}
function handleWindowResize() {
HEIGHT = window.innerHeight;
WIDTH = window.innerWidth;
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
}
var hemisphereLight, shadowLight;
function createLights() {
}
var sphere;
function createSphere() {
var geometry = new THREE.SphereGeometry( 150, 32, 32 );
var material = new THREE.MeshBasicMaterial( {color: 0xffff00} );
sphere = new THREE.Mesh( geometry, material );
sphere.visible = false;
scene.add( sphere );
}
function createParticles() {
var loader = new THREE.TextureLoader();
var texture = loader.load(
"https://i.imgur.com/9fW07EI.png",
function(texture) {
editGeometry = sphere.geometry;
var geometry = new THREE.Geometry();
for ( i = 0; i < editGeometry.vertices.length; i ++ ) {
geometry.vertices.push(editGeometry.vertices[i]);
}
var material = new THREE.PointsMaterial({
color: 0xFFFFFF,
size: 16,
map: texture,
transparent: true,
blending: THREE.AdditiveBlending,
fog: false,
depthTest: false,
});
particles = new THREE.Points( geometry, material );
particles.sortParticles = true;
scene.add( particles );
});
}
function loop() {
renderer.render(scene, camera);
requestAnimationFrame(loop);
}
function init() {
createScene();
createLights();
createSphere();
createParticles();
loop();
}
init()
body {
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r123/three.min.js"></script>
<div id="world">
</div>
Note that if your image is not on the same domain as your webpage then you can't use the image in WebGL unless you both request cross origin access and the server serving the image gives permission.
Also you can't use images from a 3rd party domain unless the server sends CORS headers for permission to use the image. The postimg.org server did not give permission for the image. imgur's server did.
You must also turn off the depthTest otherwise points drawn in front will end up blocking out points drawn in back. Since you're drawing with transparency and additive blending that's probably what you want.
It's not work for me, maybe I use a ShaderMaterial, but depthTest: false works.
let material = new THREE.ShaderMaterial({
uniforms: {
uColor: { value: new THREE.Color(0xffffff) },
uPointTexture: { value: new THREE.TextureLoader().load(require('./res/spark1')) }
},
vertexShader: _me.vertex_shader,
fragmentShader: _me.fragment_shader,
depthTest: false,
transparent: true,
// fog: false
})

Changing z rotation in three.js animation

I need to add an additional function to change the Z rotation value of the teapot from within the updateTeapot function. I saw this answer Three.js camera tilt up or down and keep horizon level, but how do I incorporate a z rotation function within this function?
function updateTeapot() {
if (teapot != null) {
teaPotHeight+=1;
teapot.position.y = teaPotHeight%200;
}
}
(function ( lab3 , $, undefined) {
lab3.init = function(hook) {
// Create a renderer
var WIDTH = 600,
HEIGHT = 500;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(WIDTH, HEIGHT);
hook.append(renderer.domElement);
var scene = new THREE.Scene();
// Create lights
var pointLight =
new THREE.PointLight(0xFFFFFF);
pointLight.position = new THREE.Vector3(-10, 100, 100);
scene.add(pointLight);
// Add ambient light
var ambient = new THREE.AmbientLight( 0x555555 );
scene.add( ambient );
// Create a camera
var VIEW_ANGLE = 65, //65 FOV is most 'natural' FOV
ASPECT = WIDTH / HEIGHT,
NEAR = 0.1, //these elements are needed for cameras to
FAR = 10000; //partition space correctly
var camera = new THREE.PerspectiveCamera(
VIEW_ANGLE,
ASPECT,
NEAR,
FAR);
camera.position.z = 300;
scene.add(camera);
// Create and add controls
var controls = new THREE.TrackballControls( camera );
controls.target.set( 0, 0, 0 );
// Create a cube
var material =
new THREE.MeshLambertMaterial(
{
color: 0x00bbcc
});
var cube = new THREE.Mesh(
new THREE.CubeGeometry(
40, 55, 30),
material);
scene.add(cube);
// Animation
function renderLoop() {
renderer.render(scene, camera);
controls.update();
window.requestAnimationFrame(renderLoop);
updateTeapot();
}
window.requestAnimationFrame(renderLoop);
////////////////////////////////////////////////
var teapot = null;
var teaPotHeight=0;
loader = new THREE.JSONLoader();
loader.load( "models/utah-teapot.json", function( geometry ) {
teapot = new THREE.Mesh( geometry, new THREE.MeshLambertMaterial({
color: 0x00bb00,
side: THREE.DoubleSide
}));
teapot.scale.set( 20, 20, 20 );
teapot.position = new THREE.Vector3(-30, 100, 20);
function updateTeapot() {
if (teapot != null) {
teaPotHeight+=1;
teapot.position.y = teaPotHeight%200;
}
}
//add it to the scene
scene.add(teapot);
});
}
})(window.lab3 = window.lab3 || {} , jQuery)
Add
teapot.rotation.z = numInRadians;

Creating a particle using an image as a map

I'm having trouble creating a particle using an image as a map on a texture. Below is my code:
var camera, scene, renderer, material, img, texture;
init();
animate();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 8000;
scene.add(camera);
img = new Image();
texture = new THREE.Texture(img);
img.onload = function() {
texture.needsUpdate = true;
makeParticle();
};
img.src = "http://www.aerotwist.com/tutorials/creating-particles-with-three-js/images/particle.png";
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function makeParticle() {
material = new THREE.ParticleBasicMaterial({
color: 0xE60000,
size: 20,
map: texture,
blending: THREE.AdditiveBlending,
transparent: true
});
// make the particle
particle = new THREE.Particle(material);
particle.scale.x = particle.scale.y = 1;
scene.add(particle);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
A fiddle with this code is here: jsfiddle
I am aware I can use the Three Image Helper as follows:
map: THREE.ImageUtils.loadTexture(
"FILE PATH"
),
But I am implementing my own asset loader and so do not wish to use it on an individual basis. Currently my code above shows no errors but no particle is displayed.
The particle is being displayed, but the camera is very far of it.
Change this line:
camera.position.z = 8000;
To something like this:
camera.position.z = 50;

Categories