mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 04:03:59 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into decouple-avatar-updates
This commit is contained in:
commit
26f63a44fc
65 changed files with 3868 additions and 155 deletions
2
BUILD.md
2
BUILD.md
|
@ -53,6 +53,8 @@ Create a build directory in the root of your checkout and then run the CMake bui
|
|||
cd build
|
||||
cmake ..
|
||||
|
||||
If cmake gives you the same error message repeatedly after the build fails (e.g. you had a typo in the QT_CMAKE_PREFIX_PATH that you fixed but the `.cmake` files still cannot be found), try removing `CMakeCache.txt`.
|
||||
|
||||
####Variables
|
||||
Any variables that need to be set for CMake to find dependencies can be set as ENV variables in your shell profile, or passed directly to CMake with a `-D` flag appended to the `cmake ..` command.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file.
|
||||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only Linux specific instructions are found in this file.
|
||||
|
||||
###Qt5 Dependencies
|
||||
Should you choose not to install Qt5 via a package manager that handles dependencies for you, you may be missing some Qt5 dependencies. On Ubuntu, for example, the following additional packages are required:
|
||||
|
||||
libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-dev libxrandr-dev
|
||||
libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev
|
||||
|
|
|
@ -13,10 +13,6 @@ link_hifi_libraries(
|
|||
physics
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})
|
||||
endif (UNIX)
|
||||
|
||||
include_application_version()
|
||||
|
||||
copy_dlls_beside_windows_executable()
|
||||
|
|
|
@ -31,5 +31,10 @@ include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
|||
# append OpenSSL to our list of libraries to link
|
||||
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES})
|
||||
|
||||
# libcrypto uses dlopen in libdl
|
||||
if (UNIX)
|
||||
target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})
|
||||
endif (UNIX)
|
||||
|
||||
include_application_version()
|
||||
copy_dlls_beside_windows_executable()
|
||||
|
|
|
@ -49,7 +49,8 @@
|
|||
if (!_this.beingGrabbed) {
|
||||
// remember we're being grabbed so we can detect being released
|
||||
_this.beingGrabbed = true;
|
||||
breakdanceStart();
|
||||
var props = Entities.getEntityProperties(entityID);
|
||||
breakdanceStart(props.modelURL, props.position);
|
||||
print("I'm was grabbed...");
|
||||
} else {
|
||||
breakdanceUpdate();
|
||||
|
|
76
examples/entityScripts/detectTouchExample.js
Normal file
76
examples/entityScripts/detectTouchExample.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// detectTouchExample.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 9/3/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example of an entity script which when assigned to an entity, will detect when the entity is being touched by the avatars hands
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
Script.include("../libraries/utils.js");
|
||||
|
||||
var _this;
|
||||
|
||||
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
|
||||
// our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
|
||||
DetectTouched = function() {
|
||||
_this = this;
|
||||
};
|
||||
|
||||
DetectTouched.prototype = {
|
||||
|
||||
// update() will be called regulary, because we've hooked the update signal in our preload() function.
|
||||
// we will check the avatars hand positions and if either hand is in our bounding box, we will notice that
|
||||
update: function() {
|
||||
// because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID
|
||||
var entityID = _this.entityID;
|
||||
|
||||
var leftHandPosition = MyAvatar.getLeftPalmPosition();
|
||||
var rightHandPosition = MyAvatar.getRightPalmPosition();
|
||||
var props = Entities.getEntityProperties(entityID);
|
||||
var entityMinPoint = props.boundingBox.brn;
|
||||
var entityMaxPoint = props.boundingBox.tfl;
|
||||
|
||||
if (pointInExtents(leftHandPosition, entityMinPoint, entityMaxPoint) || pointInExtents(rightHandPosition, entityMinPoint, entityMaxPoint)) {
|
||||
|
||||
// remember we're being grabbed so we can detect being released
|
||||
_this.beingTouched = true;
|
||||
|
||||
// print out that we're being grabbed
|
||||
print("I'm being touched...");
|
||||
|
||||
} else if (_this.beingTouched) {
|
||||
|
||||
// if we are not being grabbed, and we previously were, then we were just released, remember that
|
||||
// and print out a message
|
||||
_this.beingTouched = false;
|
||||
print("I'm am no longer being touched...");
|
||||
}
|
||||
},
|
||||
|
||||
// preload() will be called when the entity has become visible (or known) to the interface
|
||||
// it gives us a chance to set our local JavaScript object up. In this case it means:
|
||||
// * remembering our entityID, so we can access it in cases where we're called without an entityID
|
||||
// * connecting to the update signal so we can check our grabbed state
|
||||
preload: function(entityID) {
|
||||
print("preload!");
|
||||
this.entityID = entityID;
|
||||
Script.update.connect(this.update);
|
||||
},
|
||||
|
||||
// unload() will be called when our entity is no longer available. It may be because we were deleted,
|
||||
// or because we've left the domain or quit the application. In all cases we want to unhook our connection
|
||||
// to the update signal
|
||||
unload: function(entityID) {
|
||||
Script.update.disconnect(this.update);
|
||||
},
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new DetectTouched();
|
||||
})
|
170
examples/example/entities/particlesTest.js
Normal file
170
examples/example/entities/particlesTest.js
Normal file
|
@ -0,0 +1,170 @@
|
|||
//
|
||||
// particlesTest.js
|
||||
// examples/example/entities
|
||||
//
|
||||
// Created by David Rowe on 2 Sep 2015.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Click on the box entity to display different particle effects.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function () {
|
||||
var box,
|
||||
particles,
|
||||
particleExample = -1,
|
||||
NUM_PARTICLE_EXAMPLES = 11,
|
||||
PARTICLE_RADIUS = 0.04;
|
||||
|
||||
function onClickDownOnEntity(entityID) {
|
||||
if (entityID === box || entityID === particles) {
|
||||
particleExample = (particleExample + 1) % NUM_PARTICLE_EXAMPLES;
|
||||
|
||||
switch (particleExample) {
|
||||
case 0:
|
||||
print("Simple emitter");
|
||||
Entities.editEntity(particles, {
|
||||
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
radiusSpread: 0.0,
|
||||
animationIsPlaying: true
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
print("Velocity spread");
|
||||
Entities.editEntity(particles, {
|
||||
velocitySpread: { x: 0.1, y: 0.0, z: 0.1 }
|
||||
});
|
||||
break;
|
||||
case 2:
|
||||
print("Acceleration spread");
|
||||
Entities.editEntity(particles, {
|
||||
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
accelerationSpread: { x: 0.0, y: 0.1, z: 0.0 }
|
||||
});
|
||||
break;
|
||||
case 3:
|
||||
print("Radius spread");
|
||||
Entities.editEntity(particles, {
|
||||
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
radiusSpread: 0.035
|
||||
});
|
||||
break;
|
||||
case 4:
|
||||
print("Radius start and finish");
|
||||
Entities.editEntity(particles, {
|
||||
radiusSpread: 0.0,
|
||||
radiusStart: 0.0,
|
||||
radiusFinish: 0.0
|
||||
});
|
||||
break;
|
||||
case 5:
|
||||
print("Alpha 0.5");
|
||||
Entities.editEntity(particles, {
|
||||
radiusStart: PARTICLE_RADIUS,
|
||||
radiusFinish: PARTICLE_RADIUS,
|
||||
alpha: 0.5
|
||||
});
|
||||
break;
|
||||
case 6:
|
||||
print("Alpha spread");
|
||||
Entities.editEntity(particles, {
|
||||
alpha: 0.5,
|
||||
alphaSpread: 0.5
|
||||
});
|
||||
break;
|
||||
case 7:
|
||||
print("Alpha start and finish");
|
||||
Entities.editEntity(particles, {
|
||||
alphaSpread: 0.0,
|
||||
alpha: 1.0,
|
||||
alphaStart: 0.0,
|
||||
alphaFinish: 0.0
|
||||
});
|
||||
break;
|
||||
case 8:
|
||||
print("Color spread");
|
||||
Entities.editEntity(particles, {
|
||||
alpha: 1.0,
|
||||
alphaStart: 1.0,
|
||||
alphaFinish: 1.0,
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
colorSpread: { red: 128, green: 0, blue: 0 }
|
||||
});
|
||||
break;
|
||||
case 9:
|
||||
print("Color start and finish");
|
||||
Entities.editEntity(particles, {
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
colorSpread: { red: 0, green: 0, blue: 0 },
|
||||
colorStart: { red: 255, green: 0, blue: 0 },
|
||||
colorFinish: { red: 0, green: 255, blue: 0 }
|
||||
});
|
||||
break;
|
||||
case 10:
|
||||
print("Stop emitting");
|
||||
Entities.editEntity(particles, {
|
||||
colorStart: { red: 255, green: 255, blue: 255 },
|
||||
colorFinish: { red: 255, green: 255, blue: 255 },
|
||||
animationIsPlaying: false
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
var spawnPoint = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation()))),
|
||||
animation = {
|
||||
fps: 30,
|
||||
frameIndex: 0,
|
||||
running: true,
|
||||
firstFrame: 0,
|
||||
lastFrame: 30,
|
||||
loop: true
|
||||
};
|
||||
|
||||
box = Entities.addEntity({
|
||||
type: "Box",
|
||||
position: spawnPoint,
|
||||
dimensions: { x: 0.3, y: 0.3, z: 0.3 },
|
||||
color: { red: 128, green: 128, blue: 128 },
|
||||
lifetime: 3600 // 1 hour; just in case
|
||||
});
|
||||
|
||||
particles = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: spawnPoint,
|
||||
particleRadius: PARTICLE_RADIUS,
|
||||
radiusSpread: 0.0,
|
||||
emitRate: 2.0,
|
||||
emitVelocity: { x: 0.0, y: 1.0, z: 0.0 },
|
||||
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
emitAcceleration: { x: 0.0, y: -0.3, z: 0.0 },
|
||||
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
|
||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||
color: { red: 255, green: 255, blue: 255 },
|
||||
lifespan: 5.0,
|
||||
visible: true,
|
||||
locked: false,
|
||||
animationSettings: animation,
|
||||
animationIsPlaying: false,
|
||||
lifetime: 3600 // 1 hour; just in case
|
||||
});
|
||||
|
||||
Entities.clickDownOnEntity.connect(onClickDownOnEntity);
|
||||
|
||||
print("Click on the box to cycle through particle examples");
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
Entities.clickDownOnEntity.disconnect(onClickDownOnEntity);
|
||||
Entities.deleteEntity(particles);
|
||||
Entities.deleteEntity(box);
|
||||
}
|
||||
|
||||
setUp();
|
||||
Script.scriptEnding.connect(tearDown);
|
||||
}());
|
|
@ -9,11 +9,13 @@
|
|||
var currentSortOrder = 'asc';
|
||||
var entityList = null;
|
||||
var refreshEntityListTimer = null;
|
||||
var ASC_STRING = ' ▾';
|
||||
var DESC_STRING = ' ▴';
|
||||
const ASCENDING_STRING = ' ▾';
|
||||
const DESCENDING_STRING = ' ▴';
|
||||
const DELETE = 46; // Key code for the delete key.
|
||||
const MAX_ITEMS = Number.MAX_VALUE; // Used to set the max length of the list of discovered entities.
|
||||
|
||||
function loaded() {
|
||||
entityList = new List('entity-list', { valueNames: ['name', 'type', 'url']});
|
||||
entityList = new List('entity-list', { valueNames: ['name', 'type', 'url'], page: MAX_ITEMS});
|
||||
entityList.clear();
|
||||
elEntityTable = document.getElementById("entity-table");
|
||||
elEntityTableBody = document.getElementById("entity-table-body");
|
||||
|
@ -34,19 +36,19 @@
|
|||
setSortColumn('url');
|
||||
};
|
||||
|
||||
function onRowClicked(e) {
|
||||
function onRowClicked(clickEvent) {
|
||||
var id = this.dataset.entityId;
|
||||
var selection = [this.dataset.entityId];
|
||||
if (e.ctrlKey) {
|
||||
if (clickEvent.ctrlKey) {
|
||||
selection = selection.concat(selectedEntities);
|
||||
} else if (e.shiftKey && selectedEntities.length > 0) {
|
||||
} else if (clickEvent.shiftKey && selectedEntities.length > 0) {
|
||||
var previousItemFound = -1;
|
||||
var clickedItemFound = -1;
|
||||
for (var i in entityList.visibleItems) {
|
||||
if (clickedItemFound === -1 && this.dataset.entityId == entityList.visibleItems[i].values().id) {
|
||||
clickedItemFound = i;
|
||||
} else if(previousItemFound === -1 && selectedEntities[0] == entityList.visibleItems[i].values().id) {
|
||||
previousItemFound = i;
|
||||
for (var entity in entityList.visibleItems) {
|
||||
if (clickedItemFound === -1 && this.dataset.entityId == entityList.visibleItems[entity].values().id) {
|
||||
clickedItemFound = entity;
|
||||
} else if(previousItemFound === -1 && selectedEntities[0] == entityList.visibleItems[entity].values().id) {
|
||||
previousItemFound = entity;
|
||||
}
|
||||
}
|
||||
if (previousItemFound !== -1 && clickedItemFound !== -1) {
|
||||
|
@ -90,19 +92,19 @@
|
|||
var filename = urlParts[urlParts.length - 1];
|
||||
|
||||
entityList.add([{ id: id, name: name, type: type, url: filename }], function(items) {
|
||||
var el = items[0].elm;
|
||||
var currentElement = items[0].elm;
|
||||
var id = items[0]._values.id;
|
||||
entities[id] = {
|
||||
id: id,
|
||||
name: name,
|
||||
el: el,
|
||||
el: currentElement,
|
||||
item: items[0],
|
||||
};
|
||||
el.setAttribute('id', 'entity_' + id);
|
||||
el.setAttribute('title', url);
|
||||
el.dataset.entityId = id;
|
||||
el.onclick = onRowClicked;
|
||||
el.ondblclick = onRowDoubleClicked;
|
||||
currentElement.setAttribute('id', 'entity_' + id);
|
||||
currentElement.setAttribute('title', url);
|
||||
currentElement.dataset.entityId = id;
|
||||
currentElement.onclick = onRowClicked;
|
||||
currentElement.ondblclick = onRowDoubleClicked;
|
||||
});
|
||||
|
||||
if (refreshEntityListTimer) {
|
||||
|
@ -134,7 +136,7 @@
|
|||
currentSortColumn = column;
|
||||
currentSortOrder = "asc";
|
||||
}
|
||||
elSortOrder[column].innerHTML = currentSortOrder == "asc" ? ASC_STRING : DESC_STRING;
|
||||
elSortOrder[column].innerHTML = currentSortOrder == "asc" ? ASCENDING_STRING : DESCENDING_STRING;
|
||||
entityList.sort(currentSortColumn, { order: currentSortOrder });
|
||||
}
|
||||
|
||||
|
@ -177,12 +179,12 @@
|
|||
refreshEntities();
|
||||
}
|
||||
|
||||
document.addEventListener("keydown", function (e) {
|
||||
if (e.target.nodeName === "INPUT") {
|
||||
document.addEventListener("keydown", function (keyDownEvent) {
|
||||
if (keyDownEvent.target.nodeName === "INPUT") {
|
||||
return;
|
||||
}
|
||||
var keyCode = e.keyCode;
|
||||
if (keyCode === 46) {
|
||||
var keyCode = keyDownEvent.keyCode;
|
||||
if (keyCode === DELETE) {
|
||||
EventBridge.emitWebEvent(JSON.stringify({ type: 'delete' }));
|
||||
refreshEntities();
|
||||
}
|
||||
|
|
|
@ -146,3 +146,9 @@ getEyeRelativePosition = function(v) {
|
|||
getAvatarRelativeRotation = function(q) {
|
||||
return Quat.multiply(MyAvatar.orientation, q);
|
||||
}
|
||||
|
||||
pointInExtents = function(point, minPoint, maxPoint) {
|
||||
return (point.x >= minPoint.x && point.x <= maxPoint.x) &&
|
||||
(point.y >= minPoint.y && point.y <= maxPoint.y) &&
|
||||
(point.z >= minPoint.z && point.z <= maxPoint.z);
|
||||
}
|
|
@ -43,7 +43,7 @@
|
|||
emitVelocity: {x: 0, y: 5, z: 0},
|
||||
velocitySpread: {x: 2, y: 0, z: 2},
|
||||
emitAcceleration: {x: 0, y: -9.8, z: 0},
|
||||
textures: "https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png",
|
||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||
color: color,
|
||||
lifespan: 1.0,
|
||||
visible: true,
|
||||
|
|
55
examples/shaders/example.fs
Normal file
55
examples/shaders/example.fs
Normal file
|
@ -0,0 +1,55 @@
|
|||
#line 2
|
||||
|
||||
//////////////////////////////////
|
||||
//
|
||||
// Available inputs
|
||||
//
|
||||
// Uniforms: constant across the whole surface
|
||||
//
|
||||
// float iGlobalTime;
|
||||
// vec3 iWorldScale;
|
||||
//
|
||||
// Varyings: Per-pixel attributes that change for every pixel
|
||||
//
|
||||
// vec3 _normal
|
||||
// vec4 _position
|
||||
// vec2 _texCoord0 // reserved for future use, currently always vec2(0)
|
||||
// vec3 _color // reserved for future user, currently always vec3(1)
|
||||
//
|
||||
/////////////////////////////////
|
||||
|
||||
//////////////////////////////////
|
||||
//
|
||||
// Available functions
|
||||
//
|
||||
// All GLSL functions from GLSL version 4.10 and usable in fragment shaders
|
||||
// See Page 8 of this document: https://www.khronos.org/files/opengl41-quick-reference-card.pdf
|
||||
//
|
||||
// Additionally the snoise functions defined in WebGL-noise are available
|
||||
// See https://github.com/ashima/webgl-noise/tree/master/src
|
||||
//
|
||||
// float snoise(vec2)
|
||||
// float snoise(vec3)
|
||||
// float snoise(vec4)
|
||||
//
|
||||
|
||||
// Fade from black to white and back again
|
||||
vec4 getProceduralColor() {
|
||||
// set intensity to a sine wave with a frequency of 1 Hz
|
||||
float intensity = sin(iGlobalTime * 3.14159 * 2.0);
|
||||
|
||||
// Raise the wave to move between 0 and 2
|
||||
intensity += 1.0;
|
||||
|
||||
// Reducce the amplitude to between 0 and 1
|
||||
intensity /= 2.0;
|
||||
|
||||
// Set the base color to blue
|
||||
vec3 color = vec3(0.0, 0.0, 1.0);
|
||||
|
||||
// Multiply by the intensity
|
||||
color *= intensity;
|
||||
|
||||
// return the color as a vec 4
|
||||
return vec4(color, 1.0);
|
||||
}
|
49
examples/shaders/exampleFloor.fs
Normal file
49
examples/shaders/exampleFloor.fs
Normal file
|
@ -0,0 +1,49 @@
|
|||
#line 2
|
||||
|
||||
// Created by inigo quilez - iq/2014
|
||||
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||
|
||||
// { 2d cell id, distance to border, distnace to center )
|
||||
vec4 hexagon(vec2 p) {
|
||||
vec2 q = vec2(p.x * 2.0 * 0.5773503, p.y + p.x * 0.5773503);
|
||||
|
||||
vec2 pi = floor(q);
|
||||
vec2 pf = fract(q);
|
||||
|
||||
float v = mod(pi.x + pi.y, 3.0);
|
||||
|
||||
float ca = step(1.0, v);
|
||||
float cb = step(2.0, v);
|
||||
vec2 ma = step(pf.xy, pf.yx);
|
||||
|
||||
// distance to borders
|
||||
float e = dot(ma,
|
||||
1.0 - pf.yx + ca * (pf.x + pf.y - 1.0) + cb * (pf.yx - 2.0 * pf.xy));
|
||||
|
||||
// distance to center
|
||||
p = vec2(q.x + floor(0.5 + p.y / 1.5), 4.0 * p.y / 3.0) * 0.5 + 0.5;
|
||||
float f = length((fract(p) - 0.5) * vec2(1.0, 0.85));
|
||||
|
||||
return vec4(pi + ca - cb * ma, e, f);
|
||||
}
|
||||
|
||||
|
||||
float hash1(vec2 p) {
|
||||
float n = dot(p, vec2(127.1, 311.7));
|
||||
return fract(sin(n) * 43758.5453);
|
||||
}
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec2 uv = _position.xz + 0.5;
|
||||
vec2 pos = _position.xz * iWorldScale.xz;
|
||||
// gray
|
||||
vec4 h = hexagon(8.0 * pos + 0.5);
|
||||
float n = snoise(vec3(0.3 * h.xy + iGlobalTime * 0.1, iGlobalTime));
|
||||
vec3 col = 0.15 + 0.15 * hash1(h.xy + 1.2) * vec3(1.0);
|
||||
col *= smoothstep(0.10, 0.11, h.z);
|
||||
col *= smoothstep(0.10, 0.11, h.w);
|
||||
col *= 1.0 + 0.15 * sin(40.0 * h.z);
|
||||
col *= 0.75 + 0.5 * h.z * n;
|
||||
col *= pow(16.0 * uv.x * (1.0 - uv.x) * uv.y * (1.0 - uv.y), 0.1);
|
||||
return vec4(col, 1.0);
|
||||
}
|
22
examples/shaders/exampleSphere.fs
Normal file
22
examples/shaders/exampleSphere.fs
Normal file
|
@ -0,0 +1,22 @@
|
|||
#line 2
|
||||
|
||||
const vec3 RED = vec3(1.0, 0.0, 0.0);
|
||||
const vec3 GREEN = vec3(0.0, 1.0, 0.0);
|
||||
const vec3 BLUE = vec3(0.0, 0.0, 1.0);
|
||||
const vec3 YELLOW = vec3(1.0, 1.0, 0.0);
|
||||
const vec3 WHITE = vec3(1.0, 1.0, 1.0);
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
float intensity = 0.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
float modifier = pow(2, i);
|
||||
float noise = snoise(vec4(_position.xyz * 10.0 * modifier, iGlobalTime));
|
||||
noise /= modifier;
|
||||
intensity += noise;
|
||||
}
|
||||
intensity /= 2.0;
|
||||
intensity += 0.5;
|
||||
vec3 color = (intensity * BLUE) + (1.0 - intensity) * YELLOW;
|
||||
return vec4(color, 1.0);
|
||||
}
|
||||
|
17
examples/shaders/exampleSphereDisco.fs
Normal file
17
examples/shaders/exampleSphereDisco.fs
Normal file
|
@ -0,0 +1,17 @@
|
|||
#line 2
|
||||
|
||||
float noise(vec3 v) {
|
||||
return snoise(vec4(v, iGlobalTime));
|
||||
}
|
||||
|
||||
vec3 noise3_3(vec3 p) {
|
||||
float fx = noise(p);
|
||||
float fy = noise(p + vec3(1345.67, 0, 45.67));
|
||||
float fz = noise(p + vec3(0, 134.67, 3245.67));
|
||||
return vec3(fx, fy, fz);
|
||||
}
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec3 color = noise3_3(_position.xyz * 10.0);
|
||||
return vec4(color, 1.0);
|
||||
}
|
25
examples/shaders/exampleUserDataV2.json
Normal file
25
examples/shaders/exampleUserDataV2.json
Normal file
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"ProceduralEntity": {
|
||||
"shaderUrl": "file:///C:/Users/bdavis/Git/hifi/examples/shaders/exampleV2.fs",
|
||||
// V2 and onwards, shaders must include a version identifier, or they will default
|
||||
// to V1 behavior
|
||||
"version": 2,
|
||||
// Any values specified here will be passed on to uniforms with matching names in
|
||||
// the shader. Only numbers and arrays of length 1-4 of numbers are supported.
|
||||
//
|
||||
// The size of the data must match the size of the uniform:
|
||||
// a number or 1 value array = 'uniform float'
|
||||
// 2 value array = 'uniform vec2'
|
||||
// 3 value array = 'uniform vec3'
|
||||
// 4 value array = 'uniform vec4'
|
||||
//
|
||||
// Uniforms should always be declared in the shader with a default value
|
||||
// or failure to specify the value here will result in undefined behavior.
|
||||
"uniforms": {
|
||||
// uniform float iSpeed = 1.0;
|
||||
"iSpeed": 2.0,
|
||||
// uniform vec3 iSize = vec3(1.0);
|
||||
"iSize": [1.0, 2.0, 4.0]
|
||||
}
|
||||
}
|
||||
}
|
40
examples/shaders/exampleV2.fs
Normal file
40
examples/shaders/exampleV2.fs
Normal file
|
@ -0,0 +1,40 @@
|
|||
const vec3 BLUE = vec3(0.0, 0.0, 1.0);
|
||||
const vec3 YELLOW = vec3(1.0, 1.0, 0.0);
|
||||
|
||||
uniform float iSpeed = 1.0;
|
||||
uniform vec3 iSize = vec3(1.0, 1.0, 1.0);
|
||||
|
||||
vec3 getNoiseColor() {
|
||||
float intensity = 0.0;
|
||||
vec3 position = _position.xyz;
|
||||
//position = normalize(position);
|
||||
float time = iGlobalTime * iSpeed;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
float modifier = pow(2, i);
|
||||
vec3 noisePosition = position * iSize * 10.0 * modifier;
|
||||
float noise = snoise(vec4(noisePosition, time));
|
||||
noise /= modifier;
|
||||
intensity += noise;
|
||||
}
|
||||
intensity /= 2.0; intensity += 0.5;
|
||||
return (intensity * BLUE) + (1.0 - intensity) * YELLOW;
|
||||
}
|
||||
|
||||
// Produce a lit procedural surface
|
||||
float getProceduralColorsLit(inout vec3 diffuse, inout vec3 specular, inout float shininess) {
|
||||
vec3 noiseColor = getNoiseColor();
|
||||
diffuse = noiseColor;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Produce an unlit procedural surface: emulates old behavior
|
||||
float getProceduralColorsUnlit(inout vec3 diffuse, inout vec3 specular, inout float shininess) {
|
||||
vec3 noiseColor = getNoiseColor();
|
||||
diffuse = vec3(1.0);
|
||||
specular = noiseColor;
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) {
|
||||
return getProceduralColorsLit(diffuse, specular, shininess);
|
||||
}
|
102
examples/shaders/grid.fs
Normal file
102
examples/shaders/grid.fs
Normal file
|
@ -0,0 +1,102 @@
|
|||
#line 2
|
||||
|
||||
// https://www.shadertoy.com/view/lss3WS
|
||||
|
||||
// srtuss, 2013
|
||||
|
||||
// collecting some design ideas for a new game project.
|
||||
// no raymarching is used.
|
||||
|
||||
// if i could add a custom soundtrack, it'd use this one (essential for desired sensation)
|
||||
// http://www.youtube.com/watch?v=1uFAu65tZpo
|
||||
|
||||
//#define GREEN_VERSION
|
||||
|
||||
// ** improved camera shaking
|
||||
// ** cleaned up code
|
||||
// ** added stuff to the gates
|
||||
|
||||
// srtuss, 2013
|
||||
float time = iGlobalTime;
|
||||
|
||||
// some noise functions for fast developing
|
||||
float rand11(float p) {
|
||||
return fract(sin(p * 591.32) * 43758.5357);
|
||||
}
|
||||
|
||||
float rand12(vec2 p) {
|
||||
return fract(sin(dot(p.xy, vec2(12.9898, 78.233))) * 43758.5357);
|
||||
}
|
||||
|
||||
vec2 rand21(float p) {
|
||||
return fract(vec2(sin(p * 591.32), cos(p * 391.32)));
|
||||
}
|
||||
|
||||
vec2 rand22(in vec2 p)
|
||||
{
|
||||
return fract(vec2(sin(p.x * 591.32 + p.y * 154.077),
|
||||
cos(p.x * 391.32 + p.y * 49.077)));
|
||||
}
|
||||
|
||||
vec3 voronoi(in vec2 x) {
|
||||
vec2 n = floor(x); // grid cell id
|
||||
vec2 f = fract(x);// grid internal position
|
||||
vec2 mg;// shortest distance...
|
||||
vec2 mr;// ..and second shortest distance
|
||||
float md = 8.0, md2 = 8.0;
|
||||
for(int j = -1; j <= 1; j ++)
|
||||
{
|
||||
for(int i = -1; i <= 1; i ++)
|
||||
{
|
||||
vec2 g = vec2(float(i), float(j)); // cell id
|
||||
vec2 o = rand22(n + g);// offset to edge point
|
||||
vec2 r = g + o - f;
|
||||
|
||||
float d = max(abs(r.x), abs(r.y));// distance to the edge
|
||||
|
||||
if(d < md)
|
||||
{ md2 = md; md = d; mr = r; mg = g;}
|
||||
else if(d < md2)
|
||||
{ md2 = d;}
|
||||
}
|
||||
}
|
||||
return vec3(n + mg, md2 - md);
|
||||
}
|
||||
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
float inten = 0.0;
|
||||
vec3 its;
|
||||
float v, g;
|
||||
// voronoi floor layers
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float layer = float(i);
|
||||
vec2 pos = _position.xz * 100.0;
|
||||
if (i == 2) {
|
||||
pos.x += time * 0.05;
|
||||
} else if (i == 1) {
|
||||
pos.y += time * 0.07;
|
||||
}
|
||||
vec3 vo = voronoi(pos + 8.0 * rand21(float(i)));
|
||||
|
||||
v = exp(-100.0 * (vo.z - 0.02));
|
||||
float fx = 0.0;
|
||||
|
||||
// add some special fx to lowest layer
|
||||
if (i == 3) {
|
||||
float crd = 0.0; //fract(time * 0.2) * 50.0 - 25.0;
|
||||
float fxi = cos(vo.x * 0.2 + time * 0.5); //abs(crd - vo.x);
|
||||
fx = clamp(smoothstep(0.9, 1.0, fxi), 0.0, 0.9) * 1.0 * rand12(vo.xy);
|
||||
fx *= exp(-3.0 * vo.z) * 2.0;
|
||||
}
|
||||
inten += v * 0.1 + fx;
|
||||
}
|
||||
inten *= 0.4 + (sin(time) * 0.5 + 0.5) * 0.6;
|
||||
vec3 cr = vec3(0.15, 2.0, 9.0);
|
||||
vec3 cg = vec3(2.0, 0.15, 9.0);
|
||||
vec3 cb = vec3(9.0, 2.0, 0.15);
|
||||
vec3 ct = vec3(9.0, 0.25, 0.3);
|
||||
vec3 cy = vec3(0.25, 0.3, 9.3);
|
||||
vec3 col = pow(vec3(inten), 1.5 * cy);
|
||||
return vec4(col, 1.0);
|
||||
}
|
48
examples/shaders/hex.fs
Normal file
48
examples/shaders/hex.fs
Normal file
|
@ -0,0 +1,48 @@
|
|||
#line 2
|
||||
// Created by inigo quilez - iq/2014
|
||||
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||
|
||||
// { 2d cell id, distance to border, distnace to center )
|
||||
vec4 hexagon(vec2 p) {
|
||||
vec2 q = vec2(p.x * 2.0 * 0.5773503, p.y + p.x * 0.5773503);
|
||||
|
||||
vec2 pi = floor(q);
|
||||
vec2 pf = fract(q);
|
||||
|
||||
float v = mod(pi.x + pi.y, 3.0);
|
||||
|
||||
float ca = step(1.0, v);
|
||||
float cb = step(2.0, v);
|
||||
vec2 ma = step(pf.xy, pf.yx);
|
||||
|
||||
// distance to borders
|
||||
float e = dot(ma,
|
||||
1.0 - pf.yx + ca * (pf.x + pf.y - 1.0) + cb * (pf.yx - 2.0 * pf.xy));
|
||||
|
||||
// distance to center
|
||||
p = vec2(q.x + floor(0.5 + p.y / 1.5), 4.0 * p.y / 3.0) * 0.5 + 0.5;
|
||||
float f = length((fract(p) - 0.5) * vec2(1.0, 0.85));
|
||||
|
||||
return vec4(pi + ca - cb * ma, e, f);
|
||||
}
|
||||
|
||||
|
||||
float hash1(vec2 p) {
|
||||
float n = dot(p, vec2(127.1, 311.7));
|
||||
return fract(sin(n) * 43758.5453);
|
||||
}
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec2 uv = _position.xz + 0.5;
|
||||
vec2 pos = _position.xz * iWorldScale.xz;
|
||||
// gray
|
||||
vec4 h = hexagon(8.0 * pos + 0.5);
|
||||
float n = snoise(vec3(0.3 * h.xy + iGlobalTime * 0.1, iGlobalTime));
|
||||
vec3 col = 0.15 + 0.15 * hash1(h.xy + 1.2) * vec3(1.0);
|
||||
col *= smoothstep(0.10, 0.11, h.z);
|
||||
col *= smoothstep(0.10, 0.11, h.w);
|
||||
col *= 1.0 + 0.15 * sin(40.0 * h.z);
|
||||
col *= 0.75 + 0.5 * h.z * n;
|
||||
col *= pow(16.0 * uv.x * (1.0 - uv.x) * uv.y * (1.0 - uv.y), 0.1);
|
||||
return vec4(col, 1.0);
|
||||
}
|
39
examples/shaders/noise.fs
Normal file
39
examples/shaders/noise.fs
Normal file
|
@ -0,0 +1,39 @@
|
|||
#line 2
|
||||
|
||||
//////////////////////////////////
|
||||
//
|
||||
// Available inputs
|
||||
//
|
||||
// Uniforms: constant across the whole surface
|
||||
//
|
||||
// float iGlobalTime;
|
||||
// vec3 iWorldScale;
|
||||
//
|
||||
// Varyings: Per-pixel attributes that change for every pixel
|
||||
//
|
||||
// vec3 _normal
|
||||
// vec4 _position
|
||||
// vec2 _texCoord0 // reserved for future use, currently always vec2(0)
|
||||
// vec3 _color // reserved for future user, currently always vec3(1)
|
||||
//
|
||||
/////////////////////////////////
|
||||
|
||||
//////////////////////////////////
|
||||
//
|
||||
// Available functions
|
||||
//
|
||||
// All GLSL functions from GLSL version 4.10 and usable in fragment shaders
|
||||
// See Page 8 of this document: https://www.khronos.org/files/opengl41-quick-reference-card.pdf
|
||||
//
|
||||
// Additionally the snoise functions defined in WebGL-noise are available
|
||||
// See https://github.com/ashima/webgl-noise/tree/master/src
|
||||
//
|
||||
// float snoise(vec2)
|
||||
// float snoise(vec3)
|
||||
// float snoise(vec4)
|
||||
//
|
||||
|
||||
// Fade from black to white and back again
|
||||
vec4 getProceduralColor() {
|
||||
return vec4(vec3(abs((sin(iGlobalTime * 3.14159) + 1.0) / 2.0)), 1); // vec4(color, 1.0);
|
||||
}
|
136
examples/shaders/scratch.fs
Normal file
136
examples/shaders/scratch.fs
Normal file
|
@ -0,0 +1,136 @@
|
|||
#line 2
|
||||
vec2 iResolution = iWorldScale.xz;
|
||||
vec2 iMouse = vec2(0);
|
||||
|
||||
// From https://www.shadertoy.com/view/4djXzz
|
||||
|
||||
/*--------------------------------------------------------------------------------------
|
||||
License CC0 - http://creativecommons.org/publicdomain/zero/1.0/
|
||||
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
|
||||
----------------------------------------------------------------------------------------
|
||||
^ This means do ANYTHING YOU WANT with this code. Because we are programmers, not lawyers.
|
||||
-Otavio Good
|
||||
*/
|
||||
|
||||
// various noise functions
|
||||
float Hash2d(vec2 uv)
|
||||
{
|
||||
float f = uv.x + uv.y * 47.0;
|
||||
return fract(cos(f*3.333)*100003.9);
|
||||
}
|
||||
float Hash3d(vec3 uv) {
|
||||
float f = uv.x + uv.y * 37.0 + uv.z * 521.0;
|
||||
return fract(cos(f * 3.333) * 100003.9);
|
||||
}
|
||||
float mixP(float f0, float f1, float a) {
|
||||
return mix(f0, f1, a * a * (3.0 - 2.0 * a));
|
||||
}
|
||||
const vec2 zeroOne = vec2(0.0, 1.0);
|
||||
float noise2d(vec2 uv) {
|
||||
vec2 fr = fract(uv.xy);
|
||||
vec2 fl = floor(uv.xy);
|
||||
float h00 = Hash2d(fl);
|
||||
float h10 = Hash2d(fl + zeroOne.yx);
|
||||
float h01 = Hash2d(fl + zeroOne);
|
||||
float h11 = Hash2d(fl + zeroOne.yy);
|
||||
return mixP(mixP(h00, h10, fr.x), mixP(h01, h11, fr.x), fr.y);
|
||||
}
|
||||
|
||||
float noise(vec3 uv) {
|
||||
vec3 fr = fract(uv.xyz);
|
||||
vec3 fl = floor(uv.xyz);
|
||||
float h000 = Hash3d(fl);
|
||||
float h100 = Hash3d(fl + zeroOne.yxx);
|
||||
float h010 = Hash3d(fl + zeroOne.xyx);
|
||||
float h110 = Hash3d(fl + zeroOne.yyx);
|
||||
float h001 = Hash3d(fl + zeroOne.xxy);
|
||||
float h101 = Hash3d(fl + zeroOne.yxy);
|
||||
float h011 = Hash3d(fl + zeroOne.xyy);
|
||||
float h111 = Hash3d(fl + zeroOne.yyy);
|
||||
return mixP(mixP(mixP(h000, h100, fr.x), mixP(h010, h110, fr.x), fr.y),
|
||||
mixP(mixP(h001, h101, fr.x), mixP(h011, h111, fr.x), fr.y), fr.z);
|
||||
}
|
||||
|
||||
float PI = 3.14159265;
|
||||
|
||||
vec3 saturate(vec3 a) {
|
||||
return clamp(a, 0.0, 1.0);
|
||||
}
|
||||
vec2 saturate(vec2 a) {
|
||||
return clamp(a, 0.0, 1.0);
|
||||
}
|
||||
float saturate(float a) {
|
||||
return clamp(a, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float Density(vec3 p) {
|
||||
//float ws = 0.06125*0.125;
|
||||
//vec3 warp = vec3(noise(p*ws), noise(p*ws + 111.11), noise(p*ws + 7111.11));
|
||||
float final = noise(p * 0.06125); // + sin(iGlobalTime)*0.5-1.95 + warp.x*4.0;
|
||||
float other = noise(p * 0.06125 + 1234.567);
|
||||
other -= 0.5;
|
||||
final -= 0.5;
|
||||
final = 0.1 / (abs(final * final * other));
|
||||
final += 0.5;
|
||||
return final * 0.0001;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
// ---------------- First, set up the camera rays for ray marching ----------------
|
||||
vec2 uv = fragCoord.xy/iResolution.xy * 2.0 - 1.0;// - 0.5;
|
||||
|
||||
// Camera up vector.
|
||||
vec3 camUp=vec3(0,1,0);// vuv
|
||||
|
||||
// Camera lookat.
|
||||
vec3 camLookat=vec3(0,0.0,0);// vrp
|
||||
|
||||
float mx=iMouse.x/iResolution.x*PI*2.0 + iGlobalTime * 0.01;
|
||||
float my=-iMouse.y/iResolution.y*10.0 + sin(iGlobalTime * 0.03)*0.2+0.2;//*PI/2.01;
|
||||
vec3 camPos=vec3(cos(my)*cos(mx),sin(my),cos(my)*sin(mx))*(200.2);// prp
|
||||
|
||||
// Camera setup.
|
||||
vec3 camVec=normalize(camLookat - camPos);//vpn
|
||||
vec3 sideNorm=normalize(cross(camUp, camVec));// u
|
||||
vec3 upNorm=cross(camVec, sideNorm);//v
|
||||
vec3 worldFacing=(camPos + camVec);//vcv
|
||||
vec3 worldPix = worldFacing + uv.x * sideNorm * (iResolution.x/iResolution.y) + uv.y * upNorm;//scrCoord
|
||||
vec3 relVec = normalize(worldPix - camPos);//scp
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
float t = 0.0;
|
||||
float inc = 0.02;
|
||||
float maxDepth = 70.0;
|
||||
vec3 pos = vec3(0,0,0);
|
||||
float density = 0.0;
|
||||
// ray marching time
|
||||
for (int i = 0; i < 37; i++)// This is the count of how many times the ray actually marches.
|
||||
{
|
||||
if ((t > maxDepth)) break;
|
||||
pos = camPos + relVec * t;
|
||||
float temp = Density(pos);
|
||||
//temp *= saturate(t-1.0);
|
||||
|
||||
inc = 1.9 + temp*0.05;// add temp because this makes it look extra crazy!
|
||||
density += temp * inc;
|
||||
t += inc;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Now that we have done our ray marching, let's put some color on this.
|
||||
vec3 finalColor = vec3(0.01,0.1,1.0)* density*0.2;
|
||||
|
||||
// output the final color with sqrt for "gamma correction"
|
||||
fragColor = vec4(sqrt(clamp(finalColor, 0.0, 1.0)),1.0);
|
||||
}
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec4 result;
|
||||
vec2 position = _position.xz;
|
||||
position += 0.5;
|
||||
|
||||
mainImage(result, position * iWorldScale.xz);
|
||||
|
||||
return result;
|
||||
}
|
32
examples/shaders/shadertoyWrapper.fs
Normal file
32
examples/shaders/shadertoyWrapper.fs
Normal file
|
@ -0,0 +1,32 @@
|
|||
vec2 iResolution = iWorldScale.xz;
|
||||
vec2 iMouse = vec2(0);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// REPLACE BELOW
|
||||
//
|
||||
// Replace the contents of this section with a shadertoy that includes a mainImage
|
||||
// function
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
|
||||
fragColor = vec4(0, 0, 1, 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// REPLACE ABOVE
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec4 result;
|
||||
vec2 position = _position.xz;
|
||||
position += 0.5;
|
||||
|
||||
mainImage(result, position * iWorldScale.xz);
|
||||
|
||||
return result;
|
||||
}
|
231
examples/shaders/shadertoys/clock.fs
Normal file
231
examples/shaders/shadertoys/clock.fs
Normal file
|
@ -0,0 +1,231 @@
|
|||
vec2 iResolution = iWorldScale.xz;
|
||||
|
||||
// from https://www.shadertoy.com/view/Xd2XWR
|
||||
|
||||
// Created by Daniel Burke - burito/2014
|
||||
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||
|
||||
// Inspiration from Dr Who (2005) S7E13 - The Name of the Doctor
|
||||
|
||||
vec2 rot(vec2 p, float a)
|
||||
{
|
||||
float c = cos(a);
|
||||
float s = sin(a);
|
||||
return vec2(p.x*c + p.y*s,
|
||||
-p.x*s + p.y*c);
|
||||
}
|
||||
|
||||
float circle(vec2 pos, float radius)
|
||||
{
|
||||
return clamp(((1.0-abs(length(pos)-radius))-0.99)*100.0, 0.0, 1.0);
|
||||
|
||||
}
|
||||
|
||||
float circleFill(vec2 pos, float radius)
|
||||
{
|
||||
return clamp(((1.0-(length(pos)-radius))-0.99)*100.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// Thanks Iñigo Quilez!
|
||||
float line( in vec2 p, in vec2 a, in vec2 b )
|
||||
{
|
||||
vec2 pa = -p - a;
|
||||
vec2 ba = b - a;
|
||||
float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
|
||||
float d = length( pa - ba*h );
|
||||
|
||||
return clamp(((1.0 - d)-0.99)*100.0, 0.0, 1.0);
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
vec2 p = -1.0 + 2.0 * uv;
|
||||
p.x *= iResolution.x / iResolution.y;
|
||||
|
||||
vec3 colour = vec3(0);
|
||||
vec3 white = vec3(1);
|
||||
|
||||
|
||||
|
||||
float c = circle(p, 0.2);
|
||||
c += circle(p, 0.1);
|
||||
c += circle(p, 0.18);
|
||||
c += circleFill(p, 0.005);
|
||||
|
||||
// c += circle(p, 1.3);
|
||||
c += circle(p, 1.0);
|
||||
if(p.x > 0.0)c += circle(p, 0.4);
|
||||
if(p.x > 0.0)c += circle(p, 0.42);
|
||||
if(p.x < 0.0)c += circle(p, 0.47);
|
||||
c += circleFill(p+vec2(0.47, 0.0), 0.02);
|
||||
c += circleFill(p+vec2(0.84147*0.47, 0.54030*0.47), 0.02);
|
||||
c += circleFill(p+vec2(0.84147*0.47, -0.54030*0.47), 0.02);
|
||||
c += circleFill(p+vec2(0.41614*0.47, 0.90929*0.47), 0.02);
|
||||
c += circleFill(p+vec2(0.41614*0.47, -0.90929*0.47), 0.02);
|
||||
|
||||
float t = iGlobalTime;
|
||||
float t2 = t * -0.01;
|
||||
float t3 = t * 0.03;
|
||||
|
||||
vec2 angle1 = vec2(sin(t), cos(t));
|
||||
vec2 a = angle1 * 0.7;
|
||||
|
||||
t *= 0.5;
|
||||
vec2 angle2 = vec2(sin(t), cos(t));
|
||||
vec2 b = angle2 * 0.8;
|
||||
|
||||
vec2 angle3 = vec2(sin(t2), cos(t2));
|
||||
vec2 d = b + angle3* 0.4;
|
||||
|
||||
vec2 angle4 = vec2(sin(t3), cos(t3));
|
||||
vec2 e = angle4 * 0.9;
|
||||
|
||||
vec2 angle5 = vec2(sin(t3+4.0), cos(t3+4.0));
|
||||
vec2 f = angle5 * 0.8;
|
||||
|
||||
vec2 angle6 = vec2(sin(t*-0.1+5.0), cos(t*-0.1+5.0));
|
||||
vec2 h = angle6 * 0.8;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
float tt = t * 1.4;
|
||||
|
||||
float tm = mod(tt, 0.5);
|
||||
float tmt = tt - tm;
|
||||
if( tm > 0.4) tmt += (tm-0.4)*5.0;
|
||||
vec2 tangle1 = vec2(sin(tmt), cos(tmt));
|
||||
|
||||
tt *= 0.8;
|
||||
tm = mod(tt, 0.6);
|
||||
float tmt2 = tt - tm;
|
||||
if( tm > 0.2) tmt2 += (tm-0.2)*1.5;
|
||||
|
||||
vec2 tangle2 = vec2(sin(tmt2*-4.0), cos(tmt2*-4.0));
|
||||
|
||||
vec2 tangle3 = vec2(sin(tmt2), cos(tmt2));
|
||||
|
||||
tt = t+3.0;
|
||||
tm = mod(tt, 0.2);
|
||||
tmt = tt - tm;
|
||||
if( tm > 0.1) tmt += (tm-0.1)*2.0;
|
||||
vec2 tangle4 = vec2(sin(-tmt), cos(-tmt)); tmt += 0.9;
|
||||
vec2 tangle41 = vec2(sin(-tmt), cos(-tmt)); tmt += 0.5;
|
||||
vec2 tangle42 = vec2(sin(-tmt), cos(-tmt)); tmt += 0.5;
|
||||
vec2 tangle43 = vec2(sin(-tmt), cos(-tmt)); tmt += 0.5;
|
||||
vec2 tangle44 = vec2(sin(-tmt), cos(-tmt)); tmt += 0.5;
|
||||
vec2 tangle45 = vec2(sin(-tmt), cos(-tmt));
|
||||
|
||||
tt = iGlobalTime+0.001;
|
||||
tm = mod(tt, 1.0);
|
||||
tmt = tt - tm;
|
||||
if( tm > 0.9) tmt += (tm-0.9)*10.0;
|
||||
|
||||
vec2 tangle51 = 0.17*vec2(sin(-tmt), cos(-tmt)); tmt += 1.0471975511965976;
|
||||
vec2 tangle52 = 0.17*vec2(sin(-tmt), cos(-tmt)); tmt += 1.0471975511965976;
|
||||
vec2 tangle53 = 0.17*vec2(sin(-tmt), cos(-tmt));
|
||||
|
||||
c += line(p, tangle51, -tangle53);
|
||||
c += line(p, tangle52, tangle51);
|
||||
c += line(p, tangle53, tangle52);
|
||||
c += line(p, -tangle51, tangle53);
|
||||
c += line(p, -tangle52, -tangle51);
|
||||
c += line(p, -tangle53, -tangle52);
|
||||
|
||||
c += circleFill(p+tangle51, 0.01);
|
||||
c += circleFill(p+tangle52, 0.01);
|
||||
c += circleFill(p+tangle53, 0.01);
|
||||
c += circleFill(p-tangle51, 0.01);
|
||||
c += circleFill(p-tangle52, 0.01);
|
||||
c += circleFill(p-tangle53, 0.01);
|
||||
|
||||
|
||||
|
||||
c += circle(p+a, 0.2);
|
||||
c += circle(p+a, 0.14);
|
||||
c += circle(p+a, 0.1);
|
||||
c += circleFill(p+a, 0.04);
|
||||
c += circleFill(p+a+tangle3*0.2, 0.025);
|
||||
|
||||
|
||||
c += circle(p+a, 0.14);
|
||||
|
||||
|
||||
c += circle(p+b, 0.2);
|
||||
c += circle(p+b, 0.03);
|
||||
c += circle(p+b, 0.15);
|
||||
c += circle(p+b, 0.45);
|
||||
c += circleFill(p+b+tangle1*0.05, 0.01);
|
||||
c += circleFill(p+b+tangle1*0.09, 0.02);
|
||||
c += circleFill(p+b+tangle1*0.15, 0.03);
|
||||
c += circle(p+b+tangle1*-0.15, 0.03);
|
||||
c += circle(p+b+tangle1*-0.07, 0.015);
|
||||
|
||||
c += circle(p+d, 0.08);
|
||||
|
||||
|
||||
c += circle(p+e, 0.08);
|
||||
|
||||
|
||||
c += circle(p+f, 0.12);
|
||||
c += circle(p+f, 0.10);
|
||||
c += circleFill(p+f+tangle2*0.05, 0.01);
|
||||
c += circleFill(p+f+tangle2*0.10, 0.01);
|
||||
c += circle(p+f-tangle2*0.03, 0.01);
|
||||
c += circleFill(p+f+vec2(0.085), 0.005);
|
||||
c += circleFill(p+f, 0.005);
|
||||
|
||||
|
||||
vec2 g = tangle4 * 0.16;
|
||||
c += circle(p+h, 0.05);
|
||||
c += circle(p+h, 0.1);
|
||||
c += circle(p+h, 0.17);
|
||||
c += circle(p+h, 0.2);
|
||||
c += circleFill(p+h+tangle41 *0.16, 0.01);
|
||||
c += circleFill(p+h+tangle42 *0.16, 0.01);
|
||||
c += circleFill(p+h+tangle43 *0.16, 0.01);
|
||||
c += circleFill(p+h+tangle44 *0.16, 0.01);
|
||||
c += circleFill(p+h+tangle45 *0.16, 0.01);
|
||||
c += circleFill(p+h+angle1 *0.06, 0.02);
|
||||
c += circleFill(p+h+tangle43*-0.16, 0.01);
|
||||
|
||||
|
||||
c += line(p, vec2(0.0), a);
|
||||
c += circleFill(p+b, 0.005);
|
||||
c += circleFill(p+d, 0.005);
|
||||
c += circleFill(p+e, 0.005);
|
||||
|
||||
c += line(p, b, a);
|
||||
c += line(p, d, e);
|
||||
c += line(p, b+tangle1*0.15, e);
|
||||
c += line(p, e, f+vec2(0.085));
|
||||
|
||||
c += line(p, h+angle1*0.06, f);
|
||||
c += line(p, h+tangle43*-0.16, d);
|
||||
c += line(p, h+tangle42*0.16, e);
|
||||
|
||||
|
||||
// of course I'd write a line function that
|
||||
// doesn't handle perfectly vertical lines
|
||||
c += line(p, vec2(0.001, -0.5), vec2(0.0001, 0.5));
|
||||
c += circleFill(p+vec2(0.001, -0.5), 0.005);
|
||||
c += circleFill(p+vec2(0.001, 0.5), 0.005);
|
||||
|
||||
c = clamp(c, 0.0, 1.0);
|
||||
colour = white * c;
|
||||
|
||||
|
||||
fragColor = vec4(colour, 1.0);
|
||||
}
|
||||
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec4 result;
|
||||
vec2 position = _position.xz;
|
||||
position += 0.5;
|
||||
|
||||
mainImage(result, position * iWorldScale.xz);
|
||||
return result;
|
||||
}
|
269
examples/shaders/shadertoys/relentless.fs
Normal file
269
examples/shaders/shadertoys/relentless.fs
Normal file
|
@ -0,0 +1,269 @@
|
|||
vec2 iResolution = iWorldScale.xz;
|
||||
vec2 iMouse = vec2(0);
|
||||
|
||||
// From https://www.shadertoy.com/view/lss3WS
|
||||
|
||||
// srtuss, 2013
|
||||
|
||||
// collecting some design ideas for a new game project.
|
||||
// no raymarching is used.
|
||||
|
||||
// if i could add a custom soundtrack, it'd use this one (essential for desired sensation)
|
||||
// http://www.youtube.com/watch?v=1uFAu65tZpo
|
||||
|
||||
//#define GREEN_VERSION
|
||||
|
||||
// ** improved camera shaking
|
||||
// ** cleaned up code
|
||||
// ** added stuff to the gates
|
||||
|
||||
// *******************************************************************************************
|
||||
// Please do NOT use this shader in your own productions/videos/games without my permission!
|
||||
// If you'd still like to do so, please drop me a mail (stral@aon.at)
|
||||
// *******************************************************************************************
|
||||
|
||||
float time = iGlobalTime;
|
||||
|
||||
vec2 rotate(vec2 p, float a) {
|
||||
return vec2(p.x * cos(a) - p.y * sin(a), p.x * sin(a) + p.y * cos(a));
|
||||
}
|
||||
float box(vec2 p, vec2 b, float r) {
|
||||
return length(max(abs(p) - b, 0.0)) - r;
|
||||
}
|
||||
|
||||
// iq's ray-plane-intersection code
|
||||
vec3 intersect(in vec3 o, in vec3 d, vec3 c, vec3 u, vec3 v)
|
||||
{
|
||||
vec3 q = o - c;
|
||||
return vec3(
|
||||
dot(cross(u, v), q),
|
||||
dot(cross(q, u), d),
|
||||
dot(cross(v, q), d)) / dot(cross(v, u), d);
|
||||
}
|
||||
|
||||
// some noise functions for fast developing
|
||||
float rand11(float p) {
|
||||
return fract(sin(p * 591.32) * 43758.5357);
|
||||
}
|
||||
float rand12(vec2 p) {
|
||||
return fract(sin(dot(p.xy, vec2(12.9898, 78.233))) * 43758.5357);
|
||||
}
|
||||
vec2 rand21(float p) {
|
||||
return fract(vec2(sin(p * 591.32), cos(p * 391.32)));
|
||||
}
|
||||
vec2 rand22(in vec2 p)
|
||||
{
|
||||
return fract(vec2(sin(p.x * 591.32 + p.y * 154.077), cos(p.x * 391.32 + p.y * 49.077)));
|
||||
}
|
||||
|
||||
float noise11(float p) {
|
||||
float fl = floor(p);
|
||||
return mix(rand11(fl), rand11(fl + 1.0), fract(p)); //smoothstep(0.0, 1.0, fract(p)));
|
||||
}
|
||||
float fbm11(float p) {
|
||||
return noise11(p) * 0.5 + noise11(p * 2.0) * 0.25 + noise11(p * 5.0) * 0.125;
|
||||
}
|
||||
vec3 noise31(float p) {
|
||||
return vec3(noise11(p), noise11(p + 18.952), noise11(p - 11.372)) * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
// something that looks a bit like godrays coming from the surface
|
||||
float sky(vec3 p) {
|
||||
float a = atan(p.x, p.z);
|
||||
float t = time * 0.1;
|
||||
float v = rand11(floor(a * 4.0 + t)) * 0.5 + rand11(floor(a * 8.0 - t)) * 0.25
|
||||
+ rand11(floor(a * 16.0 + t)) * 0.125;
|
||||
return v;
|
||||
}
|
||||
|
||||
vec3 voronoi(in vec2 x)
|
||||
{
|
||||
vec2 n = floor(x); // grid cell id
|
||||
vec2 f = fract(x);// grid internal position
|
||||
vec2 mg;// shortest distance...
|
||||
vec2 mr;// ..and second shortest distance
|
||||
float md = 8.0, md2 = 8.0;
|
||||
for(int j = -1; j <= 1; j ++)
|
||||
{
|
||||
for(int i = -1; i <= 1; i ++)
|
||||
{
|
||||
vec2 g = vec2(float(i), float(j)); // cell id
|
||||
vec2 o = rand22(n + g);// offset to edge point
|
||||
vec2 r = g + o - f;
|
||||
|
||||
float d = max(abs(r.x), abs(r.y));// distance to the edge
|
||||
|
||||
if(d < md)
|
||||
{ md2 = md; md = d; mr = r; mg = g;}
|
||||
else if(d < md2)
|
||||
{ md2 = d;}
|
||||
}
|
||||
}
|
||||
return vec3(n + mg, md2 - md);
|
||||
}
|
||||
|
||||
#define A2V(a) vec2(sin((a) * 6.28318531 / 100.0), cos((a) * 6.28318531 / 100.0))
|
||||
|
||||
float circles(vec2 p) {
|
||||
float v, w, l, c;
|
||||
vec2 pp;
|
||||
l = length(p);
|
||||
|
||||
pp = rotate(p, time * 3.0);
|
||||
c = max(dot(pp, normalize(vec2(-0.2, 0.5))),
|
||||
-dot(pp, normalize(vec2(0.2, 0.5))));
|
||||
c = min(c,
|
||||
max(dot(pp, normalize(vec2(0.5, -0.5))),
|
||||
-dot(pp, normalize(vec2(0.2, -0.5)))));
|
||||
c = min(c,
|
||||
max(dot(pp, normalize(vec2(0.3, 0.5))),
|
||||
-dot(pp, normalize(vec2(0.2, 0.5)))));
|
||||
|
||||
// innerest stuff
|
||||
v = abs(l - 0.5) - 0.03;
|
||||
v = max(v, -c);
|
||||
v = min(v, abs(l - 0.54) - 0.02);
|
||||
v = min(v, abs(l - 0.64) - 0.05);
|
||||
|
||||
pp = rotate(p, time * -1.333);
|
||||
c = max(dot(pp, A2V(-5.0)), -dot(pp, A2V(5.0)));
|
||||
c = min(c, max(dot(pp, A2V(25.0 - 5.0)), -dot(pp, A2V(25.0 + 5.0))));
|
||||
c = min(c, max(dot(pp, A2V(50.0 - 5.0)), -dot(pp, A2V(50.0 + 5.0))));
|
||||
c = min(c, max(dot(pp, A2V(75.0 - 5.0)), -dot(pp, A2V(75.0 + 5.0))));
|
||||
|
||||
w = abs(l - 0.83) - 0.09;
|
||||
v = min(v, max(w, c));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
float shade1(float d) {
|
||||
float v = 1.0 - smoothstep(0.0, mix(0.012, 0.2, 0.0), d);
|
||||
float g = exp(d * -20.0);
|
||||
return v + g * 0.5;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
vec2 uv = fragCoord.xy / iResolution.xy;
|
||||
uv = uv * 2.0 - 1.0;
|
||||
uv.x *= iResolution.x / iResolution.y;
|
||||
|
||||
// using an iq styled camera this time :)
|
||||
// ray origin
|
||||
vec3 ro = 0.7 * vec3(cos(0.2 * time), 0.0, sin(0.2 * time));
|
||||
ro.y = cos(0.6 * time) * 0.3 + 0.65;
|
||||
// camera look at
|
||||
vec3 ta = vec3(0.0, 0.2, 0.0);
|
||||
|
||||
// camera shake intensity
|
||||
float shake = clamp(3.0 * (1.0 - length(ro.yz)), 0.3, 1.0);
|
||||
float st = mod(time, 10.0) * 143.0;
|
||||
|
||||
// build camera matrix
|
||||
vec3 ww = normalize(ta - ro + noise31(st) * shake * 0.01);
|
||||
vec3 uu = normalize(cross(ww, normalize(vec3(0.0, 1.0, 0.2 * sin(time)))));
|
||||
vec3 vv = normalize(cross(uu, ww));
|
||||
// obtain ray direction
|
||||
vec3 rd = normalize(uv.x * uu + uv.y * vv + 1.0 * ww);
|
||||
|
||||
// shaking and movement
|
||||
ro += noise31(-st) * shake * 0.015;
|
||||
ro.x += time * 2.0;
|
||||
|
||||
float inten = 0.0;
|
||||
|
||||
// background
|
||||
float sd = dot(rd, vec3(0.0, 1.0, 0.0));
|
||||
inten = pow(1.0 - abs(sd), 20.0) + pow(sky(rd), 5.0) * step(0.0, rd.y) * 0.2;
|
||||
|
||||
vec3 its;
|
||||
float v, g;
|
||||
|
||||
// voronoi floor layers
|
||||
for(int i = 0; i < 4; i ++)
|
||||
{
|
||||
float layer = float(i);
|
||||
its = intersect(ro, rd, vec3(0.0, -5.0 - layer * 5.0, 0.0), vec3(1.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0));
|
||||
if(its.x > 0.0)
|
||||
{
|
||||
vec3 vo = voronoi((its.yz) * 0.05 + 8.0 * rand21(float(i)));
|
||||
v = exp(-100.0 * (vo.z - 0.02));
|
||||
|
||||
float fx = 0.0;
|
||||
|
||||
// add some special fx to lowest layer
|
||||
if(i == 3)
|
||||
{
|
||||
float crd = 0.0; //fract(time * 0.2) * 50.0 - 25.0;
|
||||
float fxi = cos(vo.x * 0.2 + time * 1.5);//abs(crd - vo.x);
|
||||
fx = clamp(smoothstep(0.9, 1.0, fxi), 0.0, 0.9) * 1.0 * rand12(vo.xy);
|
||||
fx *= exp(-3.0 * vo.z) * 2.0;
|
||||
}
|
||||
inten += v * 0.1 + fx;
|
||||
}
|
||||
}
|
||||
|
||||
// draw the gates, 4 should be enough
|
||||
float gatex = floor(ro.x / 8.0 + 0.5) * 8.0 + 4.0;
|
||||
float go = -16.0;
|
||||
for(int i = 0; i < 4; i ++)
|
||||
{
|
||||
its = intersect(ro, rd, vec3(gatex + go, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0));
|
||||
if(dot(its.yz, its.yz) < 2.0 && its.x > 0.0)
|
||||
{
|
||||
v = circles(its.yz);
|
||||
inten += shade1(v);
|
||||
}
|
||||
|
||||
go += 8.0;
|
||||
}
|
||||
|
||||
// draw the stream
|
||||
for(int j = 0; j < 20; j ++)
|
||||
{
|
||||
float id = float(j);
|
||||
|
||||
vec3 bp = vec3(0.0, (rand11(id) * 2.0 - 1.0) * 0.25, 0.0);
|
||||
vec3 its = intersect(ro, rd, bp, vec3(1.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0));
|
||||
|
||||
if(its.x > 0.0)
|
||||
{
|
||||
vec2 pp = its.yz;
|
||||
float spd = (1.0 + rand11(id) * 3.0) * 2.5;
|
||||
pp.y += time * spd;
|
||||
pp += (rand21(id) * 2.0 - 1.0) * vec2(0.3, 1.0);
|
||||
float rep = rand11(id) + 1.5;
|
||||
pp.y = mod(pp.y, rep * 2.0) - rep;
|
||||
float d = box(pp, vec2(0.02, 0.3), 0.1);
|
||||
float foc = 0.0;
|
||||
float v = 1.0 - smoothstep(0.0, 0.03, abs(d) - 0.001);
|
||||
float g = min(exp(d * -20.0), 2.0);
|
||||
|
||||
inten += (v + g * 0.7) * 0.5;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inten *= 0.4 + (sin(time) * 0.5 + 0.5) * 0.6;
|
||||
|
||||
// find a color for the computed intensity
|
||||
#ifdef GREEN_VERSION
|
||||
vec3 col = pow(vec3(inten), vec3(2.0, 0.15, 9.0));
|
||||
#else
|
||||
vec3 col = pow(vec3(inten), 1.5 * vec3(0.15, 2.0, 9.0));
|
||||
#endif
|
||||
|
||||
fragColor = vec4(col, 1.0);
|
||||
}
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec4 result;
|
||||
vec2 position = _position.xz;
|
||||
position += 0.5;
|
||||
position.y = 1.0 - position.y;
|
||||
|
||||
mainImage(result, position * iWorldScale.xz);
|
||||
|
||||
return result;
|
||||
}
|
136
examples/shaders/shadertoys/topologica.fs
Normal file
136
examples/shaders/shadertoys/topologica.fs
Normal file
|
@ -0,0 +1,136 @@
|
|||
#line 2
|
||||
vec2 iResolution = iWorldScale.xz;
|
||||
vec2 iMouse = vec2(0);
|
||||
|
||||
// From https://www.shadertoy.com/view/4djXzz
|
||||
|
||||
/*--------------------------------------------------------------------------------------
|
||||
License CC0 - http://creativecommons.org/publicdomain/zero/1.0/
|
||||
To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty.
|
||||
----------------------------------------------------------------------------------------
|
||||
^ This means do ANYTHING YOU WANT with this code. Because we are programmers, not lawyers.
|
||||
-Otavio Good
|
||||
*/
|
||||
|
||||
// various noise functions
|
||||
float Hash2d(vec2 uv)
|
||||
{
|
||||
float f = uv.x + uv.y * 47.0;
|
||||
return fract(cos(f*3.333)*100003.9);
|
||||
}
|
||||
float Hash3d(vec3 uv) {
|
||||
float f = uv.x + uv.y * 37.0 + uv.z * 521.0;
|
||||
return fract(cos(f * 3.333) * 100003.9);
|
||||
}
|
||||
float mixP(float f0, float f1, float a) {
|
||||
return mix(f0, f1, a * a * (3.0 - 2.0 * a));
|
||||
}
|
||||
const vec2 zeroOne = vec2(0.0, 1.0);
|
||||
float noise2d(vec2 uv) {
|
||||
vec2 fr = fract(uv.xy);
|
||||
vec2 fl = floor(uv.xy);
|
||||
float h00 = Hash2d(fl);
|
||||
float h10 = Hash2d(fl + zeroOne.yx);
|
||||
float h01 = Hash2d(fl + zeroOne);
|
||||
float h11 = Hash2d(fl + zeroOne.yy);
|
||||
return mixP(mixP(h00, h10, fr.x), mixP(h01, h11, fr.x), fr.y);
|
||||
}
|
||||
|
||||
float noise(vec3 uv) {
|
||||
vec3 fr = fract(uv.xyz);
|
||||
vec3 fl = floor(uv.xyz);
|
||||
float h000 = Hash3d(fl);
|
||||
float h100 = Hash3d(fl + zeroOne.yxx);
|
||||
float h010 = Hash3d(fl + zeroOne.xyx);
|
||||
float h110 = Hash3d(fl + zeroOne.yyx);
|
||||
float h001 = Hash3d(fl + zeroOne.xxy);
|
||||
float h101 = Hash3d(fl + zeroOne.yxy);
|
||||
float h011 = Hash3d(fl + zeroOne.xyy);
|
||||
float h111 = Hash3d(fl + zeroOne.yyy);
|
||||
return mixP(mixP(mixP(h000, h100, fr.x), mixP(h010, h110, fr.x), fr.y),
|
||||
mixP(mixP(h001, h101, fr.x), mixP(h011, h111, fr.x), fr.y), fr.z);
|
||||
}
|
||||
|
||||
float PI = 3.14159265;
|
||||
|
||||
vec3 saturate(vec3 a) {
|
||||
return clamp(a, 0.0, 1.0);
|
||||
}
|
||||
vec2 saturate(vec2 a) {
|
||||
return clamp(a, 0.0, 1.0);
|
||||
}
|
||||
float saturate(float a) {
|
||||
return clamp(a, 0.0, 1.0);
|
||||
}
|
||||
|
||||
float Density(vec3 p) {
|
||||
//float ws = 0.06125*0.125;
|
||||
//vec3 warp = vec3(noise(p*ws), noise(p*ws + 111.11), noise(p*ws + 7111.11));
|
||||
float final = noise(p * 0.06125); // + sin(iGlobalTime)*0.5-1.95 + warp.x*4.0;
|
||||
float other = noise(p * 0.06125 + 1234.567);
|
||||
other -= 0.5;
|
||||
final -= 0.5;
|
||||
final = 0.1 / (abs(final * final * other));
|
||||
final += 0.5;
|
||||
return final * 0.0001;
|
||||
}
|
||||
|
||||
void mainImage( out vec4 fragColor, in vec2 fragCoord )
|
||||
{
|
||||
// ---------------- First, set up the camera rays for ray marching ----------------
|
||||
vec2 uv = fragCoord.xy/iResolution.xy * 2.0 - 1.0;// - 0.5;
|
||||
|
||||
// Camera up vector.
|
||||
vec3 camUp=vec3(0,1,0);// vuv
|
||||
|
||||
// Camera lookat.
|
||||
vec3 camLookat=vec3(0,0.0,0);// vrp
|
||||
|
||||
float mx=iMouse.x/iResolution.x*PI*2.0 + iGlobalTime * 0.01;
|
||||
float my=-iMouse.y/iResolution.y*10.0 + sin(iGlobalTime * 0.03)*0.2+0.2;//*PI/2.01;
|
||||
vec3 camPos=vec3(cos(my)*cos(mx),sin(my),cos(my)*sin(mx))*(200.2);// prp
|
||||
|
||||
// Camera setup.
|
||||
vec3 camVec=normalize(camLookat - camPos);//vpn
|
||||
vec3 sideNorm=normalize(cross(camUp, camVec));// u
|
||||
vec3 upNorm=cross(camVec, sideNorm);//v
|
||||
vec3 worldFacing=(camPos + camVec);//vcv
|
||||
vec3 worldPix = worldFacing + uv.x * sideNorm * (iResolution.x/iResolution.y) + uv.y * upNorm;//scrCoord
|
||||
vec3 relVec = normalize(worldPix - camPos);//scp
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
float t = 0.0;
|
||||
float inc = 0.02;
|
||||
float maxDepth = 70.0;
|
||||
vec3 pos = vec3(0,0,0);
|
||||
float density = 0.0;
|
||||
// ray marching time
|
||||
for (int i = 0; i < 37; i++)// This is the count of how many times the ray actually marches.
|
||||
{
|
||||
if ((t > maxDepth)) break;
|
||||
pos = camPos + relVec * t;
|
||||
float temp = Density(pos);
|
||||
//temp *= saturate(t-1.0);
|
||||
|
||||
inc = 1.9 + temp*0.05;// add temp because this makes it look extra crazy!
|
||||
density += temp * inc;
|
||||
t += inc;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Now that we have done our ray marching, let's put some color on this.
|
||||
vec3 finalColor = vec3(0.01,0.1,1.0)* density*0.2;
|
||||
|
||||
// output the final color with sqrt for "gamma correction"
|
||||
fragColor = vec4(sqrt(clamp(finalColor, 0.0, 1.0)),1.0);
|
||||
}
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec4 result;
|
||||
vec2 position = _position.xz;
|
||||
position += 0.5;
|
||||
|
||||
mainImage(result, position * iWorldScale.xz);
|
||||
|
||||
return result;
|
||||
}
|
48
examples/shaders/test.fs
Normal file
48
examples/shaders/test.fs
Normal file
|
@ -0,0 +1,48 @@
|
|||
#line 2
|
||||
// Created by inigo quilez - iq/2014
|
||||
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
|
||||
|
||||
// { 2d cell id, distance to border, distnace to center )
|
||||
vec4 hexagon(vec2 p) {
|
||||
vec2 q = vec2(p.x * 2.0 * 0.5773503, p.y + p.x * 0.5773503);
|
||||
|
||||
vec2 pi = floor(q);
|
||||
vec2 pf = fract(q);
|
||||
|
||||
float v = mod(pi.x + pi.y, 3.0);
|
||||
|
||||
float ca = step(1.0, v);
|
||||
float cb = step(2.0, v);
|
||||
vec2 ma = step(pf.xy, pf.yx);
|
||||
|
||||
// distance to borders
|
||||
float e = dot(ma,
|
||||
1.0 - pf.yx + ca * (pf.x + pf.y - 1.0) + cb * (pf.yx - 2.0 * pf.xy));
|
||||
|
||||
// distance to center
|
||||
p = vec2(q.x + floor(0.5 + p.y / 1.5), 4.0 * p.y / 3.0) * 0.5 + 0.5;
|
||||
float f = length((fract(p) - 0.5) * vec2(1.0, 0.85));
|
||||
|
||||
return vec4(pi + ca - cb * ma, e, f);
|
||||
}
|
||||
|
||||
|
||||
float hash1(vec2 p) {
|
||||
float n = dot(p, vec2(127.1, 311.7));
|
||||
return fract(sin(n) * 43758.5453);
|
||||
}
|
||||
|
||||
vec4 getProceduralColor() {
|
||||
vec2 uv = _position.xz + 0.5;
|
||||
vec2 pos = _position.xz * 40.0;
|
||||
// gray
|
||||
vec4 h = hexagon(8.0 * pos + 0.5);
|
||||
float n = snoise(vec3(0.3 * h.xy + iGlobalTime * 0.1, iGlobalTime));
|
||||
vec3 col = 0.15 + 0.15 * hash1(h.xy + 1.2) * vec3(1.0);
|
||||
col *= smoothstep(0.10, 0.11, h.z);
|
||||
col *= smoothstep(0.10, 0.11, h.w);
|
||||
col *= 1.0 + 0.15 * sin(40.0 * h.z);
|
||||
col *= 0.75 + 0.5 * h.z * n;
|
||||
col *= pow(16.0 * uv.x * (1.0 - uv.x) * uv.y * (1.0 - uv.y), 0.1);
|
||||
return vec4(col, 1.0);
|
||||
}
|
|
@ -358,13 +358,19 @@ var NATURAL_DIMENSIONS = { x: 1.63, y: 1.67, z: 0.31 };
|
|||
var DIMENSIONS = Vec3.multiply(NATURAL_DIMENSIONS, 0.3);
|
||||
var puppetEntityID;
|
||||
|
||||
function createPuppet() {
|
||||
function createPuppet(model, location) {
|
||||
if (model === undefined) {
|
||||
model = "https://hifi-public.s3.amazonaws.com/models/Bboys/bboy1/bboy1.fbx";
|
||||
}
|
||||
if (location == undefined) {
|
||||
location = getPositionPuppet();
|
||||
}
|
||||
puppetEntityID = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: "https://hifi-public.s3.amazonaws.com/models/Bboys/bboy1/bboy1.fbx",
|
||||
modelURL: model,
|
||||
animationURL: "http://s3.amazonaws.com/hifi-public/animations/Breakdancing/breakdance_ready.fbx",
|
||||
animationSettings: ANIMATION_SETTINGS,
|
||||
position: getPositionPuppet(),
|
||||
position: location,
|
||||
ignoreForCollisions: true,
|
||||
dimensions: DIMENSIONS,
|
||||
lifetime: TEMPORARY_LIFETIME
|
||||
|
@ -452,10 +458,10 @@ poses[LEFT_SIDE + RIGHT_FRONT ] = { name: "Left Side + Right Front",
|
|||
poses[LEFT_FRONT + RIGHT_FRONT ] = { name: "Left Front + Right Front", animation: "http://s3.amazonaws.com/hifi-public/animations/Breakdancing/breakdance_uprock_var_1_end.fbx" };
|
||||
|
||||
|
||||
breakdanceStart = function() {
|
||||
breakdanceStart = function(model, location) {
|
||||
print("breakdanceStart...");
|
||||
createOverlays();
|
||||
createPuppet();
|
||||
createPuppet(model, location);
|
||||
}
|
||||
|
||||
breakdanceUpdate = function(deltaTime) {
|
||||
|
|
54
examples/toys/bubblewand/bubble.js
Normal file
54
examples/toys/bubblewand/bubble.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
// bubble.js
|
||||
// part of bubblewand
|
||||
//
|
||||
// Created by James B. Pollack @imgntn -- 09/03/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// example of a nested entity. it doesn't do much now besides delete itself if it collides with something (bubbles are fragile! it would be cool if it sometimes merged with other bubbbles it hit)
|
||||
// todo: play bubble sounds from the bubble itself instead of the wand.
|
||||
// blocker: needs some sound fixes and a way to find its own position before unload for spatialization
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
(function() {
|
||||
// Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/utilities.js");
|
||||
// Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/libraries/utils.js");
|
||||
|
||||
//var popSound;
|
||||
this.preload = function(entityID) {
|
||||
// print('bubble preload')
|
||||
this.entityID = entityID;
|
||||
// popSound = SoundCache.getSound("http://hifi-public.s3.amazonaws.com/james/bubblewand/sounds/pop.wav");
|
||||
|
||||
}
|
||||
|
||||
this.collisionWithEntity = function(myID, otherID, collision) {
|
||||
//if(Entites.getEntityProperties(otherID).userData.objectType==='') { merge bubbles?}
|
||||
Entities.deleteEntity(myID);
|
||||
// this.burstBubbleSound(collision.contactPoint)
|
||||
|
||||
};
|
||||
|
||||
this.unload = function(entityID) {
|
||||
// this.properties = Entities.getEntityProperties(entityID);
|
||||
//var location = this.properties.position;
|
||||
//this.burstBubbleSound();
|
||||
};
|
||||
|
||||
|
||||
|
||||
this.burstBubbleSound = function(location) {
|
||||
|
||||
// var audioOptions = {
|
||||
// volume: 0.5,
|
||||
// position: location
|
||||
// }
|
||||
|
||||
//Audio.playSound(popSound, audioOptions);
|
||||
|
||||
}
|
||||
|
||||
|
||||
})
|
42
examples/toys/bubblewand/createWand.js
Normal file
42
examples/toys/bubblewand/createWand.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
// createWand.js
|
||||
// part of bubblewand
|
||||
//
|
||||
// Created by James B. Pollack @imgntn -- 09/03/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Loads a wand model and attaches the bubble wand behavior.
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
|
||||
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/utilities.js");
|
||||
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/libraries/utils.js");
|
||||
|
||||
var wandModel = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/wand.fbx?" + randInt(0, 10000);
|
||||
var scriptURL = "http://hifi-public.s3.amazonaws.com/james/bubblewand/scripts/wand.js?" + randInt(1, 100500)
|
||||
|
||||
|
||||
//create the wand in front of the avatar
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
|
||||
var wand = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: wandModel,
|
||||
position: center,
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 1,
|
||||
z: 0.1
|
||||
},
|
||||
//must be enabled to be grabbable in the physics engine
|
||||
collisionsWillMove: true,
|
||||
shapeType: 'box',
|
||||
script: scriptURL
|
||||
});
|
||||
|
||||
function cleanup() {
|
||||
//Entities.deleteEntity(wand);
|
||||
}
|
||||
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
317
examples/toys/bubblewand/wand.js
Normal file
317
examples/toys/bubblewand/wand.js
Normal file
|
@ -0,0 +1,317 @@
|
|||
// wand.js
|
||||
// part of bubblewand
|
||||
//
|
||||
// Created by James B. Pollack @imgntn -- 09/03/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Makes bubbles when you wave the object around, or hold it near your mouth and make noise into the microphone.
|
||||
//
|
||||
// For the example, it's attached to a wand -- but you can attach it to whatever entity you want. I dream of BubbleBees :) bzzzz...pop!
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
function convertRange(value, r1, r2) {
|
||||
return (value - r1[0]) * (r2[1] - r2[0]) / (r1[1] - r1[0]) + r2[0];
|
||||
}
|
||||
|
||||
(function() {
|
||||
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/utilities.js");
|
||||
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/libraries/utils.js");
|
||||
|
||||
var bubbleModel = "http://hifi-public.s3.amazonaws.com/james/bubblewand/models/bubble/bubble.fbx";
|
||||
var bubbleScript = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/scripts/bubble.js?' + randInt(1, 10000);
|
||||
var popSound = SoundCache.getSound("http://hifi-public.s3.amazonaws.com/james/bubblewand/sounds/pop.wav");
|
||||
|
||||
var TARGET_SIZE = 0.4;
|
||||
var TARGET_COLOR = {
|
||||
red: 128,
|
||||
green: 128,
|
||||
blue: 128
|
||||
};
|
||||
var TARGET_COLOR_HIT = {
|
||||
red: 0,
|
||||
green: 255,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var HAND_SIZE = 0.25;
|
||||
var leftCubePosition = MyAvatar.getLeftPalmPosition();
|
||||
var rightCubePosition = MyAvatar.getRightPalmPosition();
|
||||
|
||||
var leftHand = Overlays.addOverlay("cube", {
|
||||
position: leftCubePosition,
|
||||
size: HAND_SIZE,
|
||||
color: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 255
|
||||
},
|
||||
alpha: 1,
|
||||
solid: false
|
||||
});
|
||||
|
||||
var rightHand = Overlays.addOverlay("cube", {
|
||||
position: rightCubePosition,
|
||||
size: HAND_SIZE,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
},
|
||||
alpha: 1,
|
||||
solid: false
|
||||
});
|
||||
|
||||
var gustZoneOverlay = Overlays.addOverlay("cube", {
|
||||
position: getGustDetectorPosition(),
|
||||
size: TARGET_SIZE,
|
||||
color: TARGET_COLOR,
|
||||
alpha: 1,
|
||||
solid: false
|
||||
});
|
||||
|
||||
|
||||
function getGustDetectorPosition() {
|
||||
//put the zone in front of your avatar's face
|
||||
var DISTANCE_IN_FRONT = 0.2;
|
||||
var DISTANCE_UP = 0.5;
|
||||
var DISTANCE_TO_SIDE = 0.0;
|
||||
|
||||
var up = Quat.getUp(MyAvatar.orientation);
|
||||
var front = Quat.getFront(MyAvatar.orientation);
|
||||
var right = Quat.getRight(MyAvatar.orientation);
|
||||
|
||||
var upOffset = Vec3.multiply(up, DISTANCE_UP);
|
||||
var rightOffset = Vec3.multiply(right, DISTANCE_TO_SIDE);
|
||||
var frontOffset = Vec3.multiply(front, DISTANCE_IN_FRONT);
|
||||
|
||||
var offset = Vec3.sum(Vec3.sum(rightOffset, frontOffset), upOffset);
|
||||
var position = Vec3.sum(MyAvatar.position, offset);
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
var BUBBLE_GRAVITY = {
|
||||
x: 0,
|
||||
y: -0.05,
|
||||
z: 0
|
||||
}
|
||||
|
||||
|
||||
var wandEntity = this;
|
||||
|
||||
this.preload = function(entityID) {
|
||||
// print('PRELOAD')
|
||||
this.entityID = entityID;
|
||||
this.properties = Entities.getEntityProperties(this.entityID);
|
||||
}
|
||||
|
||||
this.unload = function(entityID) {
|
||||
Overlays.deleteOverlay(leftHand);
|
||||
Overlays.deleteOverlay(rightHand);
|
||||
Overlays.deleteOverlay(gustZoneOverlay)
|
||||
Entities.editEntity(entityID, {
|
||||
name: ""
|
||||
});
|
||||
Script.update.disconnect(BubbleWand.update);
|
||||
Entities.deleteEntity(BubbleWand.currentBubble);
|
||||
while (BubbleWand.bubbles.length > 0) {
|
||||
Entities.deleteEntity(BubbleWand.bubbles.pop());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
var BubbleWand = {
|
||||
bubbles: [],
|
||||
currentBubble: null,
|
||||
update: function() {
|
||||
BubbleWand.internalUpdate();
|
||||
},
|
||||
internalUpdate: function() {
|
||||
var _t = this;
|
||||
//get the current position of the wand
|
||||
var properties = Entities.getEntityProperties(wandEntity.entityID);
|
||||
var wandPosition = properties.position;
|
||||
|
||||
//debug overlays for mouth mode
|
||||
var leftHandPos = MyAvatar.getLeftPalmPosition();
|
||||
var rightHandPos = MyAvatar.getRightPalmPosition();
|
||||
|
||||
Overlays.editOverlay(leftHand, {
|
||||
position: leftHandPos
|
||||
});
|
||||
Overlays.editOverlay(rightHand, {
|
||||
position: rightHandPos
|
||||
});
|
||||
|
||||
//if the wand is in the gust detector, activate mouth mode and change the overlay color
|
||||
var hitTargetWithWand = findSphereSphereHit(wandPosition, HAND_SIZE / 2, getGustDetectorPosition(), TARGET_SIZE / 2)
|
||||
|
||||
var mouthMode;
|
||||
if (hitTargetWithWand) {
|
||||
Overlays.editOverlay(gustZoneOverlay, {
|
||||
position: getGustDetectorPosition(),
|
||||
color: TARGET_COLOR_HIT
|
||||
})
|
||||
mouthMode = true;
|
||||
|
||||
} else {
|
||||
Overlays.editOverlay(gustZoneOverlay, {
|
||||
position: getGustDetectorPosition(),
|
||||
color: TARGET_COLOR
|
||||
})
|
||||
mouthMode = false;
|
||||
}
|
||||
|
||||
var volumeLevel = MyAvatar.audioAverageLoudness;
|
||||
//volume numbers are pretty large, so lets scale them down.
|
||||
var convertedVolume = convertRange(volumeLevel, [0, 5000], [0, 10]);
|
||||
|
||||
// default is 'wave mode', where waving the object around grows the bubbles
|
||||
var velocity = Vec3.subtract(wandPosition, BubbleWand.lastPosition)
|
||||
|
||||
//store the last position of the wand for velocity calculations
|
||||
_t.lastPosition = wandPosition;
|
||||
|
||||
// velocity numbers are pretty small, so lets make them a bit bigger
|
||||
var velocityStrength = Vec3.length(velocity) * 100;
|
||||
|
||||
if (velocityStrength > 10) {
|
||||
velocityStrength = 10
|
||||
}
|
||||
|
||||
//actually grow the bubble
|
||||
var dimensions = Entities.getEntityProperties(_t.currentBubble).dimensions;
|
||||
|
||||
if (velocityStrength > 1 || convertedVolume > 1) {
|
||||
|
||||
//add some variation in bubble sizes
|
||||
var bubbleSize = randInt(1, 5);
|
||||
bubbleSize = bubbleSize / 10;
|
||||
|
||||
//release the bubble if its dimensions are bigger than the bubble size
|
||||
if (dimensions.x > bubbleSize) {
|
||||
//bubbles pop after existing for a bit -- so set a random lifetime
|
||||
var lifetime = randInt(3, 8);
|
||||
|
||||
//sound is somewhat unstable at the moment so this is commented out. really audio should be played by the bubbles, but there's a blocker.
|
||||
// Script.setTimeout(function() {
|
||||
// _t.burstBubbleSound(_t.currentBubble)
|
||||
// }, lifetime * 1000)
|
||||
|
||||
|
||||
//todo: angular velocity without the controller -- forward velocity for mouth mode bubbles
|
||||
// var angularVelocity = Controller.getSpatialControlRawAngularVelocity(hands.leftHand.tip);
|
||||
|
||||
Entities.editEntity(_t.currentBubble, {
|
||||
velocity: Vec3.normalize(velocity),
|
||||
// angularVelocity: Controller.getSpatialControlRawAngularVelocity(hands.leftHand.tip),
|
||||
lifetime: lifetime
|
||||
});
|
||||
|
||||
//release the bubble -- when we create a new bubble, it will carry on and this update loop will affect the new bubble
|
||||
BubbleWand.spawnBubble();
|
||||
|
||||
return
|
||||
} else {
|
||||
if (mouthMode) {
|
||||
dimensions.x += 0.015 * convertedVolume;
|
||||
dimensions.y += 0.015 * convertedVolume;
|
||||
dimensions.z += 0.015 * convertedVolume;
|
||||
|
||||
} else {
|
||||
dimensions.x += 0.015 * velocityStrength;
|
||||
dimensions.y += 0.015 * velocityStrength;
|
||||
dimensions.z += 0.015 * velocityStrength;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if (dimensions.x >= 0.02) {
|
||||
dimensions.x -= 0.001;
|
||||
dimensions.y -= 0.001;
|
||||
dimensions.z -= 0.001;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//update the bubble to stay with the wand tip
|
||||
Entities.editEntity(_t.currentBubble, {
|
||||
position: _t.wandTipPosition,
|
||||
dimensions: dimensions
|
||||
});
|
||||
|
||||
},
|
||||
burstBubbleSound: function(bubble) {
|
||||
//we want to play the sound at the same location and orientation as the bubble
|
||||
var position = Entities.getEntityProperties(bubble).position;
|
||||
var orientation = Entities.getEntityProperties(bubble).orientation;
|
||||
|
||||
//set the options for the audio injector
|
||||
var audioOptions = {
|
||||
volume: 0.5,
|
||||
position: position,
|
||||
orientation: orientation
|
||||
}
|
||||
|
||||
|
||||
//var audioInjector = Audio.playSound(popSound, audioOptions);
|
||||
|
||||
//remove this bubble from the array to keep things clean
|
||||
var i = BubbleWand.bubbles.indexOf(bubble);
|
||||
if (i != -1) {
|
||||
BubbleWand.bubbles.splice(i, 1);
|
||||
}
|
||||
|
||||
},
|
||||
spawnBubble: function() {
|
||||
var _t = this;
|
||||
//create a new bubble at the tip of the wand
|
||||
//the tip of the wand is going to be in a different place than the center, so we move in space relative to the model to find that position
|
||||
|
||||
var properties = Entities.getEntityProperties(wandEntity.entityID);
|
||||
var wandPosition = properties.position;
|
||||
var upVector = Quat.getUp(properties.rotation);
|
||||
var frontVector = Quat.getFront(properties.rotation);
|
||||
var upOffset = Vec3.multiply(upVector, 0.5);
|
||||
var forwardOffset = Vec3.multiply(frontVector, 0.1);
|
||||
var offsetVector = Vec3.sum(upOffset, forwardOffset);
|
||||
var wandTipPosition = Vec3.sum(wandPosition, offsetVector);
|
||||
_t.wandTipPosition = wandTipPosition;
|
||||
|
||||
//store the position of the tip on spawn for use in velocity calculations
|
||||
_t.lastPosition = wandTipPosition;
|
||||
|
||||
//create a bubble at the wand tip
|
||||
_t.currentBubble = Entities.addEntity({
|
||||
type: 'Model',
|
||||
modelURL: bubbleModel,
|
||||
position: wandTipPosition,
|
||||
dimensions: {
|
||||
x: 0.01,
|
||||
y: 0.01,
|
||||
z: 0.01
|
||||
},
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true,
|
||||
gravity: BUBBLE_GRAVITY,
|
||||
// collisionSoundURL:popSound,
|
||||
shapeType: "sphere",
|
||||
script: bubbleScript,
|
||||
});
|
||||
|
||||
//add this bubble to an array of bubbles so we can keep track of them
|
||||
_t.bubbles.push(_t.currentBubble)
|
||||
|
||||
},
|
||||
init: function() {
|
||||
this.spawnBubble();
|
||||
Script.update.connect(BubbleWand.update);
|
||||
}
|
||||
}
|
||||
|
||||
BubbleWand.init();
|
||||
|
||||
})
|
11
examples/utilities/tests/allPerfTests.js
Normal file
11
examples/utilities/tests/allPerfTests.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
//
|
||||
// Created by Seiji Emery on 9/4/15
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("entityPerfTest.js");
|
||||
Script.include("mathPerfTest.js");
|
||||
Script.include("forLoopPerfTest.js");
|
107
examples/utilities/tests/entityPerfTest.js
Normal file
107
examples/utilities/tests/entityPerfTest.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
//
|
||||
// Created by Seiji Emery on 9/4/15
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("perfTest.js");
|
||||
|
||||
function makeEntity () {
|
||||
return Entities.addEntity({
|
||||
type: "Box",
|
||||
position: Vec3.sum(MyAvatar.position, {
|
||||
x: 0.0, y: 0.0, z: 1.0
|
||||
}),
|
||||
dimensions: { x: 0.1, y: 0.1, z: 0.1 },
|
||||
userData: "fooooooooooooooooooooooo"
|
||||
});
|
||||
}
|
||||
|
||||
// Create + run tests
|
||||
(function () {
|
||||
var entityTests = new TestRunner();
|
||||
|
||||
entityTests.addTestCase('getEntityProperties')
|
||||
.before(function () {
|
||||
this.entity = makeEntity();
|
||||
})
|
||||
.after(function() {
|
||||
Entities.deleteEntity(this.entity);
|
||||
})
|
||||
.run(function() {
|
||||
var properties = Entities.getEntityProperties(this.entity);
|
||||
var foo = properties.userData;
|
||||
});
|
||||
|
||||
entityTests.addTestCase('add + delete entity')
|
||||
.run(function() {
|
||||
var entity = makeEntity();
|
||||
Entities.deleteEntity(entity);
|
||||
});
|
||||
entityTests.addTestCase('update entity')
|
||||
.before(function () {
|
||||
this.entity = makeEntity();
|
||||
})
|
||||
.after(function () {
|
||||
Entities.deleteEntity(this.entity);
|
||||
})
|
||||
.run(function() {
|
||||
Entities.editEntity(this.entity, { userData: "barrrrrrr" });
|
||||
});
|
||||
|
||||
TestCase.prototype.withEntityOp = function(op) {
|
||||
this.before(function(){
|
||||
this.entity = makeEntity();
|
||||
})
|
||||
this.after(function(){
|
||||
Entities.deleteEntity(this.entity);
|
||||
})
|
||||
this.run(op);
|
||||
}
|
||||
entityTests.addTestCase('find closest entity')
|
||||
.withEntityOp(function() {
|
||||
Entities.findClosestEntity(this.entity, MyAvatar.position, 100.0);
|
||||
})
|
||||
entityTests.addTestCase('findEntities')
|
||||
.withEntityOp(function(){
|
||||
Entities.findEntities(this.entity, MyAvatar.position, 10.0);
|
||||
})
|
||||
entityTests.addTestCase('findEntitiesInBox')
|
||||
.withEntityOp(function(){
|
||||
Entities.findEntitiesInBox(this.entity, MyAvatar.position, {x: 10.0, y: 10.0, z: 10.0});
|
||||
})
|
||||
|
||||
TestCase.prototype.withRay = function(op) {
|
||||
this.before(function(){
|
||||
this.ray = Camera.computePickRay(500, 200);
|
||||
});
|
||||
this.run(op);
|
||||
}
|
||||
entityTests.addTestCase('findRayIntersection, precisionPicking=true')
|
||||
.withRay(function(){
|
||||
Entities.findRayIntersection(this.ray, true);
|
||||
})
|
||||
entityTests.addTestCase('findRayIntersection, precisionPicking=false')
|
||||
.withRay(function(){
|
||||
Entities.findRayIntersection(this.ray, false);
|
||||
});
|
||||
entityTests.addTestCase('findRayIntersectionBlocking, precisionPicking=true')
|
||||
.withRay(function(){
|
||||
Entities.findRayIntersectionBlocking(this.ray, true);
|
||||
})
|
||||
entityTests.addTestCase('findRayIntersectionBlocking, precisionPicking=false')
|
||||
.withRay(function(){
|
||||
Entities.findRayIntersectionBlocking(this.ray, false);
|
||||
})
|
||||
entityTests.addTestCase('no-op')
|
||||
.run(function(){});
|
||||
|
||||
print("Running entity tests");
|
||||
entityTests.runAllTestsWithIterations([10, 100, 1000], 1e3, 10);
|
||||
entityTests.writeResultsToLog();
|
||||
})();
|
||||
|
||||
|
||||
|
140
examples/utilities/tests/forLoopPerfTest.js
Normal file
140
examples/utilities/tests/forLoopPerfTest.js
Normal file
|
@ -0,0 +1,140 @@
|
|||
//
|
||||
// Created by Seiji Emery on 9/4/15
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Checks various types of js iteration (for loops, for/in loops, Array.forEach, and Object.keys)
|
||||
// for speed + efficiency. Mostly a sanity check for my own code.
|
||||
//
|
||||
|
||||
Script.include("perfTest.js");
|
||||
|
||||
(function () {
|
||||
var input1 = [];
|
||||
var input2 = [];
|
||||
var N = 1000;
|
||||
for (var i = 0; i < N; ++i) {
|
||||
input1.push(Math.random());
|
||||
input2.push(Math.random());
|
||||
}
|
||||
TestCase.prototype.withArray = function(n, func) {
|
||||
this.before(function () {
|
||||
this.array = [];
|
||||
for (var i = 0; i < n; ++i) {
|
||||
this.array.push(0);
|
||||
}
|
||||
});
|
||||
this.run(fcn);
|
||||
}
|
||||
|
||||
print("For loop test -- prelim tests");
|
||||
var prelimTests = new TestRunner();
|
||||
prelimTests.addTestCase('Array.push (test component)')
|
||||
.before(function () {
|
||||
this.array = [];
|
||||
})
|
||||
.run(function () {
|
||||
this.array.push(1);
|
||||
});
|
||||
prelimTests.addTestCase('Array.push with mul op (test component)')
|
||||
.before(function() {
|
||||
this.array = [];
|
||||
})
|
||||
.run(function (i) {
|
||||
this.array.push(input1[i] * Math.PI);
|
||||
})
|
||||
prelimTests.runAllTestsWithIterations([1e4, 1e5, 1e6], 1e6, 10);
|
||||
|
||||
print("For loop test (n = " + N + ")");
|
||||
var loopTests = new TestRunner();
|
||||
loopTests.addTestCase('for (var i = 0; i < n; ++i) { ... }')
|
||||
.before(function () {
|
||||
this.array = [];
|
||||
})
|
||||
.run(function () {
|
||||
for (var i = 0; i < N; ++i) {
|
||||
this.array.push(input1[i] * Math.PI);
|
||||
}
|
||||
})
|
||||
loopTests.addTestCase('while (n --> 0) { ... } (reversed)')
|
||||
.before(function () {
|
||||
this.array = [];
|
||||
})
|
||||
.run(function () {
|
||||
var n = N;
|
||||
while (n --> 0) {
|
||||
this.array.push(input1[n] * Math.PI);
|
||||
}
|
||||
})
|
||||
loopTests.addTestCase('Array.forEach(function(v, i) { ... })')
|
||||
.before(function () {
|
||||
this.array = [];
|
||||
})
|
||||
.run(function () {
|
||||
input1.forEach(function(v) {
|
||||
this.array.push(v * Math.PI);
|
||||
}, this);
|
||||
})
|
||||
loopTests.addTestCase('Array.map(function(v, i) { ... })')
|
||||
.run(function () {
|
||||
this.array = input1.map(function (v) {
|
||||
return v * Math.PI;
|
||||
}, this);
|
||||
});
|
||||
loopTests.runAllTestsWithIterations([10, 100, 1000], 1e3, 10);
|
||||
|
||||
|
||||
// Test iteration on object keys
|
||||
|
||||
// http://stackoverflow.com/questions/10726909/random-alpha-numeric-string-in-javascript
|
||||
function makeRandomString(length, chars) {
|
||||
var result = '';
|
||||
for (var i = length; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))];
|
||||
return result;
|
||||
}
|
||||
function randomString () {
|
||||
var n = Math.floor(Math.random() * 18) + 12;
|
||||
return makeRandomString(n, '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');
|
||||
}
|
||||
|
||||
var obj = {}, numKeys = 1000;
|
||||
while (numKeys --> 0) {
|
||||
obj[randomString()] = Math.floor(Math.random() * 255);
|
||||
}
|
||||
print("Object iter tests (object has " + Object.keys(obj).length + " keys)");
|
||||
var iterTests = new TestRunner();
|
||||
iterTests.addTestCase('for (var k in obj) { foo(obj[k]); }')
|
||||
.before(function () {
|
||||
this.x = 0;
|
||||
})
|
||||
.run(function () {
|
||||
for (var k in obj) {
|
||||
this.x = (this.x + obj[k]) % 256;
|
||||
}
|
||||
});
|
||||
iterTests.addTestCase('for (var k in obj) { if (Object.hasOwnProperty(obj, k)) { foo(obj[k]); } }')
|
||||
.before(function () {
|
||||
this.x = 0;
|
||||
})
|
||||
.run(function () {
|
||||
for (var k in obj) {
|
||||
if (Object.hasOwnProperty(obj, k)) {
|
||||
this.x = (this.x + obj[k]) % 256;
|
||||
}
|
||||
}
|
||||
})
|
||||
iterTests.addTestCase('Object.keys(obj).forEach(function(k) { foo(obj[k]); }')
|
||||
.before(function () {
|
||||
this.x = 0;
|
||||
})
|
||||
.run(function () {
|
||||
Object.keys(obj).forEach(function (k) {
|
||||
this.x = (this.x + obj[k]) % 256;
|
||||
})
|
||||
})
|
||||
|
||||
iterTests.runAllTestsWithIterations([10, 100, 1000], 1e3, 10);
|
||||
})();
|
||||
|
127
examples/utilities/tests/mathPerfTest.js
Normal file
127
examples/utilities/tests/mathPerfTest.js
Normal file
|
@ -0,0 +1,127 @@
|
|||
//
|
||||
// Created by Seiji Emery on 9/4/15
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("perfTest.js");
|
||||
|
||||
// Native vec3 (for comparison)
|
||||
var Native = {};
|
||||
(function () {
|
||||
Native.Vec3 = function (x, y, z) {
|
||||
this.x = x || 0.0;
|
||||
this.y = y || 0.0;
|
||||
this.z = z || 0.0;
|
||||
}
|
||||
Native.Vec3.prototype.add = function (other) {
|
||||
this.x += other.x;
|
||||
this.y += other.y;
|
||||
this.z += other.z;
|
||||
}
|
||||
Native.Vec3.prototype.distance = function (other) {
|
||||
var rx = this.x - other.x;
|
||||
var ry = this.y - other.y;
|
||||
var rz = this.z - other.z;
|
||||
return Math.sqrt(rx * rx + ry * ry + rz * rz);
|
||||
}
|
||||
Native.Vec3.prototype.dist2 = function (other) {
|
||||
var rx = this.x - other.x;
|
||||
var ry = this.y - other.y;
|
||||
var rz = this.z - other.z;
|
||||
return rx * rx + ry * ry + rz * rz;
|
||||
}
|
||||
|
||||
Native.Quaternion = function (x, y, z, w) {
|
||||
this.x = x || 0.0;
|
||||
this.y = y || 0.0;
|
||||
this.z = z || 0.0;
|
||||
this.w = w || 0.0;
|
||||
}
|
||||
// Pulled from THREE.js
|
||||
Native.Quaternion.prototype.multiply = function(quat2) {
|
||||
var qax = this.x, qay = this.y, qaz = this.z, qaw = this.w,
|
||||
qbx = quat2.x, qby = quat2.y, qbz = quat2.z, qbw = quat2.w;
|
||||
this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
|
||||
this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
|
||||
this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
|
||||
this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
|
||||
return this;
|
||||
}
|
||||
})();
|
||||
|
||||
// Create + run tests
|
||||
(function () {
|
||||
var mathTests = new TestRunner();
|
||||
var foo;
|
||||
|
||||
print("math tests:");
|
||||
var iterations = [ 1000, 10000, 100000, 1000000 ];
|
||||
|
||||
print("builtin Vec3 + Quat (wrapped glm::vec3 + glm::quat)");
|
||||
var builtinTests = new TestRunner();
|
||||
builtinTests.addTestCase('Vec3.sum')
|
||||
.run(function () {
|
||||
foo = Vec3.sum({x: 10, y: 12, z: 3}, {x: 1, y: 2, z: 4});
|
||||
})
|
||||
builtinTests.addTestCase('Vec3.distance')
|
||||
.run(function () {
|
||||
foo = Vec3.distance({x: 1209, y: 298, z: 238}, {x: 239, y: 20, z: 23})
|
||||
})
|
||||
builtinTests.addTestCase('Quat.multiply')
|
||||
.run(function () {
|
||||
foo = Quat.multiply({x: 2190.0, y: 2109.0, z: 1209.0, w: 829.0}, {x: -1293.0, y: 1029.1, z: 2190.1, w: 129.0})
|
||||
});
|
||||
builtinTests.runAllTestsWithIterations([ 1e3, 1e4, 1e5 ], 1e3, 10);
|
||||
|
||||
print("");
|
||||
print("native JS Vec3 + Quaternion");
|
||||
var nativeTests = new TestRunner();
|
||||
nativeTests.addTestCase('Native Vec3.sum')
|
||||
.run(function () {
|
||||
foo = new Native.Vec3(10, 12, 3).add(new Native.Vec3(1, 2, 4));
|
||||
})
|
||||
nativeTests.addTestCase('Native Vec3.distance')
|
||||
.run(function () {
|
||||
foo = new Native.Vec3(1209, 298, 238).distance(new Native.Vec3(239, 20, 23));
|
||||
})
|
||||
nativeTests.addTestCase('Native Vec3.dist2')
|
||||
.run(function () {
|
||||
foo = new Native.Vec3(1209, 298, 238).dist2(new Native.Vec3(239, 20, 23));
|
||||
})
|
||||
nativeTests.addTestCase('Native Quat.multiply')
|
||||
.run(function () {
|
||||
foo = new Native.Quaternion(2190.0, 2109.0, 1209.0, 829.0).multiply(new Native.Quaternion(-1293.0, 1029.1, 2190.1, 129.0));
|
||||
});
|
||||
nativeTests.runAllTestsWithIterations([ 1e3, 1e4, 1e5, 1e6 ], 1e6, 10);
|
||||
|
||||
print("");
|
||||
print("no-ops (for test assignment / construction overhead)")
|
||||
mathTests.addTestCase('no-op')
|
||||
.run(function(){});
|
||||
mathTests.addTestCase('assign null')
|
||||
.run(function () {
|
||||
foo = null;
|
||||
});
|
||||
mathTests.addTestCase('assign object')
|
||||
.run(function () {
|
||||
foo = { x: 1902, y: 129, z: 21 };
|
||||
});
|
||||
mathTests.addTestCase('Native Vec3.construct -- 3 args')
|
||||
.run(function () {
|
||||
foo = new Native.Vec3(1209, 298, 238);
|
||||
});
|
||||
mathTests.addTestCase('Native Vec3.construct -- 2 args')
|
||||
.run(function () {
|
||||
foo = new Native.Vec3(1209, 298);
|
||||
});
|
||||
mathTests.addTestCase('Native Vec3.construct -- no args')
|
||||
.run(function() {
|
||||
foo = new Native.Vec3();
|
||||
});
|
||||
|
||||
mathTests.runAllTestsWithIterations([1e3, 1e4, 1e5, 1e6], 1e6, 10);
|
||||
mathTests.writeResultsToLog();
|
||||
})();
|
155
examples/utilities/tests/perfTest.js
Normal file
155
examples/utilities/tests/perfTest.js
Normal file
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// Created by Seiji Emery on 9/4/15
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
// Simple benchmarking library. See the test scripts for example usage.
|
||||
//
|
||||
|
||||
(function () {
|
||||
// Runs multiple 'test cases' (benchmarks that get invoked w/ varying iteration counts)
|
||||
function TestRunner () {
|
||||
this._testCases = {};
|
||||
this._testResults = [];
|
||||
}
|
||||
this.TestRunner = TestRunner;
|
||||
|
||||
// Add a test case. Define behavior by declaratively calling .before, .after, and .run w/ impls.
|
||||
TestRunner.prototype.addTestCase = function (name) {
|
||||
var testcase = new TestCase(name);
|
||||
this._testCases[name] = testcase;
|
||||
return testcase;
|
||||
}
|
||||
|
||||
// Runs a function n times. Uses context object so it runs sandboxed.
|
||||
function runTimedWithIterations (f, context, numIterations) {
|
||||
var start = new Date().getTime();
|
||||
while (numIterations --> 0) {
|
||||
f.apply(context);
|
||||
}
|
||||
var end = new Date().getTime();
|
||||
return end - start;
|
||||
}
|
||||
|
||||
function fmtSecs (secs) {
|
||||
if (secs >= 1.0) {
|
||||
return ""+secs.toFixed(3)+" secs";
|
||||
} else if (secs >= 1e-3) {
|
||||
return ""+(secs * 1e3).toFixed(3)+" ms";
|
||||
} else if (secs >= 1e-6) {
|
||||
return ""+(secs * 1e6).toFixed(3)+" µs";
|
||||
} else {
|
||||
return ""+(secs * 1e9).toFixed(3)+" ns";
|
||||
}
|
||||
}
|
||||
function avg(samples) {
|
||||
return samples.length ?
|
||||
samples.reduce(function(a, b){return a+b;}, 0.0) / samples.length : 0.0;
|
||||
}
|
||||
|
||||
// Runs a named performance test for multiple iterations, and optionally calculates an average.
|
||||
// @param name: the test name registered with addTest
|
||||
// @param iterations: a list of iteration sequences. eg. [10, 100, 1000] => runs for 10, then 100, then 1000 iterations
|
||||
// and prints the timing info for each (in ms)
|
||||
// @param iterationsForAvg: optional
|
||||
// @param samplesForAvg: optional
|
||||
// After running iterations, will compute an average if iterationsForAvg and samplesForAvg are both set:
|
||||
// average :=
|
||||
// collects n samples by running the testcase n times with i iterations
|
||||
// where n = samplesForAvg, i = iterationsForAvg
|
||||
// we then average the samples, and print that.
|
||||
//
|
||||
TestRunner.prototype.runPerfTestWithIterations = function (name, iterations, iterationsForAvg, samplesForAvg) {
|
||||
if (!this._testCases[name]) {
|
||||
print("No test case with name '" + name + "'!");
|
||||
}
|
||||
var testcase = this._testCases[name];
|
||||
|
||||
var runAverages = []; // secs
|
||||
|
||||
var noErrors = true;
|
||||
iterations.forEach(function(n, i) {
|
||||
var sandbox = {};
|
||||
try {
|
||||
if (testcase.setupFunction) {
|
||||
testcase.setupFunction.apply(sandbox);
|
||||
}
|
||||
|
||||
var dt = runTimedWithIterations(testcase.runFunction, sandbox, n);
|
||||
|
||||
if (testcase.teardownFunction) {
|
||||
testcase.teardownFunction.apply(sandbox);
|
||||
}
|
||||
|
||||
this._testResults.push(""+name+" with "+n+" iterations: "+dt+" ms");
|
||||
} catch (e) {
|
||||
this._testResults.push("Testcase '"+name+"':"+i+" ("+n+") failed with error: "+e);
|
||||
noErrors = false;
|
||||
}
|
||||
}, this);
|
||||
this.writeResultsToLog();
|
||||
if (noErrors && iterationsForAvg && samplesForAvg) {
|
||||
try {
|
||||
var samples = [];
|
||||
for (var n = samplesForAvg; n --> 0; ) {
|
||||
var sandbox = {};
|
||||
if (testcase.setupFunction) {
|
||||
testcase.setupFunction.apply(sandbox);
|
||||
}
|
||||
|
||||
var dt = runTimedWithIterations(testcase.runFunction, sandbox, iterationsForAvg);
|
||||
|
||||
if (testcase.teardownFunction) {
|
||||
testcase.teardownFunction.apply(sandbox);
|
||||
}
|
||||
samples.push(dt / iterationsForAvg * 1e-3); // dt in ms
|
||||
}
|
||||
print(" average: " + ((avg(samples) * 1e6).toFixed(3)) + " µs")
|
||||
// print("\t(" + samplesForAvg + " samples with " + iterationsForAvg + " iterations)");
|
||||
} catch (e) {
|
||||
print("Error while calculating average: " + e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Runs all registered tests w/ iteration + average parameters
|
||||
TestRunner.prototype.runAllTestsWithIterations = function (iterations, iterationsForAvg, samplesForAvg) {
|
||||
Object.keys(this._testCases).forEach(function(name) {
|
||||
this.runPerfTestWithIterations(name, iterations, iterationsForAvg, samplesForAvg);
|
||||
}, this);
|
||||
}
|
||||
|
||||
// Dump results to the debug log. You don't need to call this.
|
||||
TestRunner.prototype.writeResultsToLog = function () {
|
||||
var s = ' ' + this._testResults.join('\n ');
|
||||
this._testResults = [];
|
||||
// print(s);
|
||||
s.split('\n').forEach(function(line) {
|
||||
print(line);
|
||||
});
|
||||
}
|
||||
|
||||
// Implements a benchmark test case, that has optional setup = teardown code, and a (non-optional) run function.
|
||||
// setup + teardown get called once, and run gets called for n sequential iterations (see TestRunner.runTestWithIterations)
|
||||
// setup, run, and teardown all get applied to the same sandboxed this object, so use that for storing test data for each run.
|
||||
function TestCase (name) {
|
||||
this.name = name;
|
||||
this.setupFunction = null;
|
||||
this.runFunction = null;
|
||||
this.teardownFunction = null;
|
||||
}
|
||||
this.TestCase = TestCase;
|
||||
TestCase.prototype.before = function (f) {
|
||||
this.setupFunction = f;
|
||||
return this;
|
||||
}
|
||||
TestCase.prototype.after = function (f) {
|
||||
this.teardownFunction = f;
|
||||
return this;
|
||||
}
|
||||
TestCase.prototype.run = function (f) {
|
||||
this.runFunction = f;
|
||||
}
|
||||
})();
|
|
@ -3,62 +3,95 @@ type = body+head
|
|||
scale = 1
|
||||
filename = defaultAvatar_full/defaultAvatar_full.fbx
|
||||
texdir = defaultAvatar_full/textures
|
||||
joint = jointRightHand = RightHand
|
||||
joint = jointNeck = Head
|
||||
joint = jointLeftHand = LeftHand
|
||||
joint = jointRoot = Hips
|
||||
joint = jointHead = HeadTop_End
|
||||
joint = jointRightHand = RightHand
|
||||
joint = jointLean = Spine
|
||||
joint = jointLeftHand = LeftHand
|
||||
freeJoint = LeftArm
|
||||
freeJoint = LeftForeArm
|
||||
freeJoint = RightArm
|
||||
freeJoint = RightForeArm
|
||||
jointIndex = LeftHand = 35
|
||||
jointIndex = Reye = 3
|
||||
jointIndex = Hips = 10
|
||||
jointIndex = LeftHandIndex1 = 36
|
||||
jointIndex = LeftHandIndex2 = 37
|
||||
jointIndex = LeftHandIndex3 = 38
|
||||
jointIndex = LeftHandIndex4 = 39
|
||||
jointIndex = LeftShoulder = 32
|
||||
jointIndex = RightLeg = 12
|
||||
jointIndex = Grp_blendshapes = 0
|
||||
jointIndex = Leye = 4
|
||||
jointIndex = headphone = 8
|
||||
jointIndex = RightForeArm = 26
|
||||
jointIndex = Spine = 21
|
||||
jointIndex = LeftFoot = 18
|
||||
jointIndex = RightToeBase = 14
|
||||
jointIndex = face = 1
|
||||
jointIndex = LeftToe_End = 20
|
||||
jointIndex = Spine1 = 22
|
||||
jointIndex = body = 9
|
||||
jointIndex = Spine2 = 23
|
||||
jointIndex = RightUpLeg = 11
|
||||
jointIndex = top1 = 7
|
||||
jointIndex = Neck = 40
|
||||
jointIndex = HeadTop_End = 42
|
||||
jointIndex = RightShoulder = 24
|
||||
jointIndex = RightArm = 25
|
||||
jointIndex = Head = 41
|
||||
jointIndex = LeftLeg = 17
|
||||
jointIndex = LeftForeArm = 34
|
||||
jointIndex = hair = 6
|
||||
jointIndex = RightHand = 27
|
||||
jointIndex = LeftToeBase = 19
|
||||
jointIndex = LeftUpLeg = 16
|
||||
jointIndex = mouth = 2
|
||||
jointIndex = RightFoot = 13
|
||||
jointIndex = LeftArm = 33
|
||||
jointIndex = shield = 5
|
||||
jointIndex = RightHandIndex1 = 28
|
||||
jointIndex = RightHandIndex2 = 29
|
||||
jointIndex = RightToe_End = 15
|
||||
jointIndex = RightHandIndex3 = 30
|
||||
jointIndex = RightHandIndex4 = 31
|
||||
bs = MouthFrown_R = Mouth.MouthFrown_R = 1
|
||||
bs = EyeOpen_L = Leye1.EyeOpen_L = 1
|
||||
bs = LipsLowerDown_L = Mouth.LipsLowerDown = 0.5
|
||||
bs = LipsStretch_L = Mouth.LipsStretch_L = 1
|
||||
bs = MouthLeft = Mouth.MouthLeft = 1
|
||||
bs = MouthSmile_L = Mouth.MouthSmile_L = 1
|
||||
bs = Sneer_R = Mouth.Sneer = 0.61
|
||||
bs = LipsPucker = Mouth.LipsPucker = 1
|
||||
bs = EyeOpen_R = Reye1.EyeOut_R = 1
|
||||
bs = LipsLowerDown_R = Mouth.LipsLowerDown = 0.43
|
||||
bs = LipsStretch_R = Mouth.LipsStretch_R = 1
|
||||
bs = MouthSmile_R = Mouth.MouthSmile_R = 1
|
||||
bs = LipsFunnel = Mouth.LipsFunnel = 1
|
||||
bs = EyeUp_L = Leye1.EyeUp_L = 1
|
||||
bs = MouthDimple_L = Mouth.MouthDimple_L = 1
|
||||
bs = Puff = Mouth.Puff = 1
|
||||
bs = EyeIn_L = Leye1.EyeIn_L = 1
|
||||
bs = EyeUp_R = Reye1.EyeUp_R = 0.99
|
||||
bs = MouthDimple_R = Mouth.MouthDimple_R = 1
|
||||
bs = MouthRight = Mouth.MouthRight = 1
|
||||
bs = EyeOut_L = Leye1.EyeOut_L = 1
|
||||
bs = JawOpen = Mouth.JawOpen = 1
|
||||
bs = EyeIn_R = Reye1.EyeIn_R = 1
|
||||
bs = BrowsD_L = Leye1.BrowsD_L = 1
|
||||
bs = EyeDown_L = Leye1.EyeDown_L = 1
|
||||
bs = EyeBlink_L = Leye1.EyeBlink_L = 1
|
||||
bs = EyeOut_R = Reye1.EyeOut_R = 1
|
||||
bs = LipsUpperUp_L = Mouth.LipsUpperUp = 0.49
|
||||
bs = MouthFrown_L = Mouth.MouthFrown_L = 1
|
||||
bs = EyeDown_R = Reye1.EyeDown_R = 1
|
||||
bs = BrowsD_R = Reye1.BrowsD_R = 1
|
||||
bs = EyeBlink_R = Reye1.EyeBlink_R = 1
|
||||
bs = LipsUpperUp_R = Mouth.LipsUpperUp = 0.47
|
||||
bs = Sneer_L = Mouth.Sneer = 0.5
|
||||
jointIndex = headphone = 7
|
||||
jointIndex = LeftUpLeg = 15
|
||||
jointIndex = Spine = 20
|
||||
jointIndex = LeftArm = 32
|
||||
jointIndex = Head = 40
|
||||
jointIndex = RightUpLeg = 10
|
||||
jointIndex = hair = 5
|
||||
jointIndex = Spine1 = 21
|
||||
jointIndex = RightHandIndex1 = 27
|
||||
jointIndex = Spine2 = 22
|
||||
jointIndex = RightHandIndex2 = 28
|
||||
jointIndex = RightHandIndex3 = 29
|
||||
jointIndex = RightHandIndex4 = 30
|
||||
jointIndex = RightToe_End = 14
|
||||
jointIndex = shield = 4
|
||||
jointIndex = LeftHandIndex1 = 35
|
||||
jointIndex = LeftHandIndex2 = 36
|
||||
jointIndex = RightHand = 26
|
||||
jointIndex = LeftHandIndex3 = 37
|
||||
jointIndex = LeftHandIndex4 = 38
|
||||
jointIndex = LeftShoulder = 31
|
||||
jointIndex = LeftHand = 34
|
||||
jointIndex = RightForeArm = 25
|
||||
jointIndex = RightLeg = 11
|
||||
jointIndex = RightFoot = 12
|
||||
jointIndex = mouth = 1
|
||||
jointIndex = LeftToe_End = 19
|
||||
jointIndex = Reye = 2
|
||||
jointIndex = Hips = 9
|
||||
jointIndex = RightToeBase = 13
|
||||
jointIndex = HeadTop_End = 41
|
||||
jointIndex = LeftFoot = 17
|
||||
jointIndex = RightShoulder = 23
|
||||
jointIndex = LeftLeg = 16
|
||||
jointIndex = Leye = 3
|
||||
jointIndex = LeftForeArm = 33
|
||||
jointIndex = face = 0
|
||||
jointIndex = body = 8
|
||||
jointIndex = LeftToeBase = 18
|
||||
jointIndex = RightArm = 24
|
||||
jointIndex = top1 = 6
|
||||
jointIndex = Neck = 39
|
||||
rx = 0
|
||||
ry = 0
|
||||
rz = 0
|
||||
tx = 0
|
||||
ty = 0
|
||||
tz = 0
|
||||
rx = 0
|
||||
|
|
Binary file not shown.
|
@ -612,6 +612,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
// Setup the userInputMapper with the actions
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
connect(userInputMapper.data(), &UserInputMapper::actionEvent, &_controllerScriptingInterface, &AbstractControllerScriptingInterface::actionEvent);
|
||||
connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) {
|
||||
if (state) {
|
||||
switch (action) {
|
||||
case UserInputMapper::Action::TOGGLE_MUTE:
|
||||
DependencyManager::get<AudioClient>()->toggleMute();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Setup the keyboardMouseDevice and the user input mapper with the default bindings
|
||||
_keyboardMouseDevice->registerToUserInputMapper(*userInputMapper);
|
||||
|
@ -3071,9 +3080,8 @@ void Application::queryOctree(NodeType_t serverType, PacketType::Value packetTyp
|
|||
voxelDetailsForCode(rootCode, rootDetails);
|
||||
AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE,
|
||||
rootDetails.y * TREE_SCALE,
|
||||
rootDetails.z * TREE_SCALE),
|
||||
rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE),
|
||||
rootDetails.s * TREE_SCALE);
|
||||
|
||||
ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds);
|
||||
|
||||
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
|
||||
|
@ -3138,11 +3146,10 @@ void Application::queryOctree(NodeType_t serverType, PacketType::Value packetTyp
|
|||
voxelDetailsForCode(rootCode, rootDetails);
|
||||
AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE,
|
||||
rootDetails.y * TREE_SCALE,
|
||||
rootDetails.z * TREE_SCALE),
|
||||
rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE),
|
||||
rootDetails.s * TREE_SCALE);
|
||||
|
||||
|
||||
|
||||
ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds);
|
||||
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
|
||||
inView = true;
|
||||
|
@ -3161,7 +3168,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType::Value packetTyp
|
|||
} else if (unknownView) {
|
||||
if (wantExtraDebugging) {
|
||||
qCDebug(interfaceapp) << "no known jurisdiction for node " << *node << ", give it budget of "
|
||||
<< perUnknownServer << " to send us jurisdiction.";
|
||||
<< perUnknownServer << " to send us jurisdiction.";
|
||||
}
|
||||
|
||||
// set the query's position/orientation to be degenerate in a manner that will get the scene quickly
|
||||
|
@ -5100,11 +5107,10 @@ void Application::emulateMouse(Hand* hand, float click, float shift, int index)
|
|||
}
|
||||
|
||||
void Application::crashApplication() {
|
||||
qCDebug(interfaceapp) << "Intentionally crashed Interface";
|
||||
QObject* object = nullptr;
|
||||
bool value = object->isWindowType();
|
||||
Q_UNUSED(value);
|
||||
|
||||
qCDebug(interfaceapp) << "Intentionally crashed Interface";
|
||||
}
|
||||
|
||||
void Application::setActiveDisplayPlugin(const QString& pluginName) {
|
||||
|
|
|
@ -434,7 +434,7 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::FixGaze, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableAvatarUpdateThreading, 0, false,
|
||||
qApp, SLOT(setAvatarUpdateThreading(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableRigAnimations, 0, false,
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableRigAnimations, 0, true,
|
||||
avatar, SLOT(setEnableRigAnimations(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableAnimGraph, 0, false,
|
||||
avatar, SLOT(setEnableAnimGraph(bool)));
|
||||
|
|
|
@ -173,10 +173,9 @@ void AnimationHandle::applyFrame(float frameIndex) {
|
|||
const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at((int)glm::floor(frameIndex) % frameCount);
|
||||
const FBXAnimationFrame& ceilFrame = animationGeometry.animationFrames.at((int)glm::ceil(frameIndex) % frameCount);
|
||||
float frameFraction = glm::fract(frameIndex);
|
||||
assert(_rig->getJointStateCount() >= _jointMappings.size());
|
||||
for (int i = 0; i < _jointMappings.size(); i++) {
|
||||
int mapping = _jointMappings.at(i);
|
||||
if (mapping != -1) {
|
||||
if (mapping != -1) { // allow missing bones
|
||||
_rig->setJointRotationInConstrainedFrame(mapping,
|
||||
safeMix(floorFrame.rotations.at(i),
|
||||
ceilFrame.rotations.at(i),
|
||||
|
|
|
@ -103,7 +103,7 @@ const char IS_FINGER_POINTING_FLAG = 4;
|
|||
static const float MAX_AVATAR_SCALE = 1000.0f;
|
||||
static const float MIN_AVATAR_SCALE = .005f;
|
||||
|
||||
const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation
|
||||
const float MAX_AUDIO_LOUDNESS = 1000.0f; // close enough for mouth animation
|
||||
|
||||
const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000;
|
||||
const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000;
|
||||
|
@ -112,7 +112,7 @@ const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000;
|
|||
const QString DEFAULT_FULL_AVATAR_MODEL_NAME = QString("Default");
|
||||
|
||||
// how often should we send a full report about joint rotations, even if they haven't changed?
|
||||
const float AVATAR_SEND_FULL_UPDATE_RATIO = 0.02;
|
||||
const float AVATAR_SEND_FULL_UPDATE_RATIO = 0.02f;
|
||||
// this controls how large a change in joint-rotation must be before the interface sends it to the avatar mixer
|
||||
const float AVATAR_MIN_ROTATION_DOT = 0.9999999f;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <gpu/Batch.h>
|
||||
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <ObjectMotionState.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
|
@ -25,15 +26,31 @@ EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID,
|
|||
return std::make_shared<RenderableBoxEntityItem>(entityID, properties);
|
||||
}
|
||||
|
||||
void RenderableBoxEntityItem::setUserData(const QString& value) {
|
||||
if (value != getUserData()) {
|
||||
BoxEntityItem::setUserData(value);
|
||||
_procedural.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableBoxEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableBoxEntityItem::render");
|
||||
Q_ASSERT(getType() == EntityTypes::Box);
|
||||
glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(batch, 1.0f, cubeColor);
|
||||
glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
|
||||
if (!_procedural) {
|
||||
_procedural.reset(new ProceduralInfo(this));
|
||||
}
|
||||
|
||||
if (_procedural->ready()) {
|
||||
_procedural->prepare(batch);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(batch, 1.0f, _procedural->getColor(cubeColor));
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(batch, 1.0f, cubeColor);
|
||||
}
|
||||
|
||||
RenderableDebugableEntityItem::render(this, args);
|
||||
};
|
||||
|
|
|
@ -14,8 +14,9 @@
|
|||
|
||||
#include <BoxEntityItem.h>
|
||||
#include "RenderableEntityItem.h"
|
||||
#include "RenderableProceduralItem.h"
|
||||
|
||||
class RenderableBoxEntityItem : public BoxEntityItem {
|
||||
class RenderableBoxEntityItem : public BoxEntityItem, RenderableProceduralItem {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
|
@ -24,6 +25,7 @@ public:
|
|||
{ }
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void setUserData(const QString& value);
|
||||
|
||||
SIMPLE_RENDERABLE()
|
||||
};
|
||||
|
|
|
@ -168,50 +168,59 @@ void RenderableParticleEffectEntityItem::update(const quint64& now) {
|
|||
updateRenderItem();
|
||||
}
|
||||
|
||||
static glm::vec3 zSortAxis;
|
||||
static bool zSort(const glm::vec3& rhs, const glm::vec3& lhs) {
|
||||
return glm::dot(rhs, ::zSortAxis) > glm::dot(lhs, ::zSortAxis);
|
||||
}
|
||||
|
||||
uint32_t toRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
return ((uint32_t)r | (uint32_t)g << 8 | (uint32_t)b << 16 | (uint32_t)a << 24);
|
||||
}
|
||||
|
||||
class ParticleDetails {
|
||||
public:
|
||||
ParticleDetails(glm::vec3 position, float radius, uint32_t rgba) : position(position), radius(radius), rgba(rgba) { }
|
||||
|
||||
glm::vec3 position;
|
||||
float radius;
|
||||
uint32_t rgba;
|
||||
};
|
||||
|
||||
static glm::vec3 zSortAxis;
|
||||
static bool zSort(const ParticleDetails& rhs, const ParticleDetails& lhs) {
|
||||
return glm::dot(rhs.position, ::zSortAxis) > glm::dot(lhs.position, ::zSortAxis);
|
||||
}
|
||||
|
||||
void RenderableParticleEffectEntityItem::updateRenderItem() {
|
||||
if (!_scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
float particleRadius = getParticleRadius();
|
||||
auto xcolor = getXColor();
|
||||
auto alpha = (uint8_t)(glm::clamp(getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f);
|
||||
auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha);
|
||||
|
||||
// make a copy of each particle position
|
||||
std::vector<glm::vec3> positions;
|
||||
positions.reserve(getLivingParticleCount());
|
||||
// make a copy of each particle's details
|
||||
std::vector<ParticleDetails> particleDetails;
|
||||
particleDetails.reserve(getLivingParticleCount());
|
||||
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
|
||||
positions.push_back(_particlePositions[i]);
|
||||
auto xcolor = _particleColors[i];
|
||||
auto alpha = (uint8_t)(glm::clamp(_particleAlphas[i] * getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f);
|
||||
auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha);
|
||||
particleDetails.push_back(ParticleDetails(_particlePositions[i], _particleRadiuses[i], rgba));
|
||||
}
|
||||
|
||||
// sort particles back to front
|
||||
// NOTE: this is view frustum might be one frame out of date.
|
||||
auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum();
|
||||
::zSortAxis = frustum->getDirection();
|
||||
qSort(positions.begin(), positions.end(), zSort);
|
||||
qSort(particleDetails.begin(), particleDetails.end(), zSort);
|
||||
|
||||
// allocate vertices
|
||||
_vertices.clear();
|
||||
|
||||
// build vertices from particle positions
|
||||
const glm::vec3 upOffset = frustum->getUp() * particleRadius;
|
||||
const glm::vec3 rightOffset = frustum->getRight() * particleRadius;
|
||||
for (auto&& pos : positions) {
|
||||
// build vertices from particle positions and radiuses
|
||||
const glm::vec3 up = frustum->getUp();
|
||||
const glm::vec3 right = frustum->getRight();
|
||||
for (auto&& particle : particleDetails) {
|
||||
glm::vec3 upOffset = up * particle.radius;
|
||||
glm::vec3 rightOffset = right * particle.radius;
|
||||
// generate corners of quad aligned to face the camera.
|
||||
_vertices.emplace_back(pos + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), rgba);
|
||||
_vertices.emplace_back(pos - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), rgba);
|
||||
_vertices.emplace_back(pos - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), rgba);
|
||||
_vertices.emplace_back(pos + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), rgba);
|
||||
_vertices.emplace_back(particle.position + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), particle.rgba);
|
||||
_vertices.emplace_back(particle.position - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), particle.rgba);
|
||||
_vertices.emplace_back(particle.position - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), particle.rgba);
|
||||
_vertices.emplace_back(particle.position + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), particle.rgba);
|
||||
}
|
||||
|
||||
render::PendingChanges pendingChanges;
|
||||
|
|
237
libraries/entities-renderer/src/RenderableProceduralItem.cpp
Normal file
237
libraries/entities-renderer/src/RenderableProceduralItem.cpp
Normal file
|
@ -0,0 +1,237 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/09/05
|
||||
// Copyright 2013-2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "RenderableProceduralItem.h"
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include <ShaderCache.h>
|
||||
#include <EntityItem.h>
|
||||
#include <TextureCache.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include "RenderableProceduralItemShader.h"
|
||||
#include "../render-utils/simple_vert.h"
|
||||
|
||||
static const char* const UNIFORM_TIME_NAME= "iGlobalTime";
|
||||
static const char* const UNIFORM_SCALE_NAME = "iWorldScale";
|
||||
static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity";
|
||||
|
||||
static const QString URL_KEY = "shaderUrl";
|
||||
static const QString VERSION_KEY = "version";
|
||||
static const QString UNIFORMS_KEY = "uniforms";
|
||||
|
||||
RenderableProceduralItem::ProceduralInfo::ProceduralInfo(EntityItem* entity) : _entity(entity) {
|
||||
parse();
|
||||
}
|
||||
|
||||
void RenderableProceduralItem::ProceduralInfo::parse() {
|
||||
_enabled = false;
|
||||
QJsonObject userData;
|
||||
{
|
||||
const QString& userDataJson = _entity->getUserData();
|
||||
if (userDataJson.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QJsonParseError parseError;
|
||||
auto doc = QJsonDocument::fromJson(userDataJson.toUtf8(), &parseError);
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
return;
|
||||
}
|
||||
userData = doc.object();
|
||||
}
|
||||
|
||||
// Example
|
||||
//{
|
||||
// "ProceduralEntity": {
|
||||
// "shaderUrl": "file:///C:/Users/bdavis/Git/hifi/examples/shaders/test.fs",
|
||||
// "color" : "#FFFFFF"
|
||||
// }
|
||||
//}
|
||||
auto proceduralData = userData[PROCEDURAL_USER_DATA_KEY];
|
||||
if (proceduralData.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
parse(proceduralData.toObject());
|
||||
}
|
||||
|
||||
void RenderableProceduralItem::ProceduralInfo::parse(const QJsonObject& proceduralData) {
|
||||
// grab the version number
|
||||
{
|
||||
auto version = proceduralData[VERSION_KEY];
|
||||
if (version.isDouble()) {
|
||||
_version = (uint8_t)(floor(version.toDouble()));
|
||||
}
|
||||
}
|
||||
|
||||
// Get the path to the shader
|
||||
{
|
||||
QString shaderUrl = proceduralData[URL_KEY].toString();
|
||||
_shaderUrl = QUrl(shaderUrl);
|
||||
if (!_shaderUrl.isValid()) {
|
||||
qWarning() << "Invalid shader URL: " << shaderUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_shaderUrl.isLocalFile()) {
|
||||
_shaderPath = _shaderUrl.toLocalFile();
|
||||
qDebug() << "Shader path: " << _shaderPath;
|
||||
if (!QFile(_shaderPath).exists()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Shader url: " << _shaderUrl;
|
||||
_networkShader = ShaderCache::instance().getShader(_shaderUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// Grab any custom uniforms
|
||||
{
|
||||
auto uniforms = proceduralData[UNIFORMS_KEY];
|
||||
if (uniforms.isObject()) {
|
||||
_uniforms = uniforms.toObject();;
|
||||
}
|
||||
}
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
bool RenderableProceduralItem::ProceduralInfo::ready() {
|
||||
if (!_enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_shaderPath.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_networkShader) {
|
||||
return _networkShader->isLoaded();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void RenderableProceduralItem::ProceduralInfo::prepare(gpu::Batch& batch) {
|
||||
if (_shaderUrl.isLocalFile()) {
|
||||
auto lastModified = QFileInfo(_shaderPath).lastModified().toMSecsSinceEpoch();
|
||||
if (lastModified > _shaderModified) {
|
||||
QFile file(_shaderPath);
|
||||
file.open(QIODevice::ReadOnly);
|
||||
_shaderSource = QTextStream(&file).readAll();
|
||||
_pipelineDirty = true;
|
||||
_shaderModified = lastModified;
|
||||
}
|
||||
} else if (_networkShader && _networkShader->isLoaded()) {
|
||||
_shaderSource = _networkShader->_source;
|
||||
}
|
||||
|
||||
if (!_pipeline || _pipelineDirty) {
|
||||
_pipelineDirty = true;
|
||||
if (!_vertexShader) {
|
||||
_vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert)));
|
||||
}
|
||||
QString framentShaderSource;
|
||||
switch (_version) {
|
||||
case 1:
|
||||
framentShaderSource = SHADER_TEMPLATE_V1.arg(_shaderSource);
|
||||
break;
|
||||
|
||||
default:
|
||||
case 2:
|
||||
framentShaderSource = SHADER_TEMPLATE_V2.arg(_shaderSource);
|
||||
break;
|
||||
}
|
||||
_fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(framentShaderSource.toLocal8Bit().data())));
|
||||
_shader = gpu::ShaderPointer(gpu::Shader::createProgram(_vertexShader, _fragmentShader));
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT));
|
||||
gpu::Shader::makeProgram(*_shader, slotBindings);
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
state->setBlendFunction(false,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
_pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, state));
|
||||
_timeSlot = _shader->getUniforms().findLocation(UNIFORM_TIME_NAME);
|
||||
_scaleSlot = _shader->getUniforms().findLocation(UNIFORM_SCALE_NAME);
|
||||
_start = usecTimestampNow();
|
||||
}
|
||||
|
||||
batch.setPipeline(_pipeline);
|
||||
|
||||
if (_pipelineDirty) {
|
||||
_pipelineDirty = false;
|
||||
// Set any userdata specified uniforms
|
||||
foreach(QString key, _uniforms.keys()) {
|
||||
std::string uniformName = key.toLocal8Bit().data();
|
||||
int32_t slot = _shader->getUniforms().findLocation(uniformName);
|
||||
if (gpu::Shader::INVALID_LOCATION == slot) {
|
||||
continue;
|
||||
}
|
||||
QJsonValue value = _uniforms[key];
|
||||
if (value.isDouble()) {
|
||||
batch._glUniform1f(slot, value.toDouble());
|
||||
} else if (value.isArray()) {
|
||||
auto valueArray = value.toArray();
|
||||
switch (valueArray.size()) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 1:
|
||||
batch._glUniform1f(slot, valueArray[0].toDouble());
|
||||
break;
|
||||
case 2:
|
||||
batch._glUniform2f(slot,
|
||||
valueArray[0].toDouble(),
|
||||
valueArray[1].toDouble());
|
||||
break;
|
||||
case 3:
|
||||
batch._glUniform3f(slot,
|
||||
valueArray[0].toDouble(),
|
||||
valueArray[0].toDouble(),
|
||||
valueArray[1].toDouble());
|
||||
break;
|
||||
case 4:
|
||||
default:
|
||||
batch._glUniform4f(slot,
|
||||
valueArray[0].toDouble(),
|
||||
valueArray[1].toDouble(),
|
||||
valueArray[2].toDouble(),
|
||||
valueArray[3].toDouble());
|
||||
break;
|
||||
|
||||
}
|
||||
valueArray.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds
|
||||
float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND;
|
||||
batch._glUniform1f(_timeSlot, time);
|
||||
|
||||
// FIXME move into the 'set once' section, since this doesn't change over time
|
||||
auto scale = _entity->getDimensions();
|
||||
batch._glUniform3f(_scaleSlot, scale.x, scale.y, scale.z);
|
||||
batch.setResourceTexture(DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT, DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
|
||||
|
||||
glm::vec4 RenderableProceduralItem::ProceduralInfo::getColor(const glm::vec4& entityColor) {
|
||||
if (_version == 1) {
|
||||
return glm::vec4(1);
|
||||
}
|
||||
return entityColor;
|
||||
}
|
60
libraries/entities-renderer/src/RenderableProceduralItem.h
Normal file
60
libraries/entities-renderer/src/RenderableProceduralItem.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/09/05
|
||||
// Copyright 2013-2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_RenderableProcedrualItem_h
|
||||
#define hifi_RenderableProcedrualItem_h
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
||||
#include <ShaderCache.h>
|
||||
#include <gpu/Shader.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
class EntityItem;
|
||||
class QJsonObject;
|
||||
|
||||
class RenderableProceduralItem {
|
||||
protected:
|
||||
// FIXME better encapsulation
|
||||
// FIXME better mechanism for extending to things rendered using shaders other than simple.slv
|
||||
struct ProceduralInfo {
|
||||
ProceduralInfo(EntityItem* entity);
|
||||
void parse();
|
||||
void parse(const QJsonObject&);
|
||||
bool ready();
|
||||
void prepare(gpu::Batch& batch);
|
||||
glm::vec4 getColor(const glm::vec4& entityColor);
|
||||
|
||||
bool _enabled{ false };
|
||||
uint8_t _version{ 1 };
|
||||
gpu::PipelinePointer _pipeline;
|
||||
gpu::ShaderPointer _vertexShader;
|
||||
gpu::ShaderPointer _fragmentShader;
|
||||
gpu::ShaderPointer _shader;
|
||||
QString _shaderSource;
|
||||
QString _shaderPath;
|
||||
QUrl _shaderUrl;
|
||||
quint64 _shaderModified{ 0 };
|
||||
bool _pipelineDirty{ true };
|
||||
int32_t _timeSlot{ gpu::Shader::INVALID_LOCATION };
|
||||
int32_t _scaleSlot{ gpu::Shader::INVALID_LOCATION };
|
||||
uint64_t _start{ 0 };
|
||||
NetworkShaderPointer _networkShader;
|
||||
EntityItem* _entity;
|
||||
QJsonObject _uniforms;
|
||||
};
|
||||
|
||||
QSharedPointer<ProceduralInfo> _procedural;
|
||||
};
|
||||
|
||||
#endif
|
363
libraries/entities-renderer/src/RenderableProceduralItemShader.h
Normal file
363
libraries/entities-renderer/src/RenderableProceduralItemShader.h
Normal file
|
@ -0,0 +1,363 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/09/05
|
||||
// Copyright 2013-2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// Shader includes portions of webgl-noise:
|
||||
// Description : Array and textureless GLSL 2D/3D/4D simplex
|
||||
// noise functions.
|
||||
// Author : Ian McEwan, Ashima Arts.
|
||||
// Maintainer : ijm
|
||||
// Lastmod : 20110822 (ijm)
|
||||
// License : Copyright (C) 2011 Ashima Arts. All rights reserved.
|
||||
// Distributed under the MIT License. See LICENSE file.
|
||||
// https://github.com/ashima/webgl-noise
|
||||
//
|
||||
|
||||
|
||||
const QString SHADER_COMMON = R"SHADER(#version 410 core
|
||||
layout(location = 0) out vec4 _fragColor0;
|
||||
layout(location = 1) out vec4 _fragColor1;
|
||||
layout(location = 2) out vec4 _fragColor2;
|
||||
|
||||
// the glow intensity
|
||||
uniform float glowIntensity;
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
uniform sampler2D normalFittingMap;
|
||||
|
||||
vec3 bestFitNormal(vec3 normal) {
|
||||
vec3 absNorm = abs(normal);
|
||||
float maxNAbs = max(absNorm.z, max(absNorm.x, absNorm.y));
|
||||
|
||||
vec2 texcoord = (absNorm.z < maxNAbs ?
|
||||
(absNorm.y < maxNAbs ? absNorm.yz : absNorm.xz) :
|
||||
absNorm.xy);
|
||||
texcoord = (texcoord.x < texcoord.y ? texcoord.yx : texcoord.xy);
|
||||
texcoord.y /= texcoord.x;
|
||||
vec3 cN = normal / maxNAbs;
|
||||
float fittingScale = texture(normalFittingMap, texcoord).a;
|
||||
cN *= fittingScale;
|
||||
return (cN * 0.5 + 0.5);
|
||||
}
|
||||
|
||||
|
||||
|
||||
float mod289(float x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
vec2 mod289(vec2 x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
vec3 mod289(vec3 x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
vec4 mod289(vec4 x) {
|
||||
return x - floor(x * (1.0 / 289.0)) * 289.0;
|
||||
}
|
||||
|
||||
float permute(float x) {
|
||||
return mod289(((x*34.0)+1.0)*x);
|
||||
}
|
||||
|
||||
vec3 permute(vec3 x) {
|
||||
return mod289(((x*34.0)+1.0)*x);
|
||||
}
|
||||
|
||||
vec4 permute(vec4 x) {
|
||||
return mod289(((x*34.0)+1.0)*x);
|
||||
}
|
||||
|
||||
float taylorInvSqrt(float r) {
|
||||
return 1.79284291400159 - 0.85373472095314 * r;
|
||||
}
|
||||
|
||||
vec4 taylorInvSqrt(vec4 r) {
|
||||
return 1.79284291400159 - 0.85373472095314 * r;
|
||||
}
|
||||
|
||||
vec4 grad4(float j, vec4 ip) {
|
||||
const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);
|
||||
vec4 p, s;
|
||||
|
||||
p.xyz = floor(fract(vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;
|
||||
p.w = 1.5 - dot(abs(p.xyz), ones.xyz);
|
||||
s = vec4(lessThan(p, vec4(0.0)));
|
||||
p.xyz = p.xyz + (s.xyz * 2.0 - 1.0) * s.www;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// (sqrt(5) - 1)/4 = F4, used once below
|
||||
#define F4 0.309016994374947451
|
||||
|
||||
float snoise(vec4 v) {
|
||||
const vec4 C = vec4(0.138196601125011, // (5 - sqrt(5))/20 G4
|
||||
0.276393202250021, // 2 * G4
|
||||
0.414589803375032, // 3 * G4
|
||||
-0.447213595499958); // -1 + 4 * G4
|
||||
|
||||
// First corner
|
||||
vec4 i = floor(v + dot(v, vec4(F4)));
|
||||
vec4 x0 = v - i + dot(i, C.xxxx);
|
||||
|
||||
// Other corners
|
||||
|
||||
// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)
|
||||
vec4 i0;
|
||||
vec3 isX = step(x0.yzw, x0.xxx);
|
||||
vec3 isYZ = step(x0.zww, x0.yyz);
|
||||
i0.x = isX.x + isX.y + isX.z;
|
||||
i0.yzw = 1.0 - isX;
|
||||
i0.y += isYZ.x + isYZ.y;
|
||||
i0.zw += 1.0 - isYZ.xy;
|
||||
i0.z += isYZ.z;
|
||||
i0.w += 1.0 - isYZ.z;
|
||||
|
||||
// i0 now contains the unique values 0,1,2,3 in each channel
|
||||
vec4 i3 = clamp(i0, 0.0, 1.0);
|
||||
vec4 i2 = clamp(i0 - 1.0, 0.0, 1.0);
|
||||
vec4 i1 = clamp(i0 - 2.0, 0.0, 1.0);
|
||||
|
||||
vec4 x1 = x0 - i1 + C.xxxx;
|
||||
vec4 x2 = x0 - i2 + C.yyyy;
|
||||
vec4 x3 = x0 - i3 + C.zzzz;
|
||||
vec4 x4 = x0 + C.wwww;
|
||||
|
||||
// Permutations
|
||||
i = mod289(i);
|
||||
float j0 = permute(permute(permute(permute(i.w) + i.z) + i.y) + i.x);
|
||||
vec4 j1 = permute(
|
||||
permute(
|
||||
permute(
|
||||
permute(i.w + vec4(i1.w, i2.w, i3.w, 1.0)) + i.z
|
||||
+ vec4(i1.z, i2.z, i3.z, 1.0)) + i.y
|
||||
+ vec4(i1.y, i2.y, i3.y, 1.0)) + i.x
|
||||
+ vec4(i1.x, i2.x, i3.x, 1.0));
|
||||
|
||||
// Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope
|
||||
// 7*7*6 = 294, which is close to the ring size 17*17 = 289.
|
||||
vec4 ip = vec4(1.0 / 294.0, 1.0 / 49.0, 1.0 / 7.0, 0.0);
|
||||
|
||||
vec4 p0 = grad4(j0, ip);
|
||||
vec4 p1 = grad4(j1.x, ip);
|
||||
vec4 p2 = grad4(j1.y, ip);
|
||||
vec4 p3 = grad4(j1.z, ip);
|
||||
vec4 p4 = grad4(j1.w, ip);
|
||||
|
||||
// Normalise gradients
|
||||
vec4 norm = taylorInvSqrt(
|
||||
vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
|
||||
p0 *= norm.x;
|
||||
p1 *= norm.y;
|
||||
p2 *= norm.z;
|
||||
p3 *= norm.w;
|
||||
p4 *= taylorInvSqrt(dot(p4, p4));
|
||||
|
||||
// Mix contributions from the five corners
|
||||
vec3 m0 = max(0.6 - vec3(dot(x0, x0), dot(x1, x1), dot(x2, x2)), 0.0);
|
||||
vec2 m1 = max(0.6 - vec2(dot(x3, x3), dot(x4, x4)), 0.0);
|
||||
m0 = m0 * m0;
|
||||
m1 = m1 * m1;
|
||||
return 49.0
|
||||
* (dot(m0 * m0, vec3(dot(p0, x0), dot(p1, x1), dot(p2, x2)))
|
||||
+ dot(m1 * m1, vec2(dot(p3, x3), dot(p4, x4))));
|
||||
|
||||
}
|
||||
|
||||
float snoise(vec3 v) {
|
||||
const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);
|
||||
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
||||
|
||||
// First corner
|
||||
vec3 i = floor(v + dot(v, C.yyy));
|
||||
vec3 x0 = v - i + dot(i, C.xxx);
|
||||
|
||||
// Other corners
|
||||
vec3 g = step(x0.yzx, x0.xyz);
|
||||
vec3 l = 1.0 - g;
|
||||
vec3 i1 = min(g.xyz, l.zxy);
|
||||
vec3 i2 = max(g.xyz, l.zxy);
|
||||
|
||||
vec3 x1 = x0 - i1 + C.xxx;
|
||||
vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
|
||||
vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y
|
||||
|
||||
// Permutations
|
||||
i = mod289(i);
|
||||
vec4 p = permute(
|
||||
permute(
|
||||
permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) + i.y
|
||||
+ vec4(0.0, i1.y, i2.y, 1.0)) + i.x
|
||||
+ vec4(0.0, i1.x, i2.x, 1.0));
|
||||
|
||||
// Gradients: 7x7 points over a square, mapped onto an octahedron.
|
||||
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
|
||||
float n_ = 0.142857142857; // 1.0/7.0
|
||||
vec3 ns = n_ * D.wyz - D.xzx;
|
||||
|
||||
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7)
|
||||
|
||||
vec4 x_ = floor(j * ns.z);
|
||||
vec4 y_ = floor(j - 7.0 * x_); // mod(j,N)
|
||||
|
||||
vec4 x = x_ * ns.x + ns.yyyy;
|
||||
vec4 y = y_ * ns.x + ns.yyyy;
|
||||
vec4 h = 1.0 - abs(x) - abs(y);
|
||||
|
||||
vec4 b0 = vec4(x.xy, y.xy);
|
||||
vec4 b1 = vec4(x.zw, y.zw);
|
||||
|
||||
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
|
||||
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
|
||||
vec4 s0 = floor(b0) * 2.0 + 1.0;
|
||||
vec4 s1 = floor(b1) * 2.0 + 1.0;
|
||||
vec4 sh = -step(h, vec4(0.0));
|
||||
|
||||
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
|
||||
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
|
||||
|
||||
vec3 p0 = vec3(a0.xy, h.x);
|
||||
vec3 p1 = vec3(a0.zw, h.y);
|
||||
vec3 p2 = vec3(a1.xy, h.z);
|
||||
vec3 p3 = vec3(a1.zw, h.w);
|
||||
|
||||
//Normalise gradients
|
||||
vec4 norm = taylorInvSqrt(
|
||||
vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
|
||||
p0 *= norm.x;
|
||||
p1 *= norm.y;
|
||||
p2 *= norm.z;
|
||||
p3 *= norm.w;
|
||||
|
||||
// Mix final noise value
|
||||
vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)),
|
||||
0.0);
|
||||
m = m * m;
|
||||
return 42.0
|
||||
* dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
|
||||
}
|
||||
|
||||
float snoise(vec2 v) {
|
||||
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
|
||||
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
|
||||
-0.577350269189626, // -1.0 + 2.0 * C.x
|
||||
0.024390243902439); // 1.0 / 41.0
|
||||
// First corner
|
||||
vec2 i = floor(v + dot(v, C.yy));
|
||||
vec2 x0 = v - i + dot(i, C.xx);
|
||||
|
||||
// Other corners
|
||||
vec2 i1;
|
||||
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
|
||||
vec4 x12 = x0.xyxy + C.xxzz;
|
||||
x12.xy -= i1;
|
||||
|
||||
// Permutations
|
||||
i = mod289(i); // Avoid truncation effects in permutation
|
||||
vec3 p = permute(
|
||||
permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));
|
||||
|
||||
vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)),
|
||||
0.0);
|
||||
m = m * m;
|
||||
m = m * m;
|
||||
|
||||
// Gradients: 41 points uniformly over a line, mapped onto a diamond.
|
||||
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
|
||||
|
||||
vec3 x = 2.0 * fract(p * C.www) - 1.0;
|
||||
vec3 h = abs(x) - 0.5;
|
||||
vec3 ox = floor(x + 0.5);
|
||||
vec3 a0 = x - ox;
|
||||
|
||||
// Normalise gradients implicitly by scaling m
|
||||
// Approximation of: m *= inversesqrt( a0*a0 + h*h );
|
||||
m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);
|
||||
|
||||
// Compute final noise value at P
|
||||
vec3 g;
|
||||
g.x = a0.x * x0.x + h.x * x0.y;
|
||||
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
|
||||
return 130.0 * dot(m, g);
|
||||
}
|
||||
|
||||
// the interpolated normal
|
||||
in vec3 _normal;
|
||||
in vec3 _color;
|
||||
in vec2 _texCoord0;
|
||||
in vec4 _position;
|
||||
|
||||
// TODO add more uniforms
|
||||
uniform float iGlobalTime; // shader playback time (in seconds)
|
||||
uniform vec3 iWorldScale; // the dimensions of the object being rendered
|
||||
|
||||
// TODO add support for textures
|
||||
// TODO document available inputs other than the uniforms
|
||||
// TODO provide world scale in addition to the untransformed position
|
||||
|
||||
const vec3 DEFAULT_SPECULAR = vec3(0.1);
|
||||
const float DEFAULT_SHININESS = 10;
|
||||
|
||||
)SHADER";
|
||||
|
||||
// V1 shaders, only support emissive
|
||||
// vec4 getProceduralColor()
|
||||
const QString SHADER_TEMPLATE_V1 = SHADER_COMMON + R"SCRIBE(
|
||||
|
||||
#line 1001
|
||||
%1
|
||||
#line 317
|
||||
|
||||
void main(void) {
|
||||
vec4 emissive = getProceduralColor();
|
||||
|
||||
float alpha = glowIntensity * emissive.a;
|
||||
if (alpha != glowIntensity) {
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 diffuse = vec4(_color.rgb, alpha);
|
||||
vec4 normal = vec4(normalize(bestFitNormal(_normal)), 0.5);
|
||||
|
||||
_fragColor0 = diffuse;
|
||||
_fragColor1 = normal;
|
||||
_fragColor2 = vec4(emissive.rgb, DEFAULT_SHININESS / 128.0);
|
||||
}
|
||||
|
||||
)SCRIBE";
|
||||
|
||||
// void getProceduralDiffuseAndEmissive(out vec4 diffuse, out vec4 emissive)
|
||||
const QString SHADER_TEMPLATE_V2 = SHADER_COMMON + R"SCRIBE(
|
||||
// FIXME should we be doing the swizzle here?
|
||||
vec3 iResolution = iWorldScale.xzy;
|
||||
|
||||
// FIXME Mouse X,Y coordinates, and Z,W are for the click position if clicked (not supported in High Fidelity at the moment)
|
||||
vec4 iMouse = vec4(0);
|
||||
|
||||
// FIXME We set the seconds (iDate.w) of iDate to iGlobalTime, which contains the current date in seconds
|
||||
vec4 iDate = vec4(0, 0, 0, iGlobalTime);
|
||||
|
||||
|
||||
#line 1001
|
||||
%1
|
||||
#line 351
|
||||
|
||||
void main(void) {
|
||||
vec3 diffuse = _color.rgb;
|
||||
vec3 specular = DEFAULT_SPECULAR;
|
||||
float shininess = DEFAULT_SHININESS;
|
||||
|
||||
float emissiveAmount = getProceduralColors(diffuse, specular, shininess);
|
||||
|
||||
_fragColor0 = vec4(diffuse.rgb, 1.0);
|
||||
_fragColor1 = vec4(bestFitNormal(normalize(_normal.xyz)), 1.0 - (emissiveAmount / 2.0));
|
||||
_fragColor2 = vec4(specular, shininess / 128.0);
|
||||
}
|
||||
)SCRIBE";
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <DependencyManager.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "RenderableDebugableEntityItem.h"
|
||||
|
@ -25,21 +26,38 @@ EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entity
|
|||
return std::make_shared<RenderableSphereEntityItem>(entityID, properties);
|
||||
}
|
||||
|
||||
void RenderableSphereEntityItem::setUserData(const QString& value) {
|
||||
if (value != getUserData()) {
|
||||
SphereEntityItem::setUserData(value);
|
||||
_procedural.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableSphereEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableSphereEntityItem::render");
|
||||
Q_ASSERT(getType() == EntityTypes::Sphere);
|
||||
glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(getTransformToCenter()); // use a transform with scale, rotation, registration point and translation
|
||||
|
||||
// TODO: it would be cool to select different slices/stacks geometry based on the size of the sphere
|
||||
// and the distance to the viewer. This would allow us to reduce the triangle count for smaller spheres
|
||||
// that aren't close enough to see the tessellation and use larger triangle count for spheres that would
|
||||
// expose that effect
|
||||
const int SLICES = 15, STACKS = 15;
|
||||
static const int SLICES = 15, STACKS = 15;
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setModelTransform(getTransformToCenter()); // use a transform with scale, rotation, registration point and translation
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, sphereColor);
|
||||
if (!_procedural) {
|
||||
_procedural.reset(new ProceduralInfo(this));
|
||||
}
|
||||
|
||||
glm::vec4 sphereColor(toGlm(getXColor()), getLocalRenderAlpha());
|
||||
if (_procedural->ready()) {
|
||||
_procedural->prepare(batch);
|
||||
DependencyManager::get<GeometryCache>()->renderSphere(batch, 0.5f, SLICES, STACKS, _procedural->getColor(sphereColor));
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, sphereColor);
|
||||
}
|
||||
|
||||
|
||||
RenderableDebugableEntityItem::render(this, args);
|
||||
};
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
#define hifi_RenderableSphereEntityItem_h
|
||||
|
||||
#include <SphereEntityItem.h>
|
||||
|
||||
#include "RenderableEntityItem.h"
|
||||
#include "RenderableProceduralItem.h"
|
||||
|
||||
class RenderableSphereEntityItem : public SphereEntityItem {
|
||||
class RenderableSphereEntityItem : public SphereEntityItem, RenderableProceduralItem {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
|
@ -25,6 +25,7 @@ public:
|
|||
{ }
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void setUserData(const QString& value);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
};
|
||||
|
|
|
@ -334,7 +334,7 @@ public:
|
|||
void setLocked(bool value) { _locked = value; }
|
||||
|
||||
const QString& getUserData() const { return _userData; }
|
||||
void setUserData(const QString& value) { _userData = value; }
|
||||
virtual void setUserData(const QString& value) { _userData = value; }
|
||||
|
||||
const SimulationOwner& getSimulationOwner() const { return _simulationOwner; }
|
||||
void setSimulationOwner(const QUuid& id, quint8 priority);
|
||||
|
|
|
@ -55,6 +55,13 @@ CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
|
|||
CONSTRUCT_PROPERTY(scriptTimestamp, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP),
|
||||
CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
|
||||
CONSTRUCT_PROPERTY(color, ),
|
||||
CONSTRUCT_PROPERTY(colorSpread, ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD),
|
||||
CONSTRUCT_PROPERTY(colorStart, ParticleEffectEntityItem::DEFAULT_COLOR),
|
||||
CONSTRUCT_PROPERTY(colorFinish, ParticleEffectEntityItem::DEFAULT_COLOR),
|
||||
CONSTRUCT_PROPERTY(alpha, ENTITY_ITEM_DEFAULT_ALPHA),
|
||||
CONSTRUCT_PROPERTY(alphaSpread, ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD),
|
||||
CONSTRUCT_PROPERTY(alphaStart, ParticleEffectEntityItem::DEFAULT_ALPHA_START),
|
||||
CONSTRUCT_PROPERTY(alphaFinish, ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH),
|
||||
CONSTRUCT_PROPERTY(modelURL, ""),
|
||||
CONSTRUCT_PROPERTY(compoundShapeURL, ""),
|
||||
CONSTRUCT_PROPERTY(animationURL, ""),
|
||||
|
@ -89,6 +96,9 @@ CONSTRUCT_PROPERTY(velocitySpread, ParticleEffectEntityItem::DEFAULT_VELOCITY_SP
|
|||
CONSTRUCT_PROPERTY(emitAcceleration, ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION),
|
||||
CONSTRUCT_PROPERTY(accelerationSpread, ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD),
|
||||
CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS),
|
||||
CONSTRUCT_PROPERTY(radiusSpread, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD),
|
||||
CONSTRUCT_PROPERTY(radiusStart, ParticleEffectEntityItem::DEFAULT_RADIUS_START),
|
||||
CONSTRUCT_PROPERTY(radiusFinish, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH),
|
||||
CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID),
|
||||
CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR),
|
||||
CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY),
|
||||
|
@ -328,6 +338,13 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR_SPREAD, colorSpread);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR_START, colorStart);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR_FINISH, colorFinish);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
|
||||
|
@ -362,6 +379,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_EMIT_ACCELERATION, emitAcceleration);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ACCELERATION_SPREAD, accelerationSpread);
|
||||
CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius);
|
||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread);
|
||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart);
|
||||
CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID);
|
||||
CHECK_PROPERTY_CHANGE(PROP_NAME, name);
|
||||
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, keyLightColor);
|
||||
|
@ -439,6 +459,13 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(color);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(colorSpread);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(colorStart);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(colorFinish);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(alpha);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaSpread);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaStart);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaFinish);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
|
||||
|
@ -471,6 +498,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(emitAcceleration);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(accelerationSpread);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusSpread);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusStart);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusFinish);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(name);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL);
|
||||
|
@ -569,6 +599,13 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorSpread, xColor, setColorSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorStart, xColor, setColorStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorFinish, xColor, setColorFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationURL, QString, setAnimationURL);
|
||||
|
@ -600,6 +637,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitAcceleration, glmVec3, setEmitAcceleration);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(accelerationSpread, glmVec3, setAccelerationSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(particleRadius, float, setParticleRadius);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL);
|
||||
|
@ -850,7 +890,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent
|
|||
APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, properties.getEmitAcceleration());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, properties.getAccelerationSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, properties.getColorSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_START, properties.getColorStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, properties.getColorFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish());
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Zone) {
|
||||
|
@ -901,11 +949,11 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent
|
|||
APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, properties.getStrokeWidths());
|
||||
}
|
||||
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha());
|
||||
}
|
||||
if (propertyCount > 0) {
|
||||
int endOfEntityItemData = packetData->getUncompressedByteOffset();
|
||||
|
@ -1126,6 +1174,15 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_SPREAD, xColor, setColorSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_START, xColor, setColorStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_FINISH, xColor, setColorFinish);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish);
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Zone) {
|
||||
|
@ -1175,6 +1232,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
@ -1231,6 +1289,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_nameChanged = true;
|
||||
_visibleChanged = true;
|
||||
_colorChanged = true;
|
||||
_alphaChanged = true;
|
||||
_modelURLChanged = true;
|
||||
_compoundShapeURLChanged = true;
|
||||
_animationURLChanged = true;
|
||||
|
@ -1264,6 +1323,15 @@ void EntityItemProperties::markAllChanged() {
|
|||
_emitAccelerationChanged = true;
|
||||
_accelerationSpreadChanged = true;
|
||||
_particleRadiusChanged = true;
|
||||
_radiusSpreadChanged = true;
|
||||
_radiusStartChanged = true;
|
||||
_radiusFinishChanged = true;
|
||||
_colorSpreadChanged = true;
|
||||
_colorStartChanged = true;
|
||||
_colorFinishChanged = true;
|
||||
_alphaSpreadChanged = true;
|
||||
_alphaStartChanged = true;
|
||||
_alphaFinishChanged = true;
|
||||
|
||||
_marketplaceIDChanged = true;
|
||||
|
||||
|
|
|
@ -103,6 +103,13 @@ public:
|
|||
DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64);
|
||||
DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_START, ColorStart, colorStart, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR_FINISH, ColorFinish, colorFinish, xColor);
|
||||
DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_START, AlphaStart, alphaStart, float);
|
||||
DEFINE_PROPERTY(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float);
|
||||
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString);
|
||||
|
@ -136,6 +143,9 @@ public:
|
|||
DEFINE_PROPERTY(PROP_EMIT_ACCELERATION, EmitAcceleration, emitAcceleration, glm::vec3);
|
||||
DEFINE_PROPERTY(PROP_ACCELERATION_SPREAD, AccelerationSpread, accelerationSpread, glm::vec3);
|
||||
DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float);
|
||||
DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float);
|
||||
DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float);
|
||||
DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
|
||||
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor);
|
||||
DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
|
||||
|
@ -291,6 +301,13 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ScriptTimestamp, scriptTimestamp, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorSpread, colorSpread, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorStart, colorStart, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorFinish, colorFinish, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaSpread, alphaSpread, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaStart, alphaStart, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaFinish, alphaFinish, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, "");
|
||||
|
@ -322,6 +339,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitAcceleration, emitAcceleration, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AccelerationSpread, accelerationSpread, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusSpread, radiusSpread, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusStart, radiusStart, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusFinish, radiusFinish, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, "");
|
||||
|
|
|
@ -27,6 +27,7 @@ const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
|
|||
const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString("");
|
||||
const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid();
|
||||
|
||||
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
|
||||
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
|
||||
const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f;
|
||||
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;
|
||||
|
|
|
@ -146,6 +146,21 @@ enum EntityPropertyList {
|
|||
PROP_Y_P_NEIGHBOR_ID, // used by PolyVox
|
||||
PROP_Z_P_NEIGHBOR_ID, // used by PolyVox
|
||||
|
||||
// Used by particles
|
||||
PROP_RADIUS_SPREAD,
|
||||
PROP_RADIUS_START,
|
||||
PROP_RADIUS_FINISH,
|
||||
|
||||
PROP_ALPHA, // Supported by some derived classes
|
||||
|
||||
//Used by particles
|
||||
PROP_COLOR_SPREAD,
|
||||
PROP_COLOR_START,
|
||||
PROP_COLOR_FINISH,
|
||||
PROP_ALPHA_SPREAD,
|
||||
PROP_ALPHA_START,
|
||||
PROP_ALPHA_FINISH,
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ATTENTION: add new properties to end of list just ABOVE this line
|
||||
PROP_AFTER_LAST_ITEM,
|
||||
|
|
|
@ -43,6 +43,11 @@
|
|||
#include "ParticleEffectEntityItem.h"
|
||||
|
||||
const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 };
|
||||
const xColor ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD = { 0, 0, 0 };
|
||||
const float ParticleEffectEntityItem::DEFAULT_ALPHA = 1.0f;
|
||||
const float ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD = 0.0f;
|
||||
const float ParticleEffectEntityItem::DEFAULT_ALPHA_START = DEFAULT_ALPHA;
|
||||
const float ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH = DEFAULT_ALPHA;
|
||||
const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f;
|
||||
const bool ParticleEffectEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false;
|
||||
const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FPS = 30.0f;
|
||||
|
@ -54,6 +59,9 @@ const glm::vec3 ParticleEffectEntityItem::DEFAULT_VELOCITY_SPREAD(3.0f, 0.0f, 3.
|
|||
const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION(0.0f, -9.8f, 0.0f);
|
||||
const glm::vec3 ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD(0.0f, 0.0f, 0.0f);
|
||||
const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f;
|
||||
const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f;
|
||||
const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS;
|
||||
const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS;
|
||||
const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = "";
|
||||
|
||||
|
||||
|
@ -72,16 +80,42 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte
|
|||
_emitAcceleration(DEFAULT_EMIT_ACCELERATION),
|
||||
_accelerationSpread(DEFAULT_ACCELERATION_SPREAD),
|
||||
_particleRadius(DEFAULT_PARTICLE_RADIUS),
|
||||
_radiusSpread(DEFAULT_RADIUS_SPREAD),
|
||||
_radiusStart(DEFAULT_RADIUS_START),
|
||||
_radiusFinish(DEFAULT_RADIUS_FINISH),
|
||||
_lastAnimated(usecTimestampNow()),
|
||||
_animationLoop(),
|
||||
_animationSettings(),
|
||||
_textures(DEFAULT_TEXTURES),
|
||||
_texturesChangedFlag(false),
|
||||
_shapeType(SHAPE_TYPE_NONE),
|
||||
_colorSpread(DEFAULT_COLOR_SPREAD),
|
||||
_colorStart(DEFAULT_COLOR),
|
||||
_colorFinish(DEFAULT_COLOR),
|
||||
_isColorStartInitialized(false),
|
||||
_isColorFinishInitialized(false),
|
||||
_alpha(DEFAULT_ALPHA),
|
||||
_alphaSpread(DEFAULT_ALPHA_SPREAD),
|
||||
_alphaStart(DEFAULT_ALPHA_START),
|
||||
_alphaFinish(DEFAULT_ALPHA_FINISH),
|
||||
_isAlphaStartInitialized(false),
|
||||
_isAlphaFinishInitialized(false),
|
||||
_particleLifetimes(DEFAULT_MAX_PARTICLES, 0.0f),
|
||||
_particlePositions(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)),
|
||||
_particleVelocities(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)),
|
||||
_particleAccelerations(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)),
|
||||
_particleRadiuses(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
|
||||
_radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
|
||||
_radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
|
||||
_radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
|
||||
_particleColors(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR),
|
||||
_colorStarts(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR),
|
||||
_colorMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR),
|
||||
_colorFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR),
|
||||
_particleAlphas(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA),
|
||||
_alphaStarts(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA),
|
||||
_alphaMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA),
|
||||
_alphaFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA),
|
||||
_timeUntilNextEmit(0.0f),
|
||||
_particleHeadIndex(0),
|
||||
_particleTailIndex(0),
|
||||
|
@ -97,10 +131,6 @@ ParticleEffectEntityItem::~ParticleEffectEntityItem() {
|
|||
}
|
||||
|
||||
|
||||
void ParticleEffectEntityItem::setLifespan(float lifespan) {
|
||||
_lifespan = lifespan;
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setEmitVelocity(const glm::vec3& emitVelocity) {
|
||||
_emitVelocity = emitVelocity;
|
||||
computeAndUpdateDimensions();
|
||||
|
@ -111,7 +141,6 @@ void ParticleEffectEntityItem::setVelocitySpread(const glm::vec3& velocitySpread
|
|||
computeAndUpdateDimensions();
|
||||
}
|
||||
|
||||
|
||||
void ParticleEffectEntityItem::setEmitAcceleration(const glm::vec3& emitAcceleration) {
|
||||
_emitAcceleration = emitAcceleration;
|
||||
computeAndUpdateDimensions();
|
||||
|
@ -122,10 +151,6 @@ void ParticleEffectEntityItem::setAccelerationSpread(const glm::vec3& accelerati
|
|||
computeAndUpdateDimensions();
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setParticleRadius(float particleRadius) {
|
||||
_particleRadius = particleRadius;
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::computeAndUpdateDimensions() {
|
||||
const float time = _lifespan * 1.1f; // add 10% extra time to account for incremental timer accumulation error
|
||||
|
||||
|
@ -153,6 +178,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const {
|
|||
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFPS, getAnimationFPS);
|
||||
|
@ -163,9 +189,19 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const {
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRate, getEmitRate);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitVelocity, getEmitVelocity);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocitySpread, getVelocitySpread);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitAcceleration, getEmitAcceleration);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(accelerationSpread, getAccelerationSpread);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleRadius, getParticleRadius);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusStart, getRadiusStart);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorSpread, getColorSpread);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorStart, getColorStart);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorFinish, getColorFinish);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaSpread, getAlphaSpread);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
|
||||
|
||||
return properties;
|
||||
|
@ -175,6 +211,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
|
|||
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFPS, setAnimationFPS);
|
||||
|
@ -185,11 +222,20 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRate, setEmitRate);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitVelocity, setEmitVelocity);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocitySpread, setVelocitySpread);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitAcceleration, setEmitAcceleration);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(accelerationSpread, setAccelerationSpread);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleRadius, setParticleRadius);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusStart, setRadiusStart);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorSpread, setColorSpread);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorStart, setColorStart);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorFinish, setColorFinish);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaSpread, setAlphaSpread);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocitySpread, setVelocitySpread);
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
|
@ -257,6 +303,22 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
|
|||
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
|
||||
}
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES) {
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart);
|
||||
READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish);
|
||||
}
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES) {
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart);
|
||||
READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart);
|
||||
READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish);
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
|
@ -280,6 +342,16 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea
|
|||
requestedProperties += PROP_PARTICLE_RADIUS;
|
||||
requestedProperties += PROP_TEXTURES;
|
||||
requestedProperties += PROP_VELOCITY_SPREAD;
|
||||
requestedProperties += PROP_RADIUS_SPREAD;
|
||||
requestedProperties += PROP_RADIUS_START;
|
||||
requestedProperties += PROP_RADIUS_FINISH;
|
||||
requestedProperties += PROP_COLOR_SPREAD;
|
||||
requestedProperties += PROP_COLOR_START;
|
||||
requestedProperties += PROP_COLOR_FINISH;
|
||||
requestedProperties += PROP_ALPHA;
|
||||
requestedProperties += PROP_ALPHA_SPREAD;
|
||||
requestedProperties += PROP_ALPHA_START;
|
||||
requestedProperties += PROP_ALPHA_FINISH;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
@ -308,6 +380,16 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
|
|||
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, getParticleRadius());
|
||||
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
|
||||
APPEND_ENTITY_PROPERTY(PROP_VELOCITY_SPREAD, getVelocitySpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, getRadiusSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, getRadiusStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, getColorSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_START, getColorStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, getColorFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, getAlphaFinish());
|
||||
}
|
||||
|
||||
bool ParticleEffectEntityItem::isAnimatingSomething() const {
|
||||
|
@ -477,6 +559,27 @@ QString ParticleEffectEntityItem::getAnimationSettings() const {
|
|||
return jsonByteString;
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::updateRadius(quint32 index, float age) {
|
||||
_particleRadiuses[index] = interpolate(_radiusStarts[index], _radiusMiddles[index], _radiusFinishes[index], age);
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::updateColor(quint32 index, float age) {
|
||||
_particleColors[index].red =
|
||||
(int)glm::clamp(interpolate(_colorStarts[index].red, _colorMiddles[index].red, _colorFinishes[index].red, age),
|
||||
0.0f, 255.0f);
|
||||
_particleColors[index].green =
|
||||
(int)glm::clamp(interpolate(_colorStarts[index].green, _colorMiddles[index].green, _colorFinishes[index].green, age),
|
||||
0.0f, 255.0f);
|
||||
_particleColors[index].blue =
|
||||
(int)glm::clamp(interpolate(_colorStarts[index].blue, _colorMiddles[index].blue, _colorFinishes[index].blue, age),
|
||||
0.0f, 255.0f);
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::updateAlpha(quint32 index, float age) {
|
||||
_particleAlphas[index] = glm::clamp(interpolate(_alphaStarts[index], _alphaMiddles[index], _alphaFinishes[index], age),
|
||||
0.0f, 1.0f);
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::extendBounds(const glm::vec3& point) {
|
||||
_particleMinBound.x = glm::min(_particleMinBound.x, point.x);
|
||||
_particleMinBound.y = glm::min(_particleMinBound.y, point.y);
|
||||
|
@ -509,12 +612,16 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
|
|||
_particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles;
|
||||
}
|
||||
else {
|
||||
float age = (1.0f - _particleLifetimes[i] / _lifespan); // 0.0 .. 1.0
|
||||
updateRadius(i, age);
|
||||
updateColor(i, age);
|
||||
updateAlpha(i, age);
|
||||
integrateParticle(i, deltaTime);
|
||||
extendBounds(_particlePositions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// emit new particles, but only if animaiton is playing
|
||||
// emit new particles, but only if animation is playing
|
||||
if (getAnimationIsPlaying()) {
|
||||
|
||||
float timeLeftInFrame = deltaTime;
|
||||
|
@ -527,12 +634,24 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
|
|||
quint32 i = _particleTailIndex;
|
||||
_particleLifetimes[i] = _lifespan;
|
||||
|
||||
|
||||
// Radius
|
||||
if (_radiusSpread == 0.0f) {
|
||||
_radiusStarts[i] = getRadiusStart();
|
||||
_radiusMiddles[i] =_particleRadius;
|
||||
_radiusFinishes[i] = getRadiusFinish();
|
||||
} else {
|
||||
float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1) * _radiusSpread / _particleRadius;
|
||||
_radiusStarts[i] = spreadMultiplier * getRadiusStart();
|
||||
_radiusMiddles[i] = spreadMultiplier * _particleRadius;
|
||||
_radiusFinishes[i] = spreadMultiplier * getRadiusFinish();
|
||||
}
|
||||
updateRadius(i, 0.0f);
|
||||
|
||||
// Velocity and acceleration
|
||||
glm::vec3 spreadOffset;
|
||||
spreadOffset.x = -_velocitySpread.x + randFloat() * (_velocitySpread.x * 2.0f);
|
||||
spreadOffset.y = -_velocitySpread.y + randFloat() * (_velocitySpread.y * 2.0f);
|
||||
spreadOffset.z = -_velocitySpread.z + randFloat() * (_velocitySpread.z * 2.0f);
|
||||
|
||||
|
||||
// set initial conditions
|
||||
_particlePositions[i] = getPosition();
|
||||
|
@ -547,6 +666,48 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
|
|||
integrateParticle(i, timeLeftInFrame);
|
||||
extendBounds(_particlePositions[i]);
|
||||
|
||||
// Color
|
||||
if (_colorSpread == xColor{ 0, 0, 0 }) {
|
||||
_colorStarts[i] = getColorStart();
|
||||
_colorMiddles[i] = getXColor();
|
||||
_colorFinishes[i] = getColorFinish();
|
||||
} else {
|
||||
xColor startColor = getColorStart();
|
||||
xColor middleColor = getXColor();
|
||||
xColor finishColor = getColorFinish();
|
||||
|
||||
float spread = 2.0f * randFloat() - 1.0f;
|
||||
float spreadMultiplierRed = 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red;
|
||||
float spreadMultiplierGreen = 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green;
|
||||
float spreadMultiplierBlue = 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue;
|
||||
|
||||
_colorStarts[i].red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f);
|
||||
_colorStarts[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f);
|
||||
_colorStarts[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)startColor.blue, 0.0f, 255.0f);
|
||||
|
||||
_colorMiddles[i].red = (int)glm::clamp(spreadMultiplierRed * (float)middleColor.red, 0.0f, 255.0f);
|
||||
_colorMiddles[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)middleColor.green, 0.0f, 255.0f);
|
||||
_colorMiddles[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)middleColor.blue, 0.0f, 255.0f);
|
||||
|
||||
_colorFinishes[i].red = (int)glm::clamp(spreadMultiplierRed * (float)finishColor.red, 0.0f, 255.0f);
|
||||
_colorFinishes[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)finishColor.green, 0.0f, 255.0f);
|
||||
_colorFinishes[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)finishColor.blue, 0.0f, 255.0f);
|
||||
}
|
||||
updateColor(i, 0.0f);
|
||||
|
||||
// Alpha
|
||||
if (_alphaSpread == 0.0f) {
|
||||
_alphaStarts[i] = getAlphaStart();
|
||||
_alphaMiddles[i] = _alpha;
|
||||
_alphaFinishes[i] = getAlphaFinish();
|
||||
} else {
|
||||
float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1) * _alphaSpread / _alpha;
|
||||
_alphaStarts[i] = spreadMultiplier * getAlphaStart();
|
||||
_alphaMiddles[i] = spreadMultiplier * _alpha;
|
||||
_alphaFinishes[i] = spreadMultiplier * getAlphaFinish();
|
||||
}
|
||||
updateAlpha(i, 0.0f);
|
||||
|
||||
_particleTailIndex = (_particleTailIndex + 1) % _maxParticles;
|
||||
|
||||
// overflow! move head forward by one.
|
||||
|
@ -571,8 +732,20 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
|
|||
_particleLifetimes.resize(_maxParticles);
|
||||
_particlePositions.resize(_maxParticles);
|
||||
_particleVelocities.resize(_maxParticles);
|
||||
_particleRadiuses.resize(_maxParticles);
|
||||
_radiusStarts.resize(_maxParticles);
|
||||
_radiusMiddles.resize(_maxParticles);
|
||||
_radiusFinishes.resize(_maxParticles);
|
||||
_particleColors.resize(_maxParticles);
|
||||
_colorStarts.resize(_maxParticles);
|
||||
_colorMiddles.resize(_maxParticles);
|
||||
_colorFinishes.resize(_maxParticles);
|
||||
_particleAlphas.resize(_maxParticles);
|
||||
_alphaStarts.resize(_maxParticles);
|
||||
_alphaMiddles.resize(_maxParticles);
|
||||
_alphaFinishes.resize(_maxParticles);
|
||||
|
||||
// effectivly clear all particles and start emitting new ones from scratch.
|
||||
// effectively clear all particles and start emitting new ones from scratch.
|
||||
_particleHeadIndex = 0;
|
||||
_particleTailIndex = 0;
|
||||
_timeUntilNextEmit = 0.0f;
|
||||
|
@ -587,3 +760,42 @@ quint32 ParticleEffectEntityItem::getLivingParticleCount() const {
|
|||
return (_maxParticles - _particleHeadIndex) + _particleTailIndex;
|
||||
}
|
||||
}
|
||||
|
||||
float ParticleEffectEntityItem::cubicInterpolate(float y0, float y1, float y2, float y3, float u) {
|
||||
float a0, a1, a2, a3, uu;
|
||||
uu = u * u;
|
||||
a0 = y3 - y2 - y0 + y1;
|
||||
a1 = y0 - y1 - a0;
|
||||
a2 = y2 - y0;
|
||||
a3 = y1;
|
||||
|
||||
return (a0 * u * uu + a1 * uu + a2 * u + a3);
|
||||
}
|
||||
|
||||
float ParticleEffectEntityItem::interpolate(float start, float middle, float finish, float age) {
|
||||
float y0, y1, y2, y3, u;
|
||||
|
||||
if (age <= 0.5f) {
|
||||
if (start == middle) {
|
||||
return middle;
|
||||
}
|
||||
|
||||
y1 = start;
|
||||
y2 = middle;
|
||||
y3 = finish;
|
||||
y0 = 2.0f * y1 - y2;
|
||||
u = 2.0f * age;
|
||||
} else {
|
||||
if (middle == finish) {
|
||||
return middle;
|
||||
}
|
||||
|
||||
y0 = start;
|
||||
y1 = middle;
|
||||
y2 = finish;
|
||||
y3 = 2.0f * y2 - y1;
|
||||
u = 2.0f * age - 1.0f;
|
||||
}
|
||||
|
||||
return cubicInterpolate(y0, y1, y2, y3, u);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,36 @@ public:
|
|||
_color[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
bool _isColorStartInitialized;
|
||||
void setColorStart(const xColor& colorStart) { _colorStart = colorStart; _isColorStartInitialized = true; }
|
||||
xColor getColorStart() const { return _isColorStartInitialized ? _colorStart : getXColor(); }
|
||||
|
||||
bool _isColorFinishInitialized;
|
||||
void setColorFinish(const xColor& colorFinish) { _colorFinish = colorFinish; _isColorFinishInitialized = true; }
|
||||
xColor getColorFinish() const { return _isColorFinishInitialized ? _colorFinish : getXColor(); }
|
||||
|
||||
static const xColor DEFAULT_COLOR_SPREAD;
|
||||
void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; }
|
||||
xColor getColorSpread() const { return _colorSpread; }
|
||||
|
||||
static const float DEFAULT_ALPHA;
|
||||
void setAlpha(float alpha) { _alpha = alpha; }
|
||||
float getAlpha() const { return _alpha; }
|
||||
|
||||
static const float DEFAULT_ALPHA_START;
|
||||
bool _isAlphaStartInitialized;
|
||||
void setAlphaStart(float alphaStart) { _alphaStart = alphaStart; _isAlphaStartInitialized = true; }
|
||||
float getAlphaStart() const { return _isAlphaStartInitialized ? _alphaStart : _alpha; }
|
||||
|
||||
static const float DEFAULT_ALPHA_FINISH;
|
||||
bool _isAlphaFinishInitialized;
|
||||
void setAlphaFinish(float alphaFinish) { _alphaFinish = alphaFinish; _isAlphaFinishInitialized = true; }
|
||||
float getAlphaFinish() const { return _isAlphaFinishInitialized ? _alphaFinish : _alpha; }
|
||||
|
||||
static const float DEFAULT_ALPHA_SPREAD;
|
||||
void setAlphaSpread(float alphaSpread) { _alphaSpread = alphaSpread; }
|
||||
float getAlphaSpread() const { return _alphaSpread; }
|
||||
|
||||
void updateShapeType(ShapeType type);
|
||||
virtual ShapeType getShapeType() const { return _shapeType; }
|
||||
|
||||
|
@ -91,7 +121,7 @@ public:
|
|||
quint32 getMaxParticles() const { return _maxParticles; }
|
||||
|
||||
static const float DEFAULT_LIFESPAN;
|
||||
void setLifespan(float lifespan);
|
||||
void setLifespan(float lifespan) { _lifespan = lifespan; }
|
||||
float getLifespan() const { return _lifespan; }
|
||||
|
||||
static const float DEFAULT_EMIT_RATE;
|
||||
|
@ -102,12 +132,10 @@ public:
|
|||
void setEmitVelocity(const glm::vec3& emitVelocity);
|
||||
const glm::vec3& getEmitVelocity() const { return _emitVelocity; }
|
||||
|
||||
|
||||
static const glm::vec3 DEFAULT_VELOCITY_SPREAD;
|
||||
void setVelocitySpread(const glm::vec3& velocitySpread);
|
||||
const glm::vec3& getVelocitySpread() const { return _velocitySpread; }
|
||||
|
||||
|
||||
static const glm::vec3 DEFAULT_EMIT_ACCELERATION;
|
||||
void setEmitAcceleration(const glm::vec3& emitAcceleration);
|
||||
const glm::vec3& getEmitAcceleration() const { return _emitAcceleration; }
|
||||
|
@ -117,9 +145,23 @@ public:
|
|||
const glm::vec3& getAccelerationSpread() const { return _accelerationSpread; }
|
||||
|
||||
static const float DEFAULT_PARTICLE_RADIUS;
|
||||
void setParticleRadius(float particleRadius);
|
||||
void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; }
|
||||
float getParticleRadius() const { return _particleRadius; }
|
||||
|
||||
|
||||
static const float DEFAULT_RADIUS_START;
|
||||
bool _isRadiusStartInitialized;
|
||||
void setRadiusStart(float radiusStart) { _radiusStart = radiusStart; _isRadiusStartInitialized = true; }
|
||||
float getRadiusStart() const { return _isRadiusStartInitialized ? _radiusStart : _particleRadius; }
|
||||
|
||||
static const float DEFAULT_RADIUS_FINISH;
|
||||
bool _isRadiusFinishInitialized;
|
||||
void setRadiusFinish(float radiusFinish) { _radiusFinish = radiusFinish; _isRadiusFinishInitialized = true; }
|
||||
float getRadiusFinish() const { return _isRadiusFinishInitialized ? _radiusFinish : _particleRadius; }
|
||||
|
||||
static const float DEFAULT_RADIUS_SPREAD;
|
||||
void setRadiusSpread(float radiusSpread) { _radiusSpread = radiusSpread; }
|
||||
float getRadiusSpread() const { return _radiusSpread; }
|
||||
|
||||
void computeAndUpdateDimensions();
|
||||
|
||||
|
||||
|
@ -141,12 +183,22 @@ protected:
|
|||
|
||||
bool isAnimatingSomething() const;
|
||||
void stepSimulation(float deltaTime);
|
||||
void updateRadius(quint32 index, float age);
|
||||
void updateColor(quint32 index, float age);
|
||||
void updateAlpha(quint32 index, float age);
|
||||
void extendBounds(const glm::vec3& point);
|
||||
void integrateParticle(quint32 index, float deltaTime);
|
||||
quint32 getLivingParticleCount() const;
|
||||
|
||||
// the properties of this entity
|
||||
rgbColor _color;
|
||||
xColor _colorStart;
|
||||
xColor _colorFinish;
|
||||
xColor _colorSpread;
|
||||
float _alpha;
|
||||
float _alphaStart;
|
||||
float _alphaFinish;
|
||||
float _alphaSpread;
|
||||
quint32 _maxParticles;
|
||||
float _lifespan;
|
||||
float _emitRate;
|
||||
|
@ -155,6 +207,9 @@ protected:
|
|||
glm::vec3 _emitAcceleration;
|
||||
glm::vec3 _accelerationSpread;
|
||||
float _particleRadius;
|
||||
float _radiusStart;
|
||||
float _radiusFinish;
|
||||
float _radiusSpread;
|
||||
quint64 _lastAnimated;
|
||||
AnimationLoop _animationLoop;
|
||||
QString _animationSettings;
|
||||
|
@ -167,9 +222,22 @@ protected:
|
|||
QVector<glm::vec3> _particlePositions;
|
||||
QVector<glm::vec3> _particleVelocities;
|
||||
QVector<glm::vec3> _particleAccelerations;
|
||||
QVector<float> _particleRadiuses;
|
||||
QVector<float> _radiusStarts;
|
||||
QVector<float> _radiusMiddles;
|
||||
QVector<float> _radiusFinishes;
|
||||
QVector<xColor> _particleColors;
|
||||
QVector<xColor> _colorStarts;
|
||||
QVector<xColor> _colorMiddles;
|
||||
QVector<xColor> _colorFinishes;
|
||||
QVector<float> _particleAlphas;
|
||||
QVector<float> _alphaStarts;
|
||||
QVector<float> _alphaMiddles;
|
||||
QVector<float> _alphaFinishes;
|
||||
|
||||
float _timeUntilNextEmit;
|
||||
|
||||
// particle arrays are a ring buffer, use these indicies
|
||||
// particle arrays are a ring buffer, use these indices
|
||||
// to keep track of the living particles.
|
||||
quint32 _particleHeadIndex;
|
||||
quint32 _particleTailIndex;
|
||||
|
@ -177,6 +245,10 @@ protected:
|
|||
// bounding volume
|
||||
glm::vec3 _particleMaxBound;
|
||||
glm::vec3 _particleMinBound;
|
||||
|
||||
private:
|
||||
float cubicInterpolate(float y0, float y1, float y2, float y3, float u);
|
||||
float interpolate(float start, float middle, float finish, float age);
|
||||
};
|
||||
|
||||
#endif // hifi_ParticleEffectEntityItem_h
|
||||
|
|
|
@ -144,6 +144,7 @@ public:
|
|||
void _glUniform1f(int location, float v0);
|
||||
void _glUniform2f(int location, float v0, float v1);
|
||||
void _glUniform3f(int location, float v0, float v1, float v2);
|
||||
void _glUniform4f(int location, float v0, float v1, float v2, float v3);
|
||||
void _glUniform3fv(int location, int count, const float* value);
|
||||
void _glUniform4fv(int location, int count, const float* value);
|
||||
void _glUniform4iv(int location, int count, const int* value);
|
||||
|
@ -192,6 +193,7 @@ public:
|
|||
COMMAND_glUniform1f,
|
||||
COMMAND_glUniform2f,
|
||||
COMMAND_glUniform3f,
|
||||
COMMAND_glUniform4f,
|
||||
COMMAND_glUniform3fv,
|
||||
COMMAND_glUniform4fv,
|
||||
COMMAND_glUniform4iv,
|
||||
|
|
|
@ -56,6 +56,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::GLBackend::do_glUniform1f),
|
||||
(&::gpu::GLBackend::do_glUniform2f),
|
||||
(&::gpu::GLBackend::do_glUniform3f),
|
||||
(&::gpu::GLBackend::do_glUniform4f),
|
||||
(&::gpu::GLBackend::do_glUniform3fv),
|
||||
(&::gpu::GLBackend::do_glUniform4fv),
|
||||
(&::gpu::GLBackend::do_glUniform4iv),
|
||||
|
@ -458,6 +459,36 @@ void GLBackend::do_glUniform3f(Batch& batch, uint32 paramOffset) {
|
|||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
||||
void Batch::_glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
|
||||
ADD_COMMAND_GL(glUniform4f);
|
||||
|
||||
_params.push_back(v3);
|
||||
_params.push_back(v2);
|
||||
_params.push_back(v1);
|
||||
_params.push_back(v0);
|
||||
_params.push_back(location);
|
||||
|
||||
DO_IT_NOW(_glUniform4f, 1);
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::do_glUniform4f(Batch& batch, uint32 paramOffset) {
|
||||
if (_pipeline._program == 0) {
|
||||
// We should call updatePipeline() to bind the program but we are not doing that
|
||||
// because these uniform setters are deprecated and we don;t want to create side effect
|
||||
return;
|
||||
}
|
||||
updatePipeline();
|
||||
glUniform4f(
|
||||
batch._params[paramOffset + 4]._int,
|
||||
batch._params[paramOffset + 3]._float,
|
||||
batch._params[paramOffset + 2]._float,
|
||||
batch._params[paramOffset + 1]._float,
|
||||
batch._params[paramOffset + 0]._float);
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
void Batch::_glUniform3fv(GLint location, GLsizei count, const GLfloat* value) {
|
||||
ADD_COMMAND_GL(glUniform3fv);
|
||||
|
||||
|
|
|
@ -457,6 +457,7 @@ protected:
|
|||
void do_glUniform1f(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform2f(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform3f(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform4f(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform3fv(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform4fv(Batch& batch, uint32 paramOffset);
|
||||
void do_glUniform4iv(Batch& batch, uint32 paramOffset);
|
||||
|
|
|
@ -595,6 +595,10 @@ void SixenseManager::assignDefaultInputMapping(UserInputMapper& mapper) {
|
|||
mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0));
|
||||
mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1));
|
||||
|
||||
// TODO find a mechanism to allow users to navigate the context menu via
|
||||
mapper.addInputChannel(UserInputMapper::CONTEXT_MENU, makeInput(BUTTON_0, 0));
|
||||
mapper.addInputChannel(UserInputMapper::TOGGLE_MUTE, makeInput(BUTTON_0, 1));
|
||||
|
||||
}
|
||||
|
||||
UserInputMapper::Input SixenseManager::makeInput(unsigned int button, int index) {
|
||||
|
|
|
@ -162,6 +162,9 @@ public:
|
|||
ACTION1,
|
||||
ACTION2,
|
||||
|
||||
CONTEXT_MENU,
|
||||
TOGGLE_MUTE,
|
||||
|
||||
NUM_ACTIONS,
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,11 @@ include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}")
|
|||
# append OpenSSL to our list of libraries to link
|
||||
target_link_libraries(${TARGET_NAME} ${OPENSSL_LIBRARIES} ${TBB_LIBRARIES})
|
||||
|
||||
# libcrypto uses dlopen in libdl
|
||||
if (UNIX)
|
||||
target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})
|
||||
endif (UNIX)
|
||||
|
||||
# append tbb includes to our list of includes to bubble
|
||||
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${TBB_INCLUDE_DIRS})
|
||||
include_application_version()
|
||||
|
|
|
@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) {
|
|||
case EntityAdd:
|
||||
case EntityEdit:
|
||||
case EntityData:
|
||||
return VERSION_ENTITIES_POLYVOX_NEIGHBORS;
|
||||
return VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES;
|
||||
case AvatarData:
|
||||
return 13;
|
||||
default:
|
||||
|
|
|
@ -145,5 +145,7 @@ const PacketVersion VERSION_ENTITIES_POLYLINE = 37;
|
|||
const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39;
|
||||
const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES = 41;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES = 42;
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
32
libraries/render-utils/src/ShaderCache.cpp
Normal file
32
libraries/render-utils/src/ShaderCache.cpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/05/26
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "ShaderCache.h"
|
||||
|
||||
NetworkShader::NetworkShader(const QUrl& url, bool delayLoad)
|
||||
: Resource(url, delayLoad) {};
|
||||
|
||||
void NetworkShader::downloadFinished(QNetworkReply* reply) {
|
||||
if (reply) {
|
||||
_source = reply->readAll();
|
||||
reply->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
ShaderCache& ShaderCache::instance() {
|
||||
static ShaderCache _instance;
|
||||
return _instance;
|
||||
}
|
||||
|
||||
NetworkShaderPointer ShaderCache::getShader(const QUrl& url) {
|
||||
return ResourceCache::getResource(url, QUrl(), false, nullptr).staticCast<NetworkShader>();
|
||||
}
|
||||
|
||||
QSharedPointer<Resource> ShaderCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) {
|
||||
return QSharedPointer<Resource>(new NetworkShader(url, delayLoad), &Resource::allReferencesCleared);
|
||||
}
|
||||
|
34
libraries/render-utils/src/ShaderCache.h
Normal file
34
libraries/render-utils/src/ShaderCache.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/05/26
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_ShaderCache_h
|
||||
#define hifi_ShaderCache_h
|
||||
|
||||
#include <ResourceCache.h>
|
||||
|
||||
class NetworkShader : public Resource {
|
||||
public:
|
||||
NetworkShader(const QUrl& url, bool delayLoad);
|
||||
virtual void downloadFinished(QNetworkReply* reply) override;
|
||||
|
||||
QByteArray _source;
|
||||
};
|
||||
|
||||
using NetworkShaderPointer = QSharedPointer<NetworkShader>;
|
||||
|
||||
class ShaderCache : public ResourceCache {
|
||||
public:
|
||||
static ShaderCache& instance();
|
||||
|
||||
NetworkShaderPointer getShader(const QUrl& url);
|
||||
|
||||
protected:
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) override;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue