About using three.js with ZIM

Hello. I'm trying to use ZIM and threejs these days.
I'm looking at the examples. Which one would be the right one to use? Can you explain the differences between them?

import ZIM from "https://zimjs.org/cdn/015/zim_three"; // includes three.js R155

or
import * as THREE from "https://zimjs.org/cdn/r155/three.module.js";
import {OrbitControls} from "https://zimjs.org/cdn/r155/OrbitControls_module.js";
import ZIM from "https://zimjs.org/cdn/015/zim";

is there a difference?

Also, I think Threex.FullScreen is needed for the second use.

My other questions:
Can we use the model we made with Blender with ZIM and threejs?
Also, can you make a few tutorials starting from very simple?

We just did a few ZIM with three.js videos not too long ago. They should be good. They are listed on the ZIM Three page - I am guessing that you want to scroll down to three.js inside of ZIM section.

image

Just use

import zim from "https://zimjs.org/017/zim_three";

It comes with our latest versions of things and these - these are all quite small.

  • OrbitControls
  • FirstPersonCon{trols
  • PointerLockControls
  • VRButton
  • ObjectControls
  • GLTFLoader

You should be able to bring in Blender models without problem. Save them as GLTF files - raw or binary.

1 Like

Thank you very much

1 Like

Let us know how it goes and if you have any questions. All the best.

I'm just trying to figure it out. I think the way to communicate between ZIM and threejs is textureActives. I think this is the main point. For example, when I want to rotate a threejs object when a ZIM button is clicked, I just learned that I need to add the ZIM button with textureActives.

What I want to do is to create threejs interactions using ZIM buttons or components.

@abstract Why aren't ZIM objects responsive?
When using normal ZIM, ZIM objects grow or shrink according to the screen. This doesn't happen when I use Oyna ZIM and threejs together.


new Frame(FIT, 1440, 800, white, white, ready); There is no difference between making this place "FIT" or "FULL".

With normal ZIM, the canvas tag is being scaled to fit in the window or a tag. With ZIM TextureActive, portions of the canvas tag are being used as a texture on a three.js object. So the scale of the canvas tag does not matter - only the scale that you apply the TextureActive to the texture.

It looks like you are using the Ortho camera for a HUD like effect? Where the interface is overlayed onto the 3D world? If you put the menu inside the 3D world then it will scale with the rest of the scene. If you have it in the Ortho camera then I guess you will have to manually scale it if you need too using window dimensions.

// See Docs under Frame for FIT, FILL, FULL, and TAG
new Frame(FIT, 1440, 800, white, white, ready);
function ready() {

class ButonExtend extends Container {
    
    constructor() {
        
    super();

    this.buton=new Rectangle(220,80,white,black,1,10)
    this.yazı=new Label("Yeni",30,"Arial",black)
        
    this.yaziyiOrtala=function(){
        
        
        this.yazı.x=this.buton.width/2-this.yazı.width/2
        this.yazı.y=this.buton.height/2-this.yazı.height/2;
        
    }
    
    this.yaziyiOrtala()
    
    this.addChild(this.buton,this.yazı)

    }
}


var modellerListesi=[

    ["kup",110],
    ["karePrizma",110],
    ["dikdörtgenlerPrizma",110],
    ["silindir",130],
]

var modelSirasi=0
var animasyonKareSayisi=110

// butonlarTextureActive
const butonlarTextureActive = new TextureActive(500,700,clear)


const kupButon = new ButonExtend()
kupButon.yazı.text="Küp"
kupButon.yaziyiOrtala()
new createjs.ButtonHelper(kupButon)

const karePrizmaButon = new ButonExtend()
karePrizmaButon.yazı.text="Kare Prizma"
karePrizmaButon.yaziyiOrtala()
new createjs.ButtonHelper(karePrizmaButon)

const dikDortgenPrizmaButon = new ButonExtend()
dikDortgenPrizmaButon.yazı.text="Dikdörtgenler \nPrizması"
dikDortgenPrizmaButon.yaziyiOrtala()
new createjs.ButtonHelper(dikDortgenPrizmaButon)

const silindirButon = new ButonExtend()
silindirButon.yazı.text="Silindir"
silindirButon.yaziyiOrtala()
new createjs.ButtonHelper(silindirButon)

var elemanWindowListesi=[kupButon,karePrizmaButon,dikDortgenPrizmaButon,silindirButon]

for(var i=0; i<elemanWindowListesi.length; i++){

    elemanWindowListesi[i].addEventListener("mousedown",butonlaraTiklandi)
    elemanWindowListesi[i].name=modellerListesi[i][0]
}


const list = new List({
    width:450, 
    height:550,
    color:"red",
    backdropColor:"#F4F6F6", ////// Listenin en arkadaki rengini değiştirir....
    backgroundColor:"#00ADB5", ///// liste arka plan rengi
    list:elemanWindowListesi,
   
 }).center(butonlarTextureActive)
 .scaleTo(butonlarTextureActive,100,100)



function butonlaraTiklandi(e){
    
    slider.currentValue=0


    var indexmModel=elemanWindowListesi.indexOf(e.currentTarget)
    

    modelEkle(modellerListesi[indexmModel][0])
    animasyonKareSayisi=modellerListesi[indexmModel][1]
    
}

// sliderTextureActive 
const sliderTextureActive = new TextureActive({
    width:500,
    height:100,
    color:blue.toAlpha(.1),
    color2:blue.toAlpha(.5),
    angle:90,
    borderColor:white,
    borderWidth:3,
    backingOrbit:false
});   

// warning triangle
new Triangle(sliderTextureActive.width*.7, sliderTextureActive.height*.7, -1, "red".toAlpha(.4), null, null, [0,8,6])
    .pos(15,0,RIGHT,CENTER,sliderTextureActive);

const slider = new Slider({
    min:0,
    max:135,
    step:1,
    barColor:light,
    currentValue:0,
    button:"circle"
})
    .scaleTo(sliderTextureActive,90,80)
    .center(sliderTextureActive)       
    .change(()=>{

        let value = slider.currentValue/animasyonKareSayisi; // Slider'ı 0-1 arasına dönüştür
        
        // if (mixer && action) {
        //     console.log(value)
        //     action.paused = false; // Animasyonu kontrol etmek için duraklat
        //     mixer.setTime(value * duration); // Animasyonu belirli bir kareye al
        // }

        // action.paused = true;

        if (mixer && action) {

            action.paused = false;
            if (value >= 0.99) {
                value=0.99

            }
    
            mixer.setTime(value * duration); // Animasyonu ilgili kareye taşı
            mixer.update(0.01); // Güncelleme yap, böylece kare sıfırlanmaz
        }
        action.paused = true;



        

        
    });


 // POSITION 
 const positions = [{x:150,y:150,z:300}, {x:0,y:0,z:150}, {x:-20,y:800,z:50}];
 const position = new TextureActive(300, 100, clear);
 const tabs = new Tabs({ 
    tabs:[1,2,3], 
    bgColor:black.toAlpha(.8), 
    color:white, 
    selectedBgColor:white.toAlpha(.8), 
    selectedColor:black, 
    rollBgColor:pink.toAlpha(.8), 
    spacing:15, 
    corner:[30,0,30,0],
    currentEnabled:true
})
    .scaleTo(position,100,100)
    .center(position)
    .change(()=>{
        let p = positions[tabs.selectedIndex];
        animate({
            target:camera,
            props:{
                "position.x":p.x,
                "position.y":p.y,
                "position.z":p.z
            },       
            animateCall:()=>{camera.lookAt(0,0,0);}
        });
        
    });


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// THREEJS

// Three() comes from the ZIM three helper module
// to make renderer, scene and camera 
// Traditionally, this module helps bring threejs into ZIM ;-) 
// but we can still use the module to help make setting up easier
// It also comes with OrbitControls, FirstPersonControls and GLTFLoader
// This is optional - see https://zimjs.com/015/textureActive_raw.html for without Three()

const three = new Three({
    width:window.innerWidth, 
    height:window.innerHeight, 
    //cameraPosition:new THREE.Vector3(150,150,300),
    cameraPosition:new THREE.Vector3(100,250,250),
    ortho:true,
    textureActive:true,
    colorManagement:true
});

const scene = three.scene;
const camera = three.camera;
const renderer = three.renderer;

// for HUD
const sceneOrtho = three.sceneOrtho;
const cameraOrtho = three.cameraOrtho;


// SKYBOX
const skyTexture = new THREE.TextureLoader().load("assets/manzaraArkaPlan.png");
const skyBoxGeometry = new THREE.SphereGeometry(100000, 32, 32);
const skyBoxMaterial = new THREE.MeshBasicMaterial({map:skyTexture, side:THREE.BackSide});
const skyBox = new THREE.Mesh(skyBoxGeometry, skyBoxMaterial);
scene.add(skyBox);

// GLTFLoader ile model yükleme
const loader = new GLTFLoader();




var model;
var modelYuklendi=false
var duration;

let animasyonBitti = false;

function modelEkle(modelAdi){

    loader.load("assets/"+modelAdi+".glb", (gltf) => {

        scene.remove(model)

        model = gltf.scene;
        scene.add(model);

        model.position.set(0, 0, 0); // Modeli sahnede konumlandır
        model.scale.set(40, 40, 40); // Modeli sahnede konumlandır
        modelYuklendi=true

        if(modelYuklendi){

            setupAnimation(model, gltf)

            
        }

    }, undefined, (error) => {
        console.error('Model yüklenirken hata oluştu:', error);
    });


}

modelEkle("kup")



let mixer;
let action;
let animationPlaying = false; // Animasyonun oynayıp oynamadığını kontrol eden değişken

// GLTF Model Yüklendiğinde Çalışacak Fonksiyon
function setupAnimation(model, gltf) {

    mixer = new THREE.AnimationMixer(model);
    const clip = gltf.animations[0]; // İlk animasyonu seç
    action = mixer.clipAction(clip);

    //action.setLoop(THREE.LoopOnce, 1); // Sadece bir kez oynat
    //action.clampWhenFinished = true;   // Bittiğinde son karede kal
    duration = clip.duration;

    action.play(); // Animasyonu başlat ama ilerlemesini istemiyoruz
    mixer.setTime(0); // Animasyonu başa al
    action.paused = true; // Animasyonu durdur


}




const clock =new THREE.Clock()

function animate() {

    
    requestAnimationFrame(animate);
    //renderer.render(scene, camera);
    

    if(modelYuklendi){

        //mixer.update(clock.getDelta())

        let delta = clock.getDelta(); // Zaman farkını hesapla
        mixer.update(delta); // Animasyonu güncelle


        //model.rotation.y+=.005
    }
    
}

animate();

// CONTROLS
// https://threejs.org/docs/#examples/en/controls/OrbitControls
const controls = new OrbitControls(camera, three.canvas);
controls.enableDamping = true;
controls.dampingFactor = 0.1;
three.preRender = ()=>{controls.update();}




// animate will add a rate property which can be used to control the animation rate - 1 is normal, 2 is twice as fast, etc.


// LIGHTS 
// do not use the variable, light, as it will overwrite ZIM color light
// you can force zim namespace with zns=true in a script before loading ZIM
// but it is annoying to put zim.Frame, zim.Circle, zim.red, etc.
// Also see https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733
// Also, if using a SpotLight then set the decay = 0

const light1 = new THREE.DirectionalLight(0xffffff, 1*Math.PI);
light1.position.set(100,200,100);
scene.add(light1);

const light2 = new THREE.AmbientLight(0xffffff, .5*Math.PI);
scene.add(light2);


// TEXTUREACTIVES
// Create manager for TextureActive objects - see https://zimjs.com/docs.html?item=TextureActives
// use the t key to toggle to the actual ZIM canvas - can prevent this with toggleKey:-1 or choose another key
// Note we optionally set the active layer to 1 so that means we need to match the layer when adding meshes later on
// Parameters are actives, threejs, zimThree, renderer, scene, camera, controls, layers, near, far, ignoreList, toggleKey

const textureActivesOrtho = new TextureActives([sliderTextureActive, butonlarTextureActive, position], THREE, three, renderer, sceneOrtho, cameraOrtho, controls, 1);
// textureActivesOrtho.manager.toggleKey = -1; // turn off the toggle key


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SCENEORTHO - TextureActive work on sceneOrtho with HUD

// HUD 
// When TextureActive is to be mapped on a Plane, we can use the ZIM Three makePanel() method 
// Parameters are textureActive, textureActives, scale (default .5), curve, opacity, material, butonlarTextureActivepace
// If the TextureActives object has layers set, the mesh layer automatically will match the first layer set

// pos() has x, y, horizontal, vertical, gutter parameters
// with gutter being the minimum the left and right will squeeze together (to prevent crossing one another)



// Add HUD to group so can easily remove and add with HUD CheckBox
const hud = new THREE.Group();
sceneOrtho.add(hud);

    // butonlarTextureActive 
    const HUD_butonlarTextureActive = three.makePanel(butonlarTextureActive, textureActivesOrtho).pos(0,0,LEFT,TOP);
    hud.add(HUD_butonlarTextureActive); 

    // sliderTextureActive 
    const HUD_sliderTextureActive = three.makePanel(sliderTextureActive, textureActivesOrtho).pos(35,35,LEFT,BOTTOM,600);
    hud.add(HUD_sliderTextureActive); 

    // POSITION 
    const HUD_position = three.makePanel(position, textureActivesOrtho).pos(35,35,RIGHT,TOP,500);
    //hud.add(HUD_position); 



// THROTTLE TEST
// on some older mobiles updating the cache constantly can bog at 60 fps
let fps; const fpsT = Ticker.add(()=>{fps = Ticker.getFPS();});
timeout(2, ()=>{if (fps < 50) {Ticker.setFPS(30);}; Ticker.remove(fpsT);});

}

My code is as above. My aim is to control threejs objects using features like ZIM slider, list. It is enough for me if ZIM objects are responsive. Is there an example for this?

waauw looks very cool!
can I test it somewhere?
thanks

Another situation is that the threejs screen I created with ZIM threejs cannot be zoomed on the phone. On the computer, the mouse wheel zooms in. However, on the phone, zooming in is not possible with two fingers. The scene created with threejs alone can be zoomed in.
I made the ZIM objects responsive as in the example below. I made the three objects as in the middle. However, zooming in is not possible on the phone.
https://dersekranda.com/3dTest/geometrikCisimlerSimulasyon2/

That is kind-of good news. We always thought something was wrong with orbitControls pinch to zoom on mobile. If it works with normal three.js then it must be something to do with ZIM that is causing it to break. Will look into it.

I don't get orbitcontrols with raw three.js pinch zooming. There does not seem to be a setting for it. When you use two fingers it can do any of these:

Not that for some reason, zoom is not there. It does nothing if you try DOLLY_ZOOM or ZOOM.

I have hunted all over for the last half hour and it is very frustrating. I can't find a proper answer. This happened to me the last time I tried solving this.

I suspect that maybe I am missing something - I see posts like this:

and it is very frustrating as we want to zoom - so why is it acting like it already zooms when it does not.

I am testing here:

https://zimjs.com/three/basics.html

That does not pinch zoom for you right? It pinch pans.

When I try to zoom, it tries to rotate. I wonder if the zoom code and rotate code are mixed up? As boolean values.

Well... that is raw three.js - nothing to do with ZIM. I just do not think orbitcontrols zooms on mobile - which is ridiculous. it rotates with one finger and pans with two fingers. The zoom would not be the same as your normal pinch and zoom - it would rather zoom the camera towards and away from its target - the center unless specified. But that would probably be okay.

You could easily zoom with a slider for instance.

const slider = new Slider({min:1, max:3})
   .center()
   .change(()=>{camera.zoom=slider.value})

We will ask on the three.js forum to make sure that we are not missing anything.

https://dersekranda.com/3dTest/gunesSistemiUcretsizTexture/index.html The link above was made with just threejs and orbitcontrols. And you can zoom in on mobile.

Beautiful. Looked at it and can't figure out the difference. I adjusted the controls the same way - added the resize code at the bottom - I don't think it would matter and it did not make a difference. Ours still does not zoom. It was good to see that theirs zoomed and panned with 2 fingers. Ours just pans. But at least the zoom does not replace the pan.

So will now try and get the same versions of orbitControls - ours is not too out of date... just a few versions, I can't imagine something as stable as orbitcontrols will have changed, but there must be something.

Okay - it was in our orbitcontrols. We adjusted some things for ZIM and they must affect the zoom. So will dig into that and fix it. When we were testing we brought in an orbitControls from three.js and thought we used that... which maybe we did - and it did not work. But when we used their version, it does. So we should be able to figure out why.

1 Like

Thank you. I managed to add slider with html elements and control threejs objects. But when html elements are responsive, it doesn't look good. For this, I want to control with ZIM. Today, I compared the original orbitControls code with the ZIM orbitControls code. There are differences. But I didn't understand much.

https://dersekranda.com/3dTest/OrbitControls.js
https://dersekranda.com/3dTest/OrbitControls_module.js