mirror of
https://github.com/JulianGro/overte.git
synced 2025-05-30 12:04:31 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
This commit is contained in:
commit
06a9ac22e7
32 changed files with 1247 additions and 267 deletions
|
@ -40,6 +40,8 @@ var modelURLs = [
|
|||
|
||||
var toolBar;
|
||||
|
||||
var jointList = MyAvatar.getJointNames();
|
||||
|
||||
function isLocked(properties) {
|
||||
// special case to lock the ground plane model in hq.
|
||||
if (location.hostname == "hq.highfidelity.io" &&
|
||||
|
@ -81,10 +83,13 @@ function controller(wichSide) {
|
|||
|
||||
this.grabbing = false;
|
||||
this.modelID = { isKnownID: false };
|
||||
this.modelURL = "";
|
||||
this.oldModelRotation;
|
||||
this.oldModelPosition;
|
||||
this.oldModelRadius;
|
||||
|
||||
this.jointsIntersectingFromStart = [];
|
||||
|
||||
this.laser = Overlays.addOverlay("line3d", {
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
end: { x: 0, y: 0, z: 0 },
|
||||
|
@ -134,16 +139,65 @@ function controller(wichSide) {
|
|||
|
||||
this.grabbing = true;
|
||||
this.modelID = modelID;
|
||||
this.modelURL = properties.modelURL;
|
||||
|
||||
this.oldModelPosition = properties.position;
|
||||
this.oldModelRotation = properties.modelRotation;
|
||||
this.oldModelRadius = properties.radius;
|
||||
|
||||
this.jointsIntersectingFromStart = [];
|
||||
for (var i = 0; i < jointList.length; i++) {
|
||||
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
|
||||
if (distance < this.oldModelRadius) {
|
||||
this.jointsIntersectingFromStart.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.release = function () {
|
||||
if (this.grabbing) {
|
||||
if (jointList.length <= 0) {
|
||||
jointList = MyAvatar.getJointNames();
|
||||
}
|
||||
|
||||
var closestJointIndex = -1;
|
||||
var closestJointDistance = 10;
|
||||
for (var i = 0; i < jointList.length; i++) {
|
||||
var distance = Vec3.distance(MyAvatar.getJointPosition(jointList[i]), this.oldModelPosition);
|
||||
if (distance < closestJointDistance) {
|
||||
closestJointDistance = distance;
|
||||
closestJointIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
print("closestJoint: " + jointList[closestJointIndex]);
|
||||
print("closestJointDistance (attach max distance): " + closestJointDistance + " (" + this.oldModelRadius + ")");
|
||||
|
||||
if (closestJointDistance < this.oldModelRadius) {
|
||||
|
||||
if (this.jointsIntersectingFromStart.indexOf(closestJointIndex) != -1) {
|
||||
// Do nothing
|
||||
} else {
|
||||
print("Attaching to " + jointList[closestJointIndex]);
|
||||
var jointPosition = MyAvatar.getJointPosition(jointList[closestJointIndex]);
|
||||
var jointRotation = MyAvatar.getJointCombinedRotation(jointList[closestJointIndex]);
|
||||
|
||||
var attachmentOffset = Vec3.subtract(this.oldModelPosition, jointPosition);
|
||||
attachmentOffset = Vec3.multiplyQbyV(Quat.inverse(jointRotation), attachmentOffset);
|
||||
var attachmentRotation = Quat.multiply(Quat.inverse(jointRotation), this.oldModelRotation);
|
||||
|
||||
MyAvatar.attach(this.modelURL, jointList[closestJointIndex],
|
||||
attachmentOffset, attachmentRotation, 2.0 * this.oldModelRadius,
|
||||
true, false);
|
||||
Models.deleteModel(this.modelID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.grabbing = false;
|
||||
this.modelID.isKnownID = false;
|
||||
this.jointsIntersectingFromStart = [];
|
||||
}
|
||||
|
||||
this.checkTrigger = function () {
|
||||
|
@ -251,11 +305,6 @@ function controller(wichSide) {
|
|||
position: newPosition,
|
||||
modelRotation: newRotation
|
||||
});
|
||||
// print("Moving " + this.modelID.id);
|
||||
// Vec3.print("Old Position: ", this.oldModelPosition);
|
||||
// Vec3.print("Sav Position: ", newPosition);
|
||||
// Quat.print("Old Rotation: ", this.oldModelRotation);
|
||||
// Quat.print("New Rotation: ", newRotation);
|
||||
|
||||
this.oldModelRotation = newRotation;
|
||||
this.oldModelPosition = newPosition;
|
||||
|
@ -410,8 +459,6 @@ function checkController(deltaTime) {
|
|||
moveOverlays();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function initToolBar() {
|
||||
toolBar = new ToolBar(0, 0, ToolBar.VERTICAL);
|
||||
// New Model
|
||||
|
|
|
@ -28,8 +28,10 @@ var NEW_VOXEL_SIZE = 1.0;
|
|||
var NEW_VOXEL_DISTANCE_FROM_CAMERA = 3.0;
|
||||
var PIXELS_PER_EXTRUDE_VOXEL = 16;
|
||||
var WHEEL_PIXELS_PER_SCALE_CHANGE = 100;
|
||||
var MAX_VOXEL_SCALE = 16.0;
|
||||
var MIN_VOXEL_SCALE = 1.0 / Math.pow(2.0, 8.0);
|
||||
var MAX_VOXEL_SCALE_POWER = 4;
|
||||
var MIN_VOXEL_SCALE_POWER = -8;
|
||||
var MAX_VOXEL_SCALE = Math.pow(2.0, MAX_VOXEL_SCALE_POWER);
|
||||
var MIN_VOXEL_SCALE = Math.pow(2.0, MIN_VOXEL_SCALE_POWER);
|
||||
var WHITE_COLOR = { red: 255, green: 255, blue: 255 };
|
||||
|
||||
var MAX_PASTE_VOXEL_SCALE = 256;
|
||||
|
@ -330,6 +332,13 @@ function ScaleSelector() {
|
|||
visible: false
|
||||
});
|
||||
this.setScale = function(scale) {
|
||||
if (scale > MAX_VOXEL_SCALE) {
|
||||
scale = MAX_VOXEL_SCALE;
|
||||
}
|
||||
if (scale < MIN_VOXEL_SCALE) {
|
||||
scale = MIN_VOXEL_SCALE;
|
||||
}
|
||||
|
||||
this.scale = scale;
|
||||
this.power = Math.floor(Math.log(scale) / Math.log(2));
|
||||
rescaleImport();
|
||||
|
@ -391,12 +400,9 @@ function ScaleSelector() {
|
|||
|
||||
this.incrementScale = function() {
|
||||
copyScale = false;
|
||||
if (this.power < 13) {
|
||||
if (this.power < MAX_VOXEL_SCALE_POWER) {
|
||||
++this.power;
|
||||
this.scale *= 2.0;
|
||||
if (this.scale > MAX_VOXEL_SCALE) {
|
||||
this.scale = MAX_VOXEL_SCALE;
|
||||
}
|
||||
this.update();
|
||||
rescaleImport();
|
||||
resizeVoxelSound.play(voxelSizePlus);
|
||||
|
@ -405,7 +411,7 @@ function ScaleSelector() {
|
|||
|
||||
this.decrementScale = function() {
|
||||
copyScale = false;
|
||||
if (-4 < this.power) {
|
||||
if (MIN_VOXEL_SCALE_POWER < this.power) {
|
||||
--this.power;
|
||||
this.scale /= 2.0;
|
||||
this.update();
|
||||
|
|
43
examples/playSoundLoop.js
Normal file
43
examples/playSoundLoop.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// playSoundLoop.js
|
||||
// examples
|
||||
//
|
||||
// Created by David Rowe on 5/29/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This example script plays a sound in a continuous loop.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var sound = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Guitars/Guitar+-+Nylon+A.raw");
|
||||
|
||||
var soundPlaying = false;
|
||||
|
||||
function keyPressEvent(event) {
|
||||
if (event.text === "1") {
|
||||
if (!Audio.isInjectorPlaying(soundPlaying)) {
|
||||
var options = new AudioInjectionOptions();
|
||||
options.position = MyAvatar.position;
|
||||
options.volume = 0.5;
|
||||
options.loop = true;
|
||||
soundPlaying = Audio.playSound(sound, options);
|
||||
print("Started sound loop");
|
||||
} else {
|
||||
Audio.stopInjector(soundPlaying);
|
||||
print("Stopped sound loop");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function scriptEnding() {
|
||||
if (Audio.isInjectorPlaying(soundPlaying)) {
|
||||
Audio.stopInjector(soundPlaying);
|
||||
print("Stopped sound loop");
|
||||
}
|
||||
}
|
||||
|
||||
// Connect a call back that happens every frame
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Controller.keyPressEvent.connect(keyPressEvent);
|
40
interface/resources/shaders/cascaded_shadow_map.frag
Normal file
40
interface/resources/shaders/cascaded_shadow_map.frag
Normal file
|
@ -0,0 +1,40 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// cascaded_shadow_map.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/29/14.
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the distances to the cascade sections
|
||||
uniform vec3 shadowDistances;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the color in shadow
|
||||
varying vec4 shadowColor;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
|
||||
void main(void) {
|
||||
// compute the index of the cascade to use and the corresponding texture coordinates
|
||||
int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
||||
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
|
||||
dot(gl_EyePlaneR[shadowIndex], position));
|
||||
|
||||
gl_FragColor = mix(shadowColor, gl_Color, 0.25 *
|
||||
(shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r));
|
||||
}
|
33
interface/resources/shaders/cascaded_shadow_map.vert
Normal file
33
interface/resources/shaders/cascaded_shadow_map.vert
Normal file
|
@ -0,0 +1,33 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// cascaded_shadow_map.vert
|
||||
// vertex shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/29/14.
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
// the color in shadow
|
||||
varying vec4 shadowColor;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
|
||||
void main(void) {
|
||||
// the shadow color includes only the ambient terms
|
||||
shadowColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient);
|
||||
|
||||
// the normal color includes diffuse
|
||||
vec4 normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
|
||||
gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position)));
|
||||
|
||||
// generate the shadow texture coordinates using the eye position
|
||||
position = gl_ModelViewMatrix * gl_Vertex;
|
||||
|
||||
// use the fixed function transform
|
||||
gl_Position = ftransform();
|
||||
}
|
56
interface/resources/shaders/model_cascaded_shadow_map.frag
Normal file
56
interface/resources/shaders/model_cascaded_shadow_map.frag
Normal file
|
@ -0,0 +1,56 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// model_cascaded_shadow_map.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/29/14.
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the distances to the cascade sections
|
||||
uniform vec3 shadowDistances;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 position;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// compute the index of the cascade to use and the corresponding texture coordinates
|
||||
int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
||||
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
|
||||
dot(gl_EyePlaneR[shadowIndex], position));
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
vec4 normalizedNormal = normalize(normal);
|
||||
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
|
||||
// compute the specular component (sans exponent)
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))),
|
||||
normalizedNormal));
|
||||
|
||||
// modulate texture by base color and add specular contribution
|
||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) +
|
||||
vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// model_cascaded_shadow_normal_map.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/29/14.
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal map texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the distances to the cascade sections
|
||||
uniform vec3 shadowDistances;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 interpolatedPosition;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 interpolatedNormal;
|
||||
|
||||
// the interpolated tangent
|
||||
varying vec4 interpolatedTangent;
|
||||
|
||||
void main(void) {
|
||||
vec3 normalizedNormal = normalize(vec3(interpolatedNormal));
|
||||
vec3 normalizedTangent = normalize(vec3(interpolatedTangent));
|
||||
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
|
||||
vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0);
|
||||
|
||||
// compute the index of the cascade to use and the corresponding texture coordinates
|
||||
int shadowIndex = int(dot(step(vec3(interpolatedPosition.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
||||
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], interpolatedPosition),
|
||||
dot(gl_EyePlaneT[shadowIndex], interpolatedPosition),
|
||||
dot(gl_EyePlaneR[shadowIndex], interpolatedPosition));
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
|
||||
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
|
||||
float diffuse = dot(viewNormal, gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
|
||||
// compute the specular component (sans exponent)
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position -
|
||||
normalize(vec4(vec3(interpolatedPosition), 0.0))), viewNormal));
|
||||
|
||||
// modulate texture by base color and add specular contribution
|
||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) +
|
||||
vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0);
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// model_cascaded_shadow_normal_specular_map.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/29/14.
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the normal map texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the specular map texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the distances to the cascade sections
|
||||
uniform vec3 shadowDistances;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated position
|
||||
varying vec4 interpolatedPosition;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 interpolatedNormal;
|
||||
|
||||
// the interpolated tangent
|
||||
varying vec4 interpolatedTangent;
|
||||
|
||||
void main(void) {
|
||||
vec3 normalizedNormal = normalize(vec3(interpolatedNormal));
|
||||
vec3 normalizedTangent = normalize(vec3(interpolatedTangent));
|
||||
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
|
||||
vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0);
|
||||
|
||||
// compute the index of the cascade to use and the corresponding texture coordinates
|
||||
int shadowIndex = int(dot(step(vec3(interpolatedPosition.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
||||
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], interpolatedPosition),
|
||||
dot(gl_EyePlaneT[shadowIndex], interpolatedPosition),
|
||||
dot(gl_EyePlaneR[shadowIndex], interpolatedPosition));
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
|
||||
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
|
||||
float diffuse = dot(viewNormal, gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
|
||||
// compute the specular component (sans exponent)
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position -
|
||||
normalize(vec4(interpolatedPosition.xyz, 0.0))), viewNormal));
|
||||
|
||||
// modulate texture by base color and add specular contribution
|
||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) *
|
||||
gl_FrontLightProduct[0].specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb, 0.0);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#version 120
|
||||
|
||||
//
|
||||
// model_cascaded_shadow_specular_map.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Andrzej Kapolka on 5/29/14.
|
||||
// Copyright 2014 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
|
||||
//
|
||||
|
||||
// the diffuse texture
|
||||
uniform sampler2D diffuseMap;
|
||||
|
||||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the shadow texture
|
||||
uniform sampler2DShadow shadowMap;
|
||||
|
||||
// the distances to the cascade sections
|
||||
uniform vec3 shadowDistances;
|
||||
|
||||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the interpolated position in view space
|
||||
varying vec4 position;
|
||||
|
||||
// the interpolated normal
|
||||
varying vec4 normal;
|
||||
|
||||
void main(void) {
|
||||
// compute the index of the cascade to use and the corresponding texture coordinates
|
||||
int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0)));
|
||||
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
|
||||
dot(gl_EyePlaneR[shadowIndex], position));
|
||||
|
||||
// compute the base color based on OpenGL lighting model
|
||||
vec4 normalizedNormal = normalize(normal);
|
||||
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
|
||||
float facingLight = step(0.0, diffuse) * 0.25 *
|
||||
(shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r +
|
||||
shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r);
|
||||
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
|
||||
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
|
||||
|
||||
// compute the specular component (sans exponent)
|
||||
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))),
|
||||
normalizedNormal));
|
||||
|
||||
// modulate texture by base color and add specular contribution
|
||||
gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) *
|
||||
gl_FrontLightProduct[0].specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb, 0.0);
|
||||
}
|
|
@ -16,6 +16,7 @@ uniform sampler2DShadow shadowMap;
|
|||
// the inverse of the size of the shadow map
|
||||
const float shadowScale = 1.0 / 2048.0;
|
||||
|
||||
// the color in shadow
|
||||
varying vec4 shadowColor;
|
||||
|
||||
void main(void) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// the color in shadow
|
||||
varying vec4 shadowColor;
|
||||
|
||||
void main(void) {
|
||||
|
@ -21,10 +22,10 @@ void main(void) {
|
|||
vec4 normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
|
||||
gl_FrontColor = shadowColor + gl_Color * (gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position)));
|
||||
|
||||
// generate the shadow texture coordinate using the eye position
|
||||
// generate the shadow texture coordinates using the eye position
|
||||
vec4 eyePosition = gl_ModelViewMatrix * gl_Vertex;
|
||||
gl_TexCoord[0] = vec4(dot(gl_EyePlaneS[0], eyePosition), dot(gl_EyePlaneT[0], eyePosition),
|
||||
dot(gl_EyePlaneR[0], eyePosition), 1.0);
|
||||
dot(gl_EyePlaneR[0], eyePosition), 1.0);
|
||||
|
||||
// use the fixed function transform
|
||||
gl_Position = ftransform();
|
||||
|
|
|
@ -554,6 +554,8 @@ void Application::initializeGL() {
|
|||
}
|
||||
|
||||
void Application::paintGL() {
|
||||
PerformanceTimer perfTimer("paintGL");
|
||||
|
||||
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
||||
|
@ -618,7 +620,7 @@ void Application::paintGL() {
|
|||
whichCamera = _viewFrustumOffsetCamera;
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
||||
if (Menu::getInstance()->getShadowsEnabled()) {
|
||||
updateShadowMap();
|
||||
}
|
||||
|
||||
|
@ -648,7 +650,10 @@ void Application::paintGL() {
|
|||
_rearMirrorTools->render(true);
|
||||
}
|
||||
|
||||
_applicationOverlay.renderOverlay();
|
||||
{
|
||||
PerformanceTimer perfTimer("paintGL/renderOverlay");
|
||||
_applicationOverlay.renderOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
_frameCount++;
|
||||
|
@ -1288,11 +1293,13 @@ void Application::timer() {
|
|||
}
|
||||
|
||||
void Application::idle() {
|
||||
PerformanceTimer perfTimer("idle");
|
||||
|
||||
// Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing
|
||||
// details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing
|
||||
// details normally.
|
||||
bool showWarnings = getLogger()->extraDebugging();
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()");
|
||||
PerformanceWarning warn(showWarnings, "idle()");
|
||||
|
||||
// Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran
|
||||
|
||||
|
@ -1300,15 +1307,18 @@ void Application::idle() {
|
|||
if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) {
|
||||
_lastTimeUpdated.start();
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/update");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... update()");
|
||||
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
||||
update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS));
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/updateGL");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... updateGL()");
|
||||
_glWidget->updateGL();
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/rest");
|
||||
PerformanceWarning warn(showWarnings, "Application::idle()... rest of it");
|
||||
_idleLoopStdev.addValue(timeSinceLastUpdate);
|
||||
|
||||
|
@ -1320,14 +1330,16 @@ void Application::idle() {
|
|||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) {
|
||||
PerformanceTimer perfTimer("idle/rest/_buckyBalls");
|
||||
_buckyBalls.simulate(timeSinceLastUpdate / 1000.f, Application::getInstance()->getAvatar()->getHandData());
|
||||
}
|
||||
|
||||
// After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
|
||||
idleTimer->start(2);
|
||||
}
|
||||
if (_numChangedSettings > 0) {
|
||||
saveSettings();
|
||||
|
||||
if (_numChangedSettings > 0) {
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1729,6 +1741,7 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) {
|
|||
}
|
||||
|
||||
void Application::updateLOD() {
|
||||
PerformanceTimer perfTimer("idle/update/updateLOD");
|
||||
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD) && !isThrottleRendering()) {
|
||||
Menu::getInstance()->autoAdjustLOD(_fps);
|
||||
|
@ -1738,6 +1751,7 @@ void Application::updateLOD() {
|
|||
}
|
||||
|
||||
void Application::updateMouseRay() {
|
||||
PerformanceTimer perfTimer("idle/update/updateMouseRay");
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMouseRay()");
|
||||
|
@ -1770,6 +1784,7 @@ void Application::updateMouseRay() {
|
|||
}
|
||||
|
||||
void Application::updateFaceshift() {
|
||||
PerformanceTimer perfTimer("idle/update/updateFaceshift");
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateFaceshift()");
|
||||
|
@ -1784,6 +1799,7 @@ void Application::updateFaceshift() {
|
|||
}
|
||||
|
||||
void Application::updateVisage() {
|
||||
PerformanceTimer perfTimer("idle/update/updateVisage");
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateVisage()");
|
||||
|
@ -1793,6 +1809,7 @@ void Application::updateVisage() {
|
|||
}
|
||||
|
||||
void Application::updateMyAvatarLookAtPosition() {
|
||||
PerformanceTimer perfTimer("idle/update/updateMyAvatarLookAtPosition");
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()");
|
||||
|
@ -1858,6 +1875,7 @@ void Application::updateMyAvatarLookAtPosition() {
|
|||
}
|
||||
|
||||
void Application::updateThreads(float deltaTime) {
|
||||
PerformanceTimer perfTimer("idle/update/updateThreads");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateThreads()");
|
||||
|
||||
|
@ -1872,6 +1890,7 @@ void Application::updateThreads(float deltaTime) {
|
|||
}
|
||||
|
||||
void Application::updateMetavoxels(float deltaTime) {
|
||||
PerformanceTimer perfTimer("idle/update/updateMetavoxels");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()");
|
||||
|
||||
|
@ -1901,6 +1920,7 @@ void Application::cameraMenuChanged() {
|
|||
}
|
||||
|
||||
void Application::updateCamera(float deltaTime) {
|
||||
PerformanceTimer perfTimer("idle/update/updateCamera");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateCamera()");
|
||||
|
||||
|
@ -1918,6 +1938,7 @@ void Application::updateCamera(float deltaTime) {
|
|||
}
|
||||
|
||||
void Application::updateDialogs(float deltaTime) {
|
||||
PerformanceTimer perfTimer("idle/update/updateDialogs");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateDialogs()");
|
||||
|
||||
|
@ -1934,6 +1955,7 @@ void Application::updateDialogs(float deltaTime) {
|
|||
}
|
||||
|
||||
void Application::updateCursor(float deltaTime) {
|
||||
PerformanceTimer perfTimer("idle/update/updateCursor");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateCursor()");
|
||||
|
||||
|
@ -1958,51 +1980,87 @@ void Application::updateCursor(float deltaTime) {
|
|||
}
|
||||
|
||||
void Application::update(float deltaTime) {
|
||||
//PerformanceTimer perfTimer("idle/update"); // NOTE: we track this above in Application::idle()
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::update()");
|
||||
|
||||
updateLOD();
|
||||
|
||||
// check what's under the mouse and update the mouse voxel
|
||||
updateMouseRay();
|
||||
|
||||
updateMouseRay(); // check what's under the mouse and update the mouse voxel
|
||||
updateFaceshift();
|
||||
updateVisage();
|
||||
_myAvatar->updateLookAtTargetAvatar();
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/update/updateLookAtTargetAvatar");
|
||||
_myAvatar->updateLookAtTargetAvatar();
|
||||
}
|
||||
updateMyAvatarLookAtPosition();
|
||||
_sixenseManager.update(deltaTime);
|
||||
_joystickManager.update();
|
||||
_prioVR.update(deltaTime);
|
||||
updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/update/sixense,joystick,prioVR");
|
||||
_sixenseManager.update(deltaTime);
|
||||
_joystickManager.update();
|
||||
_prioVR.update(deltaTime);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/update/updateMyAvatar");
|
||||
updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
|
||||
}
|
||||
|
||||
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||
_avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them...
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/update/_avatarManager");
|
||||
_avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them...
|
||||
}
|
||||
updateMetavoxels(deltaTime); // update metavoxels
|
||||
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
|
||||
updateDialogs(deltaTime); // update various stats dialogs if present
|
||||
updateCursor(deltaTime); // Handle cursor updates
|
||||
|
||||
_particles.update(); // update the particles...
|
||||
_particleCollisionSystem.update(); // collide the particles...
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/update/_particles");
|
||||
_particles.update(); // update the particles...
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/update/_particleCollisionSystem");
|
||||
_particleCollisionSystem.update(); // collide the particles...
|
||||
}
|
||||
|
||||
_models.update(); // update the models...
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/update/_models");
|
||||
_models.update(); // update the models...
|
||||
}
|
||||
|
||||
_overlays.update(deltaTime);
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/update/_overlays");
|
||||
_overlays.update(deltaTime);
|
||||
}
|
||||
|
||||
// let external parties know we're updating
|
||||
emit simulating(deltaTime);
|
||||
{
|
||||
PerformanceTimer perfTimer("idle/update/emit simulating");
|
||||
// let external parties know we're updating
|
||||
emit simulating(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::updateMyAvatar(float deltaTime) {
|
||||
PerformanceTimer perfTimer("updateMyAvatar");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateMyAvatar()");
|
||||
|
||||
_myAvatar->update(deltaTime);
|
||||
{
|
||||
PerformanceTimer perfTimer("updateMyAvatar/_myAvatar->update()");
|
||||
_myAvatar->update(deltaTime);
|
||||
}
|
||||
|
||||
// send head/hand data to the avatar mixer and voxel server
|
||||
QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarData);
|
||||
packet.append(_myAvatar->toByteArray());
|
||||
|
||||
controlledBroadcastToNodes(packet, NodeSet() << NodeType::AvatarMixer);
|
||||
{
|
||||
// send head/hand data to the avatar mixer and voxel server
|
||||
PerformanceTimer perfTimer("updateMyAvatar/sendToAvatarMixer");
|
||||
QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarData);
|
||||
packet.append(_myAvatar->toByteArray());
|
||||
controlledBroadcastToNodes(packet, NodeSet() << NodeType::AvatarMixer);
|
||||
}
|
||||
|
||||
// Update _viewFrustum with latest camera and view frustum data...
|
||||
// NOTE: we get this from the view frustum, to make it simpler, since the
|
||||
|
@ -2010,22 +2068,28 @@ void Application::updateMyAvatar(float deltaTime) {
|
|||
// We could optimize this to not actually load the viewFrustum, since we don't
|
||||
// actually need to calculate the view frustum planes to send these details
|
||||
// to the server.
|
||||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
{
|
||||
PerformanceTimer perfTimer("updateMyAvatar/loadViewFrustum");
|
||||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
}
|
||||
|
||||
// Update my voxel servers with my current voxel query...
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 sinceLastQuery = now - _lastQueriedTime;
|
||||
const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND;
|
||||
bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY;
|
||||
bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum);
|
||||
{
|
||||
PerformanceTimer perfTimer("updateMyAvatar/queryOctree");
|
||||
quint64 now = usecTimestampNow();
|
||||
quint64 sinceLastQuery = now - _lastQueriedTime;
|
||||
const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND;
|
||||
bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY;
|
||||
bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum);
|
||||
|
||||
// if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it
|
||||
if (queryIsDue || viewIsDifferentEnough) {
|
||||
_lastQueriedTime = now;
|
||||
queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions);
|
||||
queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions);
|
||||
queryOctree(NodeType::ModelServer, PacketTypeModelQuery, _modelServerJurisdictions);
|
||||
_lastQueriedViewFrustum = _viewFrustum;
|
||||
// if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it
|
||||
if (queryIsDue || viewIsDifferentEnough) {
|
||||
_lastQueriedTime = now;
|
||||
queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions);
|
||||
queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions);
|
||||
queryOctree(NodeType::ModelServer, PacketTypeModelQuery, _modelServerJurisdictions);
|
||||
_lastQueriedViewFrustum = _viewFrustum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2253,99 +2317,122 @@ glm::vec3 Application::getSunDirection() {
|
|||
}
|
||||
|
||||
void Application::updateShadowMap() {
|
||||
PerformanceTimer perfTimer("paintGL/updateShadowMap");
|
||||
QOpenGLFramebufferObject* fbo = _textureCache.getShadowFramebufferObject();
|
||||
fbo->bind();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glViewport(0, 0, fbo->width(), fbo->height());
|
||||
|
||||
glm::vec3 lightDirection = -getSunDirection();
|
||||
glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection);
|
||||
glm::quat inverseRotation = glm::inverse(rotation);
|
||||
float nearScale = 0.0f;
|
||||
const float MAX_SHADOW_DISTANCE = 2.0f;
|
||||
float farScale = (MAX_SHADOW_DISTANCE - _viewFrustum.getNearClip()) /
|
||||
(_viewFrustum.getFarClip() - _viewFrustum.getNearClip());
|
||||
|
||||
const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f };
|
||||
const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f),
|
||||
glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) };
|
||||
|
||||
float frustumScale = 1.0f / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip());
|
||||
loadViewFrustum(_myCamera, _viewFrustum);
|
||||
glm::vec3 points[] = {
|
||||
glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale),
|
||||
glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale),
|
||||
glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale),
|
||||
glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) };
|
||||
glm::vec3 center;
|
||||
for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) {
|
||||
center += points[i];
|
||||
}
|
||||
center /= (float)(sizeof(points) / sizeof(points[0]));
|
||||
float radius = 0.0f;
|
||||
for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) {
|
||||
radius = qMax(radius, glm::distance(points[i], center));
|
||||
}
|
||||
center = inverseRotation * center;
|
||||
|
||||
// to reduce texture "shimmer," move in texel increments
|
||||
float texelSize = (2.0f * radius) / fbo->width();
|
||||
center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize,
|
||||
roundf(center.z / texelSize) * texelSize);
|
||||
int matrixCount = 1;
|
||||
int targetSize = fbo->width();
|
||||
float targetScale = 1.0f;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
|
||||
matrixCount = CASCADED_SHADOW_MATRIX_COUNT;
|
||||
targetSize = fbo->width() / 2;
|
||||
targetScale = 0.5f;
|
||||
}
|
||||
for (int i = 0; i < matrixCount; i++) {
|
||||
const glm::vec2& coord = MAP_COORDS[i];
|
||||
glViewport(coord.s * fbo->width(), coord.t * fbo->height(), targetSize, targetSize);
|
||||
|
||||
float nearScale = SHADOW_MATRIX_DISTANCES[i] * frustumScale;
|
||||
float farScale = SHADOW_MATRIX_DISTANCES[i + 1] * frustumScale;
|
||||
glm::vec3 points[] = {
|
||||
glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale),
|
||||
glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale),
|
||||
glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale),
|
||||
glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale),
|
||||
glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) };
|
||||
glm::vec3 center;
|
||||
for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); j++) {
|
||||
center += points[j];
|
||||
}
|
||||
center /= (float)(sizeof(points) / sizeof(points[0]));
|
||||
float radius = 0.0f;
|
||||
for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); j++) {
|
||||
radius = qMax(radius, glm::distance(points[j], center));
|
||||
}
|
||||
if (i < 3) {
|
||||
const float RADIUS_SCALE = 0.5f;
|
||||
_shadowDistances[i] = -glm::distance(_viewFrustum.getPosition(), center) - radius * RADIUS_SCALE;
|
||||
}
|
||||
center = inverseRotation * center;
|
||||
|
||||
// to reduce texture "shimmer," move in texel increments
|
||||
float texelSize = (2.0f * radius) / targetSize;
|
||||
center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize,
|
||||
roundf(center.z / texelSize) * texelSize);
|
||||
|
||||
glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius);
|
||||
glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius);
|
||||
|
||||
// stretch out our extents in z so that we get all of the avatars
|
||||
minima.z -= _viewFrustum.getFarClip() * 0.5f;
|
||||
maxima.z += _viewFrustum.getFarClip() * 0.5f;
|
||||
|
||||
// save the combined matrix for rendering
|
||||
_shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) *
|
||||
glm::scale(glm::vec3(targetScale, targetScale, 1.0f)) *
|
||||
glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) *
|
||||
glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation));
|
||||
|
||||
// update the shadow view frustum
|
||||
_shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f));
|
||||
_shadowViewFrustum.setOrientation(rotation);
|
||||
_shadowViewFrustum.setOrthographic(true);
|
||||
_shadowViewFrustum.setWidth(maxima.x - minima.x);
|
||||
_shadowViewFrustum.setHeight(maxima.y - minima.y);
|
||||
_shadowViewFrustum.setNearClip(minima.z);
|
||||
_shadowViewFrustum.setFarClip(maxima.z);
|
||||
_shadowViewFrustum.setEyeOffsetPosition(glm::vec3());
|
||||
_shadowViewFrustum.setEyeOffsetOrientation(glm::quat());
|
||||
_shadowViewFrustum.calculate();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glm::vec3 axis = glm::axis(inverseRotation);
|
||||
glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
// store view matrix without translation, which we'll use for precision-sensitive objects
|
||||
updateUntranslatedViewMatrix();
|
||||
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
|
||||
|
||||
_avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
|
||||
_particles.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
_models.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius);
|
||||
glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius);
|
||||
|
||||
// stretch out our extents in z so that we get all of the avatars
|
||||
minima.z -= _viewFrustum.getFarClip() * 0.5f;
|
||||
maxima.z += _viewFrustum.getFarClip() * 0.5f;
|
||||
|
||||
// save the combined matrix for rendering
|
||||
_shadowMatrix = glm::transpose(glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) *
|
||||
glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation));
|
||||
|
||||
// update the shadow view frustum
|
||||
_shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f));
|
||||
_shadowViewFrustum.setOrientation(rotation);
|
||||
_shadowViewFrustum.setOrthographic(true);
|
||||
_shadowViewFrustum.setWidth(maxima.x - minima.x);
|
||||
_shadowViewFrustum.setHeight(maxima.y - minima.y);
|
||||
_shadowViewFrustum.setNearClip(minima.z);
|
||||
_shadowViewFrustum.setFarClip(maxima.z);
|
||||
_shadowViewFrustum.setEyeOffsetPosition(glm::vec3());
|
||||
_shadowViewFrustum.setEyeOffsetOrientation(glm::quat());
|
||||
_shadowViewFrustum.calculate();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glm::vec3 axis = glm::axis(inverseRotation);
|
||||
glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z);
|
||||
|
||||
// store view matrix without translation, which we'll use for precision-sensitive objects
|
||||
updateUntranslatedViewMatrix();
|
||||
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt
|
||||
|
||||
_avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
|
||||
_particles.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
_models.render(OctreeRenderer::SHADOW_RENDER_MODE);
|
||||
|
||||
glDisable(GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
fbo->release();
|
||||
|
||||
glViewport(0, 0, _glWidget->width(), _glWidget->height());
|
||||
|
@ -2392,6 +2479,7 @@ QImage Application::renderAvatarBillboard() {
|
|||
}
|
||||
|
||||
void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()");
|
||||
// transform by eye offset
|
||||
|
||||
|
@ -2424,9 +2512,27 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z);
|
||||
|
||||
// Setup 3D lights (after the camera transform, so that they are positioned in world space)
|
||||
setupWorldLight();
|
||||
{
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/setupWorldLight");
|
||||
setupWorldLight();
|
||||
}
|
||||
|
||||
// setup shadow matrices (again, after the camera transform)
|
||||
int shadowMatrixCount = 0;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::SimpleShadows)) {
|
||||
shadowMatrixCount = 1;
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
|
||||
shadowMatrixCount = CASCADED_SHADOW_MATRIX_COUNT;
|
||||
}
|
||||
for (int i = shadowMatrixCount - 1; i >= 0; i--) {
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][0]);
|
||||
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][1]);
|
||||
glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][2]);
|
||||
}
|
||||
|
||||
if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/stars");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... stars...");
|
||||
if (!_stars.isStarsLoaded()) {
|
||||
|
@ -2455,6 +2561,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
|
||||
// draw the sky dome
|
||||
if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/atmosphere");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... atmosphere...");
|
||||
_environment.renderAtmospheres(whichCamera);
|
||||
|
@ -2474,10 +2581,14 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR);
|
||||
|
||||
// draw the audio reflector overlay
|
||||
_audioReflector.render();
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/audioReflector");
|
||||
_audioReflector.render();
|
||||
}
|
||||
|
||||
// Draw voxels
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/voxels");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... voxels...");
|
||||
_voxels.render();
|
||||
|
@ -2485,12 +2596,14 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
|
||||
// also, metavoxels
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/metavoxels");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... metavoxels...");
|
||||
_metavoxels.render();
|
||||
}
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/buckyBalls");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... bucky balls...");
|
||||
_buckyBalls.render();
|
||||
|
@ -2498,6 +2611,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
|
||||
// render particles...
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Particles)) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/particles");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... particles...");
|
||||
_particles.render();
|
||||
|
@ -2505,6 +2619,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
|
||||
// render models...
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/models");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... models...");
|
||||
_models.render();
|
||||
|
@ -2512,6 +2627,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
|
||||
// render the ambient occlusion effect if enabled
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/AmbientOcclusion");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... AmbientOcclusion...");
|
||||
_ambientOcclusionEffect.render();
|
||||
|
@ -2525,16 +2641,21 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
}
|
||||
|
||||
bool mirrorMode = (whichCamera.getInterpolatedMode() == CAMERA_MODE_MIRROR);
|
||||
_avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, selfAvatarOnly);
|
||||
{
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/renderAvatars");
|
||||
_avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, selfAvatarOnly);
|
||||
}
|
||||
|
||||
if (!selfAvatarOnly) {
|
||||
// Render the world box
|
||||
if (whichCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/renderWorldBox");
|
||||
renderWorldBox();
|
||||
}
|
||||
|
||||
// brad's frustum for debugging
|
||||
// view frustum for debugging
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum) && whichCamera.getMode() != CAMERA_MODE_MIRROR) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/ViewFrustum");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... renderViewFrustum...");
|
||||
renderViewFrustum(_viewFrustum);
|
||||
|
@ -2542,6 +2663,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
|
||||
// render voxel fades if they exist
|
||||
if (_voxelFades.size() > 0) {
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/voxel fades");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... voxel fades...");
|
||||
_voxelFadesLock.lockForWrite();
|
||||
|
@ -2557,10 +2679,16 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
}
|
||||
|
||||
// give external parties a change to hook in
|
||||
emit renderingInWorldInterface();
|
||||
{
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/inWorldInterface");
|
||||
emit renderingInWorldInterface();
|
||||
}
|
||||
|
||||
// render JS/scriptable overlays
|
||||
_overlays.render3D();
|
||||
{
|
||||
PerformanceTimer perfTimer("paintGL/displaySide/3dOverlays");
|
||||
_overlays.render3D();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -261,11 +261,11 @@ public:
|
|||
/// result from matrix multiplication at high translation magnitudes.
|
||||
void loadTranslatedViewMatrix(const glm::vec3& translation);
|
||||
|
||||
const glm::mat4& getShadowMatrix() const { return _shadowMatrix; }
|
||||
|
||||
void getModelViewMatrix(glm::dmat4* modelViewMatrix);
|
||||
void getProjectionMatrix(glm::dmat4* projectionMatrix);
|
||||
|
||||
const glm::vec3& getShadowDistances() const { return _shadowDistances; }
|
||||
|
||||
/// Computes the off-axis frustum parameters for the view frustum, taking mirroring into account.
|
||||
void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
|
||||
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const;
|
||||
|
@ -492,7 +492,9 @@ private:
|
|||
float _rotateMirror;
|
||||
float _raiseMirror;
|
||||
|
||||
glm::mat4 _shadowMatrix;
|
||||
static const int CASCADED_SHADOW_MATRIX_COUNT = 4;
|
||||
glm::mat4 _shadowMatrices[CASCADED_SHADOW_MATRIX_COUNT];
|
||||
glm::vec3 _shadowDistances;
|
||||
|
||||
Environment _environment;
|
||||
|
||||
|
|
|
@ -315,7 +315,12 @@ Menu::Menu() :
|
|||
appInstance->getGlowEffect(),
|
||||
SLOT(cycleRenderMode()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false);
|
||||
QMenu* shadowMenu = renderOptionsMenu->addMenu("Shadows");
|
||||
QActionGroup* shadowGroup = new QActionGroup(shadowMenu);
|
||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true));
|
||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false));
|
||||
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Metavoxels, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::BuckyBalls, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Particles, 0, true);
|
||||
|
@ -386,8 +391,18 @@ Menu::Menu() :
|
|||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlternateIK, 0, false);
|
||||
|
||||
addDisabledActionAndSeparator(developerMenu, "Testing");
|
||||
|
||||
|
||||
QMenu* timingMenu = developerMenu->addMenu("Timing and Statistics Tools");
|
||||
QMenu* perfTimerMenu = timingMenu->addMenu("Performance Timer");
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::DisplayTimingDetails, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandDisplaySideTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandAvatarSimulateTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandAvatarUpdateTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandMiscAvatarTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandIdleTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandPaintGLTiming, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(perfTimerMenu, MenuOption::ExpandUpdateTiming, 0, false);
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::TestPing, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(timingMenu, MenuOption::FrameTimer);
|
||||
addActionToQMenuAndActionHash(timingMenu, MenuOption::RunTimingTests, 0, this, SLOT(runTests()));
|
||||
|
@ -678,6 +693,10 @@ void Menu::scanMenu(QMenu* menu, settingsAction modifySetting, QSettings* set) {
|
|||
set->endGroup();
|
||||
}
|
||||
|
||||
bool Menu::getShadowsEnabled() const {
|
||||
return isOptionChecked(MenuOption::SimpleShadows) || isOptionChecked(MenuOption::CascadedShadows);
|
||||
}
|
||||
|
||||
void Menu::handleViewFrustumOffsetKeyModifier(int key) {
|
||||
const float VIEW_FRUSTUM_OFFSET_DELTA = 0.5f;
|
||||
const float VIEW_FRUSTUM_OFFSET_UP_DELTA = 0.05f;
|
||||
|
@ -848,8 +867,8 @@ void Menu::setIsOptionChecked(const QString& menuOption, bool isChecked) {
|
|||
}
|
||||
}
|
||||
|
||||
bool Menu::isOptionChecked(const QString& menuOption) {
|
||||
QAction* menu = _actionHash.value(menuOption);
|
||||
bool Menu::isOptionChecked(const QString& menuOption) const {
|
||||
const QAction* menu = _actionHash.value(menuOption);
|
||||
if (menu) {
|
||||
return menu->isChecked();
|
||||
}
|
||||
|
|
|
@ -103,6 +103,8 @@ public:
|
|||
int getMaxVoxels() const { return _maxVoxels; }
|
||||
QAction* getUseVoxelShader() const { return _useVoxelShader; }
|
||||
|
||||
bool getShadowsEnabled() const;
|
||||
|
||||
void handleViewFrustumOffsetKeyModifier(int key);
|
||||
|
||||
// User Tweakable LOD Items
|
||||
|
@ -171,7 +173,7 @@ public slots:
|
|||
void removeSeparator(const QString& menuName, const QString& separatorName);
|
||||
void addMenuItem(const MenuItemProperties& properties);
|
||||
void removeMenuItem(const QString& menuName, const QString& menuitem);
|
||||
bool isOptionChecked(const QString& menuOption);
|
||||
bool isOptionChecked(const QString& menuOption) const;
|
||||
void setIsOptionChecked(const QString& menuOption, bool isChecked);
|
||||
|
||||
private slots:
|
||||
|
@ -304,6 +306,7 @@ namespace MenuOption {
|
|||
const QString Bandwidth = "Bandwidth Display";
|
||||
const QString BandwidthDetails = "Bandwidth Details";
|
||||
const QString BuckyBalls = "Bucky Balls";
|
||||
const QString CascadedShadows = "Cascaded";
|
||||
const QString Chat = "Chat...";
|
||||
const QString ChatCircling = "Chat Circling";
|
||||
const QString CollideWithAvatars = "Collide With Avatars";
|
||||
|
@ -321,10 +324,18 @@ namespace MenuOption {
|
|||
const QString DisplayModelBounds = "Display Model Bounds";
|
||||
const QString DisplayModelElementProxy = "Display Model Element Bounds";
|
||||
const QString DisplayModelElementChildProxies = "Display Model Element Children";
|
||||
const QString DisplayTimingDetails = "Display Timing Details";
|
||||
const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes";
|
||||
const QString EchoLocalAudio = "Echo Local Audio";
|
||||
const QString EchoServerAudio = "Echo Server Audio";
|
||||
const QString Enable3DTVMode = "Enable 3DTV Mode";
|
||||
const QString ExpandMiscAvatarTiming = "Expand Misc MyAvatar Timing";
|
||||
const QString ExpandAvatarUpdateTiming = "Expand MyAvatar update Timing";
|
||||
const QString ExpandAvatarSimulateTiming = "Expand MyAvatar simulate Timing";
|
||||
const QString ExpandDisplaySideTiming = "Expand Display Side Timing";
|
||||
const QString ExpandIdleTiming = "Expand Idle Timing";
|
||||
const QString ExpandPaintGLTiming = "Expand PaintGL Timing";
|
||||
const QString ExpandUpdateTiming = "Expand Update Timing";
|
||||
const QString Faceplus = "Faceplus";
|
||||
const QString Faceshift = "Faceshift";
|
||||
const QString FilterSixense = "Smooth Sixense Movement";
|
||||
|
@ -380,7 +391,7 @@ namespace MenuOption {
|
|||
const QString ScriptEditor = "Script Editor...";
|
||||
const QString SettingsExport = "Export Settings";
|
||||
const QString SettingsImport = "Import Settings";
|
||||
const QString Shadows = "Shadows";
|
||||
const QString SimpleShadows = "Simple";
|
||||
const QString ShowBordersVoxelNodes = "Show Voxel Nodes";
|
||||
const QString ShowBordersModelNodes = "Show Model Nodes";
|
||||
const QString ShowBordersParticleNodes = "Show Particle Nodes";
|
||||
|
|
|
@ -378,10 +378,10 @@ void Avatar::simulateAttachments(float deltaTime) {
|
|||
model->setLODDistance(getLODDistance());
|
||||
}
|
||||
if (_skeletonModel.getJointPosition(jointIndex, jointPosition) &&
|
||||
_skeletonModel.getJointRotation(jointIndex, jointRotation)) {
|
||||
_skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) {
|
||||
model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale);
|
||||
model->setRotation(jointRotation * attachment.rotation);
|
||||
model->setScale(_skeletonModel.getScale() * attachment.scale);
|
||||
model->setScaleToFit(true, _scale * attachment.scale);
|
||||
model->simulate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
@ -705,6 +705,54 @@ QStringList Avatar::getJointNames() const {
|
|||
return _skeletonModel.isActive() ? _skeletonModel.getGeometry()->getFBXGeometry().getJointNames() : QStringList();
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getJointPosition(int index) const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
glm::vec3 position;
|
||||
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "getJointPosition", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(glm::vec3, position), Q_ARG(const int, index));
|
||||
return position;
|
||||
}
|
||||
glm::vec3 position;
|
||||
_skeletonModel.getJointPosition(index, position);
|
||||
return position;
|
||||
}
|
||||
|
||||
glm::vec3 Avatar::getJointPosition(const QString& name) const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
glm::vec3 position;
|
||||
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "getJointPosition", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(glm::vec3, position), Q_ARG(const QString&, name));
|
||||
return position;
|
||||
}
|
||||
glm::vec3 position;
|
||||
_skeletonModel.getJointPosition(getJointIndex(name), position);
|
||||
return position;
|
||||
}
|
||||
|
||||
glm::quat Avatar::getJointCombinedRotation(int index) const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
glm::quat rotation;
|
||||
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "getJointCombinedRotation", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(glm::quat, rotation), Q_ARG(const int, index));
|
||||
return rotation;
|
||||
}
|
||||
glm::quat rotation;
|
||||
_skeletonModel.getJointCombinedRotation(index, rotation);
|
||||
return rotation;
|
||||
}
|
||||
|
||||
glm::quat Avatar::getJointCombinedRotation(const QString& name) const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
glm::quat rotation;
|
||||
QMetaObject::invokeMethod(const_cast<Avatar*>(this), "getJointCombinedRotation", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(glm::quat, rotation), Q_ARG(const QString&, name));
|
||||
return rotation;
|
||||
}
|
||||
glm::quat rotation;
|
||||
_skeletonModel.getJointCombinedRotation(getJointIndex(name), rotation);
|
||||
return rotation;
|
||||
}
|
||||
|
||||
void Avatar::setFaceModelURL(const QUrl& faceModelURL) {
|
||||
AvatarData::setFaceModelURL(faceModelURL);
|
||||
const QUrl DEFAULT_FACE_MODEL_URL = QUrl::fromLocalFile(Application::resourcesPath() + "meshes/defaultAvatar_head.fst");
|
||||
|
@ -734,6 +782,8 @@ void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
|
|||
|
||||
// update the urls
|
||||
for (int i = 0; i < attachmentData.size(); i++) {
|
||||
_attachmentModels[i]->setSnapModelToCenter(true);
|
||||
_attachmentModels[i]->setScaleToFit(true, _scale * _attachmentData.at(i).scale);
|
||||
_attachmentModels[i]->setURL(attachmentData.at(i).modelURL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,7 +152,12 @@ public:
|
|||
|
||||
quint32 getCollisionGroups() const { return _collisionGroups; }
|
||||
virtual void setCollisionGroups(quint32 collisionGroups) { _collisionGroups = (collisionGroups & VALID_COLLISION_GROUPS); }
|
||||
|
||||
|
||||
Q_INVOKABLE glm::vec3 getJointPosition(int index) const;
|
||||
Q_INVOKABLE glm::vec3 getJointPosition(const QString& name) const;
|
||||
Q_INVOKABLE glm::quat getJointCombinedRotation(int index) const;
|
||||
Q_INVOKABLE glm::quat getJointCombinedRotation(const QString& name) const;
|
||||
|
||||
public slots:
|
||||
void updateCollisionGroups();
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@
|
|||
#include <GeometryUtil.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <ShapeCollider.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Audio.h"
|
||||
|
@ -76,8 +76,7 @@ MyAvatar::MyAvatar() :
|
|||
_lastFloorContactPoint(0.0f),
|
||||
_lookAtTargetAvatar(),
|
||||
_shouldRender(true),
|
||||
_billboardValid(false),
|
||||
_oculusYawOffset(0.0f)
|
||||
_billboardValid(false)
|
||||
{
|
||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||
_driveKeys[i] = 0.0f;
|
||||
|
@ -90,8 +89,7 @@ MyAvatar::~MyAvatar() {
|
|||
|
||||
void MyAvatar::reset() {
|
||||
_skeletonModel.reset();
|
||||
getHead()->reset();
|
||||
_oculusYawOffset = 0.0f;
|
||||
getHead()->reset();
|
||||
|
||||
setVelocity(glm::vec3(0.0f));
|
||||
setThrust(glm::vec3(0.0f));
|
||||
|
@ -103,10 +101,15 @@ void MyAvatar::reset() {
|
|||
}
|
||||
|
||||
void MyAvatar::update(float deltaTime) {
|
||||
PerformanceTimer perfTimer("MyAvatar::update/");
|
||||
Head* head = getHead();
|
||||
head->relaxLean(deltaTime);
|
||||
updateFromTrackers(deltaTime);
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::update/updateFromTrackers");
|
||||
updateFromTrackers(deltaTime);
|
||||
}
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) {
|
||||
PerformanceTimer perfTimer("MyAvatar::update/moveWithLean");
|
||||
// Faceshift drive is enabled, set the avatar drive based on the head position
|
||||
moveWithLean();
|
||||
}
|
||||
|
@ -117,13 +120,18 @@ void MyAvatar::update(float deltaTime) {
|
|||
head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness());
|
||||
|
||||
if (_motionBehaviors & AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY) {
|
||||
PerformanceTimer perfTimer("MyAvatar::update/gravityWork");
|
||||
setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition()));
|
||||
}
|
||||
|
||||
simulate(deltaTime);
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::update/simulate");
|
||||
simulate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::simulate(float deltaTime) {
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate");
|
||||
|
||||
if (_scale != _targetScale) {
|
||||
float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale;
|
||||
|
@ -134,34 +142,56 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
// no extra movement of the hand here any more ...
|
||||
_handState = HAND_STATE_NULL;
|
||||
|
||||
updateOrientation(deltaTime);
|
||||
updatePosition(deltaTime);
|
||||
|
||||
// update avatar skeleton and simulate hand and head
|
||||
getHand()->collideAgainstOurself();
|
||||
getHand()->simulate(deltaTime, true);
|
||||
|
||||
_skeletonModel.simulate(deltaTime);
|
||||
simulateAttachments(deltaTime);
|
||||
|
||||
// copy out the skeleton joints from the model
|
||||
_jointData.resize(_skeletonModel.getJointStateCount());
|
||||
for (int i = 0; i < _jointData.size(); i++) {
|
||||
JointData& data = _jointData[i];
|
||||
data.valid = _skeletonModel.getJointState(i, data.rotation);
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/updateOrientation");
|
||||
updateOrientation(deltaTime);
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/updatePosition");
|
||||
updatePosition(deltaTime);
|
||||
}
|
||||
|
||||
Head* head = getHead();
|
||||
glm::vec3 headPosition;
|
||||
if (!_skeletonModel.getHeadPosition(headPosition)) {
|
||||
headPosition = _position;
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/hand Collision,simulate");
|
||||
// update avatar skeleton and simulate hand and head
|
||||
getHand()->collideAgainstOurself();
|
||||
getHand()->simulate(deltaTime, true);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/_skeletonModel.simulate()");
|
||||
_skeletonModel.simulate(deltaTime);
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/simulateAttachments");
|
||||
simulateAttachments(deltaTime);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/copy joints");
|
||||
// copy out the skeleton joints from the model
|
||||
_jointData.resize(_skeletonModel.getJointStateCount());
|
||||
for (int i = 0; i < _jointData.size(); i++) {
|
||||
JointData& data = _jointData[i];
|
||||
data.valid = _skeletonModel.getJointState(i, data.rotation);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/head Simulate");
|
||||
Head* head = getHead();
|
||||
glm::vec3 headPosition;
|
||||
if (!_skeletonModel.getHeadPosition(headPosition)) {
|
||||
headPosition = _position;
|
||||
}
|
||||
head->setPosition(headPosition);
|
||||
head->setScale(_scale);
|
||||
head->simulate(deltaTime, true);
|
||||
}
|
||||
head->setPosition(headPosition);
|
||||
head->setScale(_scale);
|
||||
head->simulate(deltaTime, true);
|
||||
|
||||
// now that we're done stepping the avatar forward in time, compute new collisions
|
||||
if (_collisionGroups != 0) {
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/_collisionGroups");
|
||||
Camera* myCamera = Application::getInstance()->getCamera();
|
||||
|
||||
float radius = getSkeletonHeight() * COLLISION_RADIUS_SCALE;
|
||||
|
@ -171,14 +201,17 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
}
|
||||
updateShapePositions();
|
||||
if (_collisionGroups & COLLISION_GROUP_ENVIRONMENT) {
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithEnvironment");
|
||||
updateCollisionWithEnvironment(deltaTime, radius);
|
||||
}
|
||||
if (_collisionGroups & COLLISION_GROUP_VOXELS) {
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithVoxels");
|
||||
updateCollisionWithVoxels(deltaTime, radius);
|
||||
} else {
|
||||
_trapDuration = 0.0f;
|
||||
}
|
||||
if (_collisionGroups & COLLISION_GROUP_AVATARS) {
|
||||
PerformanceTimer perfTimer("MyAvatar::simulate/updateCollisionWithAvatars");
|
||||
updateCollisionWithAvatars(deltaTime);
|
||||
}
|
||||
}
|
||||
|
@ -791,6 +824,7 @@ bool MyAvatar::shouldRenderHead(const glm::vec3& cameraPosition, RenderMode rend
|
|||
}
|
||||
|
||||
float MyAvatar::computeDistanceToFloor(const glm::vec3& startPoint) {
|
||||
PerformanceTimer perfTimer("MyAvatar::computeDistanceToFloor()");
|
||||
glm::vec3 direction = -_worldUpDirection;
|
||||
OctreeElement* elementHit; // output from findRayIntersection
|
||||
float distance = FLT_MAX; // output from findRayIntersection
|
||||
|
@ -828,43 +862,8 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
OculusManager::getEulerAngles(yaw, pitch, roll);
|
||||
// ... so they need to be converted to degrees before we do math...
|
||||
|
||||
// The neck is limited in how much it can yaw, so we check its relative
|
||||
// yaw from the body and yaw the body if necessary.
|
||||
yaw *= DEGREES_PER_RADIAN;
|
||||
float bodyToHeadYaw = yaw - _oculusYawOffset;
|
||||
const float MAX_NECK_YAW = 85.0f; // degrees
|
||||
if ((fabs(bodyToHeadYaw) > 2.0f * MAX_NECK_YAW) && (yaw * _oculusYawOffset < 0.0f)) {
|
||||
// We've wrapped around the range for yaw so adjust
|
||||
// the measured yaw to be relative to _oculusYawOffset.
|
||||
if (yaw > 0.0f) {
|
||||
yaw -= 360.0f;
|
||||
} else {
|
||||
yaw += 360.0f;
|
||||
}
|
||||
bodyToHeadYaw = yaw - _oculusYawOffset;
|
||||
}
|
||||
|
||||
float delta = fabs(bodyToHeadYaw) - MAX_NECK_YAW;
|
||||
if (delta > 0.0f) {
|
||||
yaw = MAX_NECK_YAW;
|
||||
if (bodyToHeadYaw < 0.0f) {
|
||||
delta *= -1.0f;
|
||||
bodyToHeadYaw = -MAX_NECK_YAW;
|
||||
} else {
|
||||
bodyToHeadYaw = MAX_NECK_YAW;
|
||||
}
|
||||
// constrain _oculusYawOffset to be within range [-180,180]
|
||||
_oculusYawOffset = fmod((_oculusYawOffset + delta) + 180.0f, 360.0f) - 180.0f;
|
||||
|
||||
// We must adjust the body orientation using a delta rotation (rather than
|
||||
// doing yaw math) because the body's yaw ranges are not the same
|
||||
// as what the Oculus API provides.
|
||||
glm::quat bodyCorrection = glm::angleAxis(glm::radians(delta), _worldUpDirection);
|
||||
orientation = orientation * bodyCorrection;
|
||||
}
|
||||
Head* head = getHead();
|
||||
head->setBaseYaw(bodyToHeadYaw);
|
||||
|
||||
head->setBaseYaw(yaw * DEGREES_PER_RADIAN);
|
||||
head->setBasePitch(pitch * DEGREES_PER_RADIAN);
|
||||
head->setBaseRoll(roll * DEGREES_PER_RADIAN);
|
||||
}
|
||||
|
@ -876,6 +875,7 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
const float NEARBY_FLOOR_THRESHOLD = 5.0f;
|
||||
|
||||
void MyAvatar::updatePosition(float deltaTime) {
|
||||
PerformanceTimer perfTimer("MyAvatar::updatePosition");
|
||||
float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) +
|
||||
fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT]) +
|
||||
fabsf(_driveKeys[UP] - _driveKeys[DOWN]);
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "GlowEffect.h"
|
||||
#include "ProgramObject.h"
|
||||
|
@ -119,6 +121,8 @@ static void maybeRelease(QOpenGLFramebufferObject* fbo) {
|
|||
}
|
||||
|
||||
QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) {
|
||||
PerformanceTimer perfTimer("paintGL/glowEffect");
|
||||
|
||||
QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject();
|
||||
primaryFBO->release();
|
||||
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
|
||||
|
|
|
@ -65,6 +65,11 @@ ProgramObject Model::_shadowNormalMapProgram;
|
|||
ProgramObject Model::_shadowSpecularMapProgram;
|
||||
ProgramObject Model::_shadowNormalSpecularMapProgram;
|
||||
|
||||
ProgramObject Model::_cascadedShadowMapProgram;
|
||||
ProgramObject Model::_cascadedShadowNormalMapProgram;
|
||||
ProgramObject Model::_cascadedShadowSpecularMapProgram;
|
||||
ProgramObject Model::_cascadedShadowNormalSpecularMapProgram;
|
||||
|
||||
ProgramObject Model::_shadowProgram;
|
||||
|
||||
ProgramObject Model::_skinProgram;
|
||||
|
@ -77,13 +82,25 @@ ProgramObject Model::_skinShadowNormalMapProgram;
|
|||
ProgramObject Model::_skinShadowSpecularMapProgram;
|
||||
ProgramObject Model::_skinShadowNormalSpecularMapProgram;
|
||||
|
||||
ProgramObject Model::_skinCascadedShadowMapProgram;
|
||||
ProgramObject Model::_skinCascadedShadowNormalMapProgram;
|
||||
ProgramObject Model::_skinCascadedShadowSpecularMapProgram;
|
||||
ProgramObject Model::_skinCascadedShadowNormalSpecularMapProgram;
|
||||
|
||||
ProgramObject Model::_skinShadowProgram;
|
||||
|
||||
int Model::_normalMapTangentLocation;
|
||||
int Model::_normalSpecularMapTangentLocation;
|
||||
int Model::_shadowNormalMapTangentLocation;
|
||||
int Model::_shadowNormalSpecularMapTangentLocation;
|
||||
int Model::_cascadedShadowNormalMapTangentLocation;
|
||||
int Model::_cascadedShadowNormalSpecularMapTangentLocation;
|
||||
|
||||
int Model::_cascadedShadowMapDistancesLocation;
|
||||
int Model::_cascadedShadowNormalMapDistancesLocation;
|
||||
int Model::_cascadedShadowSpecularMapDistancesLocation;
|
||||
int Model::_cascadedShadowNormalSpecularMapDistancesLocation;
|
||||
|
||||
Model::SkinLocations Model::_skinLocations;
|
||||
Model::SkinLocations Model::_skinNormalMapLocations;
|
||||
Model::SkinLocations Model::_skinSpecularMapLocations;
|
||||
|
@ -92,6 +109,10 @@ Model::SkinLocations Model::_skinShadowMapLocations;
|
|||
Model::SkinLocations Model::_skinShadowNormalMapLocations;
|
||||
Model::SkinLocations Model::_skinShadowSpecularMapLocations;
|
||||
Model::SkinLocations Model::_skinShadowNormalSpecularMapLocations;
|
||||
Model::SkinLocations Model::_skinCascadedShadowMapLocations;
|
||||
Model::SkinLocations Model::_skinCascadedShadowNormalMapLocations;
|
||||
Model::SkinLocations Model::_skinCascadedShadowSpecularMapLocations;
|
||||
Model::SkinLocations Model::_skinCascadedShadowNormalSpecularMapLocations;
|
||||
Model::SkinLocations Model::_skinShadowLocations;
|
||||
|
||||
void Model::setScale(const glm::vec3& scale) {
|
||||
|
@ -128,6 +149,7 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati
|
|||
locations.clusterIndices = program.attributeLocation("clusterIndices");
|
||||
locations.clusterWeights = program.attributeLocation("clusterWeights");
|
||||
locations.tangent = program.attributeLocation("tangent");
|
||||
locations.shadowDistances = program.uniformLocation("shadowDistances");
|
||||
program.setUniformValue("diffuseMap", 0);
|
||||
program.setUniformValue("normalMap", 1);
|
||||
program.setUniformValue("specularMap", specularTextureUnit);
|
||||
|
@ -222,7 +244,7 @@ void Model::init() {
|
|||
_normalSpecularMapProgram.setUniformValue("diffuseMap", 0);
|
||||
_normalSpecularMapProgram.setUniformValue("normalMap", 1);
|
||||
_normalSpecularMapProgram.setUniformValue("specularMap", 2);
|
||||
_normalSpecularMapTangentLocation = _normalMapProgram.attributeLocation("tangent");
|
||||
_normalSpecularMapTangentLocation = _normalSpecularMapProgram.attributeLocation("tangent");
|
||||
_normalSpecularMapProgram.release();
|
||||
|
||||
|
||||
|
@ -272,10 +294,66 @@ void Model::init() {
|
|||
_shadowNormalSpecularMapProgram.setUniformValue("normalMap", 1);
|
||||
_shadowNormalSpecularMapProgram.setUniformValue("specularMap", 2);
|
||||
_shadowNormalSpecularMapProgram.setUniformValue("shadowMap", 3);
|
||||
_shadowNormalSpecularMapTangentLocation = _normalMapProgram.attributeLocation("tangent");
|
||||
_shadowNormalSpecularMapTangentLocation = _shadowNormalSpecularMapProgram.attributeLocation("tangent");
|
||||
_shadowNormalSpecularMapProgram.release();
|
||||
|
||||
|
||||
_cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
|
||||
"shaders/model.vert");
|
||||
_cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
|
||||
"shaders/model_cascaded_shadow_map.frag");
|
||||
_cascadedShadowMapProgram.link();
|
||||
|
||||
_cascadedShadowMapProgram.bind();
|
||||
_cascadedShadowMapProgram.setUniformValue("diffuseMap", 0);
|
||||
_cascadedShadowMapProgram.setUniformValue("shadowMap", 1);
|
||||
_cascadedShadowMapDistancesLocation = _cascadedShadowMapProgram.uniformLocation("shadowDistances");
|
||||
_cascadedShadowMapProgram.release();
|
||||
|
||||
_cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
|
||||
Application::resourcesPath() + "shaders/model_normal_map.vert");
|
||||
_cascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||
Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_map.frag");
|
||||
_cascadedShadowNormalMapProgram.link();
|
||||
|
||||
_cascadedShadowNormalMapProgram.bind();
|
||||
_cascadedShadowNormalMapProgram.setUniformValue("diffuseMap", 0);
|
||||
_cascadedShadowNormalMapProgram.setUniformValue("normalMap", 1);
|
||||
_cascadedShadowNormalMapProgram.setUniformValue("shadowMap", 2);
|
||||
_cascadedShadowNormalMapDistancesLocation = _cascadedShadowNormalMapProgram.uniformLocation("shadowDistances");
|
||||
_cascadedShadowNormalMapTangentLocation = _cascadedShadowNormalMapProgram.attributeLocation("tangent");
|
||||
_cascadedShadowNormalMapProgram.release();
|
||||
|
||||
_cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
|
||||
Application::resourcesPath() + "shaders/model.vert");
|
||||
_cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||
Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag");
|
||||
_cascadedShadowSpecularMapProgram.link();
|
||||
|
||||
_cascadedShadowSpecularMapProgram.bind();
|
||||
_cascadedShadowSpecularMapProgram.setUniformValue("diffuseMap", 0);
|
||||
_cascadedShadowSpecularMapProgram.setUniformValue("specularMap", 1);
|
||||
_cascadedShadowSpecularMapProgram.setUniformValue("shadowMap", 2);
|
||||
_cascadedShadowSpecularMapDistancesLocation = _cascadedShadowSpecularMapProgram.uniformLocation("shadowDistances");
|
||||
_cascadedShadowSpecularMapProgram.release();
|
||||
|
||||
_cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
|
||||
Application::resourcesPath() + "shaders/model_normal_map.vert");
|
||||
_cascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||
Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_specular_map.frag");
|
||||
_cascadedShadowNormalSpecularMapProgram.link();
|
||||
|
||||
_cascadedShadowNormalSpecularMapProgram.bind();
|
||||
_cascadedShadowNormalSpecularMapProgram.setUniformValue("diffuseMap", 0);
|
||||
_cascadedShadowNormalSpecularMapProgram.setUniformValue("normalMap", 1);
|
||||
_cascadedShadowNormalSpecularMapProgram.setUniformValue("specularMap", 2);
|
||||
_cascadedShadowNormalSpecularMapProgram.setUniformValue("shadowMap", 3);
|
||||
_cascadedShadowNormalSpecularMapDistancesLocation =
|
||||
_cascadedShadowNormalSpecularMapProgram.uniformLocation("shadowDistances");
|
||||
_cascadedShadowNormalSpecularMapTangentLocation = _cascadedShadowNormalSpecularMapProgram.attributeLocation("tangent");
|
||||
_cascadedShadowNormalSpecularMapProgram.release();
|
||||
|
||||
|
||||
_shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert");
|
||||
_shadowProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||
Application::resourcesPath() + "shaders/model_shadow.frag");
|
||||
|
@ -346,6 +424,39 @@ void Model::init() {
|
|||
initSkinProgram(_skinShadowNormalSpecularMapProgram, _skinShadowNormalSpecularMapLocations, 2, 3);
|
||||
|
||||
|
||||
_skinCascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
|
||||
"shaders/skin_model.vert");
|
||||
_skinCascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
|
||||
"shaders/model_cascaded_shadow_map.frag");
|
||||
_skinCascadedShadowMapProgram.link();
|
||||
|
||||
initSkinProgram(_skinCascadedShadowMapProgram, _skinCascadedShadowMapLocations);
|
||||
|
||||
_skinCascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
|
||||
Application::resourcesPath() + "shaders/skin_model_normal_map.vert");
|
||||
_skinCascadedShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||
Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_map.frag");
|
||||
_skinCascadedShadowNormalMapProgram.link();
|
||||
|
||||
initSkinProgram(_skinCascadedShadowNormalMapProgram, _skinCascadedShadowNormalMapLocations, 1, 2);
|
||||
|
||||
_skinCascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
|
||||
Application::resourcesPath() + "shaders/skin_model.vert");
|
||||
_skinCascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||
Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag");
|
||||
_skinCascadedShadowSpecularMapProgram.link();
|
||||
|
||||
initSkinProgram(_skinCascadedShadowSpecularMapProgram, _skinCascadedShadowSpecularMapLocations, 1, 2);
|
||||
|
||||
_skinCascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
|
||||
Application::resourcesPath() + "shaders/skin_model_normal_map.vert");
|
||||
_skinCascadedShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||
Application::resourcesPath() + "shaders/model_cascaded_shadow_normal_specular_map.frag");
|
||||
_skinCascadedShadowNormalSpecularMapProgram.link();
|
||||
|
||||
initSkinProgram(_skinCascadedShadowNormalSpecularMapProgram, _skinCascadedShadowNormalSpecularMapLocations, 2, 3);
|
||||
|
||||
|
||||
_skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex,
|
||||
Application::resourcesPath() + "shaders/skin_model_shadow.vert");
|
||||
_skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||
|
@ -501,7 +612,7 @@ bool Model::render(float alpha, RenderMode mode, bool receiveShadows) {
|
|||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.5f * alpha);
|
||||
|
||||
receiveShadows &= Menu::getInstance()->isOptionChecked(MenuOption::Shadows);
|
||||
receiveShadows &= Menu::getInstance()->getShadowsEnabled();
|
||||
renderMeshes(alpha, mode, false, receiveShadows);
|
||||
|
||||
glDisable(GL_ALPHA_TEST);
|
||||
|
@ -634,8 +745,16 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind)
|
|||
return false;
|
||||
}
|
||||
rotation = _jointStates[jointIndex]._combinedRotation *
|
||||
(fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation :
|
||||
_geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation);
|
||||
(fromBind ? _geometry->getFBXGeometry().joints[jointIndex].inverseBindRotation :
|
||||
_geometry->getFBXGeometry().joints[jointIndex].inverseDefaultRotation);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const {
|
||||
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
rotation = _jointStates[jointIndex]._combinedRotation;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1494,11 +1613,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re
|
|||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
||||
|
||||
if (receiveShadows) {
|
||||
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]);
|
||||
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]);
|
||||
glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[2]);
|
||||
}
|
||||
bool cascadedShadows = Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows);
|
||||
for (int i = 0; i < networkMeshes.size(); i++) {
|
||||
// exit early if the translucency doesn't match what we're drawing
|
||||
const NetworkMesh& networkMesh = networkMeshes.at(i);
|
||||
|
@ -1520,6 +1635,8 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re
|
|||
ProgramObject* program = &_program;
|
||||
ProgramObject* skinProgram = &_skinProgram;
|
||||
SkinLocations* skinLocations = &_skinLocations;
|
||||
int tangentLocation = _normalMapTangentLocation;
|
||||
int shadowDistancesLocation = _cascadedShadowMapDistancesLocation;
|
||||
GLenum specularTextureUnit = 0;
|
||||
GLenum shadowTextureUnit = 0;
|
||||
if (mode == SHADOW_RENDER_MODE) {
|
||||
|
@ -1530,21 +1647,40 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re
|
|||
} else if (!mesh.tangents.isEmpty()) {
|
||||
if (mesh.hasSpecularTexture()) {
|
||||
if (receiveShadows) {
|
||||
program = &_shadowNormalSpecularMapProgram;
|
||||
skinProgram = &_skinShadowNormalSpecularMapProgram;
|
||||
skinLocations = &_skinShadowNormalSpecularMapLocations;
|
||||
if (cascadedShadows) {
|
||||
program = &_cascadedShadowNormalSpecularMapProgram;
|
||||
skinProgram = &_skinCascadedShadowNormalSpecularMapProgram;
|
||||
skinLocations = &_skinCascadedShadowNormalSpecularMapLocations;
|
||||
tangentLocation = _cascadedShadowNormalSpecularMapTangentLocation;
|
||||
shadowDistancesLocation = _cascadedShadowNormalSpecularMapDistancesLocation;
|
||||
} else {
|
||||
program = &_shadowNormalSpecularMapProgram;
|
||||
skinProgram = &_skinShadowNormalSpecularMapProgram;
|
||||
skinLocations = &_skinShadowNormalSpecularMapLocations;
|
||||
tangentLocation = _shadowNormalSpecularMapTangentLocation;
|
||||
}
|
||||
shadowTextureUnit = GL_TEXTURE3;
|
||||
} else {
|
||||
program = &_normalSpecularMapProgram;
|
||||
skinProgram = &_skinNormalSpecularMapProgram;
|
||||
skinLocations = &_skinNormalSpecularMapLocations;
|
||||
tangentLocation = _normalSpecularMapTangentLocation;
|
||||
}
|
||||
specularTextureUnit = GL_TEXTURE2;
|
||||
|
||||
} else if (receiveShadows) {
|
||||
program = &_shadowNormalMapProgram;
|
||||
skinProgram = &_skinShadowNormalMapProgram;
|
||||
skinLocations = &_skinShadowNormalMapLocations;
|
||||
if (cascadedShadows) {
|
||||
program = &_cascadedShadowNormalMapProgram;
|
||||
skinProgram = &_skinCascadedShadowNormalMapProgram;
|
||||
skinLocations = &_skinCascadedShadowNormalMapLocations;
|
||||
tangentLocation = _cascadedShadowNormalMapTangentLocation;
|
||||
shadowDistancesLocation = _cascadedShadowNormalMapDistancesLocation;
|
||||
} else {
|
||||
program = &_shadowNormalMapProgram;
|
||||
skinProgram = &_skinShadowNormalMapProgram;
|
||||
skinLocations = &_skinShadowNormalMapLocations;
|
||||
tangentLocation = _shadowNormalMapTangentLocation;
|
||||
}
|
||||
shadowTextureUnit = GL_TEXTURE2;
|
||||
} else {
|
||||
program = &_normalMapProgram;
|
||||
|
@ -1553,9 +1689,16 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re
|
|||
}
|
||||
} else if (mesh.hasSpecularTexture()) {
|
||||
if (receiveShadows) {
|
||||
program = &_shadowSpecularMapProgram;
|
||||
skinProgram = &_skinShadowSpecularMapProgram;
|
||||
skinLocations = &_skinShadowSpecularMapLocations;
|
||||
if (cascadedShadows) {
|
||||
program = &_cascadedShadowSpecularMapProgram;
|
||||
skinProgram = &_skinCascadedShadowSpecularMapProgram;
|
||||
skinLocations = &_skinCascadedShadowSpecularMapLocations;
|
||||
shadowDistancesLocation = _cascadedShadowSpecularMapDistancesLocation;
|
||||
} else {
|
||||
program = &_shadowSpecularMapProgram;
|
||||
skinProgram = &_skinShadowSpecularMapProgram;
|
||||
skinLocations = &_skinShadowSpecularMapLocations;
|
||||
}
|
||||
shadowTextureUnit = GL_TEXTURE2;
|
||||
} else {
|
||||
program = &_specularMapProgram;
|
||||
|
@ -1565,15 +1708,20 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re
|
|||
specularTextureUnit = GL_TEXTURE1;
|
||||
|
||||
} else if (receiveShadows) {
|
||||
program = &_shadowMapProgram;
|
||||
skinProgram = &_skinShadowMapProgram;
|
||||
skinLocations = &_skinShadowMapLocations;
|
||||
if (cascadedShadows) {
|
||||
program = &_cascadedShadowMapProgram;
|
||||
skinProgram = &_skinCascadedShadowMapProgram;
|
||||
skinLocations = &_skinCascadedShadowMapLocations;
|
||||
} else {
|
||||
program = &_shadowMapProgram;
|
||||
skinProgram = &_skinShadowMapProgram;
|
||||
skinLocations = &_skinShadowMapLocations;
|
||||
}
|
||||
shadowTextureUnit = GL_TEXTURE1;
|
||||
}
|
||||
|
||||
const MeshState& state = _meshStates.at(i);
|
||||
ProgramObject* activeProgram = program;
|
||||
int tangentLocation = _normalMapTangentLocation;
|
||||
glPushMatrix();
|
||||
Application::getInstance()->loadTranslatedViewMatrix(_translation);
|
||||
|
||||
|
@ -1591,10 +1739,15 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re
|
|||
skinProgram->enableAttributeArray(skinLocations->clusterWeights);
|
||||
activeProgram = skinProgram;
|
||||
tangentLocation = skinLocations->tangent;
|
||||
|
||||
if (cascadedShadows) {
|
||||
program->setUniform(skinLocations->shadowDistances, Application::getInstance()->getShadowDistances());
|
||||
}
|
||||
} else {
|
||||
glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]);
|
||||
program->bind();
|
||||
if (cascadedShadows) {
|
||||
program->setUniform(shadowDistancesLocation, Application::getInstance()->getShadowDistances());
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
|
|
|
@ -144,6 +144,7 @@ public:
|
|||
|
||||
bool getJointPosition(int jointIndex, glm::vec3& position) const;
|
||||
bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const;
|
||||
bool getJointCombinedRotation(int jointIndex, glm::quat& rotation) const;
|
||||
|
||||
QStringList getJointNames() const;
|
||||
|
||||
|
@ -292,6 +293,11 @@ private:
|
|||
static ProgramObject _shadowSpecularMapProgram;
|
||||
static ProgramObject _shadowNormalSpecularMapProgram;
|
||||
|
||||
static ProgramObject _cascadedShadowMapProgram;
|
||||
static ProgramObject _cascadedShadowNormalMapProgram;
|
||||
static ProgramObject _cascadedShadowSpecularMapProgram;
|
||||
static ProgramObject _cascadedShadowNormalSpecularMapProgram;
|
||||
|
||||
static ProgramObject _shadowProgram;
|
||||
|
||||
static ProgramObject _skinProgram;
|
||||
|
@ -304,12 +310,24 @@ private:
|
|||
static ProgramObject _skinShadowSpecularMapProgram;
|
||||
static ProgramObject _skinShadowNormalSpecularMapProgram;
|
||||
|
||||
static ProgramObject _skinCascadedShadowMapProgram;
|
||||
static ProgramObject _skinCascadedShadowNormalMapProgram;
|
||||
static ProgramObject _skinCascadedShadowSpecularMapProgram;
|
||||
static ProgramObject _skinCascadedShadowNormalSpecularMapProgram;
|
||||
|
||||
static ProgramObject _skinShadowProgram;
|
||||
|
||||
static int _normalMapTangentLocation;
|
||||
static int _normalSpecularMapTangentLocation;
|
||||
static int _shadowNormalMapTangentLocation;
|
||||
static int _shadowNormalSpecularMapTangentLocation;
|
||||
static int _cascadedShadowNormalMapTangentLocation;
|
||||
static int _cascadedShadowNormalSpecularMapTangentLocation;
|
||||
|
||||
static int _cascadedShadowMapDistancesLocation;
|
||||
static int _cascadedShadowNormalMapDistancesLocation;
|
||||
static int _cascadedShadowSpecularMapDistancesLocation;
|
||||
static int _cascadedShadowNormalSpecularMapDistancesLocation;
|
||||
|
||||
class SkinLocations {
|
||||
public:
|
||||
|
@ -317,6 +335,7 @@ private:
|
|||
int clusterIndices;
|
||||
int clusterWeights;
|
||||
int tangent;
|
||||
int shadowDistances;
|
||||
};
|
||||
|
||||
static SkinLocations _skinLocations;
|
||||
|
@ -327,6 +346,10 @@ private:
|
|||
static SkinLocations _skinShadowNormalMapLocations;
|
||||
static SkinLocations _skinShadowSpecularMapLocations;
|
||||
static SkinLocations _skinShadowNormalSpecularMapLocations;
|
||||
static SkinLocations _skinCascadedShadowMapLocations;
|
||||
static SkinLocations _skinCascadedShadowNormalMapLocations;
|
||||
static SkinLocations _skinCascadedShadowSpecularMapLocations;
|
||||
static SkinLocations _skinCascadedShadowNormalSpecularMapLocations;
|
||||
static SkinLocations _skinShadowLocations;
|
||||
|
||||
static void initSkinProgram(ProgramObject& program, SkinLocations& locations,
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
||||
#include "Stats.h"
|
||||
#include "InterfaceConfig.h"
|
||||
#include "Menu.h"
|
||||
|
@ -158,6 +160,39 @@ void Stats::drawBackground(unsigned int rgba, int x, int y, int width, int heigh
|
|||
glColor4f(1, 1, 1, 1);
|
||||
}
|
||||
|
||||
bool Stats::includeTimingRecord(const QString& name) {
|
||||
bool included = false;
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
|
||||
if (name == "idle/update") {
|
||||
included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandUpdateTiming) ||
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming);
|
||||
} else if (name == "idle/updateGL") {
|
||||
included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming);
|
||||
} else if (name.startsWith("idle/update")) {
|
||||
included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandUpdateTiming);
|
||||
} else if (name.startsWith("idle/")) {
|
||||
included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandIdleTiming);
|
||||
} else if (name.startsWith("MyAvatar::simulate")) {
|
||||
included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandAvatarSimulateTiming);
|
||||
} else if (name.startsWith("MyAvatar::update/") || name.startsWith("updateMyAvatar")) {
|
||||
included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandAvatarUpdateTiming);
|
||||
} else if (name.startsWith("MyAvatar::")) {
|
||||
included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandMiscAvatarTiming);
|
||||
} else if (name == "paintGL/displaySide") {
|
||||
included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandDisplaySideTiming) ||
|
||||
Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
||||
} else if (name.startsWith("paintGL/displaySide/")) {
|
||||
included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandDisplaySideTiming);
|
||||
} else if (name.startsWith("paintGL/")) {
|
||||
included = Menu::getInstance()->isOptionChecked(MenuOption::ExpandPaintGLTiming);
|
||||
} else {
|
||||
included = true; // include everything else
|
||||
}
|
||||
}
|
||||
return included;
|
||||
}
|
||||
|
||||
// display expanded or contracted stats
|
||||
void Stats::display(
|
||||
const float* color,
|
||||
|
@ -345,11 +380,25 @@ void Stats::display(
|
|||
|
||||
VoxelSystem* voxels = Application::getInstance()->getVoxels();
|
||||
|
||||
lines = _expanded ? 12 : 3;
|
||||
lines = _expanded ? 11 : 3;
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) {
|
||||
lines += 9; // spatial audio processing adds 1 spacing line and 8 extra lines of info
|
||||
}
|
||||
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
// we will also include room for 1 line per timing record and a header
|
||||
lines += 1;
|
||||
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
lines++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10);
|
||||
horizontalOffset += 5;
|
||||
|
||||
|
@ -454,8 +503,6 @@ void Stats::display(
|
|||
}
|
||||
}
|
||||
|
||||
verticalOffset += (_expanded ? STATS_PELS_PER_LINE : 0);
|
||||
|
||||
QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' ');
|
||||
|
||||
// Server Voxels
|
||||
|
@ -508,6 +555,29 @@ void Stats::display(
|
|||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)voxelStats.str().c_str(), color);
|
||||
}
|
||||
|
||||
// TODO: the display of these timing details should all be moved to JavaScript
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::DisplayTimingDetails)) {
|
||||
// Timing details...
|
||||
const int TIMER_OUTPUT_LINE_LENGTH = 300;
|
||||
char perfLine[TIMER_OUTPUT_LINE_LENGTH];
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font,
|
||||
"--------------------- Function -------------------- --msecs- -calls--", color);
|
||||
|
||||
const QMap<QString, PerformanceTimerRecord>& allRecords = PerformanceTimer::getAllTimerRecords();
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(allRecords);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
if (includeTimingRecord(i.key())) {
|
||||
sprintf(perfLine, "%50s: %8.4f [%6llu]", qPrintable(i.key()),
|
||||
(float)i.value().getMovingAverage() / (float)USECS_PER_MSEC,
|
||||
i.value().getCount());
|
||||
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, perfLine, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_expanded && Menu::getInstance()->isOptionChecked(MenuOption::AudioSpatialProcessing)) {
|
||||
verticalOffset += STATS_PELS_PER_LINE; // space one line...
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
void checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseDragStartedY, int horizontalOffset);
|
||||
void resetWidth(int width, int horizontalOffset);
|
||||
void display(const float* color, int horizontalOffset, float fps, int packetsPerSecond, int bytesPerSecond, int voxelPacketsToProcess);
|
||||
bool includeTimingRecord(const QString& name);
|
||||
private:
|
||||
static Stats* _sharedInstance;
|
||||
|
||||
|
|
|
@ -519,6 +519,17 @@ void VoxelSystem::initVoxelMemory() {
|
|||
_shadowMapProgram.bind();
|
||||
_shadowMapProgram.setUniformValue("shadowMap", 0);
|
||||
_shadowMapProgram.release();
|
||||
|
||||
_cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
|
||||
Application::resourcesPath() + "shaders/cascaded_shadow_map.vert");
|
||||
_cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
|
||||
Application::resourcesPath() + "shaders/cascaded_shadow_map.frag");
|
||||
_cascadedShadowMapProgram.link();
|
||||
|
||||
_cascadedShadowMapProgram.bind();
|
||||
_cascadedShadowMapProgram.setUniformValue("shadowMap", 0);
|
||||
_shadowDistancesLocation = _cascadedShadowMapProgram.uniformLocation("shadowDistances");
|
||||
_cascadedShadowMapProgram.release();
|
||||
}
|
||||
}
|
||||
_renderer = new PrimitiveRenderer(_maxVoxels);
|
||||
|
@ -1166,6 +1177,8 @@ glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float vo
|
|||
|
||||
ProgramObject VoxelSystem::_perlinModulateProgram;
|
||||
ProgramObject VoxelSystem::_shadowMapProgram;
|
||||
ProgramObject VoxelSystem::_cascadedShadowMapProgram;
|
||||
int VoxelSystem::_shadowDistancesLocation;
|
||||
|
||||
void VoxelSystem::init() {
|
||||
if (_initialized) {
|
||||
|
@ -1486,14 +1499,15 @@ void VoxelSystem::render() {
|
|||
|
||||
void VoxelSystem::applyScaleAndBindProgram(bool texture) {
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
||||
_shadowMapProgram.bind();
|
||||
if (Menu::getInstance()->getShadowsEnabled()) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
|
||||
_cascadedShadowMapProgram.bind();
|
||||
_cascadedShadowMapProgram.setUniform(_shadowDistancesLocation, Application::getInstance()->getShadowDistances());
|
||||
} else {
|
||||
_shadowMapProgram.bind();
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID());
|
||||
|
||||
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]);
|
||||
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]);
|
||||
glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[2]);
|
||||
|
||||
} else if (texture) {
|
||||
_perlinModulateProgram.bind();
|
||||
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID());
|
||||
|
@ -1507,11 +1521,14 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {
|
|||
// scale back down to 1 so heads aren't massive
|
||||
glPopMatrix();
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
|
||||
_shadowMapProgram.release();
|
||||
if (Menu::getInstance()->getShadowsEnabled()) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
|
||||
_cascadedShadowMapProgram.release();
|
||||
} else {
|
||||
_shadowMapProgram.release();
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
|
||||
} else if (texture) {
|
||||
_perlinModulateProgram.release();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
|
|
@ -233,6 +233,8 @@ private:
|
|||
|
||||
static ProgramObject _perlinModulateProgram;
|
||||
static ProgramObject _shadowMapProgram;
|
||||
static ProgramObject _cascadedShadowMapProgram;
|
||||
static int _shadowDistancesLocation;
|
||||
|
||||
int _hookID;
|
||||
std::vector<glBufferIndex> _freeIndexes;
|
||||
|
|
|
@ -88,6 +88,7 @@ void AudioInjector::injectAudio() {
|
|||
int currentSendPosition = 0;
|
||||
|
||||
int numPreAudioDataBytes = injectAudioPacket.size();
|
||||
bool shouldLoop = _options.getLoop();
|
||||
|
||||
// loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks
|
||||
while (currentSendPosition < soundByteArray.size() && !_shouldStop) {
|
||||
|
@ -120,6 +121,10 @@ void AudioInjector::injectAudio() {
|
|||
usleep(usecToSleep);
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldLoop && currentSendPosition == soundByteArray.size()) {
|
||||
currentSendPosition = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ AudioInjectorOptions::AudioInjectorOptions(QObject* parent) :
|
|||
QObject(parent),
|
||||
_position(0.0f, 0.0f, 0.0f),
|
||||
_volume(1.0f),
|
||||
_loop(false),
|
||||
_orientation(glm::vec3(0.0f, 0.0f, 0.0f)),
|
||||
_loopbackAudioInterface(NULL)
|
||||
{
|
||||
|
@ -24,6 +25,7 @@ AudioInjectorOptions::AudioInjectorOptions(QObject* parent) :
|
|||
AudioInjectorOptions::AudioInjectorOptions(const AudioInjectorOptions& other) {
|
||||
_position = other._position;
|
||||
_volume = other._volume;
|
||||
_loop = other._loop;
|
||||
_orientation = other._orientation;
|
||||
_loopbackAudioInterface = other._loopbackAudioInterface;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ class AudioInjectorOptions : public QObject {
|
|||
|
||||
Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition)
|
||||
Q_PROPERTY(float volume READ getVolume WRITE setVolume)
|
||||
Q_PROPERTY(bool loop READ getLoop WRITE setLoop)
|
||||
public:
|
||||
AudioInjectorOptions(QObject* parent = 0);
|
||||
AudioInjectorOptions(const AudioInjectorOptions& other);
|
||||
|
@ -36,6 +37,9 @@ public:
|
|||
float getVolume() const { return _volume; }
|
||||
void setVolume(float volume) { _volume = volume; }
|
||||
|
||||
float getLoop() const { return _loop; }
|
||||
void setLoop(float loop) { _loop = loop; }
|
||||
|
||||
const glm::quat& getOrientation() const { return _orientation; }
|
||||
void setOrientation(const glm::quat& orientation) { _orientation = orientation; }
|
||||
|
||||
|
@ -45,6 +49,7 @@ public:
|
|||
private:
|
||||
glm::vec3 _position;
|
||||
float _volume;
|
||||
bool _loop;
|
||||
glm::quat _orientation;
|
||||
AbstractAudioInterface* _loopbackAudioInterface;
|
||||
};
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
// degrees
|
||||
const float MIN_HEAD_YAW = -110.f;
|
||||
const float MAX_HEAD_YAW = 110.f;
|
||||
const float MIN_HEAD_YAW = -180.f;
|
||||
const float MAX_HEAD_YAW = 180.f;
|
||||
const float MIN_HEAD_PITCH = -60.f;
|
||||
const float MAX_HEAD_PITCH = 60.f;
|
||||
const float MIN_HEAD_ROLL = -50.f;
|
||||
|
|
|
@ -1308,11 +1308,6 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3
|
|||
|
||||
keepSearching = true; // assume that we will continue searching after this.
|
||||
|
||||
// by default, we only allow intersections with leaves with content
|
||||
if (!canRayIntersect()) {
|
||||
return false; // we don't intersect with non-leaves, and we keep searching
|
||||
}
|
||||
|
||||
AACube cube = getAACube();
|
||||
float localDistance;
|
||||
BoxFace localFace;
|
||||
|
@ -1323,6 +1318,11 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3
|
|||
return false; // we did not intersect
|
||||
}
|
||||
|
||||
// by default, we only allow intersections with leaves with content
|
||||
if (!canRayIntersect()) {
|
||||
return false; // we don't intersect with non-leaves, and we keep searching
|
||||
}
|
||||
|
||||
// we did hit this element, so calculate appropriate distances
|
||||
localDistance *= TREE_SCALE;
|
||||
if (localDistance < distance) {
|
||||
|
@ -1346,6 +1346,7 @@ bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const g
|
|||
if (intersectedObject) {
|
||||
*intersectedObject = this;
|
||||
}
|
||||
keepSearching = false;
|
||||
return true; // we did intersect
|
||||
}
|
||||
return false; // we did not intersect
|
||||
|
|
|
@ -52,4 +52,22 @@ PerformanceWarning::~PerformanceWarning() {
|
|||
}
|
||||
};
|
||||
|
||||
QMap<QString, PerformanceTimerRecord> PerformanceTimer::_records;
|
||||
|
||||
|
||||
PerformanceTimer::~PerformanceTimer() {
|
||||
quint64 end = usecTimestampNow();
|
||||
quint64 elapsedusec = (end - _start);
|
||||
PerformanceTimerRecord& namedRecord = _records[_name];
|
||||
namedRecord.recordResult(elapsedusec);
|
||||
}
|
||||
|
||||
void PerformanceTimer::dumpAllTimerRecords() {
|
||||
QMapIterator<QString, PerformanceTimerRecord> i(_records);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
qDebug() << i.key() << ": average " << i.value().getAverage()
|
||||
<< " [" << i.value().getMovingAverage() << "]"
|
||||
<< "usecs over" << i.value().getCount() << "calls";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include "SharedUtil.h"
|
||||
#include "SimpleMovingAverage.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
@ -49,5 +50,41 @@ public:
|
|||
static void setSuppressShortTimings(bool suppressShortTimings) { _suppressShortTimings = suppressShortTimings; }
|
||||
};
|
||||
|
||||
class PerformanceTimerRecord {
|
||||
public:
|
||||
PerformanceTimerRecord() : _runningTotal(0), _totalCalls(0) {}
|
||||
|
||||
void recordResult(quint64 elapsed) { _runningTotal += elapsed; _totalCalls++; _movingAverage.updateAverage(elapsed); }
|
||||
quint64 getAverage() const { return (_totalCalls == 0) ? 0 : _runningTotal / _totalCalls; }
|
||||
quint64 getMovingAverage() const { return (_totalCalls == 0) ? 0 : _movingAverage.getAverage(); }
|
||||
quint64 getCount() const { return _totalCalls; }
|
||||
|
||||
private:
|
||||
quint64 _runningTotal;
|
||||
quint64 _totalCalls;
|
||||
SimpleMovingAverage _movingAverage;
|
||||
};
|
||||
|
||||
class PerformanceTimer {
|
||||
public:
|
||||
|
||||
PerformanceTimer(const QString& name) :
|
||||
_start(usecTimestampNow()),
|
||||
_name(name) { }
|
||||
|
||||
quint64 elapsed() const { return (usecTimestampNow() - _start); };
|
||||
|
||||
~PerformanceTimer();
|
||||
|
||||
static const PerformanceTimerRecord& getTimerRecord(const QString& name) { return _records[name]; };
|
||||
static const QMap<QString, PerformanceTimerRecord>& getAllTimerRecords() { return _records; };
|
||||
static void dumpAllTimerRecords();
|
||||
|
||||
private:
|
||||
quint64 _start;
|
||||
QString _name;
|
||||
static QMap<QString, PerformanceTimerRecord> _records;
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_PerfStat_h
|
||||
|
|
Loading…
Reference in a new issue