Using this answer I've been able to assign a points material to a loaded GLTF model.
If I apply the same technique to an animated FBX model, the model loads and points material is assigned but the animation no longer works. Presumably because the technique works by duplicating the mesh.
How can I adapt this technique to include the animation?
Using PointsMaterial for loaded GLTF: (working)
const gltfLoader = new GLTFLoader();
gltfLoader.load( 'models/model.gltf', function ( gltf ) {
model = gltf.scene;
let pointsArray = [];
let v3 = new THREE.Vector3();
model.traverse(child => {
if (child.isMesh){
let pos = child.geometry.attributes.position;
for (let i = 0; i < pos.count; i++){
v3.fromBufferAttribute(pos, i);
pointsArray.push(v3.clone());
}
}
});
let particle_model_geometry = new THREE.BufferGeometry().setFromPoints( pointsArray );
particle_model_geometry.center();
particle_model = new THREE.Points( particle_model_geometry, points_material );
scene.add( particle_model );
render();
} );
Usings PointsMaterial for loaded FBX: (not working)
const loader = new FBXLoader();
loader.load( 'models/model.fbx', function ( object ) {
mixer = new THREE.AnimationMixer( object );
const action = mixer.clipAction( object.animations[ 1 ] );
action.play();
let pointsArray = [];
let v3 = new THREE.Vector3();
object.traverse(child => {
if ( child.isMesh ){
let pos = child.geometry.attributes.position;
for (let i = 0; i < pos.count; i++){
v3.fromBufferAttribute( pos, i );
pointsArray.push( v3.clone() );
}
}
});
let particle_model_geometry = new THREE.BufferGeometry().setFromPoints( pointsArray );
particle_model_geometry.center();
particle_model = new THREE.Points( particle_model_geometry, points_material );
scene.add( particle_model );
} );
I am trying to place particles on each vertex of my OBJ model in Three.js.
The desired result should look something like this
https://codepen.io/consolacao/pen/Cdjmi
The console shows that my OBJ has loaded fine, it can access the attributes of the OBJ model... but nothing shows on the screen
I have tried changing the model, changing from buffer geometry to geometry... with no luck
Can anybody help me?
var manager = new THREE.LoadingManager();
manager.onProgress = function ( item, loaded, total ) {
console.log('webgl, twice??');
console.log( item, loaded, total );
};
var p_geom = new THREE.BufferGeometry();
var p_material = new THREE.PointsMaterial({
color: 0xd48908
});
function loadModel() {
const loader = new OBJLoader(manager);
loader.load ('src/models/faceyface.obj', function (face) {
face.position.y = 10;
face.traverse( function ( child ) {
if (child.isMesh) {
var position = child.geometry.getAttribute('position');
var normal = child.geometry.getAttribute('normal');
for (let i=0; i< position.array.length; i+=3) {
const pos = new THREE.Vector3(position.array[i],
position.array[i+1],
position.array[i+2]);
const norm = new THREE.Vector3(normal.array[i],
normal.array[i+1],
normal.array[i+2]);
p_geom.position.copy(pos);
var particles = new THREE.Points(p_geom,
p_material);
const target =
pos.clone().add(norm.multiplyScalar(10.0));
particles.lookAt(target);
}
scene.add(particles)
}
})
});
}
Here is an example of how you can achieve the desired result:
body{
overflow: hidden;
margin: 0;
}
<script type="module">
import * as THREE from "https://threejs.org/build/three.module.js";
import { OBJLoader } from 'https://threejs.org/examples/jsm/loaders/OBJLoader.js';
import {OrbitControls} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";
let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 0, 35);
let renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0x222222);
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
let controls = new OrbitControls(camera, renderer.domElement);
const loader = new OBJLoader();
loader.load( "https://threejs.org/examples/models/obj/ninja/ninjaHead_Low.obj", function ( group ) {
//console.log(group);
let pts = [];
let v3 = new THREE.Vector3();
group.traverse(child => {
if (child.isMesh){
let pos = child.geometry.attributes.position;
for (let i = 0; i < pos.count; i++){
v3.fromBufferAttribute(pos, i);
pts.push(v3.clone());
}
}
});
let g = new THREE.BufferGeometry().setFromPoints(pts);
g.center();
let m = new THREE.PointsMaterial({color: "aqua", size: 0.25});
let p = new THREE.Points(g, m);
scene.add(p);
} );
renderer.setAnimationLoop(()=>{
renderer.render(scene, camera);
});
</script>
I am trying to recreate Sketchfab's "ambient environment" feature in threejs.
see sketchfab background settings
I want my model in threejs to show a traditional environment map (360 picture of a location), but I want the scene to show a blurred, ambient image as the environement.
I tried loading two cubetextures and applying one to the envMap of the model, and the other to the scene.background:
var loader = new THREE.TextureLoader();
loader.load( "../../image/download/img1.jpg", function ( texture ) {
texture.encoding = THREE.sRGBEncoding;
texture.anisotropy = maxAnisotropy;
var cubemapGenerator = new THREE.EquirectangularToCubeGenerator( texture, { resolution: 512 } );
var cubeMapTexture = cubemapGenerator.update( renderer );
var pmremGenerator = new THREE.PMREMGenerator( cubeMapTexture );
pmremGenerator.update( renderer );
var pmremCubeUVPacker = new THREE.PMREMCubeUVPacker( pmremGenerator.cubeLods );
pmremCubeUVPacker.update( renderer );
envMapCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget;
var envMap = envMapCubeRenderTarget ? envMapCubeRenderTarget.texture : null;
texture.dispose();
pmremGenerator.dispose();
pmremCubeUVPacker.dispose();
object.material.envMap = envMap
var loader2 = new THREE.TextureLoader();
loader2.load( "../../image/download/img2.jpg", function ( texture ) {
texture.encoding = THREE.sRGBEncoding;
texture.anisotropy = maxAnisotropy;
var cubemapGenerator = new THREE.EquirectangularToCubeGenerator( texture, { resolution: 512 } );
envMapBackground = cubemapGenerator.renderTarget;
scene.background = envMapBackground; //old = texture
scene.background.anisotropy = maxAnisotropy;
});
});
When I try to use two cubemaps, my scene just renders a blank background...
I'm trying to add a background to a webgl scene(Three.js). The scene contains two animated spritesheets that I created using DAZ3D and Photoshop. I've tried just about everything but to no avail, the background is either white or black. I've tried many examples on the web then either my spritesheet animator won't work or the background won't appear. I read that I need to make two scenes with two camera's, but that doesn't seem to work as well.
I really don't understand why I would need to have two scenes anyway.
<script>
// standard global variables
var container,scene,camera,renderer,controls,stats;
var keyboard = new THREEx.KeyboardState();
var clock = new THREE.Clock();
// custom global variables
var attack,defense;
init();
animate();
// FUNCTIONS
function init(){
// SCENE
scene = new THREE.Scene();
// CAMERA
var SCREEN_WIDTH = window.innerWidth,SCREEN_HEIGHT = window.innerHeight;
var VIEW_ANGLE = 45,ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT,NEAR = 0.1,FAR = 1000;
var light = new THREE.PointLight(0xEEEEEE);
var lightAmb = new THREE.AmbientLight(0x777777);
camera = new THREE.PerspectiveCamera(VIEW_ANGLE,ASPECT,NEAR,FAR);
scene.add(camera);
camera.position.set(-10,30,400);
camera.lookAt(scene.position);
// RENDERER
if (Detector.webgl)
renderer = new THREE.WebGLRenderer({antialias:true});
else
renderer = new THREE.CanvasRenderer();
renderer.setSize(SCREEN_WIDTH,SCREEN_HEIGHT);
container = document.getElementById('ThreeJS');
container.appendChild(renderer.domElement);
// EVENTS
THREEx.WindowResize(renderer,camera);
THREEx.FullScreen.bindKey({charCode :'m'.charCodeAt(0)});
// LIGHTS
light.position.set(20,0,20);
scene.add(light);
scene.add(lightAmb);
// BACKGROUND
var texture = THREE.ImageUtils.loadTexture('images/sky.jpg');
var backgroundMesh = new THREE.Mesh(new THREE.PlaneGeometry(2,2,0),new THREE.MeshBasicMaterial({map:texture}));
backgroundMesh.material.depthTest = false;
backgroundMesh.material.depthWrite = false;
var backgroundScene = new THREE.Scene();
var backgroundCamera = new THREE.Camera();
backgroundScene.add(backgroundCamera);
backgroundScene.add(backgroundMesh);
// FLOOR
var floorTexture = new THREE.ImageUtils.loadTexture('images/checkerboard.jpg');
floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
floorTexture.repeat.set(10,10);
var floorMaterial = new THREE.MeshBasicMaterial({map:floorTexture,side:THREE.DoubleSide,shininess:30});
var floorGeometry = new THREE.PlaneGeometry(1000,1000);
var floor = new THREE.Mesh(floorGeometry,floorMaterial);
floor.position.y = -0.5;
floor.rotation.x = Math.PI / 2;
scene.add(floor);
// MESHES WITH ANIMATED TEXTURES!
var attackerTexture = new THREE.ImageUtils.loadTexture('images/kitinalevel2.png');
attack = new TextureAnimator(attackerTexture,2,13,26,25); // texture,#horiz,#vert,#total,duration.
var attackerMaterial = new THREE.MeshBasicMaterial({map:attackerTexture,side:THREE.DoubleSide,transparent:true});
var attackerGeometry = new THREE.PlaneGeometry(50,50,1,1);
var attacker = new THREE.Mesh(attackerGeometry,attackerMaterial);
attacker.position.set(-5,20,350);
scene.add(attacker);
var defenderTexture = new THREE.ImageUtils.loadTexture('images/kitinalevel1.png');
defense = new TextureAnimator(defenderTexture,2,13,26,25); // texture,#horiz,#vert,#total,duration.
var defenderMaterial = new THREE.MeshBasicMaterial({map:defenderTexture,side:THREE.DoubleSide,transparent:true});
var defenderGeometry = new THREE.PlaneGeometry(50,50,1,1);
var defenderx = new THREE.Mesh(defenderGeometry,defenderMaterial);
defenderx.position.set(25,20,350);
scene.add(defenderx);
}
function animate(){
requestAnimationFrame(animate);
render();
update();
}
function update(){
var delta = clock.getDelta();
attack.update(1000 * delta);
defense.update(1000 * delta);
//controls.update();
//stats.update();
}
function render(){
renderer.autoClear = false;
renderer.clear();
renderer.render(scene,camera);
renderer.render(backgroundScene,backgroundCamera);
}
function TextureAnimator(texture,tilesHoriz,tilesVert,numTiles,tileDispDuration){
// note:texture passed by reference,will be updated by the update function.
this.tilesHorizontal = tilesHoriz;
this.tilesVertical = tilesVert;
// how many images does this spritesheet contain?
// usually equals tilesHoriz * tilesVert,but not necessarily,
// if there at blank tiles at the bottom of the spritesheet.
this.numberOfTiles = numTiles;
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(1 / this.tilesHorizontal,1 / this.tilesVertical);
// how long should each image be displayed?
this.tileDisplayDuration = tileDispDuration;
// how long has the current image been displayed?
this.currentDisplayTime = 0;
// which image is currently being displayed?
this.currentTile = 0;
this.update = function(milliSec){
this.currentDisplayTime += milliSec;
while(this.currentDisplayTime>this.tileDisplayDuration){
this.currentDisplayTime-=this.tileDisplayDuration;
this.currentTile++;
if (this.currentTile == this.numberOfTiles)
this.currentTile = 0;
var currentColumn = this.currentTile%this.tilesHorizontal;
texture.offset.x = currentColumn/this.tilesHorizontal;
var currentRow = Math.floor(this.currentTile/this.tilesHorizontal);
texture.offset.y = currentRow/this.tilesVertical;
}
};
}
</script>
What am I doing wrong?
Thanks in advance.
Found a solution:
renderer = new THREE.WebGLRenderer({antialias:true,alpha: true });
This will keep the background transparant, then with a little css I made the background appear.
I'm trying apply a simple texture mapping to a cube, but when the texture is applied it's rotated 90° CCW.
Just for my tests I'm using the same uv mapping for all faces:
window.head = function(){
var txSplitX = 1/64;
var txSplitY = 1/32;
var mesh;
var cube = new THREE.CubeGeometry( 100, 100, 100);
var material = new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture('assets/charSkin/Superman.png') } );
var faceTx= [
new THREE.Vector2(0.125,0.75),
new THREE.Vector2(0.25,0.75),
new THREE.Vector2(0.25,0.5),
new THREE.Vector2(0.125,0.5)
];
var j=0, k=1;
for(var i=0; i<6;i++){
cube.faceVertexUvs[0][j] = [faceTx[0],faceTx[1],faceTx[3]];
cube.faceVertexUvs[0][k] = [faceTx[1],faceTx[2],faceTx[3]];
j+=2;
k+=2;
}
this.mesh = new THREE.Mesh(cube, material);
}
The result I have :
http://securilabs.free.fr/images/result.png
My texture :
http://securilabs.free.fr/images/Superman.png
How can I get the correct orientation of the texture on each face ?