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 moveImg=0,act=0,timer=0,moveStep=0,mesh=[],
acts=[
{"act":"w","time":120},
{"act":"o","time":10},
{"act":"m","time":30},
{"act":"i","time":10}
];
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( 60, 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(0x444444, 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=i*11;
mesh[i].castShadow=true;
scene.add(mesh[i]);
}
//カメラ位置
camera.position.set(0,0,4);
//camera.lookAt(new THREE.Vector3(0, 0, 0));
//スポットライト 色, 強さ,距離(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);
//背景メッシュの作成
var backMaterial=new THREE.MeshLambertMaterial({
color: 0xffffff, //色
side:THREE.FrontSide, //THREE.DoubleSide, THREE.FrontSide, THREE.BackSide
});
var backPlane=new THREE.PlaneGeometry(imageFiles.length*11+20, 20, 1, 1);
var backMesh=new THREE.Mesh(backPlane,backMaterial);
backMesh.position.z=-3;
backMesh.position.x=imageFiles.length*11/2-10;
backMesh.receiveShadow=true;
scene.add(backMesh);
//イベントの追加
renderer.domElement.addEventListener('mouseup',onMouseDown,false);
renderer.domElement.addEventListener('touchend',onMouseDown,false);
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=="o"){
camera.position.z+=0.5;
spot.position.z+=0.5;
}else if(acts[act].act=="i"){
camera.position.z-=0.5;
spot.position.z-=0.5;
}else if(acts[act].act=="m"){
if(timer==0){
let fromX=mesh[moveImg].position.x;
moveImg++;
if(moveImg>=mesh.length){moveImg=0;}
let toX=mesh[moveImg].position.x;
moveStep=(toX-fromX)/acts[act].time;
}
camera.position.x+=moveStep;
spot.position.x+=moveStep;
spot.target.position.x+=moveStep;
}
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>