diff --git a/interface/resources/shaders/deferred_light_limited.vert b/interface/resources/shaders/deferred_light_limited.vert index 8a69632f44..849d14bda4 100644 --- a/interface/resources/shaders/deferred_light_limited.vert +++ b/interface/resources/shaders/deferred_light_limited.vert @@ -11,50 +11,8 @@ // 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); + gl_Position = ftransform(); + vec4 projected = gl_Position / gl_Position.w; + gl_TexCoord[0] = vec4(dot(projected, gl_ObjectPlaneS[3]), dot(projected, gl_ObjectPlaneT[3]), 0.0, 1.0); } diff --git a/interface/resources/shaders/point_light.frag b/interface/resources/shaders/point_light.frag index 31de0fe7d2..b9ba638885 100644 --- a/interface/resources/shaders/point_light.frag +++ b/interface/resources/shaders/point_light.frag @@ -39,8 +39,13 @@ uniform vec2 depthTexCoordScale; uniform float radius; void main(void) { + // get the depth and exit early if it doesn't pass the test + float depth = texture2D(depthMap, gl_TexCoord[0].st).r; + if (depth < gl_FragCoord.z) { + discard; + } // compute the view space position using the depth - float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0); + float z = near / (depth * depthScale - 1.0); vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0); // get the normal from the map diff --git a/interface/resources/shaders/spot_light.frag b/interface/resources/shaders/spot_light.frag index 33469be0c7..a496abd7b2 100644 --- a/interface/resources/shaders/spot_light.frag +++ b/interface/resources/shaders/spot_light.frag @@ -39,8 +39,13 @@ uniform vec2 depthTexCoordScale; uniform float radius; void main(void) { + // get the depth and exit early if it doesn't pass the test + float depth = texture2D(depthMap, gl_TexCoord[0].st).r; + if (depth < gl_FragCoord.z) { + discard; + } // compute the view space position using the depth - float z = near / (texture2D(depthMap, gl_TexCoord[0].st).r * depthScale - 1.0); + float z = near / (depth * depthScale - 1.0); vec4 position = vec4((depthTexCoordOffset + gl_TexCoord[0].st * depthTexCoordScale) * z, z, 1.0); // get the normal from the map diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index 23cd52d946..7e43de9dda 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -126,6 +126,7 @@ void OculusManager::connect() { if (!_camera) { _camera = new Camera; + configureCamera(*_camera, 0, 0); // no need to use screen dimensions; they're ignored } if (!_programInitialized) { @@ -420,7 +421,7 @@ void OculusManager::endFrameTiming() { //Sets the camera FoV and aspect ratio void OculusManager::configureCamera(Camera& camera, int screenWidth, int screenHeight) { #ifdef HAVE_LIBOVR - camera.setAspectRatio((float)_renderTargetSize.w / _renderTargetSize.h); + camera.setAspectRatio(_renderTargetSize.w * 0.5f / _renderTargetSize.h); camera.setFieldOfView(atan(_eyeFov[0].UpTan) * DEGREES_PER_RADIAN * 2.0f); #endif } diff --git a/interface/src/renderer/DeferredLightingEffect.cpp b/interface/src/renderer/DeferredLightingEffect.cpp index d4e83776d8..d5551430c4 100644 --- a/interface/src/renderer/DeferredLightingEffect.cpp +++ b/interface/src/renderer/DeferredLightingEffect.cpp @@ -73,6 +73,12 @@ void DeferredLightingEffect::renderWireCube(float size) { releaseSimpleProgram(); } +void DeferredLightingEffect::renderSolidCone(float base, float height, int slices, int stacks) { + bindSimpleProgram(); + Application::getInstance()->getGeometryCache()->renderCone(base, height, slices, stacks); + 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) { @@ -216,11 +222,18 @@ void DeferredLightingEffect::render() { glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); + glEnable(GL_CULL_FACE); + 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); + // enlarge the scales slightly to account for tesselation + const float SCALE_EXPANSION = 0.1f; + + const glm::vec3& eyePoint = Application::getInstance()->getDisplayViewFrustum()->getPosition(); + if (!_pointLights.isEmpty()) { _pointLight.bind(); _pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal); @@ -238,7 +251,28 @@ void DeferredLightingEffect::render() { glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, (light.linearAttenuation > 0.f ? light.linearAttenuation : 0.f)); glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (light.quadraticAttenuation > 0.f ? light.quadraticAttenuation : 0.f)); - renderFullscreenQuad(); + glPushMatrix(); + + float expandedRadius = light.radius * (1.0f + SCALE_EXPANSION); + if (glm::distance(eyePoint, glm::vec3(light.position)) < expandedRadius) { + glLoadIdentity(); + glTranslatef(0.0f, 0.0f, -1.0f); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + renderFullscreenQuad(); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + } else { + glTranslatef(light.position.x, light.position.y, light.position.z); + Application::getInstance()->getGeometryCache()->renderSphere(expandedRadius, 64, 64); + } + + glPopMatrix(); } _pointLights.clear(); @@ -265,7 +299,34 @@ void DeferredLightingEffect::render() { glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, light.exponent); glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, glm::degrees(light.cutoff)); - renderFullscreenQuad(); + glPushMatrix(); + + float expandedRadius = light.radius * (1.0f + SCALE_EXPANSION); + float edgeRadius = expandedRadius / glm::cos(light.cutoff); + if (glm::distance(eyePoint, glm::vec3(light.position)) < edgeRadius) { + glLoadIdentity(); + glTranslatef(0.0f, 0.0f, -1.0f); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + renderFullscreenQuad(); + + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + } else { + glTranslatef(light.position.x, light.position.y, light.position.z); + glm::quat spotRotation = rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), light.direction); + glm::vec3 axis = glm::axis(spotRotation); + glRotatef(glm::degrees(glm::angle(spotRotation)), axis.x, axis.y, axis.z); + glTranslatef(0.0f, 0.0f, -light.radius * (1.0f + SCALE_EXPANSION * 0.5f)); + Application::getInstance()->getGeometryCache()->renderCone(expandedRadius * glm::tan(light.cutoff), + expandedRadius, 64, 32); + } + + glPopMatrix(); } _spotLights.clear(); @@ -285,6 +346,8 @@ void DeferredLightingEffect::render() { freeFBO->release(); + glDisable(GL_CULL_FACE); + // 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); diff --git a/interface/src/renderer/DeferredLightingEffect.h b/interface/src/renderer/DeferredLightingEffect.h index 33fe6b474d..ce8b2b9759 100644 --- a/interface/src/renderer/DeferredLightingEffect.h +++ b/interface/src/renderer/DeferredLightingEffect.h @@ -47,6 +47,9 @@ public: //// Renders a wireframe cube with the simple program. void renderWireCube(float size); + + //// Renders a solid cone with the simple program. + void renderSolidCone(float base, float height, int slices, int stacks); /// 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), diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index 9249b33031..59180dcf9d 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -110,15 +110,18 @@ void GeometryCache::renderHemisphere(int slices, int stacks) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } +const int NUM_VERTICES_PER_TRIANGLE = 3; +const int NUM_TRIANGLES_PER_QUAD = 2; +const int NUM_VERTICES_PER_TRIANGULATED_QUAD = NUM_VERTICES_PER_TRIANGLE * NUM_TRIANGLES_PER_QUAD; +const int NUM_COORDS_PER_VERTEX = 3; +const int NUM_BYTES_PER_VERTEX = NUM_COORDS_PER_VERTEX * sizeof(GLfloat); +const int NUM_BYTES_PER_INDEX = sizeof(GLushort); void GeometryCache::renderSphere(float radius, int slices, int stacks) { VerticesIndices& vbo = _sphereVBOs[IntPair(slices, stacks)]; - int vertices = slices * (stacks - 1) + 2; - const int NUM_VERTICES_PER_TRIANGLE = 3; - const int NUM_TRIANGLES_PER_QUAD = 2; - int indices = slices * NUM_TRIANGLES_PER_QUAD * NUM_VERTICES_PER_TRIANGLE * (stacks - 1) + slices * NUM_TRIANGLES_PER_QUAD * NUM_VERTICES_PER_TRIANGLE; - if (vbo.first == 0) { - const int NUM_COORDS_PER_VERTEX = 3; + int vertices = slices * (stacks - 1) + 2; + int indices = slices * stacks * NUM_VERTICES_PER_TRIANGULATED_QUAD; + if (vbo.first == 0) { GLfloat* vertexData = new GLfloat[vertices * NUM_COORDS_PER_VERTEX]; GLfloat* vertex = vertexData; @@ -148,8 +151,7 @@ void GeometryCache::renderSphere(float radius, int slices, int stacks) { glGenBuffers(1, &vbo.first); glBindBuffer(GL_ARRAY_BUFFER, vbo.first); - const int BYTES_PER_VERTEX = NUM_COORDS_PER_VERTEX * sizeof(GLfloat); - glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, vertices * NUM_BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); delete[] vertexData; GLushort* indexData = new GLushort[indices]; @@ -192,8 +194,7 @@ void GeometryCache::renderSphere(float radius, int slices, int stacks) { glGenBuffers(1, &vbo.second); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second); - const int BYTES_PER_INDEX = sizeof(GLushort); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * NUM_BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); delete[] indexData; } else { @@ -239,8 +240,7 @@ void GeometryCache::renderSquare(int xDivisions, int yDivisions) { glGenBuffers(1, &vbo.first); glBindBuffer(GL_ARRAY_BUFFER, vbo.first); - const int BYTES_PER_VERTEX = 3 * sizeof(GLfloat); - glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, vertices * NUM_BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); delete[] vertexData; GLushort* indexData = new GLushort[indices]; @@ -263,8 +263,7 @@ void GeometryCache::renderSquare(int xDivisions, int yDivisions) { glGenBuffers(1, &vbo.second); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second); - const int BYTES_PER_INDEX = sizeof(GLushort); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * NUM_BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); delete[] indexData; } else { @@ -313,8 +312,7 @@ void GeometryCache::renderHalfCylinder(int slices, int stacks) { glGenBuffers(1, &vbo.first); glBindBuffer(GL_ARRAY_BUFFER, vbo.first); - const int BYTES_PER_VERTEX = 3 * sizeof(GLfloat); - glBufferData(GL_ARRAY_BUFFER, 2 * vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, 2 * vertices * NUM_BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); delete[] vertexData; GLushort* indexData = new GLushort[indices]; @@ -337,8 +335,7 @@ void GeometryCache::renderHalfCylinder(int slices, int stacks) { glGenBuffers(1, &vbo.second); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second); - const int BYTES_PER_INDEX = sizeof(GLushort); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * NUM_BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); delete[] indexData; } else { @@ -360,6 +357,106 @@ void GeometryCache::renderHalfCylinder(int slices, int stacks) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } +void GeometryCache::renderCone(float base, float height, int slices, int stacks) { + VerticesIndices& vbo = _halfCylinderVBOs[IntPair(slices, stacks)]; + int vertices = (stacks + 2) * slices; + int baseTriangles = slices - 2; + int indices = NUM_VERTICES_PER_TRIANGULATED_QUAD * slices * stacks + NUM_VERTICES_PER_TRIANGLE * baseTriangles; + if (vbo.first == 0) { + GLfloat* vertexData = new GLfloat[vertices * NUM_COORDS_PER_VERTEX * 2]; + GLfloat* vertex = vertexData; + // cap + for (int i = 0; i < slices; i++) { + float theta = TWO_PI * i / slices; + + //normals + *(vertex++) = 0.0f; + *(vertex++) = 0.0f; + *(vertex++) = -1.0f; + + // vertices + *(vertex++) = cosf(theta); + *(vertex++) = sinf(theta); + *(vertex++) = 0.0f; + } + // body + for (int i = 0; i <= stacks; i++) { + float z = (float)i / stacks; + float radius = 1.0f - z; + + for (int j = 0; j < slices; j++) { + float theta = TWO_PI * j / slices; + + //normals + *(vertex++) = cosf(theta) / SQUARE_ROOT_OF_2; + *(vertex++) = sinf(theta) / SQUARE_ROOT_OF_2; + *(vertex++) = 1.0f / SQUARE_ROOT_OF_2; + + // vertices + *(vertex++) = radius * cosf(theta); + *(vertex++) = radius * sinf(theta); + *(vertex++) = z; + } + } + + glGenBuffers(1, &vbo.first); + glBindBuffer(GL_ARRAY_BUFFER, vbo.first); + glBufferData(GL_ARRAY_BUFFER, 2 * vertices * NUM_BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); + delete[] vertexData; + + GLushort* indexData = new GLushort[indices]; + GLushort* index = indexData; + for (int i = 0; i < baseTriangles; i++) { + *(index++) = 0; + *(index++) = i + 1; + *(index++) = i + 2; + } + for (int i = 1; i <= stacks; i++) { + GLushort bottom = i * slices; + GLushort top = bottom + slices; + for (int j = 0; j < slices; j++) { + int next = (j + 1) % slices; + + *(index++) = bottom + j; + *(index++) = top + next; + *(index++) = top + j; + + *(index++) = bottom + j; + *(index++) = bottom + next; + *(index++) = top + next; + } + } + + glGenBuffers(1, &vbo.second); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * NUM_BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); + delete[] indexData; + + } else { + glBindBuffer(GL_ARRAY_BUFFER, vbo.first); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second); + } + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + int stride = NUM_VERTICES_PER_TRIANGULATED_QUAD * sizeof(float); + glNormalPointer(GL_FLOAT, stride, 0); + glVertexPointer(NUM_COORDS_PER_VERTEX, GL_FLOAT, stride, (const void *)(NUM_COORDS_PER_VERTEX * sizeof(float))); + + glPushMatrix(); + glScalef(base, base, height); + + glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0); + + glPopMatrix(); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + void GeometryCache::renderGrid(int xDivisions, int yDivisions) { QOpenGLBuffer& buffer = _gridBuffers[IntPair(xDivisions, yDivisions)]; int vertices = (xDivisions + 1 + yDivisions + 1) * 2; diff --git a/interface/src/renderer/GeometryCache.h b/interface/src/renderer/GeometryCache.h index 0fb04cf028..72d283c931 100644 --- a/interface/src/renderer/GeometryCache.h +++ b/interface/src/renderer/GeometryCache.h @@ -44,6 +44,7 @@ public: void renderSphere(float radius, int slices, int stacks); void renderSquare(int xDivisions, int yDivisions); void renderHalfCylinder(int slices, int stacks); + void renderCone(float base, float height, int slices, int stacks); void renderGrid(int xDivisions, int yDivisions); /// Loads geometry from the specified URL. @@ -73,6 +74,7 @@ private: QHash _sphereVBOs; QHash _squareVBOs; QHash _halfCylinderVBOs; + QHash _coneVBOs; QHash _gridBuffers; QHash > _networkGeometry;