v1.0.1 commit.

This is the first commit.
This commit is contained in:
Thibaut Despoulain
2012-10-05 15:10:45 +02:00
parent a14fd2d07d
commit 9197e88e46
86 changed files with 8368 additions and 2 deletions
+149
View File
@@ -0,0 +1,149 @@
/*!
* @class bkcore.ImageData
*
* Loads an image and gives access to pixel data.
*
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
*/
/*!
* @package bkcore
*/
var bkcore = bkcore || {};
/*!
* Creates a new ImageData object
*
* @param path String The path of the image
* @param callback Function A callback function to be called once th eimage is loaded
*/
bkcore.ImageData = function(path, callback)
{
var self = this;
this.image = new Image();
this.pixels = null;
this.canvas = null;
this.loaded = false;
this.image.onload = function() {
self.canvas = document.createElement('canvas');
self.canvas.width = self.image.width;
self.canvas.height = self.image.height;
var context = self.canvas.getContext('2d');
context.drawImage(self.image, 0, 0);
self.pixels = context.getImageData(0, 0, self.canvas.width, self.canvas.height);
self.loaded = true;
context = null;
self.canvas = null;
self.image = null;
if(callback) callback.call(self);
};
this.image.crossOrigin = "anonymous";
this.image.src = path;
};
/*!
* Gets pixel RGBA data at given index
*
* @param x int In pixels
* @param y int In pixels
* @return Object{r,g,b,a}
*/
bkcore.ImageData.prototype.getPixel = function(x, y)
{
if(this.pixels == null
|| x < 0
|| y < 0
|| x >= this.pixels.width
|| y >= this.pixels.height)
return {r: 0, g: 0, b: 0, a:0};
var index = (y*this.pixels.width + x) * 4;
return {
r: this.pixels.data[index],
g: this.pixels.data[index + 1],
b: this.pixels.data[index + 2],
a: this.pixels.data[index + 3]
};
};
/*!
* Gets pixel RGBA data at given float index using bilinear interpolation
*
* @param x float In subpixels
* @param y float In subpixels
* @return Object{r,g,b,a}
*/
bkcore.ImageData.prototype.getPixelBilinear = function(fx, fy)
{
var x = Math.floor(fx);
var y = Math.floor(fy);
var rx = fx - x - .5;
var ry = fy - y - .5;
var ax = Math.abs(rx);
var ay = Math.abs(ry);
var c, cxy, cx, cy, cf1, cf2;
var dx = rx < 0 ? -1 : 1;
var dy = ry < 0 ? -1 : 1;
c = this.getPixel(x, y);
cx = this.getPixel(x+dx, y);
cy = this.getPixel(x, y+dy);
cxy = this.getPixel(x+dx, y+dy);
cf1 = [
(1-ax) * c.r + ax * cx.r,
(1-ax) * c.g + ax * cx.g,
(1-ax) * c.b + ax * cx.b,
(1-ax) * c.a + ax * cx.a
];
cf2 = [
(1-ax) * cy.r + ax * cxy.r,
(1-ax) * cy.g + ax * cxy.g,
(1-ax) * cy.b + ax * cxy.b,
(1-ax) * cy.a + ax * cxy.a
];
return {
r: (1-ay) * cf1[0] + ay * cf2[0],
g: (1-ay) * cf1[1] + ay * cf2[1],
b: (1-ay) * cf1[2] + ay * cf2[2],
a: (1-ay) * cf1[3] + ay * cf2[3]
};
}
/*!
* Gets pixel data at given index
* as 3-bytes integer (for floating-point textures erzats, from RGB values)
*
* @param x int In pixels
* @param y int In pixels
* @return int (R + G*255 + B*255*255)
*/
bkcore.ImageData.prototype.getPixelF = function(x, y)
{
var color = this.getPixel(x, y);
return color.r + color.g * 255 + color.b * 255 * 255;
};
/*!
* Gets pixel data at given float index using bilinear interpolationas
* as 3-bytes integer (for floating-point textures erzats, from RGB values)
*
* @param x float In subpixels
* @param y float In subpixels
* @return Object{r,g,b,a}
*/
bkcore.ImageData.prototype.getPixelFBilinear = function(fx, fy)
{
var color = this.getPixelBilinear(fx, fy);
return color.r + color.g * 255.0 + color.b * 255.0 * 255.0;
}
+123
View File
@@ -0,0 +1,123 @@
/*!
* @class bkcore.Timer
*
* new Date().getTime() wrapper to use as timers.
*
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
*/
/*!
* @package bkcore
*/
var bkcore = bkcore || {};
/*!
* Creates a new timer, inactive by default.
* Call Timer.start() to activate.
*/
bkcore.Timer = function()
{
this.time = {
start: 0,
current: 0,
previous: 0,
elapsed: 0,
delta: 0
}
this.active = false;
}
/*!
* Starts/restarts the timer.
*/
bkcore.Timer.prototype.start = function()
{
var now = new Date().getTime();
this.time.start = now;
this.time.current = now;
this.time.previous = now;
this.time.elapsed = 0;
this.time.delta = 0;
this.active = true;
}
/*!
* Pauses(true)/Unpauses(false) the timer.
*
* @param bool Do pause
*/
bkcore.Timer.prototype.pause = function(bool)
{
this.active = !bool;
}
/*!
* Update method to be called inside a RAF loop
*/
bkcore.Timer.prototype.update = function()
{
if(!this.active) return;
var now = new Date().getTime();
this.time.current = now;
this.time.elapsed = this.time.current - this.time.start;
this.time.delta = now - this.time.previous;
this.time.previous = now;
}
/*!
* Returns a formatted version of the current elapsed time using msToTime().
*
*
*/
bkcore.Timer.prototype.getElapsedTime = function()
{
return bkcore.Timer.msToTime(this.time.elapsed);
}
/*!
* Formats a millisecond integer into a h/m/s/ms object
*
* @param x int In milliseconds
* @return Object{h,m,s,ms}
*/
bkcore.Timer.msToTime = function(t)
{
var ms, s, m, h;
ms = t%1000;
s = Math.floor((t/1000)%60);
m = Math.floor((t/60000)%60);
h = Math.floor((t/3600000));
return {h:h, m:m, s:s, ms:ms};
}
/*!
* Formats a millisecond integer into a h/m/s/ms object with prefix zeros
*
* @param x int In milliseconds
* @return Object<string>{h,m,s,ms}
*/
bkcore.Timer.msToTimeString = function(t)
{
var ms, s, m, h;
ms = t%1000;
if(ms < 10) ms = "00"+ms;
else if(ms < 100) ms = "0"+ms;
s = Math.floor((t/1000)%60);
if(s < 10) s = "0"+s;
m = Math.floor((t/60000)%60);
h = Math.floor((t/3600000));
return {h:h, m:m, s:s, ms:ms};
}
+197
View File
@@ -0,0 +1,197 @@
/*!
* @class bkcore.Timer
*
* new Date().getTime() wrapper to use as timers.
*
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
*/
/*!
* @package bkcore
*/
var bkcore = bkcore || {};
bkcore.Utils = {};
/**
* Creates a bkcore.threejs.Shaders[ "normalV" | "normal" ] material with given parameters
*/
bkcore.Utils.createNormalMaterial = function(opts)
{
var shader = bkcore.threejs.Shaders[ opts.perPixel==false ? "normalV" : "normal" ];
var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
uniforms[ "enableDiffuse" ].value = true;
uniforms[ "enableSpecular" ].value = true;
uniforms[ "enableReflection" ].value = (opts.cube != undefined);
uniforms[ "tNormal" ].texture = opts.normal;
uniforms[ "tDiffuse" ].texture = opts.diffuse;
uniforms[ "tSpecular" ].texture = opts.specular;
uniforms[ "uAmbientColor" ].value.setHex(opts.ambient == undefined ? 0x444444 : opts.ambient);
uniforms[ "uAmbientColor" ].value.convertGammaToLinear();
uniforms[ "uNormalScale" ].value = opts.normalScale == undefined ? 1.0 : opts.normalScale;
if(opts.cube != undefined)
{
uniforms[ "tCube" ].texture = opts.cube;
uniforms[ "uReflectivity" ].value = opts.reflectivity == undefined ? 0.9 : opts.reflectivity;
}
uniforms[ "uShininess" ].value = opts.shininess == undefined ? 42 : opts.shininess;
var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: false };
var material = new THREE.ShaderMaterial( parameters );
material.perPixel = true;
material.metal = opts.metal == undefined ? false : opts.metal;
return material;
}
/**
* Projects an object origin vector to screen using given camera
* @param THREE.Object3D object The object which origin you want to project
* @param THREE.Camera camera The camera of the projection
* @return THEE.Vector3 Projected verctor
*/
bkcore.Utils.projectOnScreen = function(object, camera)
{
var mat = new THREE.Matrix4();
mat.multiply( camera.matrixWorldInverse, object.matrixWorld);
mat.multiply( camera.projectionMatrix , mat);
var c = mat.n44;
var lPos = new THREE.Vector3(mat.n14/c, mat.n24/c, mat.n34/c);
lPos.multiplyScalar(0.5);
lPos.addScalar(0.5);
return lPos;
}
bkcore.Utils.URLParameters = null;
/**
* Get an url parameter
* @param String name Parameter slug
* @return Mixed
*/
bkcore.Utils.getURLParameter = function(name)
{
if(bkcore.Utils.URLParameters == null)
{
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi,
function(m,key,value) {
vars[key] = value;
}
);
bkcore.Utils.URLParameters = vars;
}
return bkcore.Utils.URLParameters[name];
}
bkcore.Utils.getOffsetTop = function(obj)
{
var curtop = 0;
if (obj.offsetParent) {
do {
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
}
else
{
curtop = obj.offsetTop;
}
return [curtop];
}
/**
* Scrolls page to given element id
* @param string id The ID of the element
*/
bkcore.Utils.scrollTo = function(id)
{
window.scroll(
0,
bkcore.Utils.getOffsetTop(
document.getElementById(id)
)
);
}
/**
* Add or remove a class from an element
* @param string id [description]
* @param string cssclass [description]
* @param bool active [description]
*/
bkcore.Utils.updateClass = function(id, cssclass, active)
{
var element = document.getElementById(id);
if(active)
element.classList.add(cssclass);
else
element.classList.remove(cssclass);
}
/**
* PErforms an XMLHttpRequest
* @param string url [description]
* @param bool postData true = POST, false = GET
* @param {Function} callback [description]
* @param {Object} data [description]
*/
bkcore.Utils.request = function(url, postData, callback, data)
{
var XMLHttpFactories = [
function () {return new XMLHttpRequest()},
function () {return new ActiveXObject("Msxml2.XMLHTTP")},
function () {return new ActiveXObject("Msxml3.XMLHTTP")},
function () {return new ActiveXObject("Microsoft.XMLHTTP")}
];
function createXMLHTTPObject() {
var xmlhttp = false;
for (var i=0;i<XMLHttpFactories.length;i++) {
try {
xmlhttp = XMLHttpFactories[i]();
}
catch (e) {
continue;
}
break;
}
return xmlhttp;
}
var req = createXMLHTTPObject();
if (!req) return;
var method = (postData) ? "POST" : "GET";
var qdata = "o=bk";
if(data != undefined) for(var i in data)
{
qdata += "&"+i+"="+data[i];
if(!postData) url += "?"+qdata;
}
req.open(method,url,true);
if(postData)
req.setRequestHeader('Content-type','application/x-www-form-urlencoded');
req.onreadystatechange = function () {
if (req.readyState != 4) return;
if (req.status != 200 && req.status != 304) {
return;
}
callback(req);
}
req.send(qdata);
}
+50
View File
@@ -0,0 +1,50 @@
/*
* HexGL
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
*/
var bkcore = bkcore || {};
bkcore.hexgl = bkcore.hexgl || {};
bkcore.hexgl.CameraChase = function(opts)
{
this.dir = new THREE.Vector3(0,0,1);
this.up = new THREE.Vector3(0,1,0);
this.target = new THREE.Vector3();
this.speedOffset = 0;
this.speedOffsetMax = 10;
this.speedOffsetStep = 0.05;
this.camera = opts.camera;
this.targetObject = opts.target;
this.cameraCube = opts.cameraCube == undefined ? null : opts.cameraCube;
this.yoffset = opts.yoffest == undefined ? 8.0 : opts.yoffest;
this.zoffset = opts.zoffset == undefined ? 10.0 : opts.zoffset;
this.viewOffset = opts.viewOffset == undefined ? 10.0 : opts.viewOffset;
this.lerp = opts.lerp == undefined ? 0.5 : opts.lerp;
}
bkcore.hexgl.CameraChase.prototype.update = function(dt, ratio)
{
this.dir.set(0,0,1);
this.up.set(0,1,0);
this.targetObject.matrix.rotateAxis(this.up);
this.targetObject.matrix.rotateAxis(this.dir);
this.speedOffset += (this.speedOffsetMax*ratio - this.speedOffset) * Math.min(1, 0.3*dt);
this.target.copy(this.targetObject.position);
this.target.subSelf(this.dir.multiplyScalar(this.zoffset + this.speedOffset));
this.target.addSelf(this.up.multiplyScalar(this.yoffset));
this.target.y += -this.up.y + this.yoffset;
this.camera.position.copy(this.target, this.lerp);
this.camera.lookAt(this.dir.normalize().multiplyScalar(this.viewOffset).addSelf(this.targetObject.position));
if(this.cameraCube != null)
this.cameraCube.rotation.copy(this.camera.rotation);
}
+190
View File
@@ -0,0 +1,190 @@
/*
* HexGL
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
*/
var bkcore = bkcore || {};
bkcore.hexgl = bkcore.hexgl || {};
bkcore.hexgl.Gameplay = function(opts)
{
var self = this;
this.startDelay = 1000;
this.countDownDelay = 1500;
this.active = false;
this.timer = new bkcore.Timer();
this.modes = {
'timeattack':null,
'survival':null,
'replay':null
};
this.mode = opts.mode == undefined || !(opts.mode in this.modes) ? "timeattack" : opts.mode;
this.step = 0;
this.hud = opts.hud;
this.shipControls = opts.shipControls;
this.track = opts.track;
this.analyser = opts.analyser;
this.pixelRatio = opts.pixelRatio;
this.previousCheckPoint = -1;
this.results = {
FINISH: 1,
DESTROYED: 2,
WRONGWAY: 3,
NONE: -1
};
this.result = this.results.NONE;
this.lap = 1;
this.lapTimes = [];
this.lapTimeElapsed = 0;
this.maxLaps = 3;
this.score = null;
this.finishTime = null;
this.onFinish = opts.onFinish == undefined ? function(){console.log("FINISH");} : opts.onFinish;
this.modes.timeattack = function()
{
self.hud.updateTime(self.timer.getElapsedTime());
var cp = self.checkPoint();
if(cp == self.track.checkpoints.start && self.previousCheckPoint == self.track.checkpoints.last)
{
self.previousCheckPoint = cp;
var t = self.timer.time.elapsed;
self.lapTimes.push(t - self.lapTimeElapsed);
self.lapTimeElapsed = t;
if(self.lap == this.maxLaps)
{
self.end(self.results.FINISH);
}
else
{
self.lap++;
self.hud.updateLap(self.lap, self.maxLaps);
if(self.lap == self.maxLaps)
self.hud.display("Final lap", 0.5);
}
}
else if(cp != -1 && cp != self.previousCheckPoint)
{
self.previousCheckPoint = cp;
//self.hud.display("Checkpoint", 0.5);
}
if(self.shipControls.destroyed == true)
{
self.end(self.results.DESTROYED);
}
}
}
bkcore.hexgl.Gameplay.prototype.simu = function()
{
this.lapTimes = [92300, 91250, 90365];
this.finishTime = this.lapTimes[0]+this.lapTimes[1]+this.lapTimes[2];
this.hud.display("Finish");
this.step = 100;
this.result = this.results.FINISH;
this.shipControls.active = false;
}
bkcore.hexgl.Gameplay.prototype.start = function()
{
this.finishTime = null;
this.score = null;
this.lap = 1;
this.shipControls.reset(this.track.spawn, this.track.spawnRotation);
this.shipControls.active = false;
this.previousCheckPoint = this.track.checkpoints.start;
this.active = true;
this.step = 0;
this.timer.start();
this.hud.resetTime();
this.hud.display("Get ready", 1);
this.hud.updateLap(this.lap, this.maxLaps);
}
bkcore.hexgl.Gameplay.prototype.end = function(result)
{
this.score = this.timer.getElapsedTime();
this.finishTime = this.timer.time.elapsed;
this.timer.start();
this.result = result;
this.shipControls.active = false;
if(result == this.results.FINISH)
{
this.hud.display("Finish");
this.step = 100;
}
else if(result == this.results.DESTROYED)
{
this.hud.display("Destroyed");
this.step = 100;
}
}
bkcore.hexgl.Gameplay.prototype.update = function()
{
if(!this.active) return;
this.timer.update();
if(this.step == 0 && this.timer.time.elapsed >= this.countDownDelay+this.startDelay)
{
this.hud.display("3");
this.step = 1;
}
else if(this.step == 1 && this.timer.time.elapsed >= 2*this.countDownDelay+this.startDelay)
{
this.hud.display("2");
this.step = 2;
}
else if(this.step == 2 && this.timer.time.elapsed >= 3*this.countDownDelay+this.startDelay)
{
this.hud.display("1");
this.step = 3;
}
else if(this.step == 3 && this.timer.time.elapsed >= 4*this.countDownDelay+this.startDelay)
{
this.hud.display("Go", 0.5);
this.step = 4;
this.timer.start();
this.shipControls.active = true;
}
else if(this.step == 4)
{
this.modes[this.mode].call(this);
}
else if(this.step == 100 && this.timer.time.elapsed >= 2000)
{
this.active = false;
this.onFinish.call(this);
}
}
bkcore.hexgl.Gameplay.prototype.checkPoint = function()
{
var x = Math.round(this.analyser.pixels.width/2 + this.shipControls.dummy.position.x * this.pixelRatio);
var z = Math.round(this.analyser.pixels.height/2 + this.shipControls.dummy.position.z * this.pixelRatio);
var color = this.analyser.getPixel(x, z);
if(color.r == 255 && color.g == 255 && color.b < 250)
return color.b;
else
return -1;
}
+260
View File
@@ -0,0 +1,260 @@
/*
* HexGL
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
*/
var bkcore = bkcore || {};
bkcore.hexgl = bkcore.hexgl || {};
bkcore.hexgl.HUD = function(opts)
{
var self = this;
this.width = opts.width;
this.height = opts.height;
this.canvas = document.createElement('canvas');
this.canvas.width = this.width;
this.canvas.height = this.height;
this.ctx = this.canvas.getContext('2d');
this.ctx.textAlign = "center";
this.bg = opts.bg;//"textures/hud/hud-bg.png";
this.fgspeed = opts.speed;//"textures/hud/hud-fg-speed.png";
this.fgshield = opts.shield;//"textures/hud/hud-fg-shield.png";
this.speedFontRatio = 24;
this.speedBarRatio = 2.91;
this.shieldFontRatio = 64;
this.shieldBarYRatio = 34;
this.shieldBarWRatio = 18.3;
this.shieldBarHRatio = 14.3;
this.timeMarginRatio = 18;
this.timeFontRatio = 19.2;
this.font = opts.font || "Arial";
this.time = "";
this.message = "";
this.previousMessage = "";
this.messageTiming = 0;
this.messagePos = 0.0;
this.messagePosTarget = 0.0;
this.messagePosTargetRatio = 12;
this.messageA = 1.0;
this.messageAS = 1.0;
this.messageDuration = 2*60;
this.messageDurationD = 2*60;
this.messageDurationS = 30;
this.messageYRatio = 34;
this.messageFontRatio = 10;
this.messageFontRatioStart = 6;
this.messageFontRatioEnd = 10;
this.messageFontLerp = 0.4;
this.messageLerp = 0.4;
this.messageFontAlpha = 0.8;
this.lapMarginRatio = 14;
this.lap = "";
this.lapSeparator = "/";
this.timeSeparators = ["","'", "''",""];
this.step = 0;
this.maxStep = 2;
};
bkcore.hexgl.HUD.prototype.resize = function(w, h)
{
this.width = w;
this.height = h;
this.canvas.width = w;
this.canvas.height = h;
}
bkcore.hexgl.HUD.prototype.display = function(msg, duration)
{
this.messageTiming = 0;
if(this.message != "")
{
this.messageA = this.messageFontAlpha;
this.messagePos = 0.0;
this.messagePosTarget = this.width/this.messagePosTargetRatio;
this.previousMessage = this.message;
}
this.messageFontRatio = this.messageFontRatioStart;
this.messageAS = 0.0;
this.message = msg;
this.messageDuration = duration == undefined ? this.messageDurationD : duration*60;
}
bkcore.hexgl.HUD.prototype.updateLap = function(current, total)
{
this.lap = current + this.lapSeparator + total;
}
bkcore.hexgl.HUD.prototype.resetLap = function()
{
this.lap = "";
}
bkcore.hexgl.HUD.prototype.updateTime = function(time)
{
this.time = this.timeSeparators[0] + time.m + this.timeSeparators[1] + time.s + this.timeSeparators[2] + time.ms + this.timeSeparators[3];
}
bkcore.hexgl.HUD.prototype.resetTime = function()
{
this.time = "";
}
bkcore.hexgl.HUD.prototype.update = function(speed, speedRatio, shield, shieldRatio)
{
var SCREEN_WIDTH = this.width;
var SCREEN_HEIGHT = this.height;
var SCREEN_HW = SCREEN_WIDTH / 2;
var SCREEN_HH = SCREEN_HEIGHT / 2;
//this.ctx.clearRect(0 , 0 , SCREEN_WIDTH , SCREEN_HEIGHT);
var w = this.bg.width;
var h = this.bg.height;
var r = h/w;
var nw = SCREEN_WIDTH;
var nh = nw*r;
var oh = SCREEN_HEIGHT - nh;
var o = 0;
//speedbar
var ba = nh;
var bl = SCREEN_WIDTH/this.speedBarRatio;
var bw = bl * speedRatio;
//shieldbar
var sw = SCREEN_WIDTH/this.shieldBarWRatio;
var sho = SCREEN_WIDTH/this.shieldBarHRatio;
var sh = sho*shieldRatio;
var sy = (SCREEN_WIDTH/this.shieldBarYRatio)+sho-sh;
if(this.step == 0)
{
this.ctx.clearRect(0 , oh , SCREEN_WIDTH , nh);
this.ctx.drawImage(this.bg, o, oh, nw, nh);
this.ctx.save();
this.ctx.beginPath();
this.ctx.moveTo(bw+ba+SCREEN_HW, oh);
this.ctx.lineTo(-(bw+ba)+SCREEN_HW, oh);
this.ctx.lineTo(-bw+SCREEN_HW, SCREEN_HEIGHT);
this.ctx.lineTo(bw+SCREEN_HW, SCREEN_HEIGHT);
this.ctx.lineTo(bw+ba+SCREEN_HW, oh);
this.ctx.clip();
this.ctx.drawImage(this.fgspeed, o, oh, nw, nh);
this.ctx.restore();
this.ctx.save();
this.ctx.beginPath();
this.ctx.moveTo(-sw+SCREEN_HW, oh+sy);
this.ctx.lineTo(sw+SCREEN_HW, oh+sy);
this.ctx.lineTo(sw+SCREEN_HW, oh+sh+sy);
this.ctx.lineTo(-sw+SCREEN_HW, oh+sh+sy);
this.ctx.lineTo(-sw+SCREEN_HW, oh+sh);
this.ctx.clip();
this.ctx.drawImage(this.fgshield, o, oh, nw, nh);
this.ctx.restore();
// SPEED
this.ctx.font = (SCREEN_WIDTH/this.speedFontRatio)+"px "+this.font;
this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
this.ctx.fillText(speed, SCREEN_HW, SCREEN_HEIGHT - nh*0.57);
// SHIELD
this.ctx.font = (SCREEN_WIDTH/this.shieldFontRatio)+"px "+this.font;
this.ctx.fillStyle = "rgba(255, 255, 255, 0.4)";
this.ctx.fillText(shield, SCREEN_HW, SCREEN_HEIGHT - nh*0.44);
}
else if(this.step == 1)
{
this.ctx.clearRect(0 , 0 , SCREEN_WIDTH , oh);
// TIME
if(this.time != "")
{
this.ctx.font = (SCREEN_WIDTH/this.timeFontRatio)+"px "+this.font;
this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
this.ctx.fillText(this.time, SCREEN_HW, SCREEN_WIDTH/this.timeMarginRatio);
}
// LAPS
if(this.lap != "")
{
this.ctx.font = (SCREEN_WIDTH/this.timeFontRatio)+"px "+this.font;
this.ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
this.ctx.fillText(this.lap, SCREEN_WIDTH-SCREEN_WIDTH/this.lapMarginRatio, SCREEN_WIDTH/this.timeMarginRatio);
}
// MESSAGE
var my = SCREEN_HH-SCREEN_WIDTH/this.messageYRatio;
if(this.messageTiming > this.messageDuration+2000)
{
this.previousMessage = "";
this.message = "";
this.messageA = 0.0;
}
else if(this.messageTiming > this.messageDuration && this.message != "")
{
this.previousMessage = this.message;
this.message = "";
this.messagePos = 0.0;
this.messagePosTarget = SCREEN_WIDTH/this.messagePosTargetRatio;
this.messageA = this.messageFontAlpha;
}
if(this.previousMessage != "")
{
if(this.messageA < 0.001)
this.messageA = 0.0;
else
this.messageA += (0.0 - this.messageA) * this.messageLerp;
this.messagePos += (this.messagePosTarget - this.messagePos) * this.messageLerp;
this.ctx.font = (SCREEN_WIDTH/this.messageFontRatioEnd)+"px "+this.font;
this.ctx.fillStyle = "rgba(255, 255, 255, "+this.messageA+")";
this.ctx.fillText(this.previousMessage, SCREEN_HW, my+this.messagePos);
}
if(this.message != "")
{
if(this.messageTiming < this.messageDurationS)
{
this.messageAS += (this.messageFontAlpha - this.messageAS) * this.messageFontLerp;
this.messageFontRatio += (this.messageFontRatioEnd - this.messageFontRatio) * this.messageFontLerp;
}
else
{
this.messageAS = this.messageFontAlpha;
this.messageFontRatio = this.messageFontRatioEnd;
}
this.ctx.font = (SCREEN_WIDTH/this.messageFontRatio)+"px "+this.font;
this.ctx.fillStyle = "rgba(255, 255, 255, "+this.messageAS+")";
this.ctx.fillText(this.message, SCREEN_HW, my);
}
}
this.messageTiming++;
this.step++;
if(this.step == this.maxStep) this.step = 0;
}
+392
View File
@@ -0,0 +1,392 @@
/*
* HexGL
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
*/
'use strict';
'v1.0.1';
var bkcore = bkcore || {};
bkcore.hexgl = bkcore.hexgl || {};
bkcore.hexgl.HexGL = function(opts)
{
var self = this;
this.document = opts.document || document;
this.a = window.location.href;
this.active = true;
this.width = opts.width == undefined ? window.innerWidth : opts.width;
this.height = opts.height == undefined ? window.innerHeight : opts.height;
this.quality = opts.quality == undefined ? 2 : opts.quality;
this.difficulty = opts.difficulty == undefined ? 0 : opts.difficulty;
this.player = opts.player == undefined ? "Anonym" : opts.player;
this.half = opts.half == undefined ? false : opts.half;
this.track = bkcore.hexgl.tracks[ opts.track == undefined ? 'Cityscape' : opts.track ];
if(this.half)
{
this.width /= 2;
this.height /=2;
}
this.settings = null;
this.renderer = null;
this.manager = null;
this.lib = null;
this.materials = {};
this.components = {};
this.extras = {
vignetteColor: new THREE.Color(0x458ab1),
bloom: null,
fxaa: null
};
this.containers = {};
this.containers.main = opts.container == undefined ? document.body : opts.container;
this.containers.overlay = opts.overlay == undefined ? document.body : opts.overlay;
this.hud = null;
this.gameplay = null;
this.composers = {
game: null
};
this.initRenderer();
function onKeyPress(event)
{
if(event.keyCode == 27/*escape*/)
{
self.reset();
}
}
this.document.addEventListener('keydown', onKeyPress, false);
}
bkcore.hexgl.HexGL.prototype.start = function()
{
this.manager.setCurrent("game");
var self = this;
function raf()
{
requestAnimationFrame( raf );
self.update();
}
//if(this.a[15] == "o")
raf();
this.initGameplay();
}
bkcore.hexgl.HexGL.prototype.reset = function()
{
this.manager.get('game').objects.lowFPS = 0;
this.gameplay.start();
}
bkcore.hexgl.HexGL.prototype.restart = function()
{
this.document.getElementById('finish').style.display = 'none';
this.reset();
}
bkcore.hexgl.HexGL.prototype.update = function()
{
if(!this.active) return;
if(this.gameplay != null)
this.gameplay.update();
this.manager.renderCurrent();
}
bkcore.hexgl.HexGL.prototype.init = function()
{
this.initHUD();
this.track.buildMaterials(this.quality);
this.track.buildScenes(this, this.quality);
this.initGameComposer();
}
bkcore.hexgl.HexGL.prototype.load = function(opts)
{
this.track.load(opts, this.quality);
}
bkcore.hexgl.HexGL.prototype.initGameplay = function()
{
var self = this;
this.gameplay = new bkcore.hexgl.Gameplay({
mode: "timeattack",
hud: this.hud,
shipControls: this.components.shipControls,
analyser: this.track.analyser,
pixelRatio: this.track.pixelRatio,
track: {
checkpoints: this.track.checkpoints,
spawn: this.track.spawn,
spawnRotation: this.track.spawnRotation
},
onFinish: function() {
self.displayScore(this.finishTime, this.lapTimes);
}
});
this.gameplay.start();
}
bkcore.hexgl.HexGL.prototype.displayScore = function(f, l)
{
var t = 'cityscape';
var dc = this.document.getElementById("finish");
var ds = this.document.getElementById("finish-state");
var dh = this.document.getElementById("finish-hallmsg");
var dr = this.document.getElementById("finish-msg");
var dt = this.document.getElementById("finish-result");
var dl1 = this.document.getElementById("finish-lap1");
var dl2 = this.document.getElementById("finish-lap2");
var dl3 = this.document.getElementById("finish-lap3");
var dd = this.document.getElementById("finish-diff")
var st = this.document.getElementById("finish-twitter");
var sf = this.document.getElementById("finish-fb");
var sl = this.document.getElementById("lowfps-msg");
var d = this.difficulty == 0 ? 'casual' : 'hard';
var ts = this.hud.timeSeparators;
var tf = bkcore.Timer.msToTimeString(f);
var tl = [
bkcore.Timer.msToTimeString(l[0]),
bkcore.Timer.msToTimeString(l[1]),
bkcore.Timer.msToTimeString(l[2])
];
if(this.gameplay.result == this.gameplay.results.FINISH)
{
ds != undefined && (ds.innerHTML = "Finished!");
// local record
if(typeof(Storage)!=="undefined")
{
if(localStorage['score-'+t+'-'+d] == undefined || localStorage['score-'+t+'-'+d] > f)
{
dr != undefined && (dr.innerHTML = "New local record!");
localStorage['score-'+t+'-'+d] = f;
}
else
{
dr != undefined && (dr.innerHTML = "Well done!");
}
}
// ladder record
var p = bkcore.hexgl.Ladder.global[t][d][bkcore.hexgl.Ladder.global[t][d].length-2];
if(p != undefined && p['score'] > f)
{
dh != undefined && (dh.innerHTML = "You made it to the HOF!");
}
else
{
dh != undefined && (dh.innerHTML = "Hall Of Fame");
}
dt != undefined && (dt.innerHTML = tf.m + ts[1] + tf.s + ts[2] + tf.ms);
dl1 != undefined && (dl1.innerHTML = tl[0]["m"] != undefined ? tl[0].m + ts[1] + tl[0].s + ts[2] + tl[0].ms : "-");
dl2 != undefined && (dl2.innerHTML = tl[1]["m"] != undefined ? tl[1].m + ts[1] + tl[1].s + ts[2] + tl[1].ms : "-");
dl3 != undefined && (dl3.innerHTML = tl[2]["m"] != undefined ? tl[2].m + ts[1] + tl[2].s + ts[2] + tl[2].ms : "-");
// Ladder save
// Undisclosed
}
else
{
ds != undefined && (ds.innerHTML = "Destroyed!");
dr != undefined && (dr.innerHTML = "Maybe next time!");
dh != undefined && (dh.innerHTML = "Hall Of Fame");
dt != undefined && (dt.innerHTML = "None");
dl1 != undefined && (dl1.innerHTML = "None");
dl2 != undefined && (dl2.innerHTML = "None");
dl3 != undefined && (dl3.innerHTML = "None");
}
dd != undefined && (dd.innerHTML = d);
st != undefined && (st.href='http://twitter.com/share?text='+encodeURIComponent('I just scored '+dt.innerHTML+' in '+'Cityscape ('+d+') on #HexGL! Come try it and beat my record on '));
sf != undefined && (sf.href='http://www.facebook.com/sharer.php?s=100'
+'&p[title]='+encodeURIComponent('I just scored '+dt.innerHTML+' in '+'Cityscape ('+d+') on HexGL!')
+'&p[summary]='+encodeURIComponent('HexGL is a futuristic racing game built by Thibaut Despoulain (BKcore) using HTML5, Javascript and WebGL. Come challenge your friends on this fast-paced 3D game!')
+'&p[url]='+encodeURIComponent('http://hexgl.bkcore.com')
+'&p[images][0]='+encodeURIComponent('http://hexgl.bkcore.com/image.png'));
bkcore.hexgl.Ladder.displayLadder('finish-ladder', t, d, 8);
if(this.manager.get('game').objects.lowFPS >= 999)
sl != undefined && (sl.innerHTML = 'Note: Your framerate was pretty low, you should try a lesser graphic setting!');
else
sl != undefined && (sl.innerHTML = '');
dc.style.display = 'block';
}
bkcore.hexgl.HexGL.prototype.initRenderer = function()
{
var renderer = new THREE.WebGLRenderer({
antialias: false,
clearColor: 0x000000
});
renderer.physicallyBasedShading = true;
renderer.gammaInput = true;
renderer.gammaOutput = true;
renderer.shadowMapEnabled = true;
renderer.shadowMapSoft = true;
renderer.autoClear = false;
renderer.sortObjects = false;
renderer.setSize( this.width, this.height );
renderer.domElement.style.position = "relative";
this.containers.main.appendChild( renderer.domElement );
this.renderer = renderer;
this.manager = new bkcore.threejs.RenderManager(renderer);
}
bkcore.hexgl.HexGL.prototype.initHUD = function()
{
this.hud = new bkcore.hexgl.HUD({
width: this.width,
height: this.height,
font: "BebasNeueRegular",
bg: this.track.lib.get("images", "hud.bg"),
speed: this.track.lib.get("images", "hud.speed"),
shield: this.track.lib.get("images", "hud.shield")
});
this.containers.overlay.appendChild(this.hud.canvas);
}
bkcore.hexgl.HexGL.prototype.initGameComposer = function()
{
var renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
var renderTarget = new THREE.WebGLRenderTarget( this.width, this.height, renderTargetParameters );
// GAME COMPOSER
var renderSky = new THREE.RenderPass( this.manager.get("sky").scene, this.manager.get("sky").camera );
var renderModel = new THREE.RenderPass( this.manager.get("game").scene, this.manager.get("game").camera );
renderModel.clear = false;
this.composers.game = new THREE.EffectComposer( this.renderer, renderTarget );
var effectScreen = new THREE.ShaderPass( THREE.ShaderExtras[ "screen" ] );
var effectVignette = new THREE.ShaderPass( THREE.ShaderExtras[ "vignette" ] );
var effectHex = new THREE.ShaderPass( bkcore.threejs.Shaders[ "hexvignette" ] );
effectHex.uniforms[ 'size' ].value = 512.0 * (this.width/1633);
effectHex.uniforms[ 'rx' ].value = this.width;
effectHex.uniforms[ 'ry' ].value = this.height;
effectHex.uniforms[ 'tHex' ].texture = this.track.lib.get("textures", "hex");
effectHex.uniforms[ 'color' ].value = this.extras.vignetteColor;
effectHex.renderToScreen = true;
this.composers.game.addPass( renderSky );
this.composers.game.addPass( renderModel );
if(this.quality > 0)
{
var effectFXAA = new THREE.ShaderPass( THREE.ShaderExtras[ "fxaa" ] );
effectFXAA.uniforms[ 'resolution' ].value.set( 1 / this.width, 1 / this.height );
this.composers.game.addPass( effectFXAA );
this.extras.fxaa = effectFXAA;
}
if(this.quality > 1)
{
var effectBloom = new THREE.BloomPass( 0.8, 25, 4 , 256);
this.composers.game.addPass( effectBloom );
this.extras.bloom = effectBloom;
}
this.composers.game.addPass( effectHex );
}
bkcore.hexgl.HexGL.prototype.createMesh = function(parent, geometry, x, y, z, mat)
{
geometry.computeTangents();
var mesh = new THREE.Mesh( geometry, mat );
mesh.position.set( x, y, z );
parent.add(mesh);
if(this.quality > 0)
{
mesh.castShadow = true;
mesh.receiveShadow = true;
}
return mesh;
}
bkcore.hexgl.HexGL.prototype.tweakShipControls = function()
{
var c = this.components.shipControls;
if(this.difficulty == 1)
{
c.airResist = 0.035;
c.airDrift = 0.07;
c.thrust = 0.035;
c.airBrake = 0.04;
c.maxSpeed = 9.6;
c.boosterSpeed = c.maxSpeed * 0.35;
c.boosterDecay = 0.007;
c.angularSpeed = 0.0140;
c.airAngularSpeed = 0.0165;
c.rollAngle = 0.6;
c.shieldDamage = 0.03;
c.collisionSpeedDecrease = 0.8;
c.collisionSpeedDecreaseCoef = 0.5;
c.rollLerp = 0.1;
c.driftLerp = 0.4;
c.angularLerp = 0.4;
}
else if(this.difficulty == 0)
{
c.airResist = 0.02;
c.airDrift = 0.06;
c.thrust = 0.02;
c.airBrake = 0.025;
c.maxSpeed = 7.0;
c.boosterSpeed = c.maxSpeed * 0.5;
c.boosterDecay = 0.007;
c.angularSpeed = 0.0125;
c.airAngularSpeed = 0.0135;
c.rollAngle = 0.6;
c.shieldDamage = 0.06;
c.collisionSpeedDecrease = 0.8;
c.collisionSpeedDecreaseCoef = 0.5;
c.rollLerp = 0.07;
c.driftLerp = 0.3;
c.angularLerp = 0.4;
}
}
+52
View File
@@ -0,0 +1,52 @@
/*
* HexGL
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
*/
var bkcore = bkcore || {};
bkcore.hexgl = bkcore.hexgl || {};
bkcore.hexgl.Ladder = {};
bkcore.hexgl.Ladder.global = {};
bkcore.hexgl.Ladder.load = function(callback)
{
var s = encodeURIComponent(window.location.href);
bkcore.Utils.request("nothing", false, function(req)
{
try {
bkcore.Ladder.global = JSON.parse(req.responseText);
if(callback) callback.call(window);
}
catch(e)
{
console.warn('Unable to load ladder. '+e);
}
},
{
u: s
});
}
bkcore.hexgl.Ladder.displayLadder = function(id, track, mode, num)
{
var d = document.getElementById(id);
if(d == undefined || bkcore.Ladder.global[track] == undefined || !bkcore.Ladder.global[track][mode] == undefined)
{
console.warn('Undefined ladder.');
return;
}
var l = bkcore.Ladder.global[track][mode];
var h = '';
var m = Math.min((num == undefined ? 10 : num), l.length-1);
for(var i = 0; i < l.length-1; i++)
{
var t = bkcore.Timer.msToTime(l[i]['score']);
h += '<span class="ladder-row"><b>'+(i+1)+'. '+l[i]['name']+'</b><i>'+t.m+'\''+t.s+'\'\''+t.ms+'</i></span>';
}
d.innerHTML = h;
}
+535
View File
@@ -0,0 +1,535 @@
/*
* HexGL
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
*/
var bkcore = bkcore || {};
bkcore.hexgl = bkcore.hexgl || {};
bkcore.hexgl.ShipControls = function(domElement)
{
var self = this;
this.active = true;
this.destroyed = false;
this.dom = domElement;
this.mesh = null;
this.epsilon = 0.00000001;
this.zero = new THREE.Vector3(0,0,0);
this.airResist = 0.02;
this.airDrift = 0.1;
this.thrust = 0.02;
this.airBrake = 0.02;
this.maxSpeed = 7.0;
this.boosterSpeed = this.maxSpeed * 0.4;
this.boosterDecay = 0.01;
this.angularSpeed = 0.005;
this.airAngularSpeed = 0.0065;
this.repulsionRatio = 0.5;
this.repulsionCap = 2.5;
this.repulsionLerp = 0.1;
this.collisionSpeedDecrease = 0.8;
this.collisionSpeedDecreaseCoef = 0.8;
this.maxShield = 1.0;
this.shieldDelay = 60;
this.shieldTiming = 0;
this.shieldDamage = 0.25;
this.driftLerp = 0.35;
this.angularLerp = 0.35;
this.movement = new THREE.Vector3(0,0,0);
this.rotation = new THREE.Vector3(0,0,0);
this.roll = 0.0;
this.rollAxis = new THREE.Vector3();
this.drift = 0.0;
this.speed = 0.0;
this.speedRatio = 0.0;
this.boost = 0.0;
this.shield = 1.0;
this.angular = 0.0;
this.currentVelocity = new THREE.Vector3();
this.quaternion = new THREE.Quaternion();
this.dummy = new THREE.Object3D();
this.dummy.useQuaternion = true;
this.collisionMap = null;
this.collisionPixelRatio = 1.0;
this.collisionDetection = false;
this.collisionPreviousPosition = new THREE.Vector3();
this.heightMap = null;
this.heightPixelRatio = 1.0;
this.heightBias = 0.0;
this.heightLerp = 0.4;
this.heightScale = 1.0;
this.rollAngle = 0.6;
this.rollLerp = 0.08;
this.rollDirection = new THREE.Vector3(0,0,1);
this.gradient = 0.0;
this.gradientTarget = 0.0;
this.gradientLerp = 0.05;
this.gradientScale = 4.0;
this.gradientVector = new THREE.Vector3(0,0,5);
this.gradientAxis = new THREE.Vector3(1,0,0);
this.tilt = 0.0;
this.tiltTarget = 0.0;
this.tiltLerp = 0.05;
this.tiltScale = 4.0;
this.tiltVector = new THREE.Vector3(5,0,0);
this.tiltAxis = new THREE.Vector3(0,0,1);
this.repulsionVLeft = new THREE.Vector3(1,0,0);
this.repulsionVRight = new THREE.Vector3(-1,0,0);
this.repulsionVFront = new THREE.Vector3(0,0,1);
this.repulsionVScale = 4.0;
this.repulsionAmount = 0.0;
this.repulsionForce = new THREE.Vector3();
this.resetPos = null;
this.resetRot = null;
this.key = {
forward: false,
backward: false,
left: false,
right: false,
ltrigger: false,
rtrigger: false,
use: false
};
this.collision = {
front: false,
left: false,
right: false
};
function onKeyDown(event)
{
switch(event.keyCode)
{
case 38: /*up*/ self.key.forward = true; break;
case 40: /*down*/self.key.backward = true; break;
case 37: /*left*/self.key.left = true; break;
case 39: /*right*/self.key.right = true; break;
case 81: /*Q*/self.key.ltrigger = true; break;
case 65: /*A*/self.key.ltrigger = true; break;
case 68: /*D*/self.key.rtrigger = true; break;
case 69: /*E*/self.key.rtrigger = true; break;
}
};
function onKeyUp(event)
{
switch(event.keyCode)
{
case 38: /*up*/ self.key.forward = false; break;
case 40: /*down*/self.key.backward = false; break;
case 37: /*left*/self.key.left = false; break;
case 39: /*right*/self.key.right = false; break;
case 81: /*Q*/self.key.ltrigger = false; break;
case 65: /*A*/self.key.ltrigger = false; break;
case 68: /*D*/self.key.rtrigger = false; break;
case 69: /*E*/self.key.rtrigger = false; break;
}
};
domElement.addEventListener('keydown', onKeyDown, false);
domElement.addEventListener('keyup', onKeyUp, false);
};
bkcore.hexgl.ShipControls.prototype.control = function(threeMesh)
{
this.mesh = threeMesh;
this.mesh.martixAutoUpdate = false;
this.dummy.position = this.mesh.position;
};
bkcore.hexgl.ShipControls.prototype.reset = function(position, rotation)
{
this.resetPos = position;
this.resetRot = rotation;
this.movement.set(0,0,0);
this.rotation.copy(rotation);
this.roll = 0.0;
this.drift = 0.0;
this.speed = 0.0;
this.speedRatio = 0.0;
this.boost = 0.0;
this.shield = this.maxShield;
this.destroyed = false;
this.dummy.position.copy(position);
this.quaternion.set(rotation.x, rotation.y, rotation.z, 1).normalize();
this.dummy.quaternion.set(0,0,0,1);
this.dummy.quaternion.multiplySelf(this.quaternion);
this.dummy.matrix.setPosition(this.dummy.position);
this.dummy.matrix.setRotationFromQuaternion(this.dummy.quaternion);
this.mesh.matrix.identity();
this.mesh.applyMatrix(this.dummy.matrix);
}
bkcore.hexgl.ShipControls.prototype.destroy = function()
{
this.active = false;
this.destroyed = true;
this.collision.front = false;
this.collision.left = false;
this.collision.right = false;
}
bkcore.hexgl.ShipControls.prototype.update = function(dt)
{
if(!this.active) return;
this.rotation.y = 0;
this.movement.set(0,0,0);
this.drift += (0.0 - this.drift) * this.driftLerp;
this.angular += (0.0 - this.angular) * this.angularLerp * 0.5;
var rollAmount = 0.0;
var angularAmount = 0.0;
if(this.key.forward)
this.speed += this.thrust * dt;
else
this.speed -= this.airResist * dt;
if(this.key.left)
{
angularAmount += this.angularSpeed * dt;
rollAmount -= this.rollAngle;
}
if(this.key.right)
{
angularAmount -= this.angularSpeed * dt;
rollAmount += this.rollAngle;
}
if(this.key.ltrigger)
{
if(this.key.left)
angularAmount += this.airAngularSpeed * dt;
else
angularAmount += this.airAngularSpeed * 0.5 * dt;
this.speed -= this.airBrake * dt;
this.drift += (this.airDrift - this.drift) * this.driftLerp;
this.movement.x += this.speed * this.drift * dt;
if(this.drift > 0.0)
this.movement.z -= this.speed * this.drift * dt;
rollAmount -= this.rollAngle * 0.7;
}
if(this.key.rtrigger)
{
if(this.key.right)
angularAmount -= this.airAngularSpeed * dt;
else
angularAmount -= this.airAngularSpeed * 0.5 * dt;
this.speed -= this.airBrake * dt;
this.drift += (-this.airDrift - this.drift) * this.driftLerp;
this.movement.x += this.speed * this.drift * dt;
if(this.drift < 0.0)
this.movement.z += this.speed * this.drift * dt;
rollAmount += this.rollAngle * 0.7;
}
this.angular += (angularAmount - this.angular) * this.angularLerp;
this.rotation.y = this.angular;
this.speed = Math.max(0.0, Math.min(this.speed, this.maxSpeed));
this.speedRatio = this.speed / this.maxSpeed;
this.movement.z += this.speed * dt;
if(this.repulsionForce.isZero())
{
this.repulsionForce.set(0,0,0);
}
else
{
if(this.repulsionForce.z != 0.0) this.movement.z = 0;
this.movement.addSelf(this.repulsionForce);
this.repulsionForce.lerpSelf(this.zero, dt > 1.5 ? this.repulsionLerp*2 : this.repulsionLerp);
}
this.collisionPreviousPosition.copy(this.dummy.position);
this.boosterCheck(dt);
//this.movement.multiplyScalar(dt);
//this.rotation.multiplyScalar(dt);
this.dummy.translateX(this.movement.x);
this.dummy.translateZ(this.movement.z);
this.heightCheck(dt);
this.dummy.translateY(this.movement.y);
this.currentVelocity.copy(this.dummy.position).subSelf(this.collisionPreviousPosition);
this.collisionCheck(dt);
this.quaternion.set(this.rotation.x, this.rotation.y, this.rotation.z, 1).normalize();
this.dummy.quaternion.multiplySelf(this.quaternion);
this.dummy.matrix.setPosition(this.dummy.position);
this.dummy.matrix.setRotationFromQuaternion(this.dummy.quaternion);
if(this.shield <= 0.0)
{
this.shield = 0.0;
this.destroy();
}
if(this.mesh != null)
{
this.mesh.matrix.identity();
// Gradient (Mesh only, no dummy physics impact)
var gradientDelta = (this.gradientTarget - this.gradient) * this.gradientLerp;
if(Math.abs(gradientDelta) > this.epsilon) this.gradient += gradientDelta;
if(Math.abs(this.gradient) > this.epsilon)
{
this.gradientAxis.set(1,0,0);
this.mesh.matrix.rotateByAxis(this.gradientAxis, this.gradient);
}
// Tilting (Idem)
var tiltDelta = (this.tiltTarget - this.tilt) * this.tiltLerp;
if(Math.abs(tiltDelta) > this.epsilon) this.tilt += tiltDelta;
if(Math.abs(this.tilt) > this.epsilon)
{
this.tiltAxis.set(0,0,1);
this.mesh.matrix.rotateByAxis(this.tiltAxis, this.tilt);
}
// Rolling (Idem)
var rollDelta = (rollAmount - this.roll) * this.rollLerp;
if(Math.abs(rollDelta) > this.epsilon) this.roll += rollDelta;
if(Math.abs(this.roll) > this.epsilon)
{
this.rollAxis.copy(this.rollDirection);
this.mesh.matrix.rotateByAxis(this.rollAxis, this.roll);
}
this.mesh.applyMatrix(this.dummy.matrix);
this.mesh.updateMatrixWorld(true);
}
};
bkcore.hexgl.ShipControls.prototype.boosterCheck = function(dt)
{
if(!this.collisionMap || !this.collisionMap.loaded)
return false;
this.boost -= this.boosterDecay * dt;
if(this.boost < 0)
this.boost = 0.0;
var x = Math.round(this.collisionMap.pixels.width/2 + this.dummy.position.x * this.collisionPixelRatio);
var z = Math.round(this.collisionMap.pixels.height/2 + this.dummy.position.z * this.collisionPixelRatio);
var pos = new THREE.Vector3(x, 0, z);
var color = this.collisionMap.getPixel(x, z);
if(color.r == 255 && color.g < 127 && color.b < 127)
this.boost = this.boosterSpeed;
this.movement.z += this.boost * dt;
}
bkcore.hexgl.ShipControls.prototype.collisionCheck = function(dt)
{
if(!this.collisionDetection || !this.collisionMap || !this.collisionMap.loaded)
return false;
if(this.shieldDelay > 0)
this.shieldDelay -= dt;
this.collision.left = false;
this.collision.right = false;
this.collision.front = false;
var x = Math.round(this.collisionMap.pixels.width/2 + this.dummy.position.x * this.collisionPixelRatio);
var z = Math.round(this.collisionMap.pixels.height/2 + this.dummy.position.z * this.collisionPixelRatio);
var pos = new THREE.Vector3(x, 0, z);
//console.log({c: this.collisionMap.getPixel(414, 670), d: this.dummy.position, x: x, y: y, p: this.collisionMap.getPixel(x, y)})
var collision = this.collisionMap.getPixelBilinear(x, z);
if(collision.r < 255)
{
// Shield
var sr = (this.getRealSpeed() / this.maxSpeed);
this.shield -= sr * sr * 0.8 * this.shieldDamage;
// Repulsion
this.repulsionVLeft.set(1,0,0);
this.repulsionVRight.set(-1,0,0);
this.dummy.matrix.rotateAxis(this.repulsionVLeft);
this.dummy.matrix.rotateAxis(this.repulsionVRight);
this.repulsionVLeft.multiplyScalar(this.repulsionVScale);
this.repulsionVRight.multiplyScalar(this.repulsionVScale);
var lPos = this.repulsionVLeft.addSelf(pos);
var rPos = this.repulsionVRight.addSelf(pos);
var lCol = this.collisionMap.getPixel(Math.round(lPos.x), Math.round(lPos.z)).r;
var rCol = this.collisionMap.getPixel(Math.round(rPos.x), Math.round(rPos.z)).r;
this.repulsionAmount = Math.max(0.8,
Math.min(this.repulsionCap,
this.speed * this.repulsionRatio
)
);
if(rCol > lCol)
{// Repulse right
this.repulsionForce.x += -this.repulsionAmount;
this.collision.left = true;
}
else if(rCol < lCol)
{// Repulse left
this.repulsionForce.x += this.repulsionAmount;
this.collision.right = true;
}
else
{
//console.log(collision.r+" -- "+fCol+" @ "+lCol+" / "+rCol);
this.repulsionForce.z += -this.repulsionAmount*4;
this.collision.front = true;
this.speed = 0;
}
this.speed *= this.collisionSpeedDecrease;
this.speed *= (1-this.collisionSpeedDecreaseCoef*(1-collision.r/255));
this.boost = 0;
return true;
}
else
{
return false;
}
}
bkcore.hexgl.ShipControls.prototype.heightCheck = function(dt)
{
if(!this.heightMap || !this.heightMap.loaded)
return false;
var x = this.heightMap.pixels.width/2 + this.dummy.position.x * this.heightPixelRatio;
var z = this.heightMap.pixels.height/2 + this.dummy.position.z * this.heightPixelRatio;
var height = this.heightMap.getPixelFBilinear(x, z) / this.heightScale + this.heightBias;
var color = this.heightMap.getPixel(x, z);
if(height < 16777)
{
var delta = (height - this.dummy.position.y);
if(delta > 0)
{
this.movement.y += delta;
}
else
{
this.movement.y += delta * this.heightLerp;
}
}
// gradient
this.gradientVector.set(0,0,5);
this.dummy.matrix.rotateAxis(this.gradientVector);
this.gradientVector.addSelf(this.dummy.position);
x = this.heightMap.pixels.width/2 + this.gradientVector.x * this.heightPixelRatio;
z = this.heightMap.pixels.height/2 + this.gradientVector.z * this.heightPixelRatio;
var nheight = this.heightMap.getPixelFBilinear(x, z) / this.heightScale + this.heightBias;
if(nheight < 16777)
this.gradientTarget = -Math.atan2(nheight-height, 5.0)*this.gradientScale;
// tilt
this.tiltVector.set(5,0,0);
this.dummy.matrix.rotateAxis(this.tiltVector);
this.tiltVector.addSelf(this.dummy.position);
x = this.heightMap.pixels.width/2 + this.tiltVector.x * this.heightPixelRatio;
z = this.heightMap.pixels.height/2 + this.tiltVector.z * this.heightPixelRatio;
nheight = this.heightMap.getPixelFBilinear(x, z) / this.heightScale + this.heightBias;
if(nheight >= 16777) // If right project out of bounds, try left projection
{
this.tiltVector.subSelf(this.dummy.position).multiplyScalar(-1).addSelf(this.dummy.position);
x = this.heightMap.pixels.width/2 + this.tiltVector.x * this.heightPixelRatio;
z = this.heightMap.pixels.height/2 + this.tiltVector.z * this.heightPixelRatio;
nheight = this.heightMap.getPixelFBilinear(x, z) / this.heightScale + this.heightBias;
}
if(nheight < 16777)
this.tiltTarget = Math.atan2(nheight-height, 5.0)*this.tiltScale;
};
bkcore.hexgl.ShipControls.prototype.getRealSpeed = function(scale)
{
return Math.round(
(this.speed+this.boost)
* (scale == undefined ? 1 : scale)
);
};
bkcore.hexgl.ShipControls.prototype.getRealSpeedRatio = function()
{
return Math.min(
this.maxSpeed,
this.speed+this.boost
) / this.maxSpeed;
};
bkcore.hexgl.ShipControls.prototype.getSpeedRatio = function()
{
return (this.speed+this.boost)/ this.maxSpeed;
};
bkcore.hexgl.ShipControls.prototype.getBoostRatio = function()
{
return this.boost / this.boosterSpeed;
};
bkcore.hexgl.ShipControls.prototype.getShieldRatio = function()
{
return this.shield / this.maxShield;
};
bkcore.hexgl.ShipControls.prototype.getShield = function(scale)
{
return Math.round(
this.shield
* (scale == undefined ? 1 : scale)
);
};
+186
View File
@@ -0,0 +1,186 @@
/*
* HexGL
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
*/
var bkcore = bkcore || {};
bkcore.hexgl = bkcore.hexgl || {};
bkcore.hexgl.ShipEffects = function(opts)
{
this.scene = opts.scene;
this.shipControls = opts.shipControls;
this.booster = opts.booster;
this.boosterLight = opts.boosterLight;
this.boosterSprite = opts.boosterSprite;
this.useParticles = opts.useParticles;
if(this.useParticles)
{
this.pVel = new THREE.Vector3(0.5,0,0);
this.pOffset = new THREE.Vector3(-3,-0.3,0);
this.pRad = new THREE.Vector3(0,0,1.5);
this.shipVelocity = new THREE.Vector3();
this.pVelS = this.pVel.length();
this.pOffsetS = this.pOffset.length();
this.pRadS = this.pRad.length();
this.pVel.normalize();
this.pOffset.normalize();
this.pRad.normalize();
this.particles = {
leftSparks: new bkcore.threejs.Particles(
{
randomness: new THREE.Vector3(0.4,0.4,0.4),
tint: 0xffffff,
color: 0xffc000,
color2: 0xffffff,
texture: opts.textureSpark,
size: 2,
life: 60,
max: 500
}),
leftClouds: new bkcore.threejs.Particles(
{
opacity: 0.8,
tint: 0xffffff,
color: 0x666666,
color2: 0xa4f1ff,
texture: opts.textureCloud,
size: 6,
blending: THREE.NormalBlending,
life: 60,
max: 500,
spawn: new THREE.Vector3(3,-0.3,0),
spawnRadius: new THREE.Vector3(1,1,2),
velocity: new THREE.Vector3(0,0,-0.4),
randomness: new THREE.Vector3(0.05,0.05,0.1)
}),
rightSparks: new bkcore.threejs.Particles(
{
randomness: new THREE.Vector3(0.4,0.4,0.4),
tint: 0xffffff,
color: 0xffc000,
color2: 0xffffff,
texture: opts.textureSpark,
size: 2,
life: 60,
max: 500
}),
rightClouds: new bkcore.threejs.Particles(
{
opacity: 0.8,
tint: 0xffffff,
color: 0x666666,
color2: 0xa4f1ff,
texture: opts.textureCloud,
size: 6,
blending: THREE.NormalBlending,
life: 60,
max: 500,
spawn: new THREE.Vector3(-3,-0.3,0),
spawnRadius: new THREE.Vector3(1,1,2),
velocity: new THREE.Vector3(0,0,-0.4),
randomness: new THREE.Vector3(0.05,0.05,0.1)
})
};
this.shipControls.mesh.add(this.particles.leftClouds.system);
this.shipControls.mesh.add(this.particles.rightClouds.system);
this.scene.add(this.particles.leftSparks.system);
this.scene.add(this.particles.rightSparks.system);
}
}
bkcore.hexgl.ShipEffects.prototype.update = function(dt)
{
var boostRatio, opacity, scale, intensity, random;
if(this.shipControls.destroyed)
{
opacity = 0;
scale = 0;
intensity = 0;
random = 0;
}
else
{
boostRatio = this.shipControls.getBoostRatio();
opacity = this.shipControls.key.forward ? 0.8 : 0.3 + boostRatio * 0.4;
scale = (this.shipControls.key.forward ? 1.0 : 0.8) + boostRatio * 0.5;
intensity = this.shipControls.key.forward ? 4.0 : 2.0;
random = Math.random()*0.2;
}
if(this.booster)
{
this.booster.rotation.z += 1;
this.booster.scale.set(scale, scale, scale);
this.booster.material.opacity = random+opacity;
this.boosterSprite.opacity = random+opacity;
this.boosterLight.intensity = intensity*(random+0.8);
}
// PARTICLES
if(this.useParticles)
{
this.shipVelocity.copy(this.shipControls.currentVelocity).multiplyScalar(0.7);
this.particles.rightSparks.velocity.copy(this.pVel);
this.particles.rightSparks.spawnRadius.copy(this.pRad);
this.particles.rightSparks.spawn.copy(this.pOffset);
this.particles.leftSparks.velocity.copy(this.pVel).x *= -1;
this.particles.leftSparks.spawn.copy(this.pOffset).x *= -1;
if(this.shipControls.mesh)
{
// RIGHT
this.shipControls.mesh.matrix.rotateAxis(this.particles.rightSparks.spawn);
this.particles.rightSparks.spawn.multiplyScalar(this.pOffsetS).addSelf(this.shipControls.dummy.position);
this.shipControls.mesh.matrix.rotateAxis(this.particles.rightSparks.velocity);
this.particles.rightSparks.velocity.multiplyScalar(this.pVelS).addSelf(this.shipVelocity);
this.shipControls.mesh.matrix.rotateAxis(this.particles.rightSparks.spawnRadius);
this.particles.rightSparks.spawnRadius.multiplyScalar(this.pRadS);
// LEFT
this.shipControls.mesh.matrix.rotateAxis(this.particles.leftSparks.spawn);
this.particles.leftSparks.spawn.multiplyScalar(this.pOffsetS).addSelf(this.shipControls.dummy.position);
this.shipControls.mesh.matrix.rotateAxis(this.particles.leftSparks.velocity);
this.particles.leftSparks.velocity.multiplyScalar(this.pVelS).addSelf(this.shipVelocity);
this.particles.leftSparks.spawnRadius.copy(this.particles.rightSparks.spawnRadius);
}
if(this.shipControls.collision.right)
{
this.particles.rightSparks.emit(Math.round(30*dt));
this.particles.rightClouds.emit(Math.round(10*dt));
}
if(this.shipControls.collision.left)
{
this.particles.leftSparks.emit(Math.round(30*dt));
this.particles.leftClouds.emit(Math.round(10*dt));
}
this.particles.rightSparks.update(dt);
this.particles.rightClouds.update(dt);
this.particles.leftSparks.update(dt);
this.particles.leftClouds.update(dt);
}
}
+445
View File
@@ -0,0 +1,445 @@
/*
* HexGL
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
* @license This work is licensed under the Creative Commons Attribution-NonCommercial 3.0 Unported License.
* To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/3.0/.
*/
var bkcore = bkcore || {};
bkcore.hexgl = bkcore.hexgl || {};
bkcore.hexgl.tracks = bkcore.hexgl.tracks || {};
bkcore.hexgl.tracks.Cityscape = {
lib: null,
materials: {},
checkpoints: {
list: [0,1,2],
start: 0,
last: 2
},
spawn: {
x: -1134*2,
y: 387,
z: -443*2
},
spawnRotation: {
x: 0,
y: 0,
z: 0
},
analyser: null,
pixelRatio: 2048.0 / 6000.0,
load: function(opts, quality)
{
this.lib = new bkcore.threejs.Loader(opts);
if(quality < 1) // LOW
{
this.lib.load({
textures: {
'hex' : "textures/hud/hex.jpg",
'ship.feisar.diffuse' : "textures/ships/feisar/diffuse.jpg",
'booster.diffuse' : "textures/ships/feisar/booster/booster.png",
'booster.sprite' : "textures/ships/feisar/booster/boostersprite.jpg",
'track.cityscape.diffuse' : "textures/tracks/cityscape/diffuse.jpg",
'track.cityscape.scrapers1.diffuse' : "textures/tracks/cityscape/scrapers1/diffuse.jpg",
'track.cityscape.scrapers2.diffuse' : "textures/tracks/cityscape/scrapers2/diffuse.jpg",
'track.cityscape.start.diffuse' : "textures/tracks/cityscape/start/diffuse.jpg",
'track.cityscape.start.banner' : "textures/tracks/cityscape/start/start.jpg",
'bonus.base.diffuse' : "textures/bonus/base/diffuse.jpg"
},
texturesCube: {
'skybox.dawnclouds' : "textures/skybox/dawnclouds/%1.jpg"
},
geometries: {
'bonus.base' : "geometries/bonus/base/base.js",
'booster' : "geometries/booster/booster.js",
'ship.feisar' : "geometries/ships/feisar/feisar.js",
'track.cityscape' : "geometries/tracks/cityscape/track.js",
'track.cityscape.scrapers1' : "geometries/tracks/cityscape/scrapers1.js",
'track.cityscape.scrapers2' : "geometries/tracks/cityscape/scrapers2.js",
'track.cityscape.start' : "geometries/tracks/cityscape/start.js",
'track.cityscape.start.banner' : "geometries/tracks/cityscape/startbanner.js",
'track.cityscape.bonus.speed' : "geometries/tracks/cityscape/bonus/speed.js"
},
analysers: {
'track.cityscape.collision' : "textures/tracks/cityscape/collision.png",
'track.cityscape.height' : "textures/tracks/cityscape/height.png"
},
images: {
'hud.bg' : "textures/hud/hud-bg.png",
'hud.speed' : "textures/hud/hud-fg-speed.png",
'hud.shield' : "textures/hud/hud-fg-shield.png"
}
});
}
else // HIGH
{
this.lib.load({
textures: {
'hex' : "textures/hud/hex.jpg",
'spark' : "textures/particles/spark.png",
'cloud' : "textures/particles/cloud.png",
'ship.feisar.diffuse' : "textures/ships/feisar/diffuse.jpg",
'ship.feisar.specular' : "textures/ships/feisar/specular.jpg",
'ship.feisar.normal' : "textures/ships/feisar/normal.jpg",
'booster.diffuse' : "textures/ships/feisar/booster/booster.png",
'booster.sprite' : "textures/ships/feisar/booster/boostersprite.jpg",
'track.cityscape.diffuse' : "textures/tracks/cityscape/diffuse.jpg",
'track.cityscape.specular' : "textures/tracks/cityscape/specular.jpg",
'track.cityscape.normal' : "textures/tracks/cityscape/normal.jpg",
'track.cityscape.scrapers1.diffuse' : "textures/tracks/cityscape/scrapers1/diffuse.jpg",
'track.cityscape.scrapers1.specular': "textures/tracks/cityscape/scrapers1/specular.jpg",
'track.cityscape.scrapers1.normal' : "textures/tracks/cityscape/scrapers1/normal.jpg",
'track.cityscape.scrapers2.diffuse' : "textures/tracks/cityscape/scrapers2/diffuse.jpg",
'track.cityscape.scrapers2.specular': "textures/tracks/cityscape/scrapers2/specular.jpg",
'track.cityscape.scrapers2.normal' : "textures/tracks/cityscape/scrapers2/normal.jpg",
'track.cityscape.start.diffuse' : "textures/tracks/cityscape/start/diffuse.jpg",
'track.cityscape.start.specular' : "textures/tracks/cityscape/start/specular.jpg",
'track.cityscape.start.normal' : "textures/tracks/cityscape/start/normal.jpg",
'track.cityscape.start.banner' : "textures/tracks/cityscape/start/start.jpg",
'bonus.base.diffuse' : "textures/bonus/base/diffuse.jpg",
'bonus.base.normal' : "textures/bonus/base/normal.jpg",
'bonus.base.specular' : "textures/bonus/base/specular.jpg"
},
texturesCube: {
'skybox.dawnclouds' : "textures/skybox/dawnclouds/%1.jpg"
},
geometries: {
'bonus.base' : "geometries/bonus/base/base.js",
'booster' : "geometries/booster/booster.js",
'ship.feisar' : "geometries/ships/feisar/feisar.js",
'track.cityscape' : "geometries/tracks/cityscape/track.js",
'track.cityscape.scrapers1' : "geometries/tracks/cityscape/scrapers1.js",
'track.cityscape.scrapers2' : "geometries/tracks/cityscape/scrapers2.js",
'track.cityscape.start' : "geometries/tracks/cityscape/start.js",
'track.cityscape.start.banner' : "geometries/tracks/cityscape/startbanner.js",
'track.cityscape.bonus.speed' : "geometries/tracks/cityscape/bonus/speed.js"
},
analysers: {
'track.cityscape.collision' : "textures/tracks/cityscape/collision.png",
'track.cityscape.height' : "textures/tracks/cityscape/height.png"
},
images: {
'hud.bg' : "textures/hud/hud-bg.png",
'hud.speed' : "textures/hud/hud-fg-speed.png",
'hud.shield' : "textures/hud/hud-fg-shield.png"
}
});
}
},
buildMaterials: function(quality)
{
if(this.quality < 1) // LOW
{
this.materials.track = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "track.cityscape.diffuse"),
ambient: 0xcccccc
});
this.materials.bonusBase = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "bonus.base.diffuse"),
ambient: 0xcccccc
});
this.materials.bonusSpeed = new THREE.MeshBasicMaterial({
color: 0x0096ff
});
this.materials.ship = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "ship.feisar.diffuse"),
ambient: 0xaaaaaa
});
this.materials.booster = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "booster.diffuse"),
transparent: true
});
this.materials.scrapers1 = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "track.cityscape.scrapers1.diffuse"),
ambient: 0xcccccc
});
this.materials.scrapers2 = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "track.cityscape.scrapers2.diffuse"),
ambient: 0xcccccc
});
this.materials.start = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "track.cityscape.start.diffuse"),
ambient: 0xcccccc
});
this.materials.startBanner = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "track.cityscape.start.banner"),
transparent: false
});
}
else // HIGH
{
this.materials.track = bkcore.Utils.createNormalMaterial({
diffuse: this.lib.get("textures", "track.cityscape.diffuse"),
specular: this.lib.get("textures", "track.cityscape.specular"),
normal: this.lib.get("textures", "track.cityscape.normal"),
ambient: 0xffffff,
shininess: 42,
metal: true,
perPixel: true
});
this.materials.bonusBase = bkcore.Utils.createNormalMaterial({
diffuse: this.lib.get("textures", "bonus.base.diffuse"),
specular: this.lib.get("textures", "bonus.base.specular"),
normal: this.lib.get("textures", "bonus.base.normal"),
normalScale: 3.0,
ambient: 0x444444,
shininess: 42,
metal: false,
perPixel: false
});
this.materials.bonusSpeed = new THREE.MeshBasicMaterial({
color: 0x0096ff
});
this.materials.ship = bkcore.Utils.createNormalMaterial({
diffuse: this.lib.get("textures", "ship.feisar.diffuse"),
specular: this.lib.get("textures", "ship.feisar.specular"),
normal: this.lib.get("textures", "ship.feisar.normal"),
ambient: 0x444444,
shininess: 42,
metal: true,
perPixel: false
});
this.materials.booster = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "booster.diffuse"),
transparent: true
});
this.materials.scrapers1 = bkcore.Utils.createNormalMaterial({
diffuse: this.lib.get("textures", "track.cityscape.scrapers1.diffuse"),
specular: this.lib.get("textures", "track.cityscape.scrapers1.specular"),
normal: this.lib.get("textures", "track.cityscape.scrapers1.normal"),
cube: this.lib.get("texturesCube", "skybox.dawnclouds"),
reflectivity: 0.8,
ambient: 0x444444,
shininess: 42,
metal: false,
perPixel: false
});
this.materials.scrapers2 = bkcore.Utils.createNormalMaterial({
diffuse: this.lib.get("textures", "track.cityscape.scrapers2.diffuse"),
specular: this.lib.get("textures", "track.cityscape.scrapers2.specular"),
normal: this.lib.get("textures", "track.cityscape.scrapers2.normal"),
cube: this.lib.get("texturesCube", "skybox.dawnclouds"),
reflectivity: 0.8,
ambient: 0x000000,
shininess: 42,
metal: false,
perPixel: false
});
this.materials.start = bkcore.Utils.createNormalMaterial({
diffuse: this.lib.get("textures", "track.cityscape.start.diffuse"),
specular: this.lib.get("textures", "track.cityscape.start.specular"),
normal: this.lib.get("textures", "track.cityscape.start.normal"),
ambient: 0xaaaaaa,
shininess: 42,
metal: false,
perPixel: false
});
this.materials.startBanner = new THREE.MeshBasicMaterial({
map: this.lib.get("textures", "track.cityscape.start.banner"),
transparent: false
});
}
},
buildScenes: function(ctx, quality)
{
// IMPORTANT
this.analyser = this.lib.get("analysers", "track.cityscape.collision");
// SKYBOX
var sceneCube = new THREE.Scene();
var cameraCube = new THREE.PerspectiveCamera( 70, ctx.width / ctx.height, 1, 6000 );
sceneCube.add( cameraCube );
var skyshader = THREE.ShaderUtils.lib[ "cube" ];
skyshader.uniforms[ "tCube" ].texture = this.lib.get("texturesCube", "skybox.dawnclouds");
var skymaterial = new THREE.ShaderMaterial(
{
fragmentShader: skyshader.fragmentShader,
vertexShader: skyshader.vertexShader,
uniforms: skyshader.uniforms,
depthWrite: false
});
var mesh = new THREE.Mesh( new THREE.CubeGeometry( 100, 100, 100 ), skymaterial );
mesh.flipSided = true;
sceneCube.add(mesh);
ctx.manager.add("sky", sceneCube, cameraCube);
var ambient = 0xbbbbbb, diffuse = 0xffffff, specular = 0xffffff, shininess = 42, scale = 23;
// MAIN SCENE
var camera = new THREE.PerspectiveCamera( 70, ctx.width / ctx.height, 1, 60000 );
var scene = new THREE.Scene();
scene.add( camera );
scene.add( new THREE.AmbientLight( ambient ) );
// SUN
var sun = new THREE.DirectionalLight( diffuse, 1.5, 30000 );
sun.position.set( -4000, 1200, 1800 );
sun.lookAt(new THREE.Vector3());
if(quality > 0)
{
sun.castShadow = true;
sun.shadowCameraNear = 50;
sun.shadowCameraFar = camera.far*2;
sun.shadowCameraRight = 3000;
sun.shadowCameraLeft = -3000;
sun.shadowCameraTop = 3000;
sun.shadowCameraBottom = -3000;
//sun.shadowCameraVisible = true;
sun.shadowBias = 0.0001;
sun.shadowDarkness = 0.7;
sun.shadowMapWidth = 2048;
sun.shadowMapHeight = 2048;
}
scene.add( sun );
// SHIP
var ship = ctx.createMesh(scene, this.lib.get("geometries", "ship.feisar"), -1134*2, 10, -443*2, this.materials.ship);
var booster = ctx.createMesh(ship, this.lib.get("geometries", "booster"), 0, 0.665, -3.8, this.materials.booster);
booster.depthWrite = false;
var boosterSprite = new THREE.Sprite({
map: this.lib.get("textures", "booster.sprite"),
blending: THREE.AdditiveBlending,
useScreenCoordinates: false,
color: 0xffffff
});
boosterSprite.scale.set(0.02, 0.02, 0.02);
boosterSprite.mergeWith3D = false;
booster.add(boosterSprite);
var boosterLight = new THREE.PointLight(0x00a2ff, 4.0, 60);
boosterLight.position.set(0, 0.665, -4);
if(quality > 0)
ship.add(boosterLight);
// SHIP CONTROLS
var shipControls = new bkcore.hexgl.ShipControls(ctx.document);
shipControls.collisionMap = this.lib.get("analysers", "track.cityscape.collision");
shipControls.collisionPixelRatio = 2048.0 / 6000.0;
shipControls.collisionDetection = true;
shipControls.heightMap = this.lib.get("analysers", "track.cityscape.height");;
shipControls.heightPixelRatio = 2048.0 / 6000.0;
shipControls.heightBias = 4.0;
shipControls.heightScale = 10.0;
shipControls.control(ship);
ctx.components.shipControls = shipControls;
ctx.tweakShipControls();
// SHIP EFFECTS AND PARTICLES
var fxParams = {
scene: scene,
shipControls: shipControls,
booster: booster,
boosterSprite: boosterSprite,
boosterLight: boosterLight,
useParticles: false
};
if(quality > 0)
{
fxParams.textureCloud = this.lib.get("textures", "cloud");
fxParams.textureSpark = this.lib.get("textures", "spark");
fxParams.useParticles = true;
}
ctx.components.shipEffects = new bkcore.hexgl.ShipEffects(fxParams);
// TRACK
var track = ctx.createMesh(scene, this.lib.get("geometries", "track.cityscape"), 0, -5, 0, this.materials.track);
var bonusBase = ctx.createMesh(scene, this.lib.get("geometries", "bonus.base"), 0, -5, 0, this.materials.bonusBase);
var bonusSpeed = ctx.createMesh(scene, this.lib.get("geometries", "track.cityscape.bonus.speed"), 0, -5, 0, this.materials.bonusSpeed);
bonusSpeed.receiveShadow = false;
var scrapers1 = ctx.createMesh(scene, this.lib.get("geometries", "track.cityscape.scrapers1"), 0, 0, 0, this.materials.scrapers1);
var scrapers2 = ctx.createMesh(scene, this.lib.get("geometries", "track.cityscape.scrapers2"), 0, 0, 0, this.materials.scrapers2);
var start = ctx.createMesh(scene, this.lib.get("geometries", "track.cityscape.start"), 0, -5, 0, this.materials.start);
var startbanner = ctx.createMesh(scene, this.lib.get("geometries", "track.cityscape.start.banner"), 0, -5, 0, this.materials.startBanner);
startbanner.doubleSided = true;
// CAMERA
ctx.components.cameraChase = new bkcore.hexgl.CameraChase({
target: ship,
camera: camera,
cameraCube: ctx.manager.get("sky").camera,
lerp: 0.5,
yoffset: 8.0,
zoffset: 10.0,
viewOffset: 10.0
});
ctx.manager.add("game", scene, camera, function(delta, renderer)
{
if(delta > 25 && this.objects.lowFPS < 1000) this.objects.lowFPS++;
var dt = delta/16.6;
this.objects.components.shipControls.update(dt);
this.objects.components.shipEffects.update(dt);
this.objects.components.cameraChase.update(dt, this.objects.components.shipControls.getSpeedRatio());
/*this.objects.time += 0.002;
var c = this.objects.components.cameraChase.camera;
c.position.set(
Math.cos(this.objects.time)*15+this.objects.components.shipControls.dummy.position.x,
10+this.objects.components.shipControls.dummy.position.y,
Math.sin(this.objects.time)*15+this.objects.components.shipControls.dummy.position.z
);
c.lookAt(this.objects.components.shipControls.dummy.position);
this.objects.components.cameraChase.cameraCube.rotation.copy(c.rotation);*/
this.objects.composers.game.render(dt);
this.objects.hud.update(
this.objects.components.shipControls.getRealSpeed(100),
this.objects.components.shipControls.getRealSpeedRatio(),
this.objects.components.shipControls.getShield(100),
this.objects.components.shipControls.getShieldRatio()
);
if(this.objects.components.shipControls.getShieldRatio() < 0.2)
this.objects.extras.vignetteColor.setHex(0x992020);
else
this.objects.extras.vignetteColor.setHex(0x458ab1);
},
{
components: ctx.components,
composers: ctx.composers,
extras: ctx.extras,
quality: quality,
hud: ctx.hud,
time: 0.0,
lowFPS: 0
});
}
}
+231
View File
@@ -0,0 +1,231 @@
/*!
* @class bkcore.threejs.Loader
*
* Loads multiple recources, get progress, callback friendly.
* Supports textures, texturesCube, geometries, analysers, images.
*
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
*/
/*!
* @package bkcore.threejs
*/
var bkcore = bkcore || {};
bkcore.threejs = bkcore.threejs || {};
bkcore.NONE = undefined;
/**
* Creates a new loader
* @param {Object{onLoad, onError, onProgress}} opts Callbacks
*/
bkcore.threejs.Loader = function(opts)
{
var self = this;
this.jsonLoader = new THREE.JSONLoader();
this.errorCallback = opts.onError == undefined ? function(s){ console.warn("Error while loading %s.".replace("%s", s)) } : opts.onError;
this.loadCallback = opts.onLoad == undefined ? function(){ console.log("Loaded.") } : opts.onLoad;
this.progressCallback = opts.onProgress == undefined ? function(progress, type, name){ /**/ } : opts.onProgress;
this.types = {
textures: null,
texturesCube: null,
geometries: null,
analysers: null,
images: null,
sounds: null
};
this.states = {};
this.data = {};
for(var t in this.types)
{
this.data[t] = {};
this.states[t] = {};
}
this.progress = {
total: 0,
remaining: 0,
loaded: 0,
finished: false
};
}
/**
* Load the given list of resources
* @param {textures, texturesCube, geometries, analysers, images} data
*/
bkcore.threejs.Loader.prototype.load = function(data)
{
var self = this;
for(var k in this.types)
{
if(k in data)
{
var size = 0;
for(var j in data[k])
size++;
this.progress.total += size;
this.progress.remaining += size;
}
}
for(var t in data.textures)
this.loadTexture(t, data.textures[t]);
for(var c in data.texturesCube)
this.loadTextureCube(c, data.texturesCube[c]);
for(var g in data.geometries)
this.loadGeometry(g, data.geometries[g]);
for(var a in data.analysers)
this.loadAnalyser(a, data.analysers[a]);
for(var i in data.images)
this.loadImage(i, data.images[i]);
this.progressCallback.call(this, this.progress);
}
bkcore.threejs.Loader.prototype.updateState = function(type, name, state)
{
if(!(type in this.types))
{
console.warn("Unkown loader type.");
return;
}
if(state == true)
{
this.progress.remaining--;
this.progress.loaded++;
this.progressCallback.call(this, this.progress, type, name);
}
this.states[type][name] = state;
if(this.progress.loaded == this.progress.total)
{
this.loadCallback.call(this);
}
}
/**
* Get loaded resource
* @param string type [textures, texturesCube, geometries, analysers, images]
* @param string name
* @return Mixed
*/
bkcore.threejs.Loader.prototype.get = function(type, name)
{
if(!(type in this.types))
{
console.warn("Unkown loader type.");
return null;
}
if(!(name in this.data[type]))
{
console.warn("Unkown file.");
return null;
}
return this.data[type][name];
}
bkcore.threejs.Loader.prototype.loaded = function(type, name)
{
if(!(type in this.types))
{
console.warn("Unkown loader type.");
return null;
}
if(!(name in this.states[type]))
{
console.warn("Unkown file.");
return null;
}
return this.states[type][name];
}
bkcore.threejs.Loader.prototype.loadTexture = function(name, url)
{
var self = this;
this.updateState("textures", name, false);
this.data.textures[name] = THREE.ImageUtils.loadTexture(
url,
bkcore.NONE,
function(){
self.updateState("textures", name, true);
},
function(){
self.errorCallback.call(self, name);
}
);
}
bkcore.threejs.Loader.prototype.loadTextureCube = function(name, url)
{
var self = this;
var urls = [
url.replace("%1", "px"), url.replace("%1", "nx"),
url.replace("%1", "py"), url.replace("%1", "ny"),
url.replace("%1", "pz"), url.replace("%1", "nz")
];
this.updateState("texturesCube", name, false);
this.data.texturesCube[name] = THREE.ImageUtils.loadTextureCube(
urls,
new THREE.CubeRefractionMapping(),
function(){
self.updateState("texturesCube", name, true);
}
);
}
bkcore.threejs.Loader.prototype.loadGeometry = function(name, url)
{
var self = this;
this.data.geometries[name] = null;
this.updateState("geometries", name, false);
this.jsonLoader.load(
url,
function(a){
self.data.geometries[name] = a;
self.updateState("geometries", name, true);
}
);
}
bkcore.threejs.Loader.prototype.loadAnalyser = function(name, url)
{
var self = this;
this.updateState("analysers", name, false);
this.data.analysers[name] = new bkcore.ImageData(
url,
function(){
self.updateState("analysers", name, true);
}
);
}
bkcore.threejs.Loader.prototype.loadImage = function(name, url)
{
var self = this;
this.updateState("images", name, false);
var e = new Image();
e.onload = function() {
self.updateState("images", name, true) ;
};
e.crossOrigin = "anonymous";
e.src = url;
this.data.images[name] = e;
}
+191
View File
@@ -0,0 +1,191 @@
/*!
* @class bkcore.threejs.Particles
*
* Particle system wrapper/helper
*
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
*/
/*!
* @package bkcore.threejs
*/
var bkcore = bkcore || {};
bkcore.threejs = bkcore.threejs || {};
/**
* Creates a new particle system using given parameters
* @param {Object{max, spawnRate, spawn, velocity, randomness, force, spawnRadius, life, friction, color, color2, tint, texture, size, blending, depthTest, transparent, opacity}} opts
*/
bkcore.threejs.Particles = function(opts)
{
this.black = new THREE.Color(0x000000);
this.white = new THREE.Color(0xffffff);
this.material = new THREE.ParticleBasicMaterial({
color: opts.tint == undefined ? 0xffffff : opts.tint,
map: opts.texture == undefined ? null : opts.texture,
size: opts.size == undefined ? 4 : opts.size,
blending: opts.blending == undefined ? THREE.AdditiveBlending : opts.blending,
depthTest: opts.depthTest == undefined ? false : opts.depthTest,
transparent: opts.transparent == undefined ? true : opts.transparent,
vertexColors: true,
opacity: opts.opacity == undefined ? 1.0 : opts.opacity,
sizeAttenuation: true
});
this.max = opts.max == undefined ? 1000 : opts.max;
this.spawnRate = opts.spawnRate == undefined ? 0 : opts.spawnRate;
this.spawn = opts.spawn == undefined ? new THREE.Vector3() : opts.spawn;
this.velocity = opts.velocity == undefined ? new THREE.Vector3() : opts.velocity;
this.randomness = opts.randomness == undefined ? new THREE.Vector3() : opts.randomness;
this.force = opts.force == undefined ? new THREE.Vector3() : opts.force;
this.spawnRadius = opts.spawnRadius == undefined ? new THREE.Vector3() : opts.spawnRadius;
this.life = opts.life == undefined ? 60 : opts.life;
this.ageing = 1 / this.life;
this.friction = opts.friction == undefined ? 1.0 : opts.friction;
this.color = new THREE.Color(opts.color == undefined ? 0xffffff : opts.color);
this.color2 = opts.color2 == undefined ? null : new THREE.Color(opts.color2);
this.position = opts.position == undefined ? new THREE.Vector3() : opts.position;
this.rotation = opts.rotation == undefined ? new THREE.Vector3() : opts.rotation;
this.sort = opts.sort == undefined ? false : opts.sort;
this.pool = [];
this.buffer = [];
this.geometry = null;
this.system = null;
this.build();
}
bkcore.threejs.Particles.prototype.build = function()
{
this.geometry = new THREE.Geometry();
this.geometry.dynamic = true;
this.pool = [];
this.buffer = [];
for(var i = 0; i < this.max; ++i)
{
var p = new bkcore.threejs.Particle();
this.pool.push(p);
this.buffer.push(p);
this.geometry.vertices.push(p.position);
this.geometry.colors.push(p.color);
}
this.system = new THREE.ParticleSystem(this.geometry, this.material);
this.system.position = this.position;
this.system.rotation = this.rotation;
this.system.sort = this.sort;
}
/**
* Emits given number of particles
* @param int count
*/
bkcore.threejs.Particles.prototype.emit = function(count)
{
var emitable = Math.min(count, this.pool.length);
for(var i = 0; i < emitable; ++i)
{
var p = this.pool.pop();
p.available = false;
p.position.copy(this.spawn)
.addSelf(
this.randomVector()
.multiplySelf(this.spawnRadius)
);
p.velocity.copy(this.velocity)
.addSelf(
this.randomVector()
.multiplySelf(this.randomness)
);
p.force.copy(this.force);
p.basecolor.copy(this.color);
if(this.color2 != undefined) p.basecolor.lerpSelf(this.color2, Math.random());
p.life = 1.0;
}
}
bkcore.threejs.Particles.prototype.randomVector = function()
{
return new THREE.Vector3(
Math.random()*2-1,
Math.random()*2-1,
Math.random()*2-1
);
}
/**
* Updates particles (should be call in a RAF loop)
* @param float dt time delta ~1.0
*/
bkcore.threejs.Particles.prototype.update = function(dt)
{
var p, l;
var df = new THREE.Vector3();
var dv = new THREE.Vector3();
for(var i = 0; i < this.buffer.length; ++i)
{
p = this.buffer[i];
if(p.available) continue;
p.life -= this.ageing;
if(p.life <= 0 && !p.available)
{
p.reset();
this.pool.push(p);
continue;
}
l = p.life > 0.5 ? 1.0 : p.life + 0.5;
p.color.setRGB(
l * p.basecolor.r,
l * p.basecolor.g,
l * p.basecolor.b
);
if(this.friction != 1.0)
p.velocity.multiplyScalar(this.friction);
df.copy(p.force).multiplyScalar(dt);
p.velocity.addSelf(df);
dv.copy(p.velocity).multiplyScalar(dt);
p.position.addSelf(dv);
}
if(this.spawnRate > 0)
this.emit(this.spawnRate);
this.geometry.verticesNeedUpdate = true;
this.geometry.colorsNeedUpdate = true;
}
bkcore.threejs.Particle = function()
{
this.position = new THREE.Vector3(-10000,-10000,-10000);
this.velocity = new THREE.Vector3();
this.force = new THREE.Vector3();
this.color = new THREE.Color(0x000000);
this.basecolor = new THREE.Color(0x000000);
this.life = 0.0;
this.available = true;
}
bkcore.threejs.Particle.prototype.reset = function()
{
this.position.set(0,-100000,0);
this.velocity.set(0,0,0);
this.force.set(0,0,0);
this.color.setRGB(0,0,0);
this.basecolor.setRGB(0,0,0);
this.life = 0.0;
this.available = true;
}
+151
View File
@@ -0,0 +1,151 @@
/*!
* @class bkcore.threejs.Preloader
*
* Displays a small 3D preloader scene
*
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
*/
/*!
* @package bkcore.threejs
*/
var bkcore = bkcore || {};
bkcore.threejs = bkcore.threejs || {};
/**
* Creates a new preloader scene.
* You have to update Preloader.ratio with the % loaded info (float 0.0-1.0)
* @param {Object{width, height, scale, line}} opts
*/
bkcore.threejs.Preloader = function(opts)
{
this.document = opts.document || document;
this.end = false;
this.time = 0.0;
this.y = 0.3;
this.ratio = 0.0;
this.height = opts.height;
this.width = opts.width;
this.scale = opts.scale == undefined ? 10 : opts.scale
this.line = opts.line == undefined ? 3 : opts.line;
this.container = opts.container;
this.renderer = new THREE.CanvasRenderer({
clearColor: 0xffffff
});
this.renderer.setSize( opts.width, opts.height );
this.container.appendChild( this.renderer.domElement );
this.ctx = this.renderer.domElement.getContext('2d');
this.ctx.textAlign = "center";
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera( 70, opts.width / opts.height, 1, 1000 );
this.camera.position.z = 100;
this.scene.add( this.camera );
this.stage = new THREE.Object3D();
this.stage.position.set(0,10,0);
this.scene.add(this.stage);
this.cube = new THREE.Mesh( new THREE.CubeGeometry( this.scale, this.scale, this.scale, 1, 1, 1 ),
new THREE.MeshBasicMaterial( { color: 0x999999 } ) );
this.cube.scale.set(0.0,0.0,0.0);
this.stage.add(this.cube);
this.cubew = new THREE.Mesh( new THREE.CubeGeometry( this.scale, this.scale, this.scale, 1, 1, 1 ),
new THREE.MeshBasicMaterial( {
wireframe: true,
wireframeLinewidth: this.line,
//wireframeLinecap: 'square',
//wireframeLinejoin: 'square',
color: 0xffffff
} ) );
this.cube.add(this.cubew);
this.outercube = new THREE.Mesh( new THREE.CubeGeometry( this.scale, this.scale, this.scale, 1, 1, 1 ),
new THREE.MeshBasicMaterial( {
wireframe: true,
wireframeLinewidth: this.line,
//wireframeLinecap: 'square',
//wireframeLinejoin: 'square',
color: 0x0093d8
} ) );
this.stage.add(this.outercube);
var self = this;
function raf()
{
if(!self.end)
{
requestAnimationFrame( raf );
self.render();
}
}
raf();
function mm(e){
self.mouseMove.call(self, e);
}
this.mmsave = mm;
this.document.addEventListener( 'mousemove', mm, false );
}
/**
* Render method to be called from a RAF loop
*/
bkcore.threejs.Preloader.prototype.render = function()
{
this.time += 0.02;
this.ctx.clearRect(0 , 0 , this.width , this.height);
var s = (this.ratio - this.cube.scale.x) * 0.3;
this.cube.scale.addScalar(s);
this.cube.rotation.y = this.time;
this.outercube.rotation.y = this.time;
this.stage.rotation.x += (this.y - this.stage.rotation.x)*0.3;
this.renderer.render( this.scene, this.camera );
this.ctx.save();
this.ctx.font = "40px Arial";
this.ctx.fillStyle = "rgb(200, 200, 200)";
this.ctx.fillText(Math.round(this.ratio*100), this.width/2, this.height/2+30);
this.ctx.restore();
}
bkcore.threejs.Preloader.prototype.mouseMove = function(event)
{
var h2 = this.height/2;
this.y = -(event.clientY - h2)/h2+0.3;
}
/**
* Deletes the Preloader
*/
bkcore.threejs.Preloader.prototype.remove = function()
{
this.document.removeEventListener( 'mousemove', this.mm, false );
this.end = true;
this.renderer = null;
this.scene = null;
this.stage = null;
this.cube = null;
this.cubew = null;
this.innercube = null;
this.container.innerHTML = "";
}
+132
View File
@@ -0,0 +1,132 @@
/*!
* bkcore.threejs.RenderManager helps handling multiple scenes, cameras and render loops.
*
* @author Thibaut 'BKcore' Despoulain <http://bkcore.com>
* @license MIT
*
* Initialize the a RenderManager by passing a Renderer object:
* var renderManager = new bkcore.threejs.RenderManager(new THREE.WebGLRenderer());
*
* A render setup structure :
* {
* id <String> : render setup ID,
* scene <THREE.Scene> : main scene,
* camera <THREE.Camera> : main camera,
* render <Function> : render loop called when render setup is active (current),
* objects <Dic> : object references accessible in the render loop via this.objects
* }
*
* The render method's context will be the render setup's object, so in your render loop:
* function(delta, renderer)
* {
* this.scene;
* this.camera;
* this.id;
* this.objects;
* renderer.render(...);
* }
*
* Use the "objects" attribute to store useful references and variables like time, geometries, materials, etc.
* Example:
* renderManager.add('mySetup', scene, camera, function(delta, renderer)
* {
* this.objects.timer += delta;
* this.objects.torus.rotation.z = Math.PI * Math.cos(this.objects.timer);
* renderer.render(this.scene, this.camera);
* },
* {
* timer: 0,
* torus: torusMesh
* });
*/
var bkcore = bkcore || {};
bkcore.threejs = bkcore.threejs || {};
(function(w){
var perfNow;
var perfNowNames = ['now', 'webkitNow', 'msNow', 'mozNow'];
if(!!w['performance']) for(var i = 0; i < perfNowNames.length; ++i)
{
var n = perfNowNames[i];
if(!!w['performance'][n])
{
perfNow = function(){return w['performance'][n]()};
break;
}
}
if(!perfNow)
{
perfNow = Date.now;
}
w.perfNow = perfNow;
})(window);
bkcore.threejs.RenderManager = function(renderer)
{
this.renderer = renderer;
this.time = window.perfNow();
this.renders = {};
this.current = {};
this.size = 0;
this.defaultRenderMethod = function(delta, renderer)
{
renderer.render(this.scene, this.camera);
};
};
bkcore.threejs.RenderManager.prototype.add = function(id, scene, camera, render, objects)
{
render = render || this.defaultRenderMethod;
objects = objects || {};
this.renders[id] = {
id: id,
scene: scene,
camera: camera,
render: render,
objects: objects
};
if(this.size == 0) this.current = this.renders[id];
this.size++;
};
bkcore.threejs.RenderManager.prototype.get = function(id)
{
return this.renders[id];
};
bkcore.threejs.RenderManager.prototype.remove = function(id)
{
if(id in this.renders)
{
delete this.renders[id];
this.size--;
}
};
bkcore.threejs.RenderManager.prototype.renderCurrent = function()
{
if(this.current && this.current.render)
{
var now = window.perfNow();
var delta = now - this.time;
this.time = now;
this.current.render.call(this.current, delta, this.renderer);
}
else console.warn('RenderManager: No current render defined.');
};
bkcore.threejs.RenderManager.prototype.setCurrent = function(id)
{
if(id in this.renders)
{
this.current = this.renders[id];
}
else console.warn('RenderManager: Render "'+id+'" not found.');
};
+950
View File
@@ -0,0 +1,950 @@
/**
* @author Thibaut Despoulain / http://bkcore.com
* @author alteredq / http://alteredqualia.com/
* @author mr.doob / http://mrdoob.com/
*/
var bkcore = bkcore || {};
bkcore.threejs = bkcore.threejs || {};
bkcore.threejs.Shaders =
{
'additive' : {
uniforms: {
tDiffuse: { type: "t", value: 0, texture: null },
tAdd: { type: "t", value: 1, texture: null },
fCoeff: { type: "f", value: 1.0 }
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
"vUv = uv;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"uniform sampler2D tDiffuse;",
"uniform sampler2D tAdd;",
"uniform float fCoeff;",
"varying vec2 vUv;",
"void main() {",
"vec4 texel = texture2D( tDiffuse, vUv );",
"vec4 add = texture2D( tAdd, vUv );",
"gl_FragColor = texel + add * fCoeff * add.a;",
"}"
].join("\n")
},
/* ------------------------------------------------------------------------------------------------
// Hexagonal Vignette shader
// by BKcore.com
------------------------------------------------------------------------------------------------ */
'hexvignette': {
uniforms: {
tDiffuse: { type: "t", value: 0, texture: null },
tHex: {type: "t", value: 1, texture: null},
size: {type: "f", value: 512.0},
rx: {type: "f", value: 1024.0},
ry: {type: "f", value: 768.0},
color: {type: "c", value: new THREE.Color(0x458ab1)}
},
vertexShader: [
"varying vec2 vUv;",
"void main() {",
"vUv = uv;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"uniform float size;",
"uniform float rx;",
"uniform float ry;",
"uniform vec3 color;",
"uniform sampler2D tDiffuse;",
"uniform sampler2D tHex;",
"varying vec2 vUv;",
"void main() {",
"vec4 vcolor = vec4(color,1.0);",
"vec2 hexuv;",
"hexuv.x = mod(vUv.x * rx, size) / size;",
"hexuv.y = mod(vUv.y * ry, size) / size;",
"vec4 hex = texture2D( tHex, hexuv );",
"float tolerance = 0.2;",
"float vignette_size = 0.6;",
"vec2 powers = pow(abs(vec2(vUv.x - 0.5,vUv.y - 0.5)),vec2(2.0));",
"float radiusSqrd = vignette_size*vignette_size;",
"float gradient = smoothstep(radiusSqrd-tolerance, radiusSqrd+tolerance, powers.x+powers.y);",
"vec2 uv = ( vUv - vec2( 0.5 ) );",
"vec2 sample = uv * gradient * 0.5 * (1.0-hex.r);",
"vec4 texel = texture2D( tDiffuse, vUv-sample );",
"gl_FragColor = (((1.0-hex.r)*vcolor) * 0.5 * gradient) + vec4( mix( texel.rgb, vcolor.xyz*0.7, dot( uv, uv ) ), texel.a );",
"}"
].join("\n")
},
/* -------------------------------------------------------------------------
// Normal map shader (perpixel)
// - Blinn-Phong
// - normal + diffuse + specular + AO + displacement + reflection + shadow maps
// - PER-PIXEL point and directional lights (use with "lights: true" material option)
// - modified by BKcore
------------------------------------------------------------------------- */
'normal' : {
uniforms: THREE.UniformsUtils.merge( [
THREE.UniformsLib[ "fog" ],
THREE.UniformsLib[ "lights" ],
THREE.UniformsLib[ "shadowmap" ],
{
"enableAO" : { type: "i", value: 0 },
"enableDiffuse" : { type: "i", value: 0 },
"enableSpecular" : { type: "i", value: 0 },
"enableReflection": { type: "i", value: 0 },
"tDiffuse" : { type: "t", value: 0, texture: null },
"tCube" : { type: "t", value: 1, texture: null },
"tNormal" : { type: "t", value: 2, texture: null },
"tSpecular" : { type: "t", value: 3, texture: null },
"tAO" : { type: "t", value: 4, texture: null },
"tDisplacement": { type: "t", value: 5, texture: null },
"uNormalScale": { type: "f", value: 1.0 },
"uDisplacementBias": { type: "f", value: 0.0 },
"uDisplacementScale": { type: "f", value: 1.0 },
"uDiffuseColor": { type: "c", value: new THREE.Color( 0xffffff ) },
"uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
"uAmbientColor": { type: "c", value: new THREE.Color( 0xffffff ) },
"uShininess": { type: "f", value: 30 },
"uOpacity": { type: "f", value: 1 },
"uReflectivity": { type: "f", value: 0.5 },
"uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) },
"uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) },
"wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
}
] ),
fragmentShader: [
"uniform vec3 uAmbientColor;",
"uniform vec3 uDiffuseColor;",
"uniform vec3 uSpecularColor;",
"uniform float uShininess;",
"uniform float uOpacity;",
"uniform bool enableDiffuse;",
"uniform bool enableSpecular;",
"uniform bool enableAO;",
"uniform bool enableReflection;",
"uniform sampler2D tDiffuse;",
"uniform sampler2D tNormal;",
"uniform sampler2D tSpecular;",
"uniform sampler2D tAO;",
"uniform samplerCube tCube;",
"uniform float uNormalScale;",
"uniform float uReflectivity;",
"varying vec3 vTangent;",
"varying vec3 vBinormal;",
"varying vec3 vNormal;",
"varying vec2 vUv;",
"uniform vec3 ambientLightColor;",
"#if MAX_DIR_LIGHTS > 0",
"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
"#endif",
"#if MAX_POINT_LIGHTS > 0",
"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
"#endif",
"#ifdef WRAP_AROUND",
"uniform vec3 wrapRGB;",
"#endif",
"varying vec3 vViewPosition;",
THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
THREE.ShaderChunk[ "fog_pars_fragment" ],
"void main() {",
"gl_FragColor = vec4( vec3( 1.0 ), uOpacity );",
"vec3 specularTex = vec3( 1.0 );",
"vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
"normalTex.xy *= uNormalScale;",
"normalTex = normalize( normalTex );",
"if( enableDiffuse ) {",
"#ifdef GAMMA_INPUT",
"vec4 texelColor = texture2D( tDiffuse, vUv );",
"texelColor.xyz *= texelColor.xyz;",
"gl_FragColor = gl_FragColor * texelColor;",
"#else",
"gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );",
"#endif",
"}",
"if( enableAO ) {",
"#ifdef GAMMA_INPUT",
"vec4 aoColor = texture2D( tAO, vUv );",
"aoColor.xyz *= aoColor.xyz;",
"gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;",
"#else",
"gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;",
"#endif",
"}",
"if( enableSpecular )",
"specularTex = texture2D( tSpecular, vUv ).xyz;",
"mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );",
"vec3 finalNormal = tsb * normalTex;",
"vec3 normal = normalize( finalNormal );",
"vec3 viewPosition = normalize( vViewPosition );",
"#ifdef DOUBLE_SIDED",
"normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );",
"#endif",
// point lights
"#if MAX_POINT_LIGHTS > 0",
"vec3 pointDiffuse = vec3( 0.0 );",
"vec3 pointSpecular = vec3( 0.0 );",
"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
"vec3 pointVector = lPosition.xyz + vViewPosition.xyz;",
"float pointDistance = 1.0;",
"if ( pointLightDistance[ i ] > 0.0 )",
"pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );",
"pointVector = normalize( pointVector );",
// diffuse
"#ifdef WRAP_AROUND",
"float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );",
"float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );",
"vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );",
"#else",
"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
"#endif",
"pointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;",
// specular
"vec3 pointHalfVector = normalize( pointVector + viewPosition );",
"float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
"float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );",
"#ifdef PHYSICALLY_BASED_SHADING",
// 2.0 => 2.0001 is hack to work around ANGLE bug
"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
"vec3 schlick = specularTex + vec3( 1.0 - specularTex ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );",
"pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;",
"#else",
"pointSpecular += pointDistance * pointLightColor[ i ] * specularTex * pointSpecularWeight * pointDiffuseWeight;",
"#endif",
"}",
"#endif",
// directional lights
"#if MAX_DIR_LIGHTS > 0",
"vec3 dirDiffuse = vec3( 0.0 );",
"vec3 dirSpecular = vec3( 0.0 );",
"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
"vec3 dirVector = normalize( lDirection.xyz );",
// diffuse
"#ifdef WRAP_AROUND",
"float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );",
"float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
"vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );",
"#else",
"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
"#endif",
"dirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;",
// specular
"vec3 dirHalfVector = normalize( dirVector + viewPosition );",
"float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
"float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );",
"#ifdef PHYSICALLY_BASED_SHADING",
// 2.0 => 2.0001 is hack to work around ANGLE bug
"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
"vec3 schlick = specularTex + vec3( 1.0 - specularTex ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );",
"dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",
"#else",
"dirSpecular += directionalLightColor[ i ] * specularTex * dirSpecularWeight * dirDiffuseWeight;",
"#endif",
"}",
"#endif",
// all lights contribution summation
"vec3 totalDiffuse = vec3( 0.0 );",
"vec3 totalSpecular = vec3( 0.0 );",
"#if MAX_DIR_LIGHTS > 0",
"totalDiffuse += dirDiffuse;",
"totalSpecular += dirSpecular;",
"#endif",
"#if MAX_POINT_LIGHTS > 0",
"totalDiffuse += pointDiffuse;",
"totalSpecular += pointSpecular;",
"#endif",
"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor) + totalSpecular;",
"if ( enableReflection ) {",
"#ifdef DOUBLE_SIDED",
"float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );",
"#else",
"float flipNormal = 1.0;",
"#endif",
"vec3 wPos = cameraPosition - vViewPosition;",
"vec3 vReflect = reflect( normalize( wPos ), normal );",
"vec4 cubeColor = textureCube( tCube, flipNormal*vec3( -vReflect.x, vReflect.yz ) );",
"#ifdef GAMMA_INPUT",
"cubeColor.xyz *= cubeColor.xyz;",
"#endif",
"gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );",
"}",
THREE.ShaderChunk[ "shadowmap_fragment" ],
THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
THREE.ShaderChunk[ "fog_fragment" ],
"}"
].join("\n"),
vertexShader: [
"attribute vec4 tangent;",
"uniform vec2 uOffset;",
"uniform vec2 uRepeat;",
"#ifdef VERTEX_TEXTURES",
"uniform sampler2D tDisplacement;",
"uniform float uDisplacementScale;",
"uniform float uDisplacementBias;",
"#endif",
"varying vec3 vTangent;",
"varying vec3 vBinormal;",
"varying vec3 vNormal;",
"varying vec2 vUv;",
"varying vec3 vViewPosition;",
THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
"void main() {",
"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
"vViewPosition = -mvPosition.xyz;",
// normal, tangent and binormal vectors
"vNormal = normalMatrix * normal;",
"vTangent = normalMatrix * tangent.xyz;",
"vBinormal = cross( vNormal, vTangent ) * tangent.w;",
"vUv = uv * uRepeat + uOffset;",
// displacement mapping
"#ifdef VERTEX_TEXTURES",
"vec3 dv = texture2D( tDisplacement, uv ).xyz;",
"float df = uDisplacementScale * dv.x + uDisplacementBias;",
"vec4 displacedPosition = vec4( normalize( vNormal.xyz ) * df, 0.0 ) + mvPosition;",
"gl_Position = projectionMatrix * displacedPosition;",
"#else",
"gl_Position = projectionMatrix * mvPosition;",
"#endif",
THREE.ShaderChunk[ "shadowmap_vertex" ],
"}"
].join("\n")
},
/* -------------------------------------------------------------------------
// Normal map shader
// - Blinn-Phong
// - normal + diffuse + specular + AO + displacement + reflection + shadow maps
// - PER-VERTEX point and directional lights (use with "lights: true" material option)
------------------------------------------------------------------------- */
'normalV' : {
uniforms: THREE.UniformsUtils.merge( [
THREE.UniformsLib[ "fog" ],
THREE.UniformsLib[ "lights" ],
THREE.UniformsLib[ "shadowmap" ],
{
"enableAO" : { type: "i", value: 0 },
"enableDiffuse" : { type: "i", value: 0 },
"enableSpecular" : { type: "i", value: 0 },
"enableReflection": { type: "i", value: 0 },
"tDiffuse" : { type: "t", value: 0, texture: null },
"tCube" : { type: "t", value: 1, texture: null },
"tNormal" : { type: "t", value: 2, texture: null },
"tSpecular" : { type: "t", value: 3, texture: null },
"tAO" : { type: "t", value: 4, texture: null },
"tDisplacement": { type: "t", value: 5, texture: null },
"uNormalScale": { type: "f", value: 1.0 },
"uDisplacementBias": { type: "f", value: 0.0 },
"uDisplacementScale": { type: "f", value: 1.0 },
"uDiffuseColor": { type: "c", value: new THREE.Color( 0xffffff ) },
"uSpecularColor": { type: "c", value: new THREE.Color( 0x111111 ) },
"uAmbientColor": { type: "c", value: new THREE.Color( 0xffffff ) },
"uShininess": { type: "f", value: 30 },
"uOpacity": { type: "f", value: 1 },
"uReflectivity": { type: "f", value: 0.5 },
"uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) },
"uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) },
"wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) }
}
] ),
fragmentShader: [
"uniform vec3 uAmbientColor;",
"uniform vec3 uDiffuseColor;",
"uniform vec3 uSpecularColor;",
"uniform float uShininess;",
"uniform float uOpacity;",
"uniform bool enableDiffuse;",
"uniform bool enableSpecular;",
"uniform bool enableAO;",
"uniform bool enableReflection;",
"uniform sampler2D tDiffuse;",
"uniform sampler2D tNormal;",
"uniform sampler2D tSpecular;",
"uniform sampler2D tAO;",
"uniform samplerCube tCube;",
"uniform float uNormalScale;",
"uniform float uReflectivity;",
"varying vec3 vTangent;",
"varying vec3 vBinormal;",
"varying vec3 vNormal;",
"varying vec2 vUv;",
"uniform vec3 ambientLightColor;",
"#if MAX_DIR_LIGHTS > 0",
"uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];",
"uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];",
"#endif",
"#if MAX_POINT_LIGHTS > 0",
"uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];",
"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
"#endif",
"#ifdef WRAP_AROUND",
"uniform vec3 wrapRGB;",
"#endif",
"varying vec3 vViewPosition;",
THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
THREE.ShaderChunk[ "fog_pars_fragment" ],
"void main() {",
"gl_FragColor = vec4( vec3( 1.0 ), uOpacity );",
"vec3 specularTex = vec3( 1.0 );",
"vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
"normalTex.xy *= uNormalScale;",
"normalTex = normalize( normalTex );",
"if( enableDiffuse ) {",
"#ifdef GAMMA_INPUT",
"vec4 texelColor = texture2D( tDiffuse, vUv );",
"texelColor.xyz *= texelColor.xyz;",
"gl_FragColor = gl_FragColor * texelColor;",
"#else",
"gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );",
"#endif",
"}",
"if( enableAO ) {",
"#ifdef GAMMA_INPUT",
"vec4 aoColor = texture2D( tAO, vUv );",
"aoColor.xyz *= aoColor.xyz;",
"gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;",
"#else",
"gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;",
"#endif",
"}",
"if( enableSpecular )",
"specularTex = texture2D( tSpecular, vUv ).xyz;",
"mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );",
"vec3 finalNormal = tsb * normalTex;",
"vec3 normal = normalize( finalNormal );",
"vec3 viewPosition = normalize( vViewPosition );",
// point lights
"#if MAX_POINT_LIGHTS > 0",
"vec3 pointDiffuse = vec3( 0.0 );",
"vec3 pointSpecular = vec3( 0.0 );",
"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
"vec3 pointVector = normalize( vPointLight[ i ].xyz );",
"float pointDistance = vPointLight[ i ].w;",
// diffuse
"#ifdef WRAP_AROUND",
"float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );",
"float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );",
"vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );",
"#else",
"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
"#endif",
"pointDiffuse += pointDistance * pointLightColor[ i ] * uDiffuseColor * pointDiffuseWeight;",
// specular
"vec3 pointHalfVector = normalize( pointVector + viewPosition );",
"float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );",
"float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, uShininess ), 0.0 );",
"#ifdef PHYSICALLY_BASED_SHADING",
// 2.0 => 2.0001 is hack to work around ANGLE bug
"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
"vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );",
"pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;",
"#else",
"pointSpecular += pointDistance * pointLightColor[ i ] * uSpecularColor * pointSpecularWeight * pointDiffuseWeight;",
"#endif",
"}",
"#endif",
// directional lights
"#if MAX_DIR_LIGHTS > 0",
"vec3 dirDiffuse = vec3( 0.0 );",
"vec3 dirSpecular = vec3( 0.0 );",
"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
"vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
"vec3 dirVector = normalize( lDirection.xyz );",
// diffuse
"#ifdef WRAP_AROUND",
"float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );",
"float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
"vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );",
"#else",
"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
"#endif",
"dirDiffuse += directionalLightColor[ i ] * uDiffuseColor * dirDiffuseWeight;",
// specular
"vec3 dirHalfVector = normalize( dirVector + viewPosition );",
"float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );",
"float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, uShininess ), 0.0 );",
"#ifdef PHYSICALLY_BASED_SHADING",
// 2.0 => 2.0001 is hack to work around ANGLE bug
"float specularNormalization = ( uShininess + 2.0001 ) / 8.0;",
"vec3 schlick = uSpecularColor + vec3( 1.0 - uSpecularColor ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );",
"dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",
"#else",
"dirSpecular += directionalLightColor[ i ] * uSpecularColor * dirSpecularWeight * dirDiffuseWeight;",
"#endif",
"}",
"#endif",
// all lights contribution summation
"vec3 totalDiffuse = vec3( 0.0 );",
"vec3 totalSpecular = vec3( 0.0 );",
"#if MAX_DIR_LIGHTS > 0",
"totalDiffuse += dirDiffuse;",
"totalSpecular += dirSpecular;",
"#endif",
"#if MAX_POINT_LIGHTS > 0",
"totalDiffuse += pointDiffuse;",
"totalSpecular += pointSpecular;",
"#endif",
"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * uAmbientColor) + totalSpecular;",
"if ( enableReflection ) {",
"vec3 wPos = cameraPosition - vViewPosition;",
"vec3 vReflect = reflect( normalize( wPos ), normal );",
"vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );",
"#ifdef GAMMA_INPUT",
"cubeColor.xyz *= cubeColor.xyz;",
"#endif",
"gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * uReflectivity );",
"}",
THREE.ShaderChunk[ "shadowmap_fragment" ],
THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
THREE.ShaderChunk[ "fog_fragment" ],
"}"
].join("\n"),
vertexShader: [
"attribute vec4 tangent;",
"uniform vec2 uOffset;",
"uniform vec2 uRepeat;",
"#ifdef VERTEX_TEXTURES",
"uniform sampler2D tDisplacement;",
"uniform float uDisplacementScale;",
"uniform float uDisplacementBias;",
"#endif",
"varying vec3 vTangent;",
"varying vec3 vBinormal;",
"varying vec3 vNormal;",
"varying vec2 vUv;",
"#if MAX_POINT_LIGHTS > 0",
"uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];",
"uniform float pointLightDistance[ MAX_POINT_LIGHTS ];",
"varying vec4 vPointLight[ MAX_POINT_LIGHTS ];",
"#endif",
"varying vec3 vViewPosition;",
THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
"void main() {",
"vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",
"vViewPosition = -mvPosition.xyz;",
// normal, tangent and binormal vectors
"vNormal = normalMatrix * normal;",
"vTangent = normalMatrix * tangent.xyz;",
"vBinormal = cross( vNormal, vTangent ) * tangent.w;",
"vUv = uv * uRepeat + uOffset;",
// point lights
"#if MAX_POINT_LIGHTS > 0",
"for( int i = 0; i < MAX_POINT_LIGHTS; i++ ) {",
"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
"vec3 lVector = lPosition.xyz - mvPosition.xyz;",
"float lDistance = 1.0;",
"if ( pointLightDistance[ i ] > 0.0 )",
"lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );",
"lVector = normalize( lVector );",
"vPointLight[ i ] = vec4( lVector, lDistance );",
"}",
"#endif",
// displacement mapping
"#ifdef VERTEX_TEXTURES",
"vec3 dv = texture2D( tDisplacement, uv ).xyz;",
"float df = uDisplacementScale * dv.x + uDisplacementBias;",
"vec4 displacedPosition = vec4( normalize( vNormal.xyz ) * df, 0.0 ) + mvPosition;",
"gl_Position = projectionMatrix * displacedPosition;",
"#else",
"gl_Position = projectionMatrix * mvPosition;",
"#endif",
THREE.ShaderChunk[ "shadowmap_vertex" ],
"}"
].join("\n")
},
/* -------------------------------------------------------------------------
// Cube map shader
------------------------------------------------------------------------- */
'cube': {
uniforms: { "tCube": { type: "t", value: 1, texture: null },
"tFlip": { type: "f", value: -1 } },
vertexShader: [
"varying vec3 vViewPosition;",
"void main() {",
"vec4 mPosition = objectMatrix * vec4( position, 1.0 );",
"vViewPosition = cameraPosition - mPosition.xyz;",
"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
"}"
].join("\n"),
fragmentShader: [
"uniform samplerCube tCube;",
"uniform float tFlip;",
"varying vec3 vViewPosition;",
"void main() {",
"vec3 wPos = cameraPosition - vViewPosition;",
"gl_FragColor = textureCube( tCube, vec3( tFlip * wPos.x, wPos.yz ) );",
"}"
].join("\n")
}
};