WebGLとThree.jsを使用した自己学習用のサンプルです。
Last active
October 23, 2016 09:19
-
-
Save sfpgmr/573aae74c3ac996e799e to your computer and use it in GitHub Desktop.
WebGL 0002 回転するタイトル
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>WebGL Test</title> | |
<meta name="keywords" content="WebGL,HTML5,three.js" /> | |
<meta name="description" content="WebGL,HTML5,three.js" /> | |
<meta charset="UTF-8"> | |
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> | |
<script src="http://www.sfpgmr.net/scripts/three/three.js"></script> | |
<script src="http://www.sfpgmr.net/scripts/three/Detector.js"></script> | |
<script src="http://www.sfpgmr.net/scripts/three/stats.min.js"></script> | |
<script type="text/javascript" id="code"> | |
// | |
var textureRoot = 'http://www.sfpgmr.net/test/webgl/data/'; | |
var textureLength = 0; | |
var textureCount = 0; | |
var textureFiles = new Array(0); | |
//var imageLoaded = false; | |
//var ctx; | |
// キー入力 | |
var keyCheck = { up: false, down: false, left: false, right: false, z: false }; | |
var keyBuffer = Array(0); | |
function TextureFile(src,array) { | |
this.src = src; | |
this.array = array; | |
this.loadComplete = false; | |
this.loadError = false; | |
var self = this; | |
this.texture = THREE.ImageUtils.loadTexture(textureRoot + this.src, {}, | |
function (texture) { | |
self.loadComplete = true; | |
if (self.src.match(/\.png/i)) { | |
self.texture.premultiplyAlpha = true; | |
} | |
self.array.loadCompletedCount++; | |
} | |
, | |
function() | |
{ | |
self.loadError = true; | |
} | |
); | |
return this; | |
} | |
// ImageFile.prototype.load = function () { this.image.src = imageRoot + this.src; }; | |
// タスク管理コンストラクタ | |
function Tasks() { | |
this.array = new Array(0); | |
this.needSort = false; | |
return this; | |
} | |
Tasks.prototype = { | |
// indexの位置のタスクを置き換える | |
setNextTask: function (index, func, priority) { | |
if (priority == undefined) { | |
priority = 10000; | |
} | |
func.priority = priority; | |
this.array[index] = func; | |
this.needSort = true; | |
}, | |
pushTask: function (func, priority) { | |
if (priority == undefined) { | |
priority = 10000; | |
} | |
func.priority = priority; | |
for (var i = 0; i < this.length; ++i) { | |
if (this.array[i] == null) { | |
this.array[i] = func; | |
return; | |
} | |
} | |
this.array.push(func); | |
this.needSort = true; | |
}, | |
// 配列を取得する | |
getArray: function () { | |
return this.array; | |
}, | |
// タスクをクリアする | |
clear: function () { | |
this.array.length = 0; | |
}, | |
// ソートが必要かチェックし、ソートする | |
checkSort: function () { | |
if (this.needSort) { | |
this.array.sort(function (a, b) { return a.priority > b.priority; }); | |
needSort = false; | |
} | |
} | |
}; | |
var tasks = new Tasks(); | |
var CONSOLE_WIDTH = 480.0; | |
var CONSOLE_HEIGHT = 640.0; | |
var VIRTUAL_WIDTH = CONSOLE_WIDTH / 2.0; | |
var VIRTUAL_HEIGHT = CONSOLE_HEIGHT / 2.0; | |
var SPRITE_SIZE_X = 16.0; | |
var SPRITE_SIZE_Y = 16.0; | |
var renderer; | |
var stats; | |
var scene; | |
var camera; | |
var mesh; | |
var author; | |
$(window).ready(function () { | |
$('#Start')[0].disabled = true; | |
textureFiles = { | |
loadCompletedCount:0, | |
font: (new TextureFile('Font.png', textureFiles)), | |
font1: (new TextureFile('Font2.png', textureFiles)), | |
author: (new TextureFile('author.png', textureFiles))/*, | |
myship: new ImageFile('myship.png')*/ | |
}; | |
// WebGLのサポートチェック | |
if (!Detector.webgl) { | |
//Detector.addGetWebGLMessage({ parent: $("#content")[0] }); | |
$('#content').text('お使いのブラウザではWebGLはサポートしていないようです。'); | |
return; | |
} | |
$('#source-code').text($('html').html()); | |
// レンダラーの作成 | |
renderer = new THREE.WebGLRenderer({ antialias: true }); | |
renderer.setSize(CONSOLE_WIDTH, CONSOLE_HEIGHT); | |
renderer.setClearColorHex(0x000000, 1); | |
renderer.domElement.id = 'console'; | |
renderer.domElement.className = 'console'; | |
renderer.domElement.style.zIndex = 0; | |
$('#content').append(renderer.domElement); | |
// Stats オブジェクト(FPS表示)の作成表示 | |
stats = new Stats(); | |
stats.domElement.style.position = 'absolute'; | |
stats.domElement.style.top = '0px'; | |
$('#content').append(stats.domElement); | |
stats.domElement.style.left = renderer.domElement.clientWidth - stats.domElement.clientWidth + 'px'; | |
//2D描画コンテキストの表示 | |
/* ctx = $('#info-display').css('z-index', 2); | |
ctx = $('#info-display')[0].getContext('2d'); | |
ctx.setTransform(1, 0, 0, 1, 0, 0); | |
ctx.font = "12px 'MS ゴシック'";*/ | |
// シーンの作成 | |
scene = new THREE.Scene(); | |
// カメラの作成 | |
camera = new THREE.PerspectiveCamera(90.0, CONSOLE_WIDTH / CONSOLE_HEIGHT); | |
camera.position = new THREE.Vector3(0, 0, 240.0 * CONSOLE_HEIGHT / CONSOLE_WIDTH); | |
camera.lookAt(new THREE.Vector3(0, 0, 0)); | |
//var camera = new THREE.Camera(); | |
//camera.position.z = 1.0; | |
// ライトの作成 | |
//var light = new THREE.DirectionalLight(0xffffff); | |
//light.position = new THREE.Vector3(0.577, 0.577, 0.577); | |
//scene.add(light); | |
//var ambient = new THREE.AmbientLight(0xffffff); | |
//scene.add(ambient); | |
// レンダリング | |
var baseTime = +new Date; | |
var d = -0.2; | |
var start = false; | |
function game() { | |
if (start) { | |
requestAnimationFrame(game); | |
} | |
// タスクの呼び出し | |
// メインに描画 | |
try { | |
tasks.checkSort(); | |
$.each(tasks.getArray(), function (taskIndex) { | |
if (this != null) { | |
this(taskIndex); | |
} | |
} | |
); | |
} catch (e) { | |
ExitError(e); | |
} | |
}; | |
renderer.clear(); | |
// エラーで終了する。 | |
function ExitError(e) { | |
//ctx.fillStyle = "red"; | |
//ctx.fillRect(0, 0, CONSOLE_WIDTH, CONSOLE_HEIGHT); | |
//ctx.fillStyle = "white"; | |
//ctx.fillText("Error : " + e, 0, 20); | |
////alert(e); | |
start = false; | |
throw e; | |
} | |
// 開始・停止ボタンの設定 // | |
$('#Start').click(function () { | |
if (!start) { | |
start = true; | |
$('#Start').text('Stop'); | |
tasks.clear(); | |
tasks.pushTask(init); | |
tasks.pushTask(render); | |
game(); | |
} else { | |
start = false; | |
$('#Start').text('Start'); | |
} | |
}); | |
// ソースコード表示ボタンの設定 // | |
$('#Show-Code').click(function () { | |
var code = $('#source-code'); | |
if (code.css('display') == 'none') { | |
code.css('display', 'block'); | |
$('#Show-Code').text('ソース非表示'); | |
} else { | |
code.css('display', 'none'); | |
$('#Show-Code').text('ソース表示'); | |
} | |
}); | |
// キー入力処理 // | |
$(document).keydown(function (e) { | |
if (keyBuffer.length > 16) { | |
keyBuffer.shift(); | |
} | |
keyBuffer.push(e.keyCode); | |
switch (e.keyCode) { | |
case 37: | |
keyCheck.left = true; | |
break; | |
case 38: | |
keyCheck.up = true; | |
break; | |
case 39: | |
keyCheck.right = true; | |
break; | |
case 40: | |
keyCheck.down = true; | |
break; | |
case 90: | |
keyCheck.z = true; | |
break; | |
} | |
}); | |
$(document).keyup(function (e) { | |
switch (e.keyCode) { | |
case 37: | |
keyCheck.left = false; | |
break; | |
case 38: | |
keyCheck.up = false; | |
break; | |
case 39: | |
keyCheck.right = false; | |
break; | |
case 40: | |
keyCheck.down = false; | |
break; | |
case 90: | |
keyCheck.z = false; | |
break; | |
} | |
}); | |
// 表示エリアの調整 // | |
$('#content').height($('#console').height()); | |
$('#content').width($('#console').width()); | |
/* $('#info-display').height($('#console').height()); | |
$('#info-display').width($('#console').width());*/ | |
$('#source-code').width($('#content').width()); | |
$('#source-code').height($('#content').height()); | |
$('#source-code').css('top', $('#navigation').height() + 'px'); | |
// 初期化タスク // | |
function render(taskIndex) { | |
renderer.render(scene, camera); | |
stats.update(); | |
} | |
function init(taskIndex) { | |
scene = new THREE.Scene(); | |
// 物体を作成 | |
{ | |
var canvas = $('<canvas>')[0]; | |
//$('body').append(canvas); | |
var w = textureFiles.author.texture.image.width; | |
var h = textureFiles.author.texture.image.height; | |
canvas.width = w; | |
canvas.height = h; | |
var ctx = canvas.getContext('2d'); | |
ctx.drawImage(textureFiles.author.texture.image, 0, 0); | |
var data = ctx.getImageData(0, 0, w, h); | |
var geometry = new THREE.Geometry(); | |
geometry.vert_start = []; | |
geometry.vert_end = []; | |
{ | |
var i = 0; | |
for (var y = 0; y < h; ++y) { | |
for (var x = 0; x < w; ++x) { | |
var color = new THREE.Color(); | |
var r = data.data[i++]; | |
var g = data.data[i++]; | |
var b = data.data[i++]; | |
var a = data.data[i++]; | |
if (a != 0) { | |
color.setRGB(r / 255.0, g / 255.0, b / 255.0); | |
var vert = new THREE.Vector3(((x - w / 2.0)) * 2.0, ((y - h / 2)) * -2.0, 0.0); | |
var vert2 = new THREE.Vector3(1200 * Math.random() - 600, 1200 * Math.random() - 600, 1200 * Math.random() - 600); | |
geometry.vert_start.push(new THREE.Vector3(vert2.x - vert.x,vert2.y - vert.y,vert2.z - vert.z)); | |
geometry.vertices.push(vert2); | |
geometry.vert_end.push(vert); | |
geometry.colors.push(color); | |
} | |
} | |
} | |
} | |
// マテリアルを作成 | |
//var texture = THREE.ImageUtils.loadTexture('images/particle1.png'); | |
var material = new THREE.ParticleBasicMaterial({ | |
size: 2 , blending: THREE.NormalBlending, | |
transparent: true, vertexColors: true, depthTest: false//, map: texture | |
}); | |
author = new THREE.ParticleSystem(geometry, material); | |
author.position = new THREE.Vector3(0.0, 0.0, 0.0); | |
author.geometry.vertices.length; | |
//mesh.sortParticles = false; | |
//var mesh1 = new THREE.ParticleSystem(); | |
//mesh.scale.x = mesh.scale.y = 8.0; | |
//var material = new THREE.MeshBasicMaterial({ map: textureFiles.author.texture }); | |
////material.shading = THREE.FlatShading; | |
////material.antialias = false; | |
//material.transparent = true; | |
//author = new THREE.Mesh( | |
// new THREE.PlaneGeometry(textureFiles.author.texture.image.width , textureFiles.author.texture.image.height ), | |
// material | |
// ); | |
//author.scale.x = author.scale.y = 2.0; | |
scene.add(author); | |
} | |
tasks.setNextTask(taskIndex, printAuthor()); | |
} | |
// 作者表示 | |
function printAuthor() { | |
var step = 0; | |
var count = 1.0; | |
var wait = 60; | |
var proc_count = 0; | |
keyBuffer.length = 0; | |
return function (taskIndex) { | |
// 何かキー入力があった場合は次のタスクへ | |
//if (keyBuffer.length > 0) { | |
// keyBuffer.length = 0; | |
// step = 4; | |
//} | |
switch (step) { | |
// フェード・イン | |
case 0: | |
if (count <= 0.01) { | |
count -= 0.0005; | |
} else { | |
count -= 0.0025; | |
} | |
if (count < 0.0) { | |
author.rotation.x = author.rotation.y = author.rotation.z = 0.0; | |
var end = author.geometry.vertices.length; | |
for (var i = 0; i < end; ++i) { | |
author.geometry.vertices[i].x = author.geometry.vert_end[i].x; | |
author.geometry.vertices[i].y = author.geometry.vert_end[i].y; | |
author.geometry.vertices[i].z = author.geometry.vert_end[i].z; | |
} | |
author.geometry.verticesNeedUpdate = true; | |
step++; | |
} else { | |
var end = author.geometry.vertices.length; | |
var v = author.geometry.vertices; | |
var d = author.geometry.vert_start; | |
var v2 = author.geometry.vert_end; | |
for (var i = 0; i < end; ++i) { | |
v[i].x = v2[i].x + d[i].x * count; | |
v[i].y = v2[i].y + d[i].y * count; | |
v[i].z = v2[i].z + d[i].z * count; | |
} | |
author.geometry.verticesNeedUpdate = true; | |
author.rotation.x = author.rotation.y = author.rotation.z = count * 4.0; | |
author.material.opacity = 1.0; | |
} | |
break; | |
// 待ち | |
case 1: | |
if (! --wait) step++; | |
break; | |
//フェードアウト | |
case 2: | |
count += 0.05; | |
author.material.opacity = 1.0 - count; | |
if (count >= 1.0) { | |
count = 1.0; | |
wait = 60; | |
step++; | |
} | |
break; | |
// 少し待ち | |
case 3: | |
if (! --wait) { | |
step = 0; | |
wait = 60; | |
//step++; | |
} | |
break; | |
// 次のタスクへ | |
case 4: | |
{ | |
scene.remove(author); | |
// 表示する物体の作成 | |
// 形状データを作成 | |
var color = { | |
'0': new THREE.Color(0x000000), | |
'1': new THREE.Color(0x0000FF), | |
'2': new THREE.Color(0x00FF00), | |
'3': new THREE.Color(0x00FFFF), | |
'4': new THREE.Color(0xFF0000), | |
'5': new THREE.Color(0xFF00FF), | |
'6': new THREE.Color(0xFFFF00), | |
'7': new THREE.Color(0xFFFFFF), | |
'8': new THREE.Color(0x000000), | |
'9': new THREE.Color(0x000080), | |
'A': new THREE.Color(0x008000), | |
'B': new THREE.Color(0x008080), | |
'C': new THREE.Color(0x800000), | |
'D': new THREE.Color(0x800080), | |
'E': new THREE.Color(0x808000), | |
'F': new THREE.Color(0x808080) | |
} | |
var enemy = | |
"0000777777770000" + | |
"0007777777777000" + | |
"0777777777777770" + | |
"7777777777777777" + | |
"7770000770000777" + | |
"7770000770000777" + | |
"7777777777777777" + | |
"0777777777777770" + | |
"0077777777777700" + | |
"0007777777777000" + | |
"0077777777777700" + | |
"0777777777777770" + | |
"7777777007777777" + | |
"7777770000777777" + | |
"7777700000077777" + | |
"0777000000007770"; | |
var my_ship = | |
"00000007F0000000" + | |
"00000007F0000000" + | |
"00000077FF000000" + | |
"0000007198000000" + | |
"000000711F000000" + | |
"0000077198800000" + | |
"000007719F800000" + | |
"0000077778800000" + | |
"00007777FF870000" + | |
"0007777778877000" + | |
"07777777FF877770" + | |
"77777777F8877777" + | |
"77777777F8887777" + | |
"77777777F8887777" + | |
"000077F008880000" + | |
"000044C004C80000"; | |
//var tex = THREE.ImageUtils.loadTexture('test.png'); | |
//{ | |
var geometry = new THREE.Geometry(); | |
var i = 0; | |
for (var y = 0; y < SPRITE_SIZE_Y; ++y) { | |
for (var x = 0; x < SPRITE_SIZE_X; ++x) { | |
var pixel = my_ship.charAt(i++); | |
if (pixel != '0') { | |
geometry.vertices.push(new THREE.Vector3(((x - SPRITE_SIZE_X / 2.0)) * 2.0, ((y - SPRITE_SIZE_Y / 2)) * -2.0, 0.0)); | |
// geometry.vertices.push(new THREE.Vector3((x - SPRITE_SIZE_X / 2) * 2 , -(y - SPRITE_SIZE_Y / 2) * 2 , 0.0)); | |
geometry.colors.push(color[pixel]); | |
} | |
} | |
} | |
// マテリアルを作成 | |
//var texture = THREE.ImageUtils.loadTexture('images/particle1.png'); | |
var material = new THREE.ParticleBasicMaterial({ | |
size: 2 * 8.0, blending: THREE.NoBlending, | |
transparent: true, vertexColors: true, depthTest: false//, map: texture | |
}); | |
mesh = new THREE.ParticleSystem(geometry, material); | |
mesh.position = new THREE.Vector3(-0.0, -0.0, 0.0); | |
mesh.sortParticles = false; | |
//var mesh1 = new THREE.ParticleSystem(); | |
mesh.scale.x = mesh.scale.y = 8.0; | |
//ctx.clearRect(0, 0, CONSOLE_WIDTH, CONSOLE_HEIGHT); | |
scene.add(mesh); | |
tasks.setNextTask(taskIndex, myship_action); | |
} | |
break; | |
} | |
//ctx.fillStyle = "rgba(127,127,0,1.0)"; | |
//ctx.fillRect(0, 0, CONSOLE_WIDTH, CONSOLE_HEIGHT); | |
//var backup = ctx.globalAlpha; | |
//ctx.globalAlpha = count; | |
//ctx.drawImage(imageFiles.font.image, (CONSOLE_WIDTH - imageFiles.font.image.width) / 2, (CONSOLE_HEIGHT - imageFiles.font.image.height) / 2); | |
//ctx.globalAlpha = backup; | |
}; | |
} | |
function myship_action(taskIndex) { | |
var t = (+new Date - baseTime) / 1000; | |
mesh.rotation.z = t * 0.5; | |
} | |
$('#Start')[0].disabled = false; | |
}); | |
</script> | |
<style type="text/css"> | |
.content { | |
width: 640px; | |
position: relative; | |
margin-left: auto; | |
margin-right: auto; | |
margin-top: 0; | |
margin-bottom: 0; | |
padding: 0; | |
border: 0; | |
} | |
.navigation { | |
position: relative; | |
display: block; | |
vertical-align: top; | |
margin-top: 2px; | |
margin-bottom: 2px; | |
} | |
body { | |
padding: 0; | |
border: 0; | |
margin: 0; | |
} | |
nav > button { | |
width: 100px; | |
height: 45px; | |
border: 2px solid rgba(255,0,0,1.0); | |
padding: 2px; | |
margin: 2px; | |
color: rgba(255,0,0,1.0); | |
background: rgba(0,0,0,0); | |
} | |
nav > button:hover { | |
border-color: rgba(255,0,0,1.0); | |
color: rgba(255,0,0,1.0); | |
background: rgba(255,0,0,0.55); | |
} | |
.source-code { | |
position: absolute; | |
display: none; | |
left: 0; | |
padding-top: 0px; | |
margin: 0px; | |
border: 0px; | |
overflow-y: auto; | |
overflow-wrap: break-word; | |
background: rgba(0,0,0,0.5); | |
color: white; | |
font-size: 10px; | |
} | |
.console { | |
margin: 0; | |
padding: 0; | |
border: 0; | |
} | |
.header { | |
position: relative; | |
height: 50px; | |
} | |
.info-display{ | |
position:absolute; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="content" class="content"> | |
<header class="header"> | |
<nav id="navigation" class="navigation"> | |
<button id="Start" title="クリックすると開始・停止">Start</button> | |
<button id="Show-Code" title="ソースコードの表示">ソース表示</button> | |
</nav> | |
</header> | |
<pre id="source-code" class="source-code"> | |
</pre> | |
</div> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment