Merge pull request #3463 from ey6es/deference

Break deferred lighting business out into its own class, use deferred lighting for voxels/avatars/entities/particles in addition to metavoxels.  Don't merge until after conference, obviously.
This commit is contained in:
AndrewMeadows 2014-09-22 10:42:25 -07:00
commit 3d89aa9c9c
68 changed files with 1277 additions and 1649 deletions

View file

@ -14,6 +14,9 @@
// the depth texture // the depth texture
uniform sampler2D depthTexture; uniform sampler2D depthTexture;
// the normal texture
uniform sampler2D normalTexture;
// the random rotation texture // the random rotation texture
uniform sampler2D rotationTexture; uniform sampler2D rotationTexture;
@ -57,9 +60,10 @@ vec3 texCoordToViewSpace(vec2 texCoord) {
} }
void main(void) { void main(void) {
vec3 rotationX = texture2D(rotationTexture, gl_TexCoord[0].st * noiseScale).rgb; vec3 rotationZ = texture2D(normalTexture, gl_TexCoord[0].st).xyz * 2.0 - vec3(1.0, 1.0, 1.0);
vec3 rotationY = normalize(cross(rotationX, vec3(0.0, 0.0, 1.0))); vec3 rotationY = normalize(cross(rotationZ, texture2D(rotationTexture,
mat3 rotation = mat3(rotationX, rotationY, cross(rotationX, rotationY)); gl_TexCoord[0].st * noiseScale).xyz - vec3(0.5, 0.5, 0.5)));
mat3 rotation = mat3(cross(rotationY, rotationZ), rotationY, rotationZ);
vec3 center = texCoordToViewSpace(gl_TexCoord[0].st); vec3 center = texCoordToViewSpace(gl_TexCoord[0].st);

View file

@ -1,40 +0,0 @@
#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));
}

View file

@ -1,33 +0,0 @@
#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();
}

View file

@ -0,0 +1,17 @@
#version 120
//
// deferred_light.vert
// vertex shader
//
// Created by Andrzej Kapolka on 9/18/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
//
void main(void) {
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_Vertex;
}

View file

@ -0,0 +1,60 @@
#version 120
//
// deferred_light_limited.vert
// vertex shader
//
// Created by Andrzej Kapolka on 9/19/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 radius (hard cutoff) of the light effect
uniform float radius;
void main(void) {
// find the right "right" direction
vec3 firstRightCandidate = cross(gl_LightSource[1].spotDirection, vec3(0.0, 1.0, 0.0));
vec3 secondRightCandidate = cross(gl_LightSource[1].spotDirection, vec3(1.0, 0.0, 0.0));
vec3 right = mix(firstRightCandidate, secondRightCandidate, step(length(firstRightCandidate), length(secondRightCandidate)));
right = normalize(right);
// and the "up"
vec3 up = cross(right, gl_LightSource[1].spotDirection);
// and the "back," which depends on whether this is a spot light
vec3 back = -gl_LightSource[1].spotDirection * step(gl_LightSource[1].spotCosCutoff, 0.0);
// find the eight corners of the bounds
vec4 c0 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (-up - right + back), 1.0);
vec4 c1 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (-up + right + back), 1.0);
vec4 c2 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (up - right + back), 1.0);
vec4 c3 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (up + right + back), 1.0);
vec4 c4 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (-up - right + gl_LightSource[1].spotDirection), 1.0);
vec4 c5 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (-up + right + gl_LightSource[1].spotDirection), 1.0);
vec4 c6 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (up - right + gl_LightSource[1].spotDirection), 1.0);
vec4 c7 = gl_ProjectionMatrix * vec4(gl_LightSource[1].position.xyz +
radius * (up + right + gl_LightSource[1].spotDirection), 1.0);
// find their projected extents
vec2 extents = max(
max(max(gl_Vertex.xy * (c0.xy / max(c0.w, 0.001)), gl_Vertex.xy * (c1.xy / max(c1.w, 0.001))),
max(gl_Vertex.xy * (c2.xy / max(c2.w, 0.001)), gl_Vertex.xy * (c3.xy / max(c3.w, 0.001)))),
max(max(gl_Vertex.xy * (c4.xy / max(c4.w, 0.001)), gl_Vertex.xy * (c5.xy / max(c5.w, 0.001))),
max(gl_Vertex.xy * (c6.xy / max(c6.w, 0.001)), gl_Vertex.xy * (c7.xy / max(c7.w, 0.001)))));
// make sure they don't extend beyond the screen
extents = min(extents, vec2(1.0, 1.0));
gl_Position = vec4(gl_Vertex.xy * extents, 0.0, 1.0);
gl_TexCoord[0] = vec4(dot(gl_Position, gl_ObjectPlaneS[3]), dot(gl_Position, gl_ObjectPlaneT[3]), 0.0, 1.0);
}

View file

@ -17,10 +17,44 @@ uniform sampler2D diffuseMap;
// the normal texture // the normal texture
uniform sampler2D normalMap; uniform sampler2D normalMap;
// the specular texture
uniform sampler2D specularMap;
// the depth texture
uniform sampler2D depthMap;
// the distance to the near clip plane
uniform float near;
// scale factor for depth: (far - near) / far
uniform float depthScale;
// offset for depth texture coordinates
uniform vec2 depthTexCoordOffset;
// scale for depth texture coordinates
uniform vec2 depthTexCoordScale;
void main(void) { void main(void) {
// compute the base color based on OpenGL lighting model // compute the view space position using the depth
float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0);
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 0.0);
// get the normal from the map
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st); vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
gl_FragColor = vec4((texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor + vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * max(0.0, dot(normal * 2.0 -
vec4(1.0, 1.0, 1.0, 2.0), gl_LightSource[0].position)))).rgb, normal.a); // compute the base color based on OpenGL lighting model
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
float facingLight = step(0.0, diffuse);
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor +
gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
// compute the specular multiplier (sans exponent)
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(position)),
normalizedNormal));
// add specular contribution
vec4 specularColor = texture2D(specularMap, gl_TexCoord[0].st);
gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normal.a);
} }

View file

@ -17,6 +17,9 @@ uniform sampler2D diffuseMap;
// the normal texture // the normal texture
uniform sampler2D normalMap; uniform sampler2D normalMap;
// the specular texture
uniform sampler2D specularMap;
// the depth texture // the depth texture
uniform sampler2D depthMap; uniform sampler2D depthMap;
@ -51,15 +54,27 @@ void main(void) {
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position),
dot(gl_EyePlaneR[shadowIndex], position)); dot(gl_EyePlaneR[shadowIndex], position));
// compute the color based on OpenGL lighting model, use the alpha from the normal map // get the normal from the map
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st); vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
float diffuse = dot(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0), gl_LightSource[0].position); vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
// average values from the shadow map
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
float facingLight = step(0.0, diffuse) * 0.25 * 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 +
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);
// compute the base color based on OpenGL lighting model
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor + vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor +
gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
gl_FragColor = vec4(baseColor.rgb, normal.a);
// compute the specular multiplier (sans exponent)
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))),
normalizedNormal));
// add specular contribution
vec4 specularColor = texture2D(specularMap, gl_TexCoord[0].st);
gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normal.a);
} }

View file

@ -17,6 +17,9 @@ uniform sampler2D diffuseMap;
// the normal texture // the normal texture
uniform sampler2D normalMap; uniform sampler2D normalMap;
// the specular texture
uniform sampler2D specularMap;
// the depth texture // the depth texture
uniform sampler2D depthMap; uniform sampler2D depthMap;
@ -46,15 +49,27 @@ void main(void) {
// compute the corresponding texture coordinates // compute the corresponding texture coordinates
vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position)); vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position));
// compute the color based on OpenGL lighting model, use the alpha from the normal map // get the normal from the map
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st); vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
float diffuse = dot(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0), gl_LightSource[0].position); vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
// average values from the shadow map
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
float facingLight = step(0.0, diffuse) * 0.25 * 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 +
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);
// compute the base color based on OpenGL lighting model
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor + vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightModelProduct.sceneColor +
gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight));
gl_FragColor = vec4(baseColor.rgb, normal.a);
// compute the specular multiplier (sans exponent)
float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))),
normalizedNormal));
// add specular contribution
vec4 specularColor = texture2D(specularMap, gl_TexCoord[0].st);
gl_FragColor = vec4(baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb, normal.a);
} }

View file

@ -11,43 +11,19 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
// the maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// the diffuse texture // the diffuse texture
uniform sampler2D diffuseMap; uniform sampler2D diffuseMap;
// the interpolated position // the alpha threshold
varying vec4 position; uniform float alphaThreshold;
// the interpolated normal // the interpolated normal
varying vec4 normal; varying vec4 normal;
void main(void) { void main(void) {
// add up the local lights // set the diffuse, normal, specular data
vec4 normalizedNormal = normalize(normal); vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0); gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) { gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
localLight += localLightColors[i] * max(0.0, dot(normalizedNormal, localLightDirections[i])); gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0);
}
// compute the base color based on OpenGL lighting model
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
float facingLight = step(0.0, diffuse);
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight) + localLight);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * texture2D(diffuseMap, gl_TexCoord[0].st) +
vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0);
} }

View file

@ -11,31 +11,19 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
const int MAX_LOCAL_LIGHTS = 4;
// the interpolated position
varying vec4 position;
// the interpolated normal // the interpolated normal
varying vec4 normal; varying vec4 normal;
void main(void) { void main(void) {
// transform and store the normal for interpolation // transform and store the normal for interpolation
normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
// likewise with the position // pass along the diffuse color
position = gl_ModelViewMatrix * gl_Vertex; gl_FrontColor = gl_Color * gl_FrontMaterial.diffuse;
// pass along the vertex color
gl_FrontColor = gl_Color;
// and the texture coordinates // and the texture coordinates
gl_TexCoord[0] = gl_MultiTexCoord0; gl_TexCoord[0] = gl_MultiTexCoord0;
// and the shadow texture coordinates
gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0);
// use standard pipeline transform // use standard pipeline transform
gl_Position = ftransform(); gl_Position = ftransform();
} }

View file

@ -1,71 +0,0 @@
#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 maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// 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));
// add up the local lights
vec4 normalizedNormal = normalize(normal);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
localLight += localLightColors[i] * max(0.0, dot(normalizedNormal, localLightDirections[i]));
}
// compute the base color based on OpenGL lighting model
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) + localLight);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * texture2D(diffuseMap, gl_TexCoord[0].st) +
vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0);
}

View file

@ -1,84 +0,0 @@
#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 maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// 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));
// add up the local lights
vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
localLight += localLightColors[i] * max(0.0, dot(viewNormal, localLightDirections[i]));
}
// compute the base color based on OpenGL lighting model
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) + localLight);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * texture2D(diffuseMap, gl_TexCoord[0].st) +
vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0);
}

View file

@ -1,88 +0,0 @@
#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 maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// 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));
// add up the local lights
vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
localLight += localLightColors[i] * max(0.0, dot(viewNormal, localLightDirections[i]));
}
// compute the base color based on OpenGL lighting model
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) + localLight);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * 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);
}

View file

@ -1,75 +0,0 @@
#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 maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// 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));
// add up the local lights
vec4 normalizedNormal = normalize(normal);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
localLight += localLightColors[i] * max(0.0, dot(normalizedNormal, localLightDirections[i]));
}
// compute the base color based on OpenGL lighting model
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) + localLight);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * 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);
}

View file

@ -11,23 +11,14 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
// the maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// the diffuse texture // the diffuse texture
uniform sampler2D diffuseMap; uniform sampler2D diffuseMap;
// the normal map texture // the normal map texture
uniform sampler2D normalMap; uniform sampler2D normalMap;
// the interpolated position // the alpha threshold
varying vec4 interpolatedPosition; uniform float alphaThreshold;
// the interpolated normal // the interpolated normal
varying vec4 interpolatedNormal; varying vec4 interpolatedNormal;
@ -36,30 +27,17 @@ varying vec4 interpolatedNormal;
varying vec4 interpolatedTangent; varying vec4 interpolatedTangent;
void main(void) { void main(void) {
// compute the view normal from the various bits
vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); vec3 normalizedNormal = normalize(vec3(interpolatedNormal));
vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); vec3 normalizedTangent = normalize(vec3(interpolatedTangent));
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0); vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) - vec3(0.5, 0.5, 0.5);
// add up the local lights
vec4 viewNormal = vec4(normalizedTangent * localNormal.x + vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
localLight += localLightColors[i] * max(0.0, dot(viewNormal, localLightDirections[i]));
}
// compute the base color based on OpenGL lighting model // set the diffuse, normal, specular data
float diffuse = dot(viewNormal, gl_LightSource[0].position); vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
float facingLight = step(0.0, diffuse); gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + gl_FragData[1] = viewNormal + vec4(0.5, 0.5, 0.5, 1.0);
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight) + localLight); gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * texture2D(diffuseMap, gl_TexCoord[0].st) +
vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0);
} }

View file

@ -14,9 +14,6 @@
// the tangent vector // the tangent vector
attribute vec3 tangent; attribute vec3 tangent;
// the interpolated position
varying vec4 interpolatedPosition;
// the interpolated normal // the interpolated normal
varying vec4 interpolatedNormal; varying vec4 interpolatedNormal;
@ -24,22 +21,16 @@ varying vec4 interpolatedNormal;
varying vec4 interpolatedTangent; varying vec4 interpolatedTangent;
void main(void) { void main(void) {
// transform and store the normal and tangent for interpolation
// transform and store the position, normal and tangent for interpolation
interpolatedPosition = gl_ModelViewMatrix * gl_Vertex;
interpolatedNormal = gl_ModelViewMatrix * vec4(gl_Normal, 0.0); interpolatedNormal = gl_ModelViewMatrix * vec4(gl_Normal, 0.0);
interpolatedTangent = gl_ModelViewMatrix * vec4(tangent, 0.0); interpolatedTangent = gl_ModelViewMatrix * vec4(tangent, 0.0);
// pass along the vertex color // pass along the diffuse color
gl_FrontColor = gl_Color; gl_FrontColor = gl_Color * gl_FrontMaterial.diffuse;
// and the texture coordinates // and the texture coordinates
gl_TexCoord[0] = gl_MultiTexCoord0; gl_TexCoord[0] = gl_MultiTexCoord0;
// and the shadow texture coordinates
gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], interpolatedPosition), dot(gl_EyePlaneT[0], interpolatedPosition),
dot(gl_EyePlaneR[0], interpolatedPosition), 1.0);
// use standard pipeline transform // use standard pipeline transform
gl_Position = ftransform(); gl_Position = ftransform();
} }

View file

@ -11,15 +11,6 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
// the maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// the diffuse texture // the diffuse texture
uniform sampler2D diffuseMap; uniform sampler2D diffuseMap;
@ -29,8 +20,8 @@ uniform sampler2D normalMap;
// the specular map texture // the specular map texture
uniform sampler2D specularMap; uniform sampler2D specularMap;
// the interpolated position // the alpha threshold
varying vec4 interpolatedPosition; uniform float alphaThreshold;
// the interpolated normal // the interpolated normal
varying vec4 interpolatedNormal; varying vec4 interpolatedNormal;
@ -39,31 +30,18 @@ varying vec4 interpolatedNormal;
varying vec4 interpolatedTangent; varying vec4 interpolatedTangent;
void main(void) { void main(void) {
// compute the view normal from the various bits
vec3 normalizedNormal = normalize(vec3(interpolatedNormal)); vec3 normalizedNormal = normalize(vec3(interpolatedNormal));
vec3 normalizedTangent = normalize(vec3(interpolatedTangent)); vec3 normalizedTangent = normalize(vec3(interpolatedTangent));
vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent)); vec3 normalizedBitangent = normalize(cross(normalizedNormal, normalizedTangent));
vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) * 2.0 - vec3(1.0, 1.0, 1.0); vec3 localNormal = vec3(texture2D(normalMap, gl_TexCoord[0].st)) - vec3(0.5, 0.5, 0.5);
// add up the local lights
vec4 viewNormal = vec4(normalizedTangent * localNormal.x + vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
localLight += localLightColors[i] * max(0.0, dot(viewNormal, localLightDirections[i]));
}
// compute the base color based on OpenGL lighting model // set the diffuse, normal, specular data
float diffuse = dot(viewNormal, gl_LightSource[0].position); vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
float facingLight = step(0.0, diffuse); gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + gl_FragData[1] = viewNormal + vec4(0.5, 0.5, 0.5, 1.0);
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight) + localLight); gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb,
gl_FrontMaterial.shininess / 128.0);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * 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);
} }

View file

@ -13,5 +13,5 @@
void main(void) { void main(void) {
// fixed color for now (we may eventually want to use texture alpha) // fixed color for now (we may eventually want to use texture alpha)
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); gl_FragColor = vec4(1.0, 1.0, 1.0, 0.0);
} }

View file

@ -1,63 +0,0 @@
#version 120
//
// model_shadow_map.frag
// fragment shader
//
// Created by Andrzej Kapolka on 5/23/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 maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// the diffuse texture
uniform sampler2D diffuseMap;
// the shadow texture
uniform sampler2DShadow shadowMap;
// 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) {
// add up the local lights
vec4 normalizedNormal = normalize(normal);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
localLight += localLightColors[i] * max(0.0, dot(normalizedNormal, localLightDirections[i]));
}
// compute the base color based on OpenGL lighting model
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) + localLight);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * texture2D(diffuseMap, gl_TexCoord[0].st) +
vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0);
}

View file

@ -1,75 +0,0 @@
#version 120
//
// model_shadow_normal_map.frag
// fragment shader
//
// Created by Andrzej Kapolka on 5/23/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 maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// the diffuse texture
uniform sampler2D diffuseMap;
// the normal map texture
uniform sampler2D normalMap;
// the shadow texture
uniform sampler2DShadow shadowMap;
// 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);
// add up the local lights
vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
localLight += localLightColors[i] * max(0.0, dot(viewNormal, localLightDirections[i]));
}
// compute the base color based on OpenGL lighting model
float diffuse = dot(viewNormal, 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) + localLight);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * texture2D(diffuseMap, gl_TexCoord[0].st) +
vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0);
}

View file

@ -1,79 +0,0 @@
#version 120
//
// model_shadow_normal_specular_map.frag
// fragment shader
//
// Created by Andrzej Kapolka on 5/23/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 maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// 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 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);
// add up the local lights
vec4 viewNormal = vec4(normalizedTangent * localNormal.x +
normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
localLight += localLightColors[i] * max(0.0, dot(viewNormal, localLightDirections[i]));
}
// compute the base color based on OpenGL lighting model
float diffuse = dot(viewNormal, 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) + localLight);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * 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);
}

View file

@ -1,67 +0,0 @@
#version 120
//
// model_shadow_specular_map.frag
// fragment shader
//
// Created by Andrzej Kapolka on 5/23/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 maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// the diffuse texture
uniform sampler2D diffuseMap;
// the specular texture
uniform sampler2D specularMap;
// the shadow texture
uniform sampler2DShadow shadowMap;
// 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) {
// add up the local lights
vec4 normalizedNormal = normalize(normal);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
localLight += localLightColors[i] * max(0.0, dot(normalizedNormal, localLightDirections[i]));
}
// compute the base color based on OpenGL lighting model
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) + localLight);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * 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);
}

View file

@ -11,47 +11,23 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
// the maximum number of local lights to apply
const int MAX_LOCAL_LIGHTS = 2;
// the color of each local light
uniform vec4 localLightColors[MAX_LOCAL_LIGHTS];
// the direction of each local light
uniform vec4 localLightDirections[MAX_LOCAL_LIGHTS];
// the diffuse texture // the diffuse texture
uniform sampler2D diffuseMap; uniform sampler2D diffuseMap;
// the specular texture // the specular texture
uniform sampler2D specularMap; uniform sampler2D specularMap;
// the interpolated position in view space // the alpha threshold
varying vec4 position; uniform float alphaThreshold;
// the interpolated normal // the interpolated normal
varying vec4 normal; varying vec4 normal;
void main(void) { void main(void) {
// add up the local lights // set the diffuse, normal, specular data
vec4 normalizedNormal = normalize(normal); vec4 diffuse = texture2D(diffuseMap, gl_TexCoord[0].st);
vec4 localLight = vec4(0.0, 0.0, 0.0, 0.0); gl_FragData[0] = vec4(gl_Color.rgb * diffuse.rgb, mix(gl_Color.a, 1.0 - gl_Color.a, step(diffuse.a, alphaThreshold)));
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) { gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
localLight += localLightColors[i] * max(0.0, dot(normalizedNormal, localLightDirections[i])); gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb * texture2D(specularMap, gl_TexCoord[0].st).rgb,
} gl_FrontMaterial.shininess / 128.0);
// compute the base color based on OpenGL lighting model
float diffuse = dot(normalizedNormal, gl_LightSource[0].position);
float facingLight = step(0.0, diffuse);
vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient +
gl_FrontLightProduct[0].diffuse * (diffuse * facingLight) + localLight);
// 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 = vec4(base.rgb, gl_FrontMaterial.diffuse.a) * 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);
} }

View file

@ -0,0 +1,20 @@
#version 120
//
// model_translucent.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/19/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;
void main(void) {
// set the diffuse data
gl_FragData[0] = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].st);
}

View file

@ -26,6 +26,9 @@ const float amplitude = 0.5;
// the position in model space // the position in model space
varying vec3 position; varying vec3 position;
// the normal in view space
varying vec4 normal;
// gradient based on gradients from cube edge centers rather than random from texture lookup // gradient based on gradients from cube edge centers rather than random from texture lookup
float randomEdgeGrad(int hash, vec3 position){ float randomEdgeGrad(int hash, vec3 position){
int h = int(mod(hash, 16)); int h = int(mod(hash, 16));
@ -114,7 +117,8 @@ void main(void) {
// apply vertex lighting // apply vertex lighting
vec3 color = gl_Color.rgb * vec3(noise, noise, noise); vec3 color = gl_Color.rgb * vec3(noise, noise, noise);
gl_FragColor = vec4(color, 1); gl_FragData[0] = vec4(color, 1);
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
} }

View file

@ -14,10 +14,12 @@
// the position in model space // the position in model space
varying vec3 position; varying vec3 position;
// the interpolated normal
varying vec4 normal;
void main(void) { void main(void) {
position = gl_Vertex.xyz; position = gl_Vertex.xyz;
vec4 normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); normal = vec4(gl_NormalMatrix * gl_Normal, 0.0);
gl_FrontColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient + gl_FrontColor = gl_Color;
gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position)));
gl_Position = ftransform(); gl_Position = ftransform();
} }

View file

@ -0,0 +1,69 @@
#version 120
//
// spot_light.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/18/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 texture
uniform sampler2D normalMap;
// the specular texture
uniform sampler2D specularMap;
// the depth texture
uniform sampler2D depthMap;
// the distance to the near clip plane
uniform float near;
// scale factor for depth: (far - near) / far
uniform float depthScale;
// offset for depth texture coordinates
uniform vec2 depthTexCoordOffset;
// scale for depth texture coordinates
uniform vec2 depthTexCoordScale;
// the radius (hard cutoff) of the light effect
uniform float radius;
void main(void) {
// compute the view space position using the depth
float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0);
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0);
// get the normal from the map
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
// compute the base color based on OpenGL lighting model
vec4 lightVector = gl_LightSource[1].position - position;
float lightDistance = length(lightVector);
lightVector = lightVector / lightDistance;
float diffuse = dot(normalizedNormal, lightVector);
float facingLight = step(0.0, diffuse);
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightProduct[1].ambient +
gl_FrontLightProduct[1].diffuse * (diffuse * facingLight));
// compute attenuation based on distance, etc.
float attenuation = step(lightDistance, radius) / dot(vec3(gl_LightSource[1].constantAttenuation,
gl_LightSource[1].linearAttenuation, gl_LightSource[1].quadraticAttenuation),
vec3(1.0, lightDistance, lightDistance * lightDistance));
// add base to specular, modulate by attenuation
float specular = facingLight * max(0.0, dot(normalize(lightVector - normalize(vec4(position.xyz, 0.0))),
normalizedNormal));
vec4 specularColor = texture2D(specularMap, gl_TexCoord[0].st);
gl_FragColor = vec4((baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb) * attenuation, 0.0);
}

View file

@ -1,28 +0,0 @@
#version 120
//
// shadow_map.frag
// fragment shader
//
// Created by Andrzej Kapolka on 11/21/13.
// Copyright 2013 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
//
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) {
gl_FragColor = mix(shadowColor, gl_Color, 0.25 *
(shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, -shadowScale, 0.0)).r +
shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(-shadowScale, shadowScale, 0.0)).r +
shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, -shadowScale, 0.0)).r +
shadow2D(shadowMap, gl_TexCoord[0].stp + vec3(shadowScale, shadowScale, 0.0)).r));
}

View file

@ -1,32 +0,0 @@
#version 120
//
// shadow_map.vert
// vertex shader
//
// Created by Andrzej Kapolka on 3/27/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;
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
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);
// use the fixed function transform
gl_Position = ftransform();
}

View file

@ -0,0 +1,25 @@
#version 120
//
// simple.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/15/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 interpolated normal
varying vec4 normal;
// the glow intensity
uniform float glowIntensity;
void main(void) {
// set the diffuse, normal, specular data
gl_FragData[0] = vec4(gl_Color.rgb, glowIntensity);
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
gl_FragData[2] = vec4(gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess / 128.0);
}

View file

@ -0,0 +1,26 @@
#version 120
//
// simple.vert
// vertex shader
//
// Created by Andrzej Kapolka on 9/15/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 interpolated normal
varying vec4 normal;
void main(void) {
// transform and store the normal for interpolation
normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
// pass along the diffuse color
gl_FrontColor = gl_Color;
// use standard pipeline transform
gl_Position = ftransform();
}

View file

@ -19,14 +19,11 @@ uniform mat4 clusterMatrices[MAX_CLUSTERS];
attribute vec4 clusterIndices; attribute vec4 clusterIndices;
attribute vec4 clusterWeights; attribute vec4 clusterWeights;
// the interpolated position
varying vec4 position;
// the interpolated normal // the interpolated normal
varying vec4 normal; varying vec4 normal;
void main(void) { void main(void) {
position = vec4(0.0, 0.0, 0.0, 0.0); vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
normal = vec4(0.0, 0.0, 0.0, 0.0); normal = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) { for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[int(clusterIndices[i])]; mat4 clusterMatrix = clusterMatrices[int(clusterIndices[i])];
@ -35,17 +32,13 @@ void main(void) {
normal += clusterMatrix * vec4(gl_Normal, 0.0) * clusterWeight; normal += clusterMatrix * vec4(gl_Normal, 0.0) * clusterWeight;
} }
position = gl_ModelViewMatrix * position;
normal = normalize(gl_ModelViewMatrix * normal); normal = normalize(gl_ModelViewMatrix * normal);
// pass along the vertex color // pass along the diffuse color
gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0); gl_FrontColor = gl_FrontMaterial.diffuse;
// and the texture coordinates // and the texture coordinates
gl_TexCoord[0] = gl_MultiTexCoord0; gl_TexCoord[0] = gl_MultiTexCoord0;
// and the shadow texture coordinates gl_Position = gl_ModelViewProjectionMatrix * position;
gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0);
gl_Position = gl_ProjectionMatrix * position;
} }

View file

@ -22,9 +22,6 @@ attribute vec3 tangent;
attribute vec4 clusterIndices; attribute vec4 clusterIndices;
attribute vec4 clusterWeights; attribute vec4 clusterWeights;
// the interpolated position
varying vec4 interpolatedPosition;
// the interpolated normal // the interpolated normal
varying vec4 interpolatedNormal; varying vec4 interpolatedNormal;
@ -32,7 +29,7 @@ varying vec4 interpolatedNormal;
varying vec4 interpolatedTangent; varying vec4 interpolatedTangent;
void main(void) { void main(void) {
interpolatedPosition = vec4(0.0, 0.0, 0.0, 0.0); vec4 interpolatedPosition = vec4(0.0, 0.0, 0.0, 0.0);
interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0); interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0);
interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0); interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) { for (int i = 0; i < INDICES_PER_VERTEX; i++) {
@ -42,19 +39,14 @@ void main(void) {
interpolatedNormal += clusterMatrix * vec4(gl_Normal, 0.0) * clusterWeight; interpolatedNormal += clusterMatrix * vec4(gl_Normal, 0.0) * clusterWeight;
interpolatedTangent += clusterMatrix * vec4(tangent, 0.0) * clusterWeight; interpolatedTangent += clusterMatrix * vec4(tangent, 0.0) * clusterWeight;
} }
interpolatedPosition = gl_ModelViewMatrix * interpolatedPosition;
interpolatedNormal = gl_ModelViewMatrix * interpolatedNormal; interpolatedNormal = gl_ModelViewMatrix * interpolatedNormal;
interpolatedTangent = gl_ModelViewMatrix * interpolatedTangent; interpolatedTangent = gl_ModelViewMatrix * interpolatedTangent;
// pass along the vertex color // pass along the diffuse color
gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0); gl_FrontColor = gl_FrontMaterial.diffuse;
// and the texture coordinates // and the texture coordinates
gl_TexCoord[0] = gl_MultiTexCoord0; gl_TexCoord[0] = gl_MultiTexCoord0;
// and the shadow texture coordinates gl_Position = gl_ModelViewProjectionMatrix * interpolatedPosition;
gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], interpolatedPosition), dot(gl_EyePlaneT[0], interpolatedPosition),
dot(gl_EyePlaneR[0], interpolatedPosition), 1.0);
gl_Position = gl_ProjectionMatrix * interpolatedPosition;
} }

View file

@ -0,0 +1,71 @@
#version 120
//
// spot_light.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/18/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 texture
uniform sampler2D normalMap;
// the specular texture
uniform sampler2D specularMap;
// the depth texture
uniform sampler2D depthMap;
// the distance to the near clip plane
uniform float near;
// scale factor for depth: (far - near) / far
uniform float depthScale;
// offset for depth texture coordinates
uniform vec2 depthTexCoordOffset;
// scale for depth texture coordinates
uniform vec2 depthTexCoordScale;
// the radius (hard cutoff) of the light effect
uniform float radius;
void main(void) {
// compute the view space position using the depth
float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0);
vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0);
// get the normal from the map
vec4 normal = texture2D(normalMap, gl_TexCoord[0].st);
vec4 normalizedNormal = normalize(normal * 2.0 - vec4(1.0, 1.0, 1.0, 2.0));
// compute the base color based on OpenGL lighting model
vec4 lightVector = gl_LightSource[1].position - position;
float lightDistance = length(lightVector);
lightVector = lightVector / lightDistance;
float diffuse = dot(normalizedNormal, lightVector);
float facingLight = step(0.0, diffuse);
vec4 baseColor = texture2D(diffuseMap, gl_TexCoord[0].st) * (gl_FrontLightProduct[1].ambient +
gl_FrontLightProduct[1].diffuse * (diffuse * facingLight));
// compute attenuation based on spot angle, distance, etc.
float cosSpotAngle = max(-dot(lightVector.xyz, gl_LightSource[1].spotDirection), 0.0);
float attenuation = step(lightDistance, radius) * step(gl_LightSource[1].spotCosCutoff, cosSpotAngle) *
pow(cosSpotAngle, gl_LightSource[1].spotExponent) / dot(vec3(gl_LightSource[1].constantAttenuation,
gl_LightSource[1].linearAttenuation, gl_LightSource[1].quadraticAttenuation),
vec3(1.0, lightDistance, lightDistance * lightDistance));
// add base to specular, modulate by attenuation
float specular = facingLight * max(0.0, dot(normalize(lightVector - normalize(vec4(position.xyz, 0.0))),
normalizedNormal));
vec4 specularColor = texture2D(specularMap, gl_TexCoord[0].st);
gl_FragColor = vec4((baseColor.rgb + pow(specular, specularColor.a * 128.0) * specularColor.rgb) * attenuation, 0.0);
}

View file

@ -0,0 +1,21 @@
#version 120
//
// voxel.frag
// fragment shader
//
// Created by Andrzej Kapolka on 9/11/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 interpolated normal
varying vec4 normal;
void main(void) {
// store the color and normal directly
gl_FragData[0] = gl_Color;
gl_FragData[1] = normalize(normal) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
}

View file

@ -0,0 +1,26 @@
#version 120
//
// voxel.vert
// vertex shader
//
// Created by Andrzej Kapolka on 9/11/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 interpolated normal
varying vec4 normal;
void main(void) {
// store the normal for interpolation
normal = vec4(gl_NormalMatrix * gl_Normal, 0.0);
// use the standard position
gl_Position = ftransform();
// store the color directly
gl_FrontColor = vec4(gl_Color.rgb, 0.0);
}

View file

@ -698,8 +698,6 @@ void Application::paintGL() {
displaySide(whichCamera); displaySide(whichCamera);
glPopMatrix(); glPopMatrix();
_glowEffect.render();
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
renderRearViewMirror(_mirrorViewRect); renderRearViewMirror(_mirrorViewRect);
@ -707,6 +705,8 @@ void Application::paintGL() {
_rearMirrorTools->render(true); _rearMirrorTools->render(true);
} }
_glowEffect.render();
{ {
PerformanceTimer perfTimer("renderOverlay"); PerformanceTimer perfTimer("renderOverlay");
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
@ -1754,6 +1754,7 @@ void Application::init() {
_environment.init(); _environment.init();
_deferredLightingEffect.init();
_glowEffect.init(); _glowEffect.init();
_ambientOcclusionEffect.init(); _ambientOcclusionEffect.init();
_voxelShader.init(); _voxelShader.init();
@ -2709,7 +2710,6 @@ void Application::updateShadowMap() {
const GLfloat WORLD_AMBIENT_COLOR[] = { 0.525f, 0.525f, 0.6f }; const GLfloat WORLD_AMBIENT_COLOR[] = { 0.525f, 0.525f, 0.6f };
const GLfloat WORLD_DIFFUSE_COLOR[] = { 0.6f, 0.525f, 0.525f }; const GLfloat WORLD_DIFFUSE_COLOR[] = { 0.6f, 0.525f, 0.525f };
const GLfloat WORLD_SPECULAR_COLOR[] = { 0.94f, 0.94f, 0.737f, 1.0f }; const GLfloat WORLD_SPECULAR_COLOR[] = { 0.94f, 0.94f, 0.737f, 1.0f };
const GLfloat NO_SPECULAR_COLOR[] = { 0.0f, 0.0f, 0.0f, 1.0f };
void Application::setupWorldLight() { void Application::setupWorldLight() {
@ -2843,6 +2843,8 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
_deferredLightingEffect.prepare();
if (!selfAvatarOnly) { if (!selfAvatarOnly) {
// draw a red sphere // draw a red sphere
float originSphereRadius = 0.05f; float originSphereRadius = 0.05f;
@ -2851,15 +2853,19 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
glutSolidSphere(originSphereRadius, 15, 15); glutSolidSphere(originSphereRadius, 15, 15);
glPopMatrix(); glPopMatrix();
// disable specular lighting for ground and voxels
glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR);
// draw the audio reflector overlay // draw the audio reflector overlay
{ {
PerformanceTimer perfTimer("audio"); PerformanceTimer perfTimer("audio");
_audioReflector.render(); _audioReflector.render();
} }
if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) {
PerformanceTimer perfTimer("buckyBalls");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... bucky balls...");
_buckyBalls.render();
}
// Draw voxels // Draw voxels
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
PerformanceTimer perfTimer("voxels"); PerformanceTimer perfTimer("voxels");
@ -2876,13 +2882,6 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
_metavoxels.render(); _metavoxels.render();
} }
if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) {
PerformanceTimer perfTimer("buckyBalls");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... bucky balls...");
_buckyBalls.render();
}
// render particles... // render particles...
if (Menu::getInstance()->isOptionChecked(MenuOption::Particles)) { if (Menu::getInstance()->isOptionChecked(MenuOption::Particles)) {
PerformanceTimer perfTimer("particles"); PerformanceTimer perfTimer("particles");
@ -2906,27 +2905,34 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
"Application::displaySide() ... AmbientOcclusion..."); "Application::displaySide() ... AmbientOcclusion...");
_ambientOcclusionEffect.render(); _ambientOcclusionEffect.render();
} }
// restore default, white specular
glMaterialfv(GL_FRONT, GL_SPECULAR, WORLD_SPECULAR_COLOR);
_nodeBoundsDisplay.draw();
} }
bool mirrorMode = (whichCamera.getInterpolatedMode() == CAMERA_MODE_MIRROR); bool mirrorMode = (whichCamera.getInterpolatedMode() == CAMERA_MODE_MIRROR);
{ {
PerformanceTimer perfTimer("avatars"); PerformanceTimer perfTimer("avatars");
_avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE,
false, selfAvatarOnly);
}
_avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, selfAvatarOnly); {
PerformanceTimer perfTimer("lighting");
_deferredLightingEffect.render();
}
{
PerformanceTimer perfTimer("avatarsPostLighting");
_avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE,
true, selfAvatarOnly);
}
//Render the sixense lasers //Render the sixense lasers
if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) { if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseLasers)) {
_myAvatar->renderLaserPointers(); _myAvatar->renderLaserPointers();
} }
}
if (!selfAvatarOnly) { if (!selfAvatarOnly) {
_nodeBoundsDisplay.draw();
// Render the world box // Render the world box
if (whichCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats) && if (whichCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) {
@ -3001,7 +3007,7 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const {
// allow 3DTV/Oculus to override parameters from camera // allow 3DTV/Oculus to override parameters from camera
_viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); _displayViewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
if (OculusManager::isConnected()) { if (OculusManager::isConnected()) {
OculusManager::overrideOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); OculusManager::overrideOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
@ -3800,8 +3806,8 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
scriptEngine->getEntityScriptingInterface()->setPacketSender(&_entityEditSender); scriptEngine->getEntityScriptingInterface()->setPacketSender(&_entityEditSender);
scriptEngine->getEntityScriptingInterface()->setEntityTree(_entities.getTree()); scriptEngine->getEntityScriptingInterface()->setEntityTree(_entities.getTree());
// model has some custom types // AvatarManager has some custom types
Model::registerMetaTypes(scriptEngine); AvatarManager::registerMetaTypes(scriptEngine);
// hook our avatar object into this script engine // hook our avatar object into this script engine
scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features

View file

@ -68,6 +68,7 @@
#include "entities/EntityTreeRenderer.h" #include "entities/EntityTreeRenderer.h"
#include "particles/ParticleTreeRenderer.h" #include "particles/ParticleTreeRenderer.h"
#include "renderer/AmbientOcclusionEffect.h" #include "renderer/AmbientOcclusionEffect.h"
#include "renderer/DeferredLightingEffect.h"
#include "renderer/GeometryCache.h" #include "renderer/GeometryCache.h"
#include "renderer/GlowEffect.h" #include "renderer/GlowEffect.h"
#include "renderer/PointShader.h" #include "renderer/PointShader.h"
@ -247,6 +248,7 @@ public:
GeometryCache* getGeometryCache() { return &_geometryCache; } GeometryCache* getGeometryCache() { return &_geometryCache; }
AnimationCache* getAnimationCache() { return &_animationCache; } AnimationCache* getAnimationCache() { return &_animationCache; }
TextureCache* getTextureCache() { return &_textureCache; } TextureCache* getTextureCache() { return &_textureCache; }
DeferredLightingEffect* getDeferredLightingEffect() { return &_deferredLightingEffect; }
GlowEffect* getGlowEffect() { return &_glowEffect; } GlowEffect* getGlowEffect() { return &_glowEffect; }
ControllerScriptingInterface* getControllerScriptingInterface() { return &_controllerScriptingInterface; } ControllerScriptingInterface* getControllerScriptingInterface() { return &_controllerScriptingInterface; }
@ -559,6 +561,7 @@ private:
AnimationCache _animationCache; AnimationCache _animationCache;
TextureCache _textureCache; TextureCache _textureCache;
DeferredLightingEffect _deferredLightingEffect;
GlowEffect _glowEffect; GlowEffect _glowEffect;
AmbientOcclusionEffect _ambientOcclusionEffect; AmbientOcclusionEffect _ambientOcclusionEffect;
VoxelShader _voxelShader; VoxelShader _voxelShader;

View file

@ -367,7 +367,6 @@ Menu::Menu() :
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, "None", 0, true));
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::SimpleShadows, 0, false));
shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false)); shadowGroup->addAction(addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::CascadedShadows, 0, false));
addCheckableActionToQMenuAndActionHash(shadowMenu, MenuOption::AvatarsReceiveShadows, 0, true);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true);

View file

@ -346,7 +346,6 @@ namespace MenuOption {
const QString AudioSourcePinkNoise = "Pink Noise"; const QString AudioSourcePinkNoise = "Pink Noise";
const QString AudioSourceSine440 = "Sine 440hz"; const QString AudioSourceSine440 = "Sine 440hz";
const QString Avatars = "Avatars"; const QString Avatars = "Avatars";
const QString AvatarsReceiveShadows = "Avatars Receive Shadows";
const QString Bandwidth = "Bandwidth Display"; const QString Bandwidth = "Bandwidth Display";
const QString BandwidthDetails = "Bandwidth Details"; const QString BandwidthDetails = "Bandwidth Details";
const QString BlueSpeechSphere = "Blue Sphere While Speaking"; const QString BlueSpeechSphere = "Blue Sphere While Speaking";

View file

@ -51,12 +51,6 @@ void MetavoxelSystem::init() {
new BufferDataAttribute("voxelBuffer")); new BufferDataAttribute("voxelBuffer"));
_voxelBufferAttribute->setLODThresholdMultiplier( _voxelBufferAttribute->setLODThresholdMultiplier(
AttributeRegistry::getInstance()->getVoxelColorAttribute()->getLODThresholdMultiplier()); AttributeRegistry::getInstance()->getVoxelColorAttribute()->getLODThresholdMultiplier());
loadLightProgram("shaders/directional_light.frag", _directionalLight, _directionalLightLocations);
loadLightProgram("shaders/directional_light_shadow_map.frag", _directionalLightShadowMap,
_directionalLightShadowMapLocations);
loadLightProgram("shaders/directional_light_cascaded_shadow_map.frag", _directionalLightCascadedShadowMap,
_directionalLightCascadedShadowMapLocations);
} }
MetavoxelLOD MetavoxelSystem::getLOD() { MetavoxelLOD MetavoxelSystem::getLOD() {
@ -127,10 +121,6 @@ int RenderVisitor::visit(MetavoxelInfo& info) {
return STOP_RECURSION; return STOP_RECURSION;
} }
const GLenum COLOR_DRAW_BUFFERS[] = { GL_COLOR_ATTACHMENT0 };
const GLenum NORMAL_DRAW_BUFFERS[] = { GL_COLOR_ATTACHMENT1 };
const GLenum COLOR_NORMAL_DRAW_BUFFERS[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
void MetavoxelSystem::render() { void MetavoxelSystem::render() {
// update the frustum // update the frustum
ViewFrustum* viewFrustum = Application::getInstance()->getDisplayViewFrustum(); ViewFrustum* viewFrustum = Application::getInstance()->getDisplayViewFrustum();
@ -138,139 +128,11 @@ void MetavoxelSystem::render() {
viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(), viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(),
viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight());
_needToLight = false;
// clear the normal buffer
glDrawBuffers(sizeof(NORMAL_DRAW_BUFFERS) / sizeof(NORMAL_DRAW_BUFFERS[0]), NORMAL_DRAW_BUFFERS);
glClear(GL_COLOR_BUFFER_BIT);
glDrawBuffers(sizeof(COLOR_DRAW_BUFFERS) / sizeof(COLOR_DRAW_BUFFERS[0]), COLOR_DRAW_BUFFERS);
RenderVisitor renderVisitor(getLOD()); RenderVisitor renderVisitor(getLOD());
guideToAugmented(renderVisitor, true); guideToAugmented(renderVisitor, true);
// give external parties a chance to join in // give external parties a chance to join in
emit rendering(); emit rendering();
if (!_needToLight) {
return; // skip lighting if not needed
}
// perform deferred lighting, rendering to free fbo
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glDisable(GL_BLEND);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glDepthMask(false);
QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject();
primaryFBO->release();
QOpenGLFramebufferObject* freeFBO = Application::getInstance()->getGlowEffect()->getFreeFramebufferObject();
freeFBO->bind();
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryNormalTextureID());
// get the viewport side (left, right, both)
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
const int VIEWPORT_X_INDEX = 0;
const int VIEWPORT_WIDTH_INDEX = 2;
float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width();
float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width();
if (Menu::getInstance()->getShadowsEnabled()) {
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID());
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID());
ProgramObject* program = &_directionalLightShadowMap;
const LightLocations* locations = &_directionalLightShadowMapLocations;
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
program = &_directionalLightCascadedShadowMap;
locations = &_directionalLightCascadedShadowMapLocations;
_directionalLightCascadedShadowMap.bind();
_directionalLightCascadedShadowMap.setUniform(locations->shadowDistances,
Application::getInstance()->getShadowDistances());
} else {
program->bind();
}
program->setUniformValue(locations->shadowScale,
1.0f / Application::getInstance()->getTextureCache()->getShadowFramebufferObject()->width());
float left, right, bottom, top, nearVal, farVal;
glm::vec4 nearClipPlane, farClipPlane;
Application::getInstance()->computeOffAxisFrustum(
left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
program->setUniformValue(locations->nearLocation, nearVal);
program->setUniformValue(locations->depthScale, (farVal - nearVal) / farVal);
float nearScale = -1.0f / nearVal;
float sScale = 1.0f / sWidth;
float depthTexCoordScaleS = (right - left) * nearScale * sScale;
program->setUniformValue(locations->depthTexCoordOffset, left * nearScale - sMin * depthTexCoordScaleS,
bottom * nearScale);
program->setUniformValue(locations->depthTexCoordScale, depthTexCoordScaleS, (top - bottom) * nearScale);
renderFullscreenQuad(sMin, sMin + sWidth);
program->release();
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1);
} else {
_directionalLight.bind();
renderFullscreenQuad(sMin, sMin + sWidth);
_directionalLight.release();
}
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
freeFBO->release();
// now transfer the lit region to the primary fbo
glEnable(GL_BLEND);
primaryFBO->bind();
glBindTexture(GL_TEXTURE_2D, freeFBO->texture());
glEnable(GL_TEXTURE_2D);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
renderFullscreenQuad(sMin, sMin + sWidth);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
glDisable(GL_ALPHA_TEST);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
} }
class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor { class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor {
@ -630,24 +492,6 @@ void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor, bool render) {
} }
} }
void MetavoxelSystem::loadLightProgram(const char* name, ProgramObject& program, LightLocations& locations) {
program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + name);
program.link();
program.bind();
program.setUniformValue("diffuseMap", 0);
program.setUniformValue("normalMap", 1);
program.setUniformValue("depthMap", 2);
program.setUniformValue("shadowMap", 3);
locations.shadowDistances = program.uniformLocation("shadowDistances");
locations.shadowScale = program.uniformLocation("shadowScale");
locations.nearLocation = program.uniformLocation("near");
locations.depthScale = program.uniformLocation("depthScale");
locations.depthTexCoordOffset = program.uniformLocation("depthTexCoordOffset");
locations.depthTexCoordScale = program.uniformLocation("depthTexCoordScale");
program.release();
}
MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) : MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) :
MetavoxelClient(node, updater) { MetavoxelClient(node, updater) {
} }
@ -980,7 +824,7 @@ void HeightfieldBuffer::render(bool cursor) {
glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0);
glDrawBuffers(sizeof(COLOR_DRAW_BUFFERS) / sizeof(COLOR_DRAW_BUFFERS[0]), COLOR_DRAW_BUFFERS); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
glDepthMask(false); glDepthMask(false);
@ -1053,7 +897,7 @@ void HeightfieldBuffer::render(bool cursor) {
glDepthMask(true); glDepthMask(true);
glDepthFunc(GL_LESS); glDepthFunc(GL_LESS);
glDrawBuffers(sizeof(COLOR_NORMAL_DRAW_BUFFERS) / sizeof(COLOR_NORMAL_DRAW_BUFFERS[0]), COLOR_NORMAL_DRAW_BUFFERS); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().bind(); DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().bind();
@ -1077,14 +921,12 @@ void HeightfieldBuffer::render(bool cursor) {
bufferPair.first.release(); bufferPair.first.release();
bufferPair.second.release(); bufferPair.second.release();
Application::getInstance()->getMetavoxels()->noteNeedToLight();
} }
QHash<int, HeightfieldBuffer::BufferPair> HeightfieldBuffer::_bufferPairs; QHash<int, HeightfieldBuffer::BufferPair> HeightfieldBuffer::_bufferPairs;
void HeightfieldPreview::render(const glm::vec3& translation, float scale) const { void HeightfieldPreview::render(const glm::vec3& translation, float scale) const {
glDrawBuffers(sizeof(COLOR_NORMAL_DRAW_BUFFERS) / sizeof(COLOR_NORMAL_DRAW_BUFFERS[0]), COLOR_NORMAL_DRAW_BUFFERS); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
glDisable(GL_BLEND); glDisable(GL_BLEND);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
@ -1117,7 +959,7 @@ void HeightfieldPreview::render(const glm::vec3& translation, float scale) const
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glDrawBuffers(sizeof(COLOR_DRAW_BUFFERS) / sizeof(COLOR_DRAW_BUFFERS[0]), COLOR_DRAW_BUFFERS); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
} }
VoxelBuffer::VoxelBuffer(const QVector<VoxelPoint>& vertices, const QVector<int>& indices, VoxelBuffer::VoxelBuffer(const QVector<VoxelPoint>& vertices, const QVector<int>& indices,
@ -1165,7 +1007,7 @@ void VoxelBuffer::render(bool cursor) {
glDrawRangeElements(GL_QUADS, 0, _vertexCount - 1, _indexCount, GL_UNSIGNED_INT, 0); glDrawRangeElements(GL_QUADS, 0, _vertexCount - 1, _indexCount, GL_UNSIGNED_INT, 0);
if (!_materials.isEmpty()) { if (!_materials.isEmpty()) {
glDrawBuffers(sizeof(COLOR_DRAW_BUFFERS) / sizeof(COLOR_DRAW_BUFFERS[0]), COLOR_DRAW_BUFFERS); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
glDepthMask(false); glDepthMask(false);
@ -1235,7 +1077,7 @@ void VoxelBuffer::render(bool cursor) {
glDepthMask(true); glDepthMask(true);
glDepthFunc(GL_LESS); glDepthFunc(GL_LESS);
glDrawBuffers(sizeof(COLOR_NORMAL_DRAW_BUFFERS) / sizeof(COLOR_NORMAL_DRAW_BUFFERS[0]), COLOR_NORMAL_DRAW_BUFFERS); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().disableAttributeArray(locations.materials); DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().disableAttributeArray(locations.materials);
DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().disableAttributeArray(locations.materialWeights); DefaultMetavoxelRendererImplementation::getSplatVoxelProgram().disableAttributeArray(locations.materialWeights);
@ -1245,8 +1087,6 @@ void VoxelBuffer::render(bool cursor) {
_vertexBuffer.release(); _vertexBuffer.release();
_indexBuffer.release(); _indexBuffer.release();
Application::getInstance()->getMetavoxels()->noteNeedToLight();
} }
BufferDataAttribute::BufferDataAttribute(const QString& name) : BufferDataAttribute::BufferDataAttribute(const QString& name) :
@ -2282,7 +2122,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
_pointProgram.release(); _pointProgram.release();
glDrawBuffers(sizeof(COLOR_NORMAL_DRAW_BUFFERS) / sizeof(COLOR_NORMAL_DRAW_BUFFERS[0]), COLOR_NORMAL_DRAW_BUFFERS); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glEnable(GL_ALPHA_TEST); glEnable(GL_ALPHA_TEST);
@ -2325,7 +2165,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox
glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
glDrawBuffers(sizeof(COLOR_DRAW_BUFFERS) / sizeof(COLOR_DRAW_BUFFERS[0]), COLOR_DRAW_BUFFERS); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
} }
void DefaultMetavoxelRendererImplementation::loadSplatProgram(const char* type, void DefaultMetavoxelRendererImplementation::loadSplatProgram(const char* type,

View file

@ -52,8 +52,6 @@ public:
Q_INVOKABLE void deleteTextures(int heightID, int colorID, int textureID); Q_INVOKABLE void deleteTextures(int heightID, int colorID, int textureID);
void noteNeedToLight() { _needToLight = true; }
signals: signals:
void rendering(); void rendering();
@ -66,18 +64,6 @@ private:
void guideToAugmented(MetavoxelVisitor& visitor, bool render = false); void guideToAugmented(MetavoxelVisitor& visitor, bool render = false);
class LightLocations {
public:
int shadowDistances;
int shadowScale;
int nearLocation;
int depthScale;
int depthTexCoordOffset;
int depthTexCoordScale;
};
static void loadLightProgram(const char* name, ProgramObject& program, LightLocations& locations);
AttributePointer _pointBufferAttribute; AttributePointer _pointBufferAttribute;
AttributePointer _heightfieldBufferAttribute; AttributePointer _heightfieldBufferAttribute;
AttributePointer _voxelBufferAttribute; AttributePointer _voxelBufferAttribute;
@ -85,14 +71,6 @@ private:
MetavoxelLOD _lod; MetavoxelLOD _lod;
QReadWriteLock _lodLock; QReadWriteLock _lodLock;
Frustum _frustum; Frustum _frustum;
bool _needToLight;
ProgramObject _directionalLight;
LightLocations _directionalLightLocations;
ProgramObject _directionalLightShadowMap;
LightLocations _directionalLightShadowMapLocations;
ProgramObject _directionalLightCascadedShadowMap;
LightLocations _directionalLightCascadedShadowMapLocations;
}; };
/// Describes contents of a point in a point buffer. /// Describes contents of a point in a point buffer.

View file

@ -273,13 +273,12 @@ static TextRenderer* textRenderer(TextRendererType type) {
return displayNameRenderer; return displayNameRenderer;
} }
void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool postLighting) {
if (_referential) { if (_referential) {
_referential->update(); _referential->update();
} }
if (glm::distance(Application::getInstance()->getAvatar()->getPosition(), if (postLighting && glm::distance(Application::getInstance()->getAvatar()->getPosition(), _position) < 10.0f) {
_position) < 10.0f) {
// render pointing lasers // render pointing lasers
glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f); glm::vec3 laserColor = glm::vec3(1.0f, 0.0f, 1.0f);
float laserLength = 50.0f; float laserLength = 50.0f;
@ -351,17 +350,28 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
? 1.0f ? 1.0f
: GLOW_FROM_AVERAGE_LOUDNESS; : GLOW_FROM_AVERAGE_LOUDNESS;
// local lights directions and colors
const QVector<Model::LocalLight>& localLights = Application::getInstance()->getAvatarManager().getLocalLights();
_skeletonModel.setLocalLights(localLights);
getHead()->getFaceModel().setLocalLights(localLights);
// render body // render body
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { if (!postLighting && Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
renderBody(renderMode, glowLevel); renderBody(renderMode, glowLevel);
}
if (renderMode != SHADOW_RENDER_MODE) { if (renderMode != SHADOW_RENDER_MODE) {
// add local lights
const float BASE_LIGHT_DISTANCE = 2.0f;
const float LIGHT_EXPONENT = 1.0f;
const float LIGHT_CUTOFF = glm::radians(80.0f);
float distance = BASE_LIGHT_DISTANCE * _scale;
glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f);
glm::quat orientation = getOrientation();
foreach (const AvatarManager::LocalLight& light, Application::getInstance()->getAvatarManager().getLocalLights()) {
glm::vec3 direction = orientation * light.direction;
Application::getInstance()->getDeferredLightingEffect()->addSpotLight(position - direction * distance,
distance * 2.0f, glm::vec3(), light.color, light.color, 1.0f, 0.5f, 0.0f, direction,
LIGHT_EXPONENT, LIGHT_CUTOFF);
}
}
}
if (postLighting) {
bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes); bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes);
bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes); bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes);
bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes);
@ -397,7 +407,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
// quick check before falling into the code below: // quick check before falling into the code below:
// (a 10 degree breadth of an almost 2 meter avatar kicks in at about 12m) // (a 10 degree breadth of an almost 2 meter avatar kicks in at about 12m)
const float MIN_VOICE_SPHERE_DISTANCE = 12.0f; const float MIN_VOICE_SPHERE_DISTANCE = 12.0f;
if (Menu::getInstance()->isOptionChecked(MenuOption::BlueSpeechSphere) if (postLighting && Menu::getInstance()->isOptionChecked(MenuOption::BlueSpeechSphere)
&& distanceToTarget > MIN_VOICE_SPHERE_DISTANCE) { && distanceToTarget > MIN_VOICE_SPHERE_DISTANCE) {
// render voice intensity sphere for avatars that are farther away // render voice intensity sphere for avatars that are farther away
@ -425,7 +435,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
const float DISPLAYNAME_DISTANCE = 20.0f; const float DISPLAYNAME_DISTANCE = 20.0f;
setShowDisplayName(renderMode == NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE); setShowDisplayName(renderMode == NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE);
if (renderMode != NORMAL_RENDER_MODE || (isMyAvatar() && if (!postLighting || renderMode != NORMAL_RENDER_MODE || (isMyAvatar() &&
Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) { Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) {
return; return;
} }
@ -501,7 +511,7 @@ void Avatar::renderBody(RenderMode renderMode, float glowLevel) {
return; return;
} }
_skeletonModel.render(1.0f, modelRenderMode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)); _skeletonModel.render(1.0f, modelRenderMode);
renderAttachments(renderMode); renderAttachments(renderMode);
getHand()->render(false, modelRenderMode); getHand()->render(false, modelRenderMode);
} }
@ -547,9 +557,8 @@ void Avatar::simulateAttachments(float deltaTime) {
void Avatar::renderAttachments(RenderMode renderMode) { void Avatar::renderAttachments(RenderMode renderMode) {
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows);
foreach (Model* model, _attachmentModels) { foreach (Model* model, _attachmentModels) {
model->render(1.0f, modelRenderMode, receiveShadows); model->render(1.0f, modelRenderMode);
} }
} }

View file

@ -79,7 +79,8 @@ public:
enum RenderMode { NORMAL_RENDER_MODE, SHADOW_RENDER_MODE, MIRROR_RENDER_MODE }; enum RenderMode { NORMAL_RENDER_MODE, SHADOW_RENDER_MODE, MIRROR_RENDER_MODE };
virtual void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE); virtual void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE,
bool postLighting = false);
//setters //setters
void setDisplayingLookatVectors(bool displayingLookatVectors) { getHead()->setRenderLookatVectors(displayingLookatVectors); } void setDisplayingLookatVectors(bool displayingLookatVectors) { getHead()->setRenderLookatVectors(displayingLookatVectors); }

View file

@ -11,9 +11,12 @@
#include <string> #include <string>
#include <QScriptEngine>
#include <glm/gtx/string_cast.hpp> #include <glm/gtx/string_cast.hpp>
#include <PerfStat.h> #include <PerfStat.h>
#include <RegisteredMetaTypes.h>
#include <UUID.h> #include <UUID.h>
#include "Application.h" #include "Application.h"
@ -26,6 +29,23 @@
// We add _myAvatar into the hash with all the other AvatarData, and we use the default NULL QUid as the key. // We add _myAvatar into the hash with all the other AvatarData, and we use the default NULL QUid as the key.
const QUuid MY_AVATAR_KEY; // NULL key const QUuid MY_AVATAR_KEY; // NULL key
static QScriptValue localLightToScriptValue(QScriptEngine* engine, const AvatarManager::LocalLight& light) {
QScriptValue object = engine->newObject();
object.setProperty("direction", vec3toScriptValue(engine, light.direction));
object.setProperty("color", vec3toScriptValue(engine, light.color));
return object;
}
static void localLightFromScriptValue(const QScriptValue& value, AvatarManager::LocalLight& light) {
vec3FromScriptValue(value.property("direction"), light.direction);
vec3FromScriptValue(value.property("color"), light.color);
}
void AvatarManager::registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, localLightToScriptValue, localLightFromScriptValue);
qScriptRegisterSequenceMetaType<QVector<AvatarManager::LocalLight> >(engine);
}
AvatarManager::AvatarManager(QObject* parent) : AvatarManager::AvatarManager(QObject* parent) :
_avatarFades() { _avatarFades() {
// register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar // register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar
@ -79,7 +99,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
simulateAvatarFades(deltaTime); simulateAvatarFades(deltaTime);
} }
void AvatarManager::renderAvatars(Avatar::RenderMode renderMode, bool selfAvatarOnly) { void AvatarManager::renderAvatars(Avatar::RenderMode renderMode, bool postLighting, bool selfAvatarOnly) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::renderAvatars()"); "Application::renderAvatars()");
bool renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderLookAtVectors); bool renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderLookAtVectors);
@ -92,13 +112,13 @@ void AvatarManager::renderAvatars(Avatar::RenderMode renderMode, bool selfAvatar
if (!avatar->isInitialized()) { if (!avatar->isInitialized()) {
continue; continue;
} }
avatar->render(cameraPosition, renderMode); avatar->render(cameraPosition, renderMode, postLighting);
avatar->setDisplayingLookatVectors(renderLookAtVectors); avatar->setDisplayingLookatVectors(renderLookAtVectors);
} }
renderAvatarFades(cameraPosition, renderMode); renderAvatarFades(cameraPosition, renderMode);
} else { } else {
// just render myAvatar // just render myAvatar
_myAvatar->render(cameraPosition, renderMode); _myAvatar->render(cameraPosition, renderMode, postLighting);
_myAvatar->setDisplayingLookatVectors(renderLookAtVectors); _myAvatar->setDisplayingLookatVectors(renderLookAtVectors);
} }
} }
@ -159,19 +179,19 @@ void AvatarManager::clearOtherAvatars() {
_myAvatar->clearLookAtTargetAvatar(); _myAvatar->clearLookAtTargetAvatar();
} }
void AvatarManager::setLocalLights(const QVector<Model::LocalLight>& localLights) { void AvatarManager::setLocalLights(const QVector<AvatarManager::LocalLight>& localLights) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setLocalLights", Q_ARG(const QVector<Model::LocalLight>&, localLights)); QMetaObject::invokeMethod(this, "setLocalLights", Q_ARG(const QVector<AvatarManager::LocalLight>&, localLights));
return; return;
} }
_localLights = localLights; _localLights = localLights;
} }
QVector<Model::LocalLight> AvatarManager::getLocalLights() const { QVector<AvatarManager::LocalLight> AvatarManager::getLocalLights() const {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QVector<Model::LocalLight> result; QVector<AvatarManager::LocalLight> result;
QMetaObject::invokeMethod(const_cast<AvatarManager*>(this), "getLocalLights", Qt::BlockingQueuedConnection, QMetaObject::invokeMethod(const_cast<AvatarManager*>(this), "getLocalLights", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(QVector<Model::LocalLight>, result)); Q_RETURN_ARG(QVector<AvatarManager::LocalLight>, result));
return result; return result;
} }
return _localLights; return _localLights;

View file

@ -26,6 +26,10 @@ class AvatarManager : public AvatarHashMap {
Q_OBJECT Q_OBJECT
public: public:
/// Registers the script types associated with the avatar manager.
static void registerMetaTypes(QScriptEngine* engine);
AvatarManager(QObject* parent = 0); AvatarManager(QObject* parent = 0);
void init(); void init();
@ -33,12 +37,18 @@ public:
MyAvatar* getMyAvatar() { return _myAvatar.data(); } MyAvatar* getMyAvatar() { return _myAvatar.data(); }
void updateOtherAvatars(float deltaTime); void updateOtherAvatars(float deltaTime);
void renderAvatars(Avatar::RenderMode renderMode, bool selfAvatarOnly = false); void renderAvatars(Avatar::RenderMode renderMode, bool postLighting = false, bool selfAvatarOnly = false);
void clearOtherAvatars(); void clearOtherAvatars();
Q_INVOKABLE void setLocalLights(const QVector<Model::LocalLight>& localLights); class LocalLight {
Q_INVOKABLE QVector<Model::LocalLight> getLocalLights() const; public:
glm::vec3 color;
glm::vec3 direction;
};
Q_INVOKABLE void setLocalLights(const QVector<AvatarManager::LocalLight>& localLights);
Q_INVOKABLE QVector<AvatarManager::LocalLight> getLocalLights() const;
private: private:
AvatarManager(const AvatarManager& other); AvatarManager(const AvatarManager& other);
@ -54,7 +64,10 @@ private:
QVector<AvatarSharedPointer> _avatarFades; QVector<AvatarSharedPointer> _avatarFades;
QSharedPointer<MyAvatar> _myAvatar; QSharedPointer<MyAvatar> _myAvatar;
QVector<Model::LocalLight> _localLights; QVector<AvatarManager::LocalLight> _localLights;
}; };
Q_DECLARE_METATYPE(AvatarManager::LocalLight)
Q_DECLARE_METATYPE(QVector<AvatarManager::LocalLight>)
#endif // hifi_AvatarManager_h #endif // hifi_AvatarManager_h

View file

@ -194,12 +194,16 @@ void Head::relaxLean(float deltaTime) {
} }
void Head::render(float alpha, Model::RenderMode mode) { void Head::render(float alpha, Model::RenderMode mode) {
_faceModel.render(alpha, mode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)); _faceModel.render(alpha, mode);
if (_renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) { if (_renderLookatVectors && mode != Model::SHADOW_RENDER_MODE) {
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); Application::getInstance()->getDeferredLightingEffect()->addPostLightingRenderable(this);
} }
} }
void Head::renderPostLighting() {
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
}
void Head::setScale (float scale) { void Head::setScale (float scale) {
if (_scale == scale) { if (_scale == scale) {
return; return;

View file

@ -23,6 +23,7 @@
#include "FaceModel.h" #include "FaceModel.h"
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
#include "world.h" #include "world.h"
#include "renderer/DeferredLightingEffect.h"
enum eyeContactTargets { enum eyeContactTargets {
LEFT_EYE, LEFT_EYE,
@ -35,7 +36,7 @@ const float EYE_EAR_GAP = 0.08f;
class Avatar; class Avatar;
class ProgramObject; class ProgramObject;
class Head : public HeadData { class Head : public HeadData, public PostLightingRenderable {
public: public:
Head(Avatar* owningAvatar); Head(Avatar* owningAvatar);
@ -43,6 +44,7 @@ public:
void reset(); void reset();
void simulate(float deltaTime, bool isMine, bool billboard = false); void simulate(float deltaTime, bool isMine, bool billboard = false);
void render(float alpha, Model::RenderMode mode); void render(float alpha, Model::RenderMode mode);
virtual void renderPostLighting();
void setScale(float scale); void setScale(float scale);
void setPosition(glm::vec3 position) { _position = position; } void setPosition(glm::vec3 position) { _position = position; }
void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; }

View file

@ -411,16 +411,16 @@ void MyAvatar::renderDebugBodyPoints() {
} }
// virtual // virtual
void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode, bool postLighting) {
// don't render if we've been asked to disable local rendering // don't render if we've been asked to disable local rendering
if (!_shouldRender) { if (!_shouldRender) {
return; // exit early return; // exit early
} }
Avatar::render(cameraPosition, renderMode); Avatar::render(cameraPosition, renderMode, postLighting);
// don't display IK constraints in shadow mode // don't display IK constraints in shadow mode
if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints) && renderMode != SHADOW_RENDER_MODE) { if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints) && postLighting) {
_skeletonModel.renderIKConstraints(); _skeletonModel.renderIKConstraints();
} }
} }
@ -1104,7 +1104,7 @@ void MyAvatar::renderBody(RenderMode renderMode, float glowLevel) {
// Render the body's voxels and head // Render the body's voxels and head
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
_skeletonModel.render(1.0f, modelRenderMode, Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows)); _skeletonModel.render(1.0f, modelRenderMode);
renderAttachments(renderMode); renderAttachments(renderMode);
// Render head so long as the camera isn't inside it // Render head so long as the camera isn't inside it
@ -1939,11 +1939,10 @@ void MyAvatar::renderAttachments(RenderMode renderMode) {
QString headJointName = (geometry.headJointIndex == -1) ? QString() : geometry.joints.at(geometry.headJointIndex).name; QString headJointName = (geometry.headJointIndex == -1) ? QString() : geometry.joints.at(geometry.headJointIndex).name;
Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ? Model::RenderMode modelRenderMode = (renderMode == SHADOW_RENDER_MODE) ?
Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE; Model::SHADOW_RENDER_MODE : Model::DEFAULT_RENDER_MODE;
bool receiveShadows = Menu::getInstance()->isOptionChecked(MenuOption::AvatarsReceiveShadows);
for (int i = 0; i < _attachmentData.size(); i++) { for (int i = 0; i < _attachmentData.size(); i++) {
const QString& jointName = _attachmentData.at(i).jointName; const QString& jointName = _attachmentData.at(i).jointName;
if (jointName != headJointName && jointName != "Head") { if (jointName != headJointName && jointName != "Head") {
_attachmentModels.at(i)->render(1.0f, modelRenderMode, receiveShadows); _attachmentModels.at(i)->render(1.0f, modelRenderMode);
} }
} }
} }

View file

@ -48,7 +48,7 @@ public:
void updateFromTrackers(float deltaTime); void updateFromTrackers(float deltaTime);
void moveWithLean(); void moveWithLean();
void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE); void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE, bool postLighting = false);
void renderBody(RenderMode renderMode, float glowLevel = 0.0f); void renderBody(RenderMode renderMode, float glowLevel = 0.0f);
bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const; bool shouldRenderHead(const glm::vec3& cameraPosition, RenderMode renderMode) const;
void renderDebugBodyPoints(); void renderDebugBodyPoints();

View file

@ -50,7 +50,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
glm::vec3 positionToCenter = center - position; glm::vec3 positionToCenter = center - position;
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
glScalef(dimensions.x, dimensions.y, dimensions.z); glScalef(dimensions.x, dimensions.y, dimensions.z);
glutSolidCube(1.0f); Application::getInstance()->getDeferredLightingEffect()->renderSolidCube(1.0f);
glPopMatrix(); glPopMatrix();
glPopMatrix(); glPopMatrix();
} else { } else {
@ -86,6 +86,8 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]); glColor3ub(getColor()[RED_INDEX], getColor()[GREEN_INDEX], getColor()[BLUE_INDEX]);
Application::getInstance()->getDeferredLightingEffect()->bindSimpleProgram();
glPushMatrix(); glPushMatrix();
glTranslatef(position.x, position.y, position.z); glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation); glm::vec3 axis = glm::axis(rotation);
@ -99,6 +101,8 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
glPopMatrix(); glPopMatrix();
glPopMatrix(); glPopMatrix();
Application::getInstance()->getDeferredLightingEffect()->releaseSimpleProgram();
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
} }

View file

@ -125,7 +125,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]); glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]);
glPushMatrix(); glPushMatrix();
glTranslatef(position.x, position.y, position.z); glTranslatef(position.x, position.y, position.z);
glutWireCube(size); Application::getInstance()->getDeferredLightingEffect()->renderWireCube(size);
glPopMatrix(); glPopMatrix();
} }
} else { } else {
@ -133,7 +133,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]); glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]);
glPushMatrix(); glPushMatrix();
glTranslatef(position.x, position.y, position.z); glTranslatef(position.x, position.y, position.z);
glutWireCube(size); Application::getInstance()->getDeferredLightingEffect()->renderWireCube(size);
glPopMatrix(); glPopMatrix();
} }
} }
@ -142,7 +142,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]); glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]);
glPushMatrix(); glPushMatrix();
glTranslatef(position.x, position.y, position.z); glTranslatef(position.x, position.y, position.z);
glutWireCube(size); Application::getInstance()->getDeferredLightingEffect()->renderWireCube(size);
glPopMatrix(); glPopMatrix();
} }
} }

View file

@ -48,7 +48,7 @@ void RenderableSphereEntityItem::render(RenderArgs* args) {
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
glScalef(dimensions.x, dimensions.y, dimensions.z); glScalef(dimensions.x, dimensions.y, dimensions.z);
glutSolidSphere(0.5f, 15, 15); Application::getInstance()->getDeferredLightingEffect()->renderSolidSphere(0.5f, 15, 15);
glPopMatrix(); glPopMatrix();
glPopMatrix(); glPopMatrix();
}; };

View file

@ -11,6 +11,7 @@
#include <glm/gtx/quaternion.hpp> #include <glm/gtx/quaternion.hpp>
#include "Application.h"
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
#include "ParticleTreeRenderer.h" #include "ParticleTreeRenderer.h"
@ -112,7 +113,7 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg
if (wantDebugSphere) { if (wantDebugSphere) {
glPushMatrix(); glPushMatrix();
glTranslatef(position.x, position.y, position.z); glTranslatef(position.x, position.y, position.z);
glutWireSphere(radius, 15, 15); Application::getInstance()->getDeferredLightingEffect()->renderWireSphere(radius, 15, 15);
glPopMatrix(); glPopMatrix();
} }
@ -120,7 +121,7 @@ void ParticleTreeRenderer::renderElement(OctreeElement* element, RenderArgs* arg
} else { } else {
glPushMatrix(); glPushMatrix();
glTranslatef(position.x, position.y, position.z); glTranslatef(position.x, position.y, position.z);
glutSolidSphere(radius, 15, 15); Application::getInstance()->getDeferredLightingEffect()->renderSolidSphere(radius, 15, 15);
glPopMatrix(); glPopMatrix();
} }
} }

View file

@ -36,7 +36,7 @@ void AmbientOcclusionEffect::init() {
+ "shaders/ambient_occlusion.frag"); + "shaders/ambient_occlusion.frag");
_occlusionProgram->link(); _occlusionProgram->link();
// create the sample kernel: an array of spherically distributed offset vectors // create the sample kernel: an array of hemispherically distributed offset vectors
const int SAMPLE_KERNEL_SIZE = 16; const int SAMPLE_KERNEL_SIZE = 16;
QVector3D sampleKernel[SAMPLE_KERNEL_SIZE]; QVector3D sampleKernel[SAMPLE_KERNEL_SIZE];
for (int i = 0; i < SAMPLE_KERNEL_SIZE; i++) { for (int i = 0; i < SAMPLE_KERNEL_SIZE; i++) {
@ -51,7 +51,8 @@ void AmbientOcclusionEffect::init() {
_occlusionProgram->bind(); _occlusionProgram->bind();
_occlusionProgram->setUniformValue("depthTexture", 0); _occlusionProgram->setUniformValue("depthTexture", 0);
_occlusionProgram->setUniformValue("rotationTexture", 1); _occlusionProgram->setUniformValue("normalTexture", 1);
_occlusionProgram->setUniformValue("rotationTexture", 2);
_occlusionProgram->setUniformValueArray("sampleKernel", sampleKernel, SAMPLE_KERNEL_SIZE); _occlusionProgram->setUniformValueArray("sampleKernel", sampleKernel, SAMPLE_KERNEL_SIZE);
_occlusionProgram->setUniformValue("radius", 0.1f); _occlusionProgram->setUniformValue("radius", 0.1f);
_occlusionProgram->release(); _occlusionProgram->release();
@ -71,10 +72,10 @@ void AmbientOcclusionEffect::init() {
unsigned char rotationData[ROTATION_WIDTH * ROTATION_HEIGHT * ELEMENTS_PER_PIXEL]; unsigned char rotationData[ROTATION_WIDTH * ROTATION_HEIGHT * ELEMENTS_PER_PIXEL];
unsigned char* rotation = rotationData; unsigned char* rotation = rotationData;
for (int i = 0; i < ROTATION_WIDTH * ROTATION_HEIGHT; i++) { for (int i = 0; i < ROTATION_WIDTH * ROTATION_HEIGHT; i++) {
glm::vec3 randvec = glm::sphericalRand(1.0f); glm::vec3 vector = glm::sphericalRand(1.0f);
*rotation++ = ((randvec.x + 1.0f) / 2.0f) * 255.0f; *rotation++ = ((vector.x + 1.0f) / 2.0f) * 255.0f;
*rotation++ = ((randvec.y + 1.0f) / 2.0f) * 255.0f; *rotation++ = ((vector.y + 1.0f) / 2.0f) * 255.0f;
*rotation++ = ((randvec.z + 1.0f) / 2.0f) * 255.0f; *rotation++ = ((vector.z + 1.0f) / 2.0f) * 255.0f;
} }
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ROTATION_WIDTH, ROTATION_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, rotationData); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ROTATION_WIDTH, ROTATION_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, rotationData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@ -101,6 +102,9 @@ void AmbientOcclusionEffect::render() {
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID()); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID());
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryNormalTextureID());
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, _rotationTextureID); glBindTexture(GL_TEXTURE_2D, _rotationTextureID);
// render with the occlusion shader to the secondary/tertiary buffer // render with the occlusion shader to the secondary/tertiary buffer
@ -137,6 +141,10 @@ void AmbientOcclusionEffect::render() {
freeFBO->release(); freeFBO->release();
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
// now render secondary to primary with 4x4 blur // now render secondary to primary with 4x4 blur

View file

@ -0,0 +1,347 @@
//
// DeferredLightingEffect.cpp
// interface/src/renderer
//
// Created by Andrzej Kapolka on 9/11/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
//
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
#include "InterfaceConfig.h"
#include <QOpenGLFramebufferObject>
#include "Application.h"
#include "DeferredLightingEffect.h"
#include "RenderUtil.h"
void DeferredLightingEffect::init() {
_simpleProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/simple.vert");
_simpleProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/simple.frag");
_simpleProgram.link();
_simpleProgram.bind();
_glowIntensityLocation = _simpleProgram.uniformLocation("glowIntensity");
_simpleProgram.release();
loadLightProgram("shaders/directional_light.frag", false, _directionalLight, _directionalLightLocations);
loadLightProgram("shaders/directional_light_shadow_map.frag", false, _directionalLightShadowMap,
_directionalLightShadowMapLocations);
loadLightProgram("shaders/directional_light_cascaded_shadow_map.frag", false, _directionalLightCascadedShadowMap,
_directionalLightCascadedShadowMapLocations);
loadLightProgram("shaders/point_light.frag", true, _pointLight, _pointLightLocations);
loadLightProgram("shaders/spot_light.frag", true, _spotLight, _spotLightLocations);
}
void DeferredLightingEffect::bindSimpleProgram() {
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true, true);
_simpleProgram.bind();
_simpleProgram.setUniformValue(_glowIntensityLocation, Application::getInstance()->getGlowEffect()->getIntensity());
glDisable(GL_BLEND);
}
void DeferredLightingEffect::releaseSimpleProgram() {
glEnable(GL_BLEND);
_simpleProgram.release();
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false, false);
}
void DeferredLightingEffect::renderSolidSphere(float radius, int slices, int stacks) {
bindSimpleProgram();
glutSolidSphere(radius, slices, stacks);
releaseSimpleProgram();
}
void DeferredLightingEffect::renderWireSphere(float radius, int slices, int stacks) {
bindSimpleProgram();
glutWireSphere(radius, slices, stacks);
releaseSimpleProgram();
}
void DeferredLightingEffect::renderSolidCube(float size) {
bindSimpleProgram();
glutSolidCube(size);
releaseSimpleProgram();
}
void DeferredLightingEffect::renderWireCube(float size) {
bindSimpleProgram();
glutWireCube(size);
releaseSimpleProgram();
}
void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radius, const glm::vec3& ambient,
const glm::vec3& diffuse, const glm::vec3& specular, float constantAttenuation,
float linearAttenuation, float quadraticAttenuation) {
addSpotLight(position, radius, ambient, diffuse, specular, constantAttenuation, linearAttenuation, quadraticAttenuation);
}
void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& ambient,
const glm::vec3& diffuse, const glm::vec3& specular, float constantAttenuation, float linearAttenuation,
float quadraticAttenuation, const glm::vec3& direction, float exponent, float cutoff) {
if (exponent == 0.0f && cutoff == PI) {
PointLight light;
light.position = glm::vec4(position, 1.0f);
light.radius = radius;
light.ambient = glm::vec4(ambient, 1.0f);
light.diffuse = glm::vec4(diffuse, 1.0f);
light.specular = glm::vec4(specular, 1.0f);
light.constantAttenuation = constantAttenuation;
light.linearAttenuation = linearAttenuation;
_pointLights.append(light);
} else {
SpotLight light;
light.position = glm::vec4(position, 1.0f);
light.radius = radius;
light.ambient = glm::vec4(ambient, 1.0f);
light.diffuse = glm::vec4(diffuse, 1.0f);
light.specular = glm::vec4(specular, 1.0f);
light.constantAttenuation = constantAttenuation;
light.linearAttenuation = linearAttenuation;
light.direction = direction;
light.exponent = exponent;
light.cutoff = cutoff;
_spotLights.append(light);
}
}
void DeferredLightingEffect::prepare() {
// clear the normal and specular buffers
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, false);
glClear(GL_COLOR_BUFFER_BIT);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, false, true);
// clearing to zero alpha for specular causes problems on my Nvidia card; clear to lowest non-zero value instead
const float MAX_SPECULAR_EXPONENT = 128.0f;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f / MAX_SPECULAR_EXPONENT);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false, false);
}
void DeferredLightingEffect::render() {
// perform deferred lighting, rendering to free fbo
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glDisable(GL_BLEND);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glDisable(GL_COLOR_MATERIAL);
glDepthMask(false);
QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject();
primaryFBO->release();
QOpenGLFramebufferObject* freeFBO = Application::getInstance()->getGlowEffect()->getFreeFramebufferObject();
freeFBO->bind();
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, primaryFBO->texture());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryNormalTextureID());
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimarySpecularTextureID());
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID());
// get the viewport side (left, right, both)
int viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
const int VIEWPORT_X_INDEX = 0;
const int VIEWPORT_Y_INDEX = 1;
const int VIEWPORT_WIDTH_INDEX = 2;
const int VIEWPORT_HEIGHT_INDEX = 3;
float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width();
float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width();
float tMin = viewport[VIEWPORT_Y_INDEX] / (float)primaryFBO->height();
float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)primaryFBO->height();
ProgramObject* program = &_directionalLight;
const LightLocations* locations = &_directionalLightLocations;
bool shadowsEnabled = Menu::getInstance()->getShadowsEnabled();
if (shadowsEnabled) {
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID());
program = &_directionalLightShadowMap;
locations = &_directionalLightShadowMapLocations;
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
program = &_directionalLightCascadedShadowMap;
locations = &_directionalLightCascadedShadowMapLocations;
_directionalLightCascadedShadowMap.bind();
_directionalLightCascadedShadowMap.setUniform(locations->shadowDistances,
Application::getInstance()->getShadowDistances());
} else {
program->bind();
}
program->setUniformValue(locations->shadowScale,
1.0f / Application::getInstance()->getTextureCache()->getShadowFramebufferObject()->width());
} else {
program->bind();
}
float left, right, bottom, top, nearVal, farVal;
glm::vec4 nearClipPlane, farClipPlane;
Application::getInstance()->computeOffAxisFrustum(
left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane);
program->setUniformValue(locations->nearLocation, nearVal);
float depthScale = (farVal - nearVal) / farVal;
program->setUniformValue(locations->depthScale, depthScale);
float nearScale = -1.0f / nearVal;
float depthTexCoordScaleS = (right - left) * nearScale / sWidth;
float depthTexCoordScaleT = (top - bottom) * nearScale / tHeight;
float depthTexCoordOffsetS = left * nearScale - sMin * depthTexCoordScaleS;
float depthTexCoordOffsetT = bottom * nearScale - tMin * depthTexCoordScaleT;
program->setUniformValue(locations->depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT);
program->setUniformValue(locations->depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT);
renderFullscreenQuad(sMin, sMin + sWidth, tMin, tMin + tHeight);
program->release();
if (shadowsEnabled) {
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE3);
}
// additive blending
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glm::vec4 sCoefficients(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f);
glm::vec4 tCoefficients(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f);
glTexGenfv(GL_S, GL_OBJECT_PLANE, (const GLfloat*)&sCoefficients);
glTexGenfv(GL_T, GL_OBJECT_PLANE, (const GLfloat*)&tCoefficients);
if (!_pointLights.isEmpty()) {
_pointLight.bind();
_pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal);
_pointLight.setUniformValue(_pointLightLocations.depthScale, depthScale);
_pointLight.setUniformValue(_pointLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT);
_pointLight.setUniformValue(_pointLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT);
foreach (const PointLight& light, _pointLights) {
_pointLight.setUniformValue(_pointLightLocations.radius, light.radius);
glLightfv(GL_LIGHT1, GL_AMBIENT, (const GLfloat*)&light.ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, (const GLfloat*)&light.diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, (const GLfloat*)&light.specular);
glLightfv(GL_LIGHT1, GL_POSITION, (const GLfloat*)&light.position);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, light.constantAttenuation);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, light.linearAttenuation);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, light.quadraticAttenuation);
renderFullscreenQuad();
}
_pointLights.clear();
_pointLight.release();
}
if (!_spotLights.isEmpty()) {
_spotLight.bind();
_spotLight.setUniformValue(_spotLightLocations.nearLocation, nearVal);
_spotLight.setUniformValue(_spotLightLocations.depthScale, depthScale);
_spotLight.setUniformValue(_spotLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT);
_spotLight.setUniformValue(_spotLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT);
foreach (const SpotLight& light, _spotLights) {
_spotLight.setUniformValue(_spotLightLocations.radius, light.radius);
glLightfv(GL_LIGHT1, GL_AMBIENT, (const GLfloat*)&light.ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, (const GLfloat*)&light.diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, (const GLfloat*)&light.specular);
glLightfv(GL_LIGHT1, GL_POSITION, (const GLfloat*)&light.position);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, light.constantAttenuation);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, light.linearAttenuation);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, light.quadraticAttenuation);
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, (const GLfloat*)&light.direction);
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, light.exponent);
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, glm::degrees(light.cutoff));
renderFullscreenQuad();
}
_spotLights.clear();
_spotLight.release();
}
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, 0);
freeFBO->release();
// now transfer the lit region to the primary fbo
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
glColorMask(true, true, true, false);
primaryFBO->bind();
glBindTexture(GL_TEXTURE_2D, freeFBO->texture());
glEnable(GL_TEXTURE_2D);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
renderFullscreenQuad(sMin, sMin + sWidth, tMin, tMin + tHeight);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glColorMask(true, true, true, true);
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_DEPTH_TEST);
glDepthMask(true);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
// now render the objects we held back until after deferred lighting
foreach (PostLightingRenderable* renderable, _postLightingRenderables) {
renderable->renderPostLighting();
}
_postLightingRenderables.clear();
}
void DeferredLightingEffect::loadLightProgram(const char* name, bool limited, ProgramObject& program, LightLocations& locations) {
program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
(limited ? "shaders/deferred_light_limited.vert" : "shaders/deferred_light.vert"));
program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + name);
program.link();
program.bind();
program.setUniformValue("diffuseMap", 0);
program.setUniformValue("normalMap", 1);
program.setUniformValue("specularMap", 2);
program.setUniformValue("depthMap", 3);
program.setUniformValue("shadowMap", 4);
locations.shadowDistances = program.uniformLocation("shadowDistances");
locations.shadowScale = program.uniformLocation("shadowScale");
locations.nearLocation = program.uniformLocation("near");
locations.depthScale = program.uniformLocation("depthScale");
locations.depthTexCoordOffset = program.uniformLocation("depthTexCoordOffset");
locations.depthTexCoordScale = program.uniformLocation("depthTexCoordScale");
locations.radius = program.uniformLocation("radius");
program.release();
}

View file

@ -0,0 +1,127 @@
//
// DeferredLightingEffect.h
// interface/src/renderer
//
// Created by Andrzej Kapolka on 9/11/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
//
#ifndef hifi_DeferredLightingEffect_h
#define hifi_DeferredLightingEffect_h
#include <QVector>
#include <SharedUtil.h>
#include "ProgramObject.h"
class PostLightingRenderable;
/// Handles deferred lighting for the bits that require it (voxels, metavoxels...)
class DeferredLightingEffect {
public:
void init();
/// Returns a reference to a simple program suitable for rendering static
/// untextured geometry (such as that generated by glutSolidSphere, etc.)
ProgramObject& getSimpleProgram() { return _simpleProgram; }
/// Sets up the state necessary to render static untextured geometry with the simple program.
void bindSimpleProgram();
/// Tears down the state necessary to render static untextured geometry with the simple program.
void releaseSimpleProgram();
//// Renders a solid sphere with the simple program.
void renderSolidSphere(float radius, int slices, int stacks);
//// Renders a wireframe sphere with the simple program.
void renderWireSphere(float radius, int slices, int stacks);
//// Renders a solid cube with the simple program.
void renderSolidCube(float size);
//// Renders a wireframe cube with the simple program.
void renderWireCube(float size);
/// Adds a point light to render for the current frame.
void addPointLight(const glm::vec3& position, float radius, const glm::vec3& ambient = glm::vec3(0.0f, 0.0f, 0.0f),
const glm::vec3& diffuse = glm::vec3(1.0f, 1.0f, 1.0f), const glm::vec3& specular = glm::vec3(1.0f, 1.0f, 1.0f),
float constantAttenuation = 1.0f, float linearAttenuation = 0.0f, float quadraticAttenuation = 0.0f);
/// Adds a spot light to render for the current frame.
void addSpotLight(const glm::vec3& position, float radius, const glm::vec3& ambient = glm::vec3(0.0f, 0.0f, 0.0f),
const glm::vec3& diffuse = glm::vec3(1.0f, 1.0f, 1.0f), const glm::vec3& specular = glm::vec3(1.0f, 1.0f, 1.0f),
float constantAttenuation = 1.0f, float linearAttenuation = 0.0f, float quadraticAttenuation = 0.0f,
const glm::vec3& direction = glm::vec3(0.0f, 0.0f, -1.0f), float exponent = 0.0f, float cutoff = PI);
/// Adds an object to render after performing the deferred lighting for the current frame (e.g., a translucent object).
void addPostLightingRenderable(PostLightingRenderable* renderable) { _postLightingRenderables.append(renderable); }
void prepare();
void render();
private:
class LightLocations {
public:
int shadowDistances;
int shadowScale;
int nearLocation;
int depthScale;
int depthTexCoordOffset;
int depthTexCoordScale;
int radius;
};
static void loadLightProgram(const char* name, bool limited, ProgramObject& program, LightLocations& locations);
ProgramObject _simpleProgram;
int _glowIntensityLocation;
ProgramObject _directionalLight;
LightLocations _directionalLightLocations;
ProgramObject _directionalLightShadowMap;
LightLocations _directionalLightShadowMapLocations;
ProgramObject _directionalLightCascadedShadowMap;
LightLocations _directionalLightCascadedShadowMapLocations;
ProgramObject _pointLight;
LightLocations _pointLightLocations;
ProgramObject _spotLight;
LightLocations _spotLightLocations;
class PointLight {
public:
glm::vec4 position;
float radius;
glm::vec4 ambient;
glm::vec4 diffuse;
glm::vec4 specular;
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
};
class SpotLight : public PointLight {
public:
glm::vec3 direction;
float exponent;
float cutoff;
};
QVector<PointLight> _pointLights;
QVector<SpotLight> _spotLights;
QVector<PostLightingRenderable*> _postLightingRenderables;
};
/// Simple interface for objects that require something to be rendered after deferred lighting.
class PostLightingRenderable {
public:
virtual void renderPostLighting() = 0;
};
#endif // hifi_DeferredLightingEffect_h

View file

@ -43,6 +43,9 @@ public:
/// Stops using the glow effect. /// Stops using the glow effect.
void end(); void end();
/// Returns the current glow intensity.
float getIntensity() const { return _intensity; }
/// Renders the glow effect. To be called after rendering the scene. /// Renders the glow effect. To be called after rendering the scene.
/// \param toTexture whether to render to a texture, rather than to the frame buffer /// \param toTexture whether to render to a texture, rather than to the frame buffer
/// \return the framebuffer object to which we rendered, or NULL if to the frame buffer /// \return the framebuffer object to which we rendered, or NULL if to the frame buffer

View file

@ -11,7 +11,6 @@
#include <QMetaType> #include <QMetaType>
#include <QRunnable> #include <QRunnable>
#include <QScriptEngine>
#include <QThreadPool> #include <QThreadPool>
#include <glm/gtx/transform.hpp> #include <glm/gtx/transform.hpp>
@ -20,7 +19,6 @@
#include <CapsuleShape.h> #include <CapsuleShape.h>
#include <GeometryUtil.h> #include <GeometryUtil.h>
#include <PhysicsEntity.h> #include <PhysicsEntity.h>
#include <RegisteredMetaTypes.h>
#include <ShapeCollider.h> #include <ShapeCollider.h>
#include <SphereShape.h> #include <SphereShape.h>
@ -33,23 +31,6 @@ static int modelPointerTypeId = qRegisterMetaType<QPointer<Model> >();
static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<QWeakPointer<NetworkGeometry> >(); static int weakNetworkGeometryPointerTypeId = qRegisterMetaType<QWeakPointer<NetworkGeometry> >();
static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >(); static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
static QScriptValue localLightToScriptValue(QScriptEngine* engine, const Model::LocalLight& light) {
QScriptValue object = engine->newObject();
object.setProperty("direction", vec3toScriptValue(engine, light.direction));
object.setProperty("color", vec3toScriptValue(engine, light.color));
return object;
}
static void localLightFromScriptValue(const QScriptValue& value, Model::LocalLight& light) {
vec3FromScriptValue(value.property("direction"), light.direction);
vec3FromScriptValue(value.property("color"), light.color);
}
void Model::registerMetaTypes(QScriptEngine* engine) {
qScriptRegisterMetaType(engine, localLightToScriptValue, localLightFromScriptValue);
qScriptRegisterSequenceMetaType<QVector<Model::LocalLight> >(engine);
}
Model::Model(QObject* parent) : Model::Model(QObject* parent) :
QObject(parent), QObject(parent),
_scale(1.0f, 1.0f, 1.0f), _scale(1.0f, 1.0f, 1.0f),
@ -77,16 +58,7 @@ ProgramObject Model::_program;
ProgramObject Model::_normalMapProgram; ProgramObject Model::_normalMapProgram;
ProgramObject Model::_specularMapProgram; ProgramObject Model::_specularMapProgram;
ProgramObject Model::_normalSpecularMapProgram; ProgramObject Model::_normalSpecularMapProgram;
ProgramObject Model::_translucentProgram;
ProgramObject Model::_shadowMapProgram;
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::_shadowProgram;
@ -94,16 +66,7 @@ ProgramObject Model::_skinProgram;
ProgramObject Model::_skinNormalMapProgram; ProgramObject Model::_skinNormalMapProgram;
ProgramObject Model::_skinSpecularMapProgram; ProgramObject Model::_skinSpecularMapProgram;
ProgramObject Model::_skinNormalSpecularMapProgram; ProgramObject Model::_skinNormalSpecularMapProgram;
ProgramObject Model::_skinTranslucentProgram;
ProgramObject Model::_skinShadowMapProgram;
ProgramObject Model::_skinShadowNormalMapProgram;
ProgramObject Model::_skinShadowSpecularMapProgram;
ProgramObject Model::_skinShadowNormalSpecularMapProgram;
ProgramObject Model::_skinCascadedShadowMapProgram;
ProgramObject Model::_skinCascadedShadowNormalMapProgram;
ProgramObject Model::_skinCascadedShadowSpecularMapProgram;
ProgramObject Model::_skinCascadedShadowNormalSpecularMapProgram;
ProgramObject Model::_skinShadowProgram; ProgramObject Model::_skinShadowProgram;
@ -111,28 +74,14 @@ Model::Locations Model::_locations;
Model::Locations Model::_normalMapLocations; Model::Locations Model::_normalMapLocations;
Model::Locations Model::_specularMapLocations; Model::Locations Model::_specularMapLocations;
Model::Locations Model::_normalSpecularMapLocations; Model::Locations Model::_normalSpecularMapLocations;
Model::Locations Model::_shadowMapLocations; Model::Locations Model::_translucentLocations;
Model::Locations Model::_shadowNormalMapLocations;
Model::Locations Model::_shadowSpecularMapLocations;
Model::Locations Model::_shadowNormalSpecularMapLocations;
Model::Locations Model::_cascadedShadowMapLocations;
Model::Locations Model::_cascadedShadowNormalMapLocations;
Model::Locations Model::_cascadedShadowSpecularMapLocations;
Model::Locations Model::_cascadedShadowNormalSpecularMapLocations;
Model::SkinLocations Model::_skinLocations; Model::SkinLocations Model::_skinLocations;
Model::SkinLocations Model::_skinNormalMapLocations; Model::SkinLocations Model::_skinNormalMapLocations;
Model::SkinLocations Model::_skinSpecularMapLocations; Model::SkinLocations Model::_skinSpecularMapLocations;
Model::SkinLocations Model::_skinNormalSpecularMapLocations; Model::SkinLocations Model::_skinNormalSpecularMapLocations;
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; Model::SkinLocations Model::_skinShadowLocations;
Model::SkinLocations Model::_skinTranslucentLocations;
void Model::setScale(const glm::vec3& scale) { void Model::setScale(const glm::vec3& scale) {
setScaleInternal(scale); setScaleInternal(scale);
@ -164,23 +113,18 @@ void Model::setOffset(const glm::vec3& offset) {
_snappedToRegistrationPoint = false; _snappedToRegistrationPoint = false;
} }
void Model::initProgram(ProgramObject& program, Model::Locations& locations, void Model::initProgram(ProgramObject& program, Model::Locations& locations, int specularTextureUnit) {
int specularTextureUnit, int shadowTextureUnit) {
program.bind(); program.bind();
locations.tangent = program.attributeLocation("tangent"); locations.tangent = program.attributeLocation("tangent");
locations.shadowDistances = program.uniformLocation("shadowDistances"); locations.alphaThreshold = program.uniformLocation("alphaThreshold");
locations.localLightColors = program.uniformLocation("localLightColors");
locations.localLightDirections = program.uniformLocation("localLightDirections");
program.setUniformValue("diffuseMap", 0); program.setUniformValue("diffuseMap", 0);
program.setUniformValue("normalMap", 1); program.setUniformValue("normalMap", 1);
program.setUniformValue("specularMap", specularTextureUnit); program.setUniformValue("specularMap", specularTextureUnit);
program.setUniformValue("shadowMap", shadowTextureUnit);
program.release(); program.release();
} }
void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations, int specularTextureUnit) {
int specularTextureUnit, int shadowTextureUnit) { initProgram(program, locations, specularTextureUnit);
initProgram(program, locations, specularTextureUnit, shadowTextureUnit);
program.bind(); program.bind();
locations.clusterMatrices = program.uniformLocation("clusterMatrices"); locations.clusterMatrices = program.uniformLocation("clusterMatrices");
@ -253,78 +197,19 @@ void Model::init() {
initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations, 2); initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations, 2);
_translucentProgram.addShaderFromSourceFile(QGLShader::Vertex,
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model.vert");
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
"shaders/model_shadow_map.frag");
_shadowMapProgram.link();
initProgram(_shadowMapProgram, _shadowMapLocations);
_shadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/model_normal_map.vert");
_shadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/model_shadow_normal_map.frag");
_shadowNormalMapProgram.link();
initProgram(_shadowNormalMapProgram, _shadowNormalMapLocations, 1, 2);
_shadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/model.vert"); Application::resourcesPath() + "shaders/model.vert");
_shadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment, _translucentProgram.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/model_shadow_specular_map.frag"); Application::resourcesPath() + "shaders/model_translucent.frag");
_shadowSpecularMapProgram.link(); _translucentProgram.link();
initProgram(_shadowSpecularMapProgram, _shadowSpecularMapLocations, 1, 2);
_shadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/model_normal_map.vert");
_shadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/model_shadow_normal_specular_map.frag");
_shadowNormalSpecularMapProgram.link();
initProgram(_shadowNormalSpecularMapProgram, _shadowNormalSpecularMapLocations, 2, 3);
_cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
"shaders/model.vert");
_cascadedShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
"shaders/model_cascaded_shadow_map.frag");
_cascadedShadowMapProgram.link();
initProgram(_cascadedShadowMapProgram, _cascadedShadowMapLocations);
_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();
initProgram(_cascadedShadowNormalMapProgram, _cascadedShadowNormalMapLocations, 1, 2);
_cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/model.vert");
_cascadedShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/model_cascaded_shadow_specular_map.frag");
_cascadedShadowSpecularMapProgram.link();
initProgram(_cascadedShadowSpecularMapProgram, _cascadedShadowSpecularMapLocations, 1, 2);
_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();
initProgram(_cascadedShadowNormalSpecularMapProgram, _cascadedShadowNormalSpecularMapLocations, 2, 3);
initProgram(_translucentProgram, _translucentLocations);
_shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert"); _shadowProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/model_shadow.vert");
_shadowProgram.addShaderFromSourceFile(QGLShader::Fragment, _shadowProgram.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/model_shadow.frag"); Application::resourcesPath() + "shaders/model_shadow.frag");
_shadowProgram.link(); _shadowProgram.link();
_skinProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert"); _skinProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/skin_model.vert");
_skinProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag"); _skinProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + "shaders/model.frag");
_skinProgram.link(); _skinProgram.link();
@ -355,73 +240,6 @@ void Model::init() {
initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations, 2); initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations, 2);
_skinShadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() +
"shaders/skin_model.vert");
_skinShadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() +
"shaders/model_shadow_map.frag");
_skinShadowMapProgram.link();
initSkinProgram(_skinShadowMapProgram, _skinShadowMapLocations);
_skinShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/skin_model_normal_map.vert");
_skinShadowNormalMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/model_shadow_normal_map.frag");
_skinShadowNormalMapProgram.link();
initSkinProgram(_skinShadowNormalMapProgram, _skinShadowNormalMapLocations, 1, 2);
_skinShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/skin_model.vert");
_skinShadowSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/model_shadow_specular_map.frag");
_skinShadowSpecularMapProgram.link();
initSkinProgram(_skinShadowSpecularMapProgram, _skinShadowSpecularMapLocations, 1, 2);
_skinShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/skin_model_normal_map.vert");
_skinShadowNormalSpecularMapProgram.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/model_shadow_normal_specular_map.frag");
_skinShadowNormalSpecularMapProgram.link();
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, _skinShadowProgram.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/skin_model_shadow.vert"); Application::resourcesPath() + "shaders/skin_model_shadow.vert");
_skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment, _skinShadowProgram.addShaderFromSourceFile(QGLShader::Fragment,
@ -429,6 +247,14 @@ void Model::init() {
_skinShadowProgram.link(); _skinShadowProgram.link();
initSkinProgram(_skinShadowProgram, _skinShadowLocations); initSkinProgram(_skinShadowProgram, _skinShadowLocations);
_skinTranslucentProgram.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/skin_model.vert");
_skinTranslucentProgram.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/model_translucent.frag");
_skinTranslucentProgram.link();
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
} }
} }
@ -558,7 +384,7 @@ void Model::setJointStates(QVector<JointState> states) {
_boundingRadius = radius; _boundingRadius = radius;
} }
bool Model::render(float alpha, RenderMode mode, bool receiveShadows) { bool Model::render(float alpha, RenderMode mode) {
// render the attachments // render the attachments
foreach (Model* attachment, _attachments) { foreach (Model* attachment, _attachments) {
attachment->render(alpha, mode); attachment->render(alpha, mode);
@ -588,34 +414,42 @@ bool Model::render(float alpha, RenderMode mode, bool receiveShadows) {
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
if (mode == SHADOW_RENDER_MODE) { if (mode == SHADOW_RENDER_MODE) {
glCullFace(GL_FRONT); glCullFace(GL_FRONT);
} else if (mode == DEFAULT_RENDER_MODE) {
// update the local lights
for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) {
if (i < _localLights.size()) {
_localLightDirections[i] = glm::normalize(Application::getInstance()->getUntranslatedViewMatrix() *
glm::vec4(_rotation * _localLights.at(i).direction, 0.0f));
} else {
_localLightColors[i] = glm::vec4();
}
}
} }
} }
// render opaque meshes with alpha testing // render opaque meshes with alpha testing
glDisable(GL_BLEND);
glEnable(GL_ALPHA_TEST); glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.5f * alpha);
receiveShadows &= Menu::getInstance()->getShadowsEnabled(); if (mode == SHADOW_RENDER_MODE) {
renderMeshes(mode, false, receiveShadows); glAlphaFunc(GL_EQUAL, 0.0f);
}
glDisable(GL_ALPHA_TEST); Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(
mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE,
mode == DEFAULT_RENDER_MODE || mode == NORMAL_RENDER_MODE,
mode == DEFAULT_RENDER_MODE);
renderMeshes(mode, false);
// render translucent meshes afterwards // render translucent meshes afterwards
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(false, true, true);
renderMeshes(mode, true, 0.75f);
renderMeshes(mode, true, receiveShadows); glDisable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDepthMask(false);
glDepthFunc(GL_LEQUAL);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true);
if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) {
renderMeshes(mode, true, 0.0f);
}
glDepthMask(true);
glDepthFunc(GL_LESS);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
if (mode == SHADOW_RENDER_MODE) { if (mode == SHADOW_RENDER_MODE) {
@ -1358,12 +1192,11 @@ void Model::deleteGeometry() {
_blendedBlendshapeCoefficients.clear(); _blendedBlendshapeCoefficients.clear();
} }
void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows) { void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold) {
updateVisibleJointStates(); updateVisibleJointStates();
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes(); const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
bool cascadedShadows = Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows);
for (int i = 0; i < networkMeshes.size(); i++) { for (int i = 0; i < networkMeshes.size(); i++) {
// exit early if the translucency doesn't match what we're drawing // exit early if the translucency doesn't match what we're drawing
const NetworkMesh& networkMesh = networkMeshes.at(i); const NetworkMesh& networkMesh = networkMeshes.at(i);
@ -1387,48 +1220,25 @@ void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows)
ProgramObject* skinProgram = &_skinProgram; ProgramObject* skinProgram = &_skinProgram;
SkinLocations* skinLocations = &_skinLocations; SkinLocations* skinLocations = &_skinLocations;
GLenum specularTextureUnit = 0; GLenum specularTextureUnit = 0;
GLenum shadowTextureUnit = 0;
if (mode == SHADOW_RENDER_MODE) { if (mode == SHADOW_RENDER_MODE) {
program = &_shadowProgram; program = &_shadowProgram;
skinProgram = &_skinShadowProgram; skinProgram = &_skinShadowProgram;
skinLocations = &_skinShadowLocations; skinLocations = &_skinShadowLocations;
} else if (translucent && alphaThreshold == 0.0f) {
program = &_translucentProgram;
locations = &_translucentLocations;
skinProgram = &_skinTranslucentProgram;
skinLocations = &_skinTranslucentLocations;
} else if (!mesh.tangents.isEmpty()) { } else if (!mesh.tangents.isEmpty()) {
if (mesh.hasSpecularTexture()) { if (mesh.hasSpecularTexture()) {
if (receiveShadows) {
if (cascadedShadows) {
program = &_cascadedShadowNormalSpecularMapProgram;
locations = &_cascadedShadowNormalSpecularMapLocations;
skinProgram = &_skinCascadedShadowNormalSpecularMapProgram;
skinLocations = &_skinCascadedShadowNormalSpecularMapLocations;
} else {
program = &_shadowNormalSpecularMapProgram;
locations = &_shadowNormalSpecularMapLocations;
skinProgram = &_skinShadowNormalSpecularMapProgram;
skinLocations = &_skinShadowNormalSpecularMapLocations;
}
shadowTextureUnit = GL_TEXTURE3;
} else {
program = &_normalSpecularMapProgram; program = &_normalSpecularMapProgram;
locations = &_normalSpecularMapLocations; locations = &_normalSpecularMapLocations;
skinProgram = &_skinNormalSpecularMapProgram; skinProgram = &_skinNormalSpecularMapProgram;
skinLocations = &_skinNormalSpecularMapLocations; skinLocations = &_skinNormalSpecularMapLocations;
}
specularTextureUnit = GL_TEXTURE2; specularTextureUnit = GL_TEXTURE2;
} else if (receiveShadows) {
if (cascadedShadows) {
program = &_cascadedShadowNormalMapProgram;
locations = &_cascadedShadowNormalMapLocations;
skinProgram = &_skinCascadedShadowNormalMapProgram;
skinLocations = &_skinCascadedShadowNormalMapLocations;
} else {
program = &_shadowNormalMapProgram;
locations = &_shadowNormalMapLocations;
skinProgram = &_skinShadowNormalMapProgram;
skinLocations = &_skinShadowNormalMapLocations;
}
shadowTextureUnit = GL_TEXTURE2;
} else { } else {
program = &_normalMapProgram; program = &_normalMapProgram;
locations = &_normalMapLocations; locations = &_normalMapLocations;
@ -1436,40 +1246,11 @@ void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows)
skinLocations = &_skinNormalMapLocations; skinLocations = &_skinNormalMapLocations;
} }
} else if (mesh.hasSpecularTexture()) { } else if (mesh.hasSpecularTexture()) {
if (receiveShadows) {
if (cascadedShadows) {
program = &_cascadedShadowSpecularMapProgram;
locations = &_cascadedShadowSpecularMapLocations;
skinProgram = &_skinCascadedShadowSpecularMapProgram;
skinLocations = &_skinCascadedShadowSpecularMapLocations;
} else {
program = &_shadowSpecularMapProgram;
locations = &_shadowSpecularMapLocations;
skinProgram = &_skinShadowSpecularMapProgram;
skinLocations = &_skinShadowSpecularMapLocations;
}
shadowTextureUnit = GL_TEXTURE2;
} else {
program = &_specularMapProgram; program = &_specularMapProgram;
locations = &_specularMapLocations; locations = &_specularMapLocations;
skinProgram = &_skinSpecularMapProgram; skinProgram = &_skinSpecularMapProgram;
skinLocations = &_skinSpecularMapLocations; skinLocations = &_skinSpecularMapLocations;
}
specularTextureUnit = GL_TEXTURE1; specularTextureUnit = GL_TEXTURE1;
} else if (receiveShadows) {
if (cascadedShadows) {
program = &_cascadedShadowMapProgram;
locations = &_cascadedShadowMapLocations;
skinProgram = &_skinCascadedShadowMapProgram;
skinLocations = &_skinCascadedShadowMapLocations;
} else {
program = &_shadowMapProgram;
locations = &_shadowMapLocations;
skinProgram = &_skinShadowMapProgram;
skinLocations = &_skinShadowMapLocations;
}
shadowTextureUnit = GL_TEXTURE1;
} }
const MeshState& state = _meshStates.at(i); const MeshState& state = _meshStates.at(i);
@ -1497,13 +1278,8 @@ void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows)
glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]);
program->bind(); program->bind();
} }
if (cascadedShadows) {
activeProgram->setUniform(activeLocations->shadowDistances, Application::getInstance()->getShadowDistances()); activeProgram->setUniformValue(activeLocations->alphaThreshold, alphaThreshold);
}
if (mode != SHADOW_RENDER_MODE) {
activeProgram->setUniformValueArray(activeLocations->localLightDirections,
(const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4);
}
if (mesh.blendshapes.isEmpty()) { if (mesh.blendshapes.isEmpty()) {
if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) {
@ -1550,18 +1326,19 @@ void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows)
} else { } else {
glm::vec4 diffuse = glm::vec4(part.diffuseColor, part.opacity); glm::vec4 diffuse = glm::vec4(part.diffuseColor, part.opacity);
glm::vec4 specular = glm::vec4(part.specularColor, part.opacity); if (!(translucent && alphaThreshold == 0.0f)) {
float emissive = (part.emissiveColor.r + part.emissiveColor.g + part.emissiveColor.b) / 3.0f;
diffuse.a = qMax(Application::getInstance()->getGlowEffect()->getIntensity(), emissive);
glAlphaFunc(GL_EQUAL, diffuse.a);
diffuse = glm::vec4(qMax(diffuse.r, part.emissiveColor.r), qMax(diffuse.g, part.emissiveColor.g),
qMax(diffuse.b, part.emissiveColor.b), diffuse.a);
}
glm::vec4 specular = glm::vec4(part.specularColor, 1.0f);
glMaterialfv(GL_FRONT, GL_AMBIENT, (const float*)&diffuse); glMaterialfv(GL_FRONT, GL_AMBIENT, (const float*)&diffuse);
glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse); glMaterialfv(GL_FRONT, GL_DIFFUSE, (const float*)&diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular); glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular);
glMaterialf(GL_FRONT, GL_SHININESS, part.shininess); glMaterialf(GL_FRONT, GL_SHININESS, part.shininess);
for (int k = 0; k < qMin(MAX_LOCAL_LIGHTS, _localLights.size()); k++) {
_localLightColors[k] = glm::vec4(_localLights.at(k).color, 1.0f) * diffuse;
}
activeProgram->setUniformValueArray(activeLocations->localLightColors,
(const GLfloat*)_localLightColors, MAX_LOCAL_LIGHTS, 4);
Texture* diffuseMap = networkPart.diffuseTexture.data(); Texture* diffuseMap = networkPart.diffuseTexture.data();
if (mesh.isEye && diffuseMap) { if (mesh.isEye && diffuseMap) {
diffuseMap = (_dilatedTextures[i][j] = diffuseMap = (_dilatedTextures[i][j] =
@ -1570,7 +1347,6 @@ void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows)
glBindTexture(GL_TEXTURE_2D, !diffuseMap ? glBindTexture(GL_TEXTURE_2D, !diffuseMap ?
Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID()); Application::getInstance()->getTextureCache()->getWhiteTextureID() : diffuseMap->getID());
if (!mesh.tangents.isEmpty()) { if (!mesh.tangents.isEmpty()) {
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
Texture* normalMap = networkPart.normalTexture.data(); Texture* normalMap = networkPart.normalTexture.data();
@ -1586,12 +1362,6 @@ void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows)
Application::getInstance()->getTextureCache()->getWhiteTextureID() : specularMap->getID()); Application::getInstance()->getTextureCache()->getWhiteTextureID() : specularMap->getID());
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
} }
if (shadowTextureUnit) {
glActiveTexture(shadowTextureUnit);
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID());
glActiveTexture(GL_TEXTURE0);
}
} }
glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset); glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, part.quadIndices.size(), GL_UNSIGNED_INT, (void*)offset);
offset += part.quadIndices.size() * sizeof(int); offset += part.quadIndices.size() * sizeof(int);
@ -1621,12 +1391,6 @@ void Model::renderMeshes(RenderMode mode, bool translucent, bool receiveShadows)
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
} }
if (shadowTextureUnit) {
glActiveTexture(shadowTextureUnit);
glBindTexture(GL_TEXTURE_2D, 0);
glActiveTexture(GL_TEXTURE0);
}
if (state.clusterMatrices.size() > 1) { if (state.clusterMatrices.size() > 1) {
skinProgram->disableAttributeArray(skinLocations->clusterIndices); skinProgram->disableAttributeArray(skinLocations->clusterIndices);
skinProgram->disableAttributeArray(skinLocations->clusterWeights); skinProgram->disableAttributeArray(skinLocations->clusterWeights);

View file

@ -34,17 +34,12 @@ class Shape;
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer; typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer; typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
const int MAX_LOCAL_LIGHTS = 2;
/// A generic 3D model displaying geometry loaded from a URL. /// A generic 3D model displaying geometry loaded from a URL.
class Model : public QObject, public PhysicsEntity { class Model : public QObject, public PhysicsEntity {
Q_OBJECT Q_OBJECT
public: public:
/// Registers the script types associated with models.
static void registerMetaTypes(QScriptEngine* engine);
Model(QObject* parent = NULL); Model(QObject* parent = NULL);
virtual ~Model(); virtual ~Model();
@ -89,7 +84,7 @@ public:
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE }; enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE };
bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE, bool receiveShadows = true); bool render(float alpha = 1.0f, RenderMode mode = DEFAULT_RENDER_MODE);
/// Sets the URL of the model to render. /// Sets the URL of the model to render.
/// \param fallback the URL of a fallback model to render if the requested model fails to load /// \param fallback the URL of a fallback model to render if the requested model fails to load
@ -171,15 +166,6 @@ public:
void setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeometry>& geometry, void setBlendedVertices(int blendNumber, const QWeakPointer<NetworkGeometry>& geometry,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals); const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
class LocalLight {
public:
glm::vec3 color;
glm::vec3 direction;
};
void setLocalLights(const QVector<LocalLight>& localLights) { _localLights = localLights; }
const QVector<LocalLight>& getLocalLights() const { return _localLights; }
void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; } void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; }
QVector<JointState>& getJointStates() { return _jointStates; } QVector<JointState>& getJointStates() { return _jointStates; }
@ -203,8 +189,6 @@ protected:
bool _showTrueJointTransforms; bool _showTrueJointTransforms;
QVector<LocalLight> _localLights;
QVector<JointState> _jointStates; QVector<JointState> _jointStates;
class MeshState { class MeshState {
@ -258,7 +242,7 @@ private:
void applyNextGeometry(); void applyNextGeometry();
void deleteGeometry(); void deleteGeometry();
void renderMeshes(RenderMode mode, bool translucent, bool receiveShadows); void renderMeshes(RenderMode mode, bool translucent, float alphaThreshold = 0.5f);
QVector<JointState> createJointStates(const FBXGeometry& geometry); QVector<JointState> createJointStates(const FBXGeometry& geometry);
void initJointTransforms(); void initJointTransforms();
@ -284,9 +268,6 @@ private:
QList<AnimationHandlePointer> _runningAnimations; QList<AnimationHandlePointer> _runningAnimations;
glm::vec4 _localLightColors[MAX_LOCAL_LIGHTS];
glm::vec4 _localLightDirections[MAX_LOCAL_LIGHTS];
QVector<float> _blendedBlendshapeCoefficients; QVector<float> _blendedBlendshapeCoefficients;
int _blendNumber; int _blendNumber;
int _appliedBlendNumber; int _appliedBlendNumber;
@ -295,16 +276,7 @@ private:
static ProgramObject _normalMapProgram; static ProgramObject _normalMapProgram;
static ProgramObject _specularMapProgram; static ProgramObject _specularMapProgram;
static ProgramObject _normalSpecularMapProgram; static ProgramObject _normalSpecularMapProgram;
static ProgramObject _translucentProgram;
static ProgramObject _shadowMapProgram;
static ProgramObject _shadowNormalMapProgram;
static ProgramObject _shadowSpecularMapProgram;
static ProgramObject _shadowNormalSpecularMapProgram;
static ProgramObject _cascadedShadowMapProgram;
static ProgramObject _cascadedShadowNormalMapProgram;
static ProgramObject _cascadedShadowSpecularMapProgram;
static ProgramObject _cascadedShadowNormalSpecularMapProgram;
static ProgramObject _shadowProgram; static ProgramObject _shadowProgram;
@ -312,54 +284,26 @@ private:
static ProgramObject _skinNormalMapProgram; static ProgramObject _skinNormalMapProgram;
static ProgramObject _skinSpecularMapProgram; static ProgramObject _skinSpecularMapProgram;
static ProgramObject _skinNormalSpecularMapProgram; static ProgramObject _skinNormalSpecularMapProgram;
static ProgramObject _skinTranslucentProgram;
static ProgramObject _skinShadowMapProgram;
static ProgramObject _skinShadowNormalMapProgram;
static ProgramObject _skinShadowSpecularMapProgram;
static ProgramObject _skinShadowNormalSpecularMapProgram;
static ProgramObject _skinCascadedShadowMapProgram;
static ProgramObject _skinCascadedShadowNormalMapProgram;
static ProgramObject _skinCascadedShadowSpecularMapProgram;
static ProgramObject _skinCascadedShadowNormalSpecularMapProgram;
static ProgramObject _skinShadowProgram; static ProgramObject _skinShadowProgram;
static int _normalMapTangentLocation; static int _normalMapTangentLocation;
static int _normalSpecularMapTangentLocation; 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 Locations { class Locations {
public: public:
int localLightColors;
int localLightDirections;
int tangent; int tangent;
int shadowDistances; int alphaThreshold;
}; };
static Locations _locations; static Locations _locations;
static Locations _normalMapLocations; static Locations _normalMapLocations;
static Locations _specularMapLocations; static Locations _specularMapLocations;
static Locations _normalSpecularMapLocations; static Locations _normalSpecularMapLocations;
static Locations _shadowMapLocations; static Locations _translucentLocations;
static Locations _shadowNormalMapLocations;
static Locations _shadowSpecularMapLocations;
static Locations _shadowNormalSpecularMapLocations;
static Locations _cascadedShadowMapLocations;
static Locations _cascadedShadowNormalMapLocations;
static Locations _cascadedShadowSpecularMapLocations;
static Locations _cascadedShadowNormalSpecularMapLocations;
static void initProgram(ProgramObject& program, Locations& locations, static void initProgram(ProgramObject& program, Locations& locations, int specularTextureUnit = 1);
int specularTextureUnit = 1, int shadowTextureUnit = 1);
class SkinLocations : public Locations { class SkinLocations : public Locations {
public: public:
@ -372,25 +316,15 @@ private:
static SkinLocations _skinNormalMapLocations; static SkinLocations _skinNormalMapLocations;
static SkinLocations _skinSpecularMapLocations; static SkinLocations _skinSpecularMapLocations;
static SkinLocations _skinNormalSpecularMapLocations; static SkinLocations _skinNormalSpecularMapLocations;
static SkinLocations _skinShadowMapLocations;
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 SkinLocations _skinShadowLocations;
static SkinLocations _skinTranslucentLocations;
static void initSkinProgram(ProgramObject& program, SkinLocations& locations, static void initSkinProgram(ProgramObject& program, SkinLocations& locations, int specularTextureUnit = 1);
int specularTextureUnit = 1, int shadowTextureUnit = 1);
}; };
Q_DECLARE_METATYPE(QPointer<Model>) Q_DECLARE_METATYPE(QPointer<Model>)
Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>) Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>)
Q_DECLARE_METATYPE(QVector<glm::vec3>) Q_DECLARE_METATYPE(QVector<glm::vec3>)
Q_DECLARE_METATYPE(Model::LocalLight)
Q_DECLARE_METATYPE(QVector<Model::LocalLight>)
/// Represents a handle to a model animation. /// Represents a handle to a model animation.
class AnimationHandle : public QObject { class AnimationHandle : public QObject {

View file

@ -12,15 +12,15 @@
#include "InterfaceConfig.h" #include "InterfaceConfig.h"
#include "RenderUtil.h" #include "RenderUtil.h"
void renderFullscreenQuad(float sMin, float sMax) { void renderFullscreenQuad(float sMin, float sMax, float tMin, float tMax) {
glBegin(GL_QUADS); glBegin(GL_QUADS);
glTexCoord2f(sMin, 0.0f); glTexCoord2f(sMin, tMin);
glVertex2f(-1.0f, -1.0f); glVertex2f(-1.0f, -1.0f);
glTexCoord2f(sMax, 0.0f); glTexCoord2f(sMax, tMin);
glVertex2f(1.0f, -1.0f); glVertex2f(1.0f, -1.0f);
glTexCoord2f(sMax, 1.0f); glTexCoord2f(sMax, tMax);
glVertex2f(1.0f, 1.0f); glVertex2f(1.0f, 1.0f);
glTexCoord2f(sMin, 1.0f); glTexCoord2f(sMin, tMax);
glVertex2f(-1.0f, 1.0f); glVertex2f(-1.0f, 1.0f);
glEnd(); glEnd();
} }

View file

@ -12,7 +12,7 @@
#ifndef hifi_RenderUtil_h #ifndef hifi_RenderUtil_h
#define hifi_RenderUtil_h #define hifi_RenderUtil_h
/// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, 0) to (sMax, 1). /// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, tMin) to (sMax, tMax).
void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f); void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f, float tMin = 0.0f, float tMax = 1.0f);
#endif // hifi_RenderUtil_h #endif // hifi_RenderUtil_h

View file

@ -30,6 +30,7 @@ TextureCache::TextureCache() :
_blueTextureID(0), _blueTextureID(0),
_primaryDepthTextureID(0), _primaryDepthTextureID(0),
_primaryNormalTextureID(0), _primaryNormalTextureID(0),
_primarySpecularTextureID(0),
_primaryFramebufferObject(NULL), _primaryFramebufferObject(NULL),
_secondaryFramebufferObject(NULL), _secondaryFramebufferObject(NULL),
_tertiaryFramebufferObject(NULL), _tertiaryFramebufferObject(NULL),
@ -48,6 +49,7 @@ TextureCache::~TextureCache() {
if (_primaryFramebufferObject) { if (_primaryFramebufferObject) {
glDeleteTextures(1, &_primaryDepthTextureID); glDeleteTextures(1, &_primaryDepthTextureID);
glDeleteTextures(1, &_primaryNormalTextureID); glDeleteTextures(1, &_primaryNormalTextureID);
glDeleteTextures(1, &_primarySpecularTextureID);
} }
if (_primaryFramebufferObject) { if (_primaryFramebufferObject) {
@ -75,6 +77,8 @@ void TextureCache::setFrameBufferSize(QSize frameBufferSize) {
_primaryDepthTextureID = 0; _primaryDepthTextureID = 0;
glDeleteTextures(1, &_primaryNormalTextureID); glDeleteTextures(1, &_primaryNormalTextureID);
_primaryNormalTextureID = 0; _primaryNormalTextureID = 0;
glDeleteTextures(1, &_primarySpecularTextureID);
_primarySpecularTextureID = 0;
} }
if (_secondaryFramebufferObject) { if (_secondaryFramebufferObject) {
@ -222,9 +226,18 @@ QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
glGenTextures(1, &_primarySpecularTextureID);
glBindTexture(GL_TEXTURE_2D, _primarySpecularTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _frameBufferSize.width(), _frameBufferSize.height(),
0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0);
_primaryFramebufferObject->bind(); _primaryFramebufferObject->bind();
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _primaryDepthTextureID, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _primaryDepthTextureID, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, _primaryNormalTextureID, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, _primaryNormalTextureID, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, _primarySpecularTextureID, 0);
_primaryFramebufferObject->release(); _primaryFramebufferObject->release();
} }
return _primaryFramebufferObject; return _primaryFramebufferObject;
@ -242,6 +255,26 @@ GLuint TextureCache::getPrimaryNormalTextureID() {
return _primaryNormalTextureID; return _primaryNormalTextureID;
} }
GLuint TextureCache::getPrimarySpecularTextureID() {
getPrimaryFramebufferObject();
return _primarySpecularTextureID;
}
void TextureCache::setPrimaryDrawBuffers(bool color, bool normal, bool specular) {
GLenum buffers[3];
int bufferCount = 0;
if (color) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT0;
}
if (normal) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT1;
}
if (specular) {
buffers[bufferCount++] = GL_COLOR_ATTACHMENT2;
}
glDrawBuffers(bufferCount, buffers);
}
QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() { QOpenGLFramebufferObject* TextureCache::getSecondaryFramebufferObject() {
if (!_secondaryFramebufferObject) { if (!_secondaryFramebufferObject) {
_secondaryFramebufferObject = createFramebufferObject(); _secondaryFramebufferObject = createFramebufferObject();
@ -296,6 +329,7 @@ bool TextureCache::eventFilter(QObject* watched, QEvent* event) {
_primaryFramebufferObject = NULL; _primaryFramebufferObject = NULL;
glDeleteTextures(1, &_primaryDepthTextureID); glDeleteTextures(1, &_primaryDepthTextureID);
glDeleteTextures(1, &_primaryNormalTextureID); glDeleteTextures(1, &_primaryNormalTextureID);
glDeleteTextures(1, &_primarySpecularTextureID);
} }
if (_secondaryFramebufferObject && _secondaryFramebufferObject->size() != size) { if (_secondaryFramebufferObject && _secondaryFramebufferObject->size() != size) {
delete _secondaryFramebufferObject; delete _secondaryFramebufferObject;

View file

@ -64,6 +64,12 @@ public:
/// Returns the ID of the primary framebuffer object's normal texture. /// Returns the ID of the primary framebuffer object's normal texture.
GLuint getPrimaryNormalTextureID(); GLuint getPrimaryNormalTextureID();
/// Returns the ID of the primary framebuffer object's specular texture.
GLuint getPrimarySpecularTextureID();
/// Enables or disables draw buffers on the primary framebuffer. Note: the primary framebuffer must be bound.
void setPrimaryDrawBuffers(bool color, bool normal = false, bool specular = false);
/// Returns a pointer to the secondary framebuffer object, used as an additional render target when performing full /// Returns a pointer to the secondary framebuffer object, used as an additional render target when performing full
/// screen effects. /// screen effects.
QOpenGLFramebufferObject* getSecondaryFramebufferObject(); QOpenGLFramebufferObject* getSecondaryFramebufferObject();
@ -99,6 +105,7 @@ private:
GLuint _primaryDepthTextureID; GLuint _primaryDepthTextureID;
GLuint _primaryNormalTextureID; GLuint _primaryNormalTextureID;
GLuint _primarySpecularTextureID;
QOpenGLFramebufferObject* _primaryFramebufferObject; QOpenGLFramebufferObject* _primaryFramebufferObject;
QOpenGLFramebufferObject* _secondaryFramebufferObject; QOpenGLFramebufferObject* _secondaryFramebufferObject;
QOpenGLFramebufferObject* _tertiaryFramebufferObject; QOpenGLFramebufferObject* _tertiaryFramebufferObject;

View file

@ -506,29 +506,13 @@ void VoxelSystem::initVoxelMemory() {
_memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels); _memoryUsageRAM += (sizeof(GLubyte) * vertexPointsPerVoxel * _maxVoxels);
// create our simple fragment shader if we're the first system to init // create our simple fragment shader if we're the first system to init
if (!_shadowMapProgram.isLinked()) { if (!_program.isLinked()) {
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Vertex, _program.addShaderFromSourceFile(QGLShader::Vertex,
Application::resourcesPath() + "shaders/shadow_map.vert"); Application::resourcesPath() + "shaders/voxel.vert");
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, _program.addShaderFromSourceFile(QGLShader::Fragment,
Application::resourcesPath() + "shaders/shadow_map.frag"); Application::resourcesPath() + "shaders/voxel.frag");
_shadowMapProgram.link(); _program.link();
_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); _renderer = new PrimitiveRenderer(_maxVoxels);
@ -1150,10 +1134,8 @@ glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float vo
return startVertex + glm::vec3(identityVertex[0], identityVertex[1], identityVertex[2]) * voxelScale; return startVertex + glm::vec3(identityVertex[0], identityVertex[1], identityVertex[2]) * voxelScale;
} }
ProgramObject VoxelSystem::_program;
ProgramObject VoxelSystem::_perlinModulateProgram; ProgramObject VoxelSystem::_perlinModulateProgram;
ProgramObject VoxelSystem::_shadowMapProgram;
ProgramObject VoxelSystem::_cascadedShadowMapProgram;
int VoxelSystem::_shadowDistancesLocation;
void VoxelSystem::init() { void VoxelSystem::init() {
if (_initialized) { if (_initialized) {
@ -1410,8 +1392,11 @@ void VoxelSystem::render() {
applyScaleAndBindProgram(texture); applyScaleAndBindProgram(texture);
// for performance, enable backface culling // for performance, enable backface culling and disable blending
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glDisable(GL_BLEND);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
} }
// draw voxels in 6 passes // draw voxels in 6 passes
@ -1453,6 +1438,7 @@ void VoxelSystem::render() {
PerformanceWarning warn(showWarnings, "render().. cleanup after glDrawRangeElementsEXT()..."); PerformanceWarning warn(showWarnings, "render().. cleanup after glDrawRangeElementsEXT()...");
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
removeScaleAndReleaseProgram(texture); removeScaleAndReleaseProgram(texture);
@ -1478,41 +1464,31 @@ void VoxelSystem::render() {
} }
void VoxelSystem::applyScaleAndBindProgram(bool texture) { void VoxelSystem::applyScaleAndBindProgram(bool texture) {
if (texture) {
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());
} else if (texture) {
bindPerlinModulateProgram(); bindPerlinModulateProgram();
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID()); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID());
} else {
_program.bind();
} }
glPushMatrix(); glPushMatrix();
glScalef(_treeScale, _treeScale, _treeScale); glScalef(_treeScale, _treeScale, _treeScale);
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, true);
} }
void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {
// scale back down to 1 so heads aren't massive // scale back down to 1 so heads aren't massive
glPopMatrix(); glPopMatrix();
if (Menu::getInstance()->getShadowsEnabled()) { if (texture) {
if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) {
_cascadedShadowMapProgram.release();
} else {
_shadowMapProgram.release();
}
glBindTexture(GL_TEXTURE_2D, 0);
} else if (texture) {
_perlinModulateProgram.release(); _perlinModulateProgram.release();
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} else {
_program.release();
} }
Application::getInstance()->getTextureCache()->setPrimaryDrawBuffers(true, false);
} }
int VoxelSystem::_nodeCount = 0; int VoxelSystem::_nodeCount = 0;

View file

@ -228,10 +228,8 @@ private:
bool _voxelsDirty; bool _voxelsDirty;
static ProgramObject _program;
static ProgramObject _perlinModulateProgram; static ProgramObject _perlinModulateProgram;
static ProgramObject _shadowMapProgram;
static ProgramObject _cascadedShadowMapProgram;
static int _shadowDistancesLocation;
static void bindPerlinModulateProgram(); static void bindPerlinModulateProgram();

View file

@ -656,6 +656,7 @@ class Material {
public: public:
glm::vec3 diffuse; glm::vec3 diffuse;
glm::vec3 specular; glm::vec3 specular;
glm::vec3 emissive;
float shininess; float shininess;
float opacity; float opacity;
}; };
@ -1281,7 +1282,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
textureContent.insert(filename, content); textureContent.insert(filename, content);
} }
} else if (object.name == "Material") { } else if (object.name == "Material") {
Material material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), 96.0f, 1.0f }; Material material = { glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(), 96.0f, 1.0f };
foreach (const FBXNode& subobject, object.children) { foreach (const FBXNode& subobject, object.children) {
bool properties = false; bool properties = false;
QByteArray propertyName; QByteArray propertyName;
@ -1305,6 +1306,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
} else if (property.properties.at(0) == "SpecularColor") { } else if (property.properties.at(0) == "SpecularColor") {
material.specular = getVec3(property.properties, index); material.specular = getVec3(property.properties, index);
} else if (property.properties.at(0) == "Emissive") {
material.emissive = getVec3(property.properties, index);
} else if (property.properties.at(0) == "Shininess") { } else if (property.properties.at(0) == "Shininess") {
material.shininess = property.properties.at(index).value<double>(); material.shininess = property.properties.at(index).value<double>();
@ -1605,6 +1609,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
FBXMeshPart& part = extracted.mesh.parts[j]; FBXMeshPart& part = extracted.mesh.parts[j];
part.diffuseColor = material.diffuse; part.diffuseColor = material.diffuse;
part.specularColor = material.specular; part.specularColor = material.specular;
part.emissiveColor = material.emissive;
part.shininess = material.shininess; part.shininess = material.shininess;
part.opacity = material.opacity; part.opacity = material.opacity;
if (!diffuseTexture.filename.isNull()) { if (!diffuseTexture.filename.isNull()) {

View file

@ -108,6 +108,7 @@ public:
glm::vec3 diffuseColor; glm::vec3 diffuseColor;
glm::vec3 specularColor; glm::vec3 specularColor;
glm::vec3 emissiveColor;
float shininess; float shininess;
float opacity; float opacity;