3Dカルーセルの作成(Three.js[r145]を使用)
ソースコード
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="./three_r145/three.min.js"></script>
<script>
//X:→ Y:↑ Z:手前、反時計回り
var camera,spot;
var imageFiles=[
'./imgs/fc01.png',
'./imgs/fc02.png',
'./imgs/fc03.png',
'./imgs/fc04.png',
'./imgs/fc05.png',
'./imgs/fc06.png',
];
var imageLinkURL=[
'https://mam-mam.net/javascript/three_js_material.html',
'https://mam-mam.net/javascript/three_js_geometry.html',
'https://mam-mam.net/javascript/three_js_baseball.html',
'https://mam-mam.net/javascript/css_ul_li.html',
'https://mam-mam.net/javascript/css_nav_horizontal_menu.html',
'https://mam-mam.net/javascript/css_toggle_switch.html',
];
var rrr=10,//半径10
rrate=Math.PI/3,//回転角
rrrate=1/rrate*Math.PI/2;
var moveImg=0,act=0,timer=0,moveStep={x:0,y:0,z:0,r:0},mesh=[],
acts=[
{"act":"w","time":120},
{"act":"m","time":30},
];
async function loadImage(src){
return new Promise(function(resolve,reject){
let img=new Image();
img.onload=function(){resolve(img);}
img.onerror=function(e){reject(e);}
img.src=src;
});
}
window.addEventListener( 'DOMContentLoaded', async function(){
var images=[];
var material=[];
var texture=[];
//シーンを作成
scene = new THREE.Scene();
//カメラを作って設定
var width = document.getElementById("can").getAttribute("width");
var height = document.getElementById("can").getAttribute("height");
// 視野角,アスペクト比,近距離,遠距離
camera = new THREE.PerspectiveCamera( 40, width/height, 1, 10000 );
//レンダラーをDOM上に設置する
renderer = new THREE.WebGLRenderer({'canvas':document.getElementById('can') , antialias: true});//アンチエイリアスをtureにする
renderer.setSize( width, height );
renderer.shadowMap.enabled = true;//影可能
renderer.shadowMapSoft = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
document.getElementById('can').style.width="100%";
document.getElementById('can').style.height="auto";
//■背景色の設定
//renderer.setClearColor(0x88ccff, 1);
renderer.setClearColor(0x000000, 1);
//光源------------------------------------------------
//環境光(すべての物体にすべての方向から与える光)これがないと光の当たらない部分は真っ黒になる
var AmbientLight=new THREE.AmbientLight(0xffffff,0.2);
scene.add( AmbientLight );
//画像のロード
images=await Promise.all(imageFiles.map(loadImage));
//テクスチャのロード
for(let i=0;i<imageFiles.length;i++){
texture[i]=new THREE.TextureLoader().load(imageFiles[i]);
material[i]=new THREE.MeshLambertMaterial({
color: 0xffffff, //色
map:texture[i],
side:THREE.DoubleSide, //THREE.DoubleSide, THREE.FrontSide, THREE.BackSide
});
}
//メッシュの作成
for(let i=0;i<texture.length;i++){
let w=10;//w:h=ww:hh h=w*hh/ww
let h=w/images[i].naturalWidth*images[i].naturalHeight;
var plane=new THREE.PlaneGeometry(w, h, 1, 1);
mesh[i]=new THREE.Mesh(plane,material[i]);
mesh[i].position.x=Math.random()*20-10;
mesh[i].position.y=Math.random()*20-10;
mesh[i].position.z=-i*rrr;
mesh[i].rotation.z=Math.random()*Math.PI*2;
mesh[i].castShadow=true;
scene.add(mesh[i]);
}
//スポットライト 色, 強さ,距離(distance),角度(angle),半影[0-1],減衰[1,1.5]
spot=new THREE.SpotLight(0xffffff, 1.5, 24,Math.PI*0.35, 0.8, 1.2);
spot.position.set(0,4,8);
spot.target.position.set(0,-4,0);
spot.castShadow=true;//影を表示可能に
spot.shadow.mapSize.width = 4096; //影をきれいにする
spot.shadow.mapSize.height = 4096; //影をきれいにする
spot.shadow.radius=8;
scene.add(spot);
scene.add(spot.target);
//イベントの追加
renderer.domElement.addEventListener('mouseup',onMouseDown,false);
renderer.domElement.addEventListener('touchend',onMouseDown,false);
//カメラ位置
camera.position.set(mesh[0].position.x,mesh[0].position.y,mesh[0].position.z+rrr/2);
camera.rotation.z=mesh[0].rotation.z;
spot.position.set(mesh[0].position.x,mesh[0].position.y,mesh[0].position.z+rrr/2);
spot.target.position.set(mesh[0].position.x,mesh[0].position.y,mesh[0].position.z);
renderLoop();
});
function renderLoop () {
//シナリオの実行
timer++;
if(timer>=acts[act].time){
timer=0;
act++;
if(act>=acts.length){
act=0;
}
}
if(acts[act].act=="w"){
//待つだけ
}else if(acts[act].act=="m"){
if(timer==0){
let fm=mesh[moveImg];
moveImg++;
if(moveImg>=mesh.length){moveImg=0;}
let tm=mesh[moveImg];
moveStep.x=(fm.position.x-tm.position.x)/acts[act].time;
moveStep.y=(fm.position.y-tm.position.y)/acts[act].time;
moveStep.z=(fm.position.z-tm.position.z)/acts[act].time;
moveStep.r=(fm.rotation.z-tm.rotation.z)/acts[act].time;
}
camera.position.x-=moveStep.x;
camera.position.y-=moveStep.y;
camera.position.z-=moveStep.z;
camera.rotation.z-=moveStep.r;
spot.position.x-=moveStep.x;
spot.position.y-=moveStep.y;
spot.position.z-=moveStep.z;
spot.target.position.x-=moveStep.x;
spot.target.position.y-=moveStep.y;
spot.target.position.z-=moveStep.z;
}
renderer.render( scene, camera );
setTimeout(renderLoop,33);
}
function onMouseDown(event){
event.preventDefault();
// 要素の位置を取得
var clientRect = this.getBoundingClientRect() ;
var positionX = clientRect.left;
var positionY = clientRect.top;
let st=window.getComputedStyle(document.getElementById("can"));
let www=parseInt(st.width);
let hhh=parseInt(st.height);
let xxx,yyy;
if(event.clientX){
xxx= ((event.clientX-positionX) / www) * 2 - 1;
yyy= -((event.clientY-positionY) / hhh) * 2 + 1;
}else{
xxx = ((event.changedTouches[0].pageX-positionX) / www) * 2 - 1;
yyy = -((event.changedTouches[0].pageY-positionY) / hhh) * 2 + 1;
}
var pos=new THREE.Vector3(xxx,yyy,-10);
pos.unproject(camera);
// 始点、向きベクトルを渡してレイを作成
var ray = new THREE.Raycaster(camera.position, pos.sub(camera.position).normalize());
var intersects=ray.intersectObjects(scene.children);
if(intersects.length > 0){
for(i=0;i<mesh.length;i++){
for(j=0;j<intersects.length;j++){
if(mesh[i]==intersects[j].object){
if(imageLinkURL[i]!=""){
window.open(imageLinkURL[i],'_blank');
}
}
}
}
}
}
</script>
</head>
<body>
<canvas id="can" style="width: 100%; height: auto; max-width:calc(100vw - 32px);max-height:calc(100vw - 32px);cursor:pointer;"
width="1000" height="300"></canvas>
</body>
</html>