void LightDirectionEmission::render(const sf::View &view, sf::RenderTexture &lightTempTexture, sf::RenderTexture &antumbraTempTexture, const std::vector<QuadtreeOccupant*> &shapes, sf::Shader &unshadowShader, float shadowExtension) { lightTempTexture.setView(view); LightSystem::clear(lightTempTexture, sf::Color::White); // Mask off light shape (over-masking - mask too much, reveal penumbra/antumbra afterwards) for (int i = 0; i < shapes.size(); i++) { LightShape* pLightShape = static_cast<LightShape*>(shapes[i]); // Get boundaries std::vector<LightSystem::Penumbra> penumbras; std::vector<int> innerBoundaryIndices; std::vector<int> outerBoundaryIndices; std::vector<sf::Vector2f> innerBoundaryVectors; std::vector<sf::Vector2f> outerBoundaryVectors; LightSystem::getPenumbrasDirection(penumbras, innerBoundaryIndices, innerBoundaryVectors, outerBoundaryIndices, outerBoundaryVectors, pLightShape->_shape, _castDirection, _sourceRadius, _sourceDistance); if (innerBoundaryIndices.size() != 2 || outerBoundaryIndices.size() != 2) continue; LightSystem::clear(antumbraTempTexture, sf::Color::White); antumbraTempTexture.setView(view); sf::ConvexShape maskShape; float maxDist = 0.0f; for (int j = 0; j < pLightShape->_shape.getPointCount(); j++) maxDist = std::max(maxDist, vectorMagnitude(view.getCenter() - pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(j)))); float totalShadowExtension = shadowExtension + maxDist; maskShape.setPointCount(4); maskShape.setPoint(0, pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(innerBoundaryIndices[0]))); maskShape.setPoint(1, pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(innerBoundaryIndices[1]))); maskShape.setPoint(2, pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(innerBoundaryIndices[1])) + vectorNormalize(innerBoundaryVectors[1]) * totalShadowExtension); maskShape.setPoint(3, pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(innerBoundaryIndices[0])) + vectorNormalize(innerBoundaryVectors[0]) * totalShadowExtension); maskShape.setFillColor(sf::Color::Black); antumbraTempTexture.draw(maskShape); sf::VertexArray vertexArray; vertexArray.setPrimitiveType(sf::PrimitiveType::Triangles); vertexArray.resize(3); { sf::RenderStates states; states.blendMode = sf::BlendAdd; states.shader = &unshadowShader; // Unmask with penumbras for (int j = 0; j < penumbras.size(); j++) { unshadowShader.setParameter("lightBrightness", penumbras[j]._lightBrightness); unshadowShader.setParameter("darkBrightness", penumbras[j]._darkBrightness); vertexArray[0].position = penumbras[j]._source; vertexArray[1].position = penumbras[j]._source + vectorNormalize(penumbras[j]._lightEdge) * totalShadowExtension; vertexArray[2].position = penumbras[j]._source + vectorNormalize(penumbras[j]._darkEdge) * totalShadowExtension; vertexArray[0].texCoords = sf::Vector2f(0.0f, 1.0f); vertexArray[1].texCoords = sf::Vector2f(1.0f, 0.0f); vertexArray[2].texCoords = sf::Vector2f(0.0f, 0.0f); antumbraTempTexture.draw(vertexArray, states); } } antumbraTempTexture.display(); // Multiply back to lightTempTexture sf::RenderStates antumbraRenderStates; antumbraRenderStates.blendMode = sf::BlendMultiply; sf::Sprite s; s.setTexture(antumbraTempTexture.getTexture()); lightTempTexture.setView(lightTempTexture.getDefaultView()); lightTempTexture.draw(s, antumbraRenderStates); lightTempTexture.setView(view); } for (int i = 0; i < shapes.size(); i++) { LightShape* pLightShape = static_cast<LightShape*>(shapes[i]); if (pLightShape->_renderLightOverShape) { pLightShape->_shape.setFillColor(sf::Color::White); lightTempTexture.draw(pLightShape->_shape); } } // Multiplicatively blend the light over the shadows sf::RenderStates lightRenderStates; lightRenderStates.blendMode = sf::BlendMultiply; lightTempTexture.setView(lightTempTexture.getDefaultView()); lightTempTexture.draw(_emissionSprite, lightRenderStates); lightTempTexture.display(); }
void LightPointEmission::render(const sf::View &view, sf::RenderTexture &lightTempTexture, sf::RenderTexture &emissionTempTexture, sf::RenderTexture &antumbraTempTexture, const std::vector<QuadtreeOccupant*> &shapes, sf::Shader &unshadowShader, sf::Shader &lightOverShapeShader) { LightSystem::clear(emissionTempTexture, sf::Color::Black); emissionTempTexture.setView(view); emissionTempTexture.draw(_emissionSprite); emissionTempTexture.display(); LightSystem::clear(lightTempTexture, sf::Color::Black); lightTempTexture.setView(view); lightTempTexture.draw(_emissionSprite); sf::Transform t; t.translate(_emissionSprite.getPosition()); t.rotate(_emissionSprite.getRotation()); t.scale(_emissionSprite.getScale()); sf::Vector2f castCenter = t.transformPoint(_localCastCenter); float shadowExtension = _shadowOverExtendMultiplier * (getAABB().width + getAABB().height); struct OuterEdges { std::vector<int> _outerBoundaryIndices; std::vector<sf::Vector2f> _outerBoundaryVectors; }; std::vector<OuterEdges> outerEdges(shapes.size()); // Mask off light shape (over-masking - mask too much, reveal penumbra/antumbra afterwards) for (unsigned i = 0; i < shapes.size(); i++) { LightShape* pLightShape = static_cast<LightShape*>(shapes[i]); // Get boundaries std::vector<int> innerBoundaryIndices; std::vector<sf::Vector2f> innerBoundaryVectors; std::vector<LightSystem::Penumbra> penumbras; LightSystem::getPenumbrasPoint(penumbras, innerBoundaryIndices, innerBoundaryVectors, outerEdges[i]._outerBoundaryIndices, outerEdges[i]._outerBoundaryVectors, pLightShape->_shape, castCenter, _sourceRadius); if (innerBoundaryIndices.size() != 2 || outerEdges[i]._outerBoundaryIndices.size() != 2) continue; // Render shape if (!pLightShape->_renderLightOverShape) { pLightShape->_shape.setFillColor(sf::Color::Black); lightTempTexture.draw(pLightShape->_shape); } sf::RenderStates maskRenderStates; maskRenderStates.blendMode = sf::BlendNone; sf::Vector2f as = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(outerEdges[i]._outerBoundaryIndices[0])); sf::Vector2f bs = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(outerEdges[i]._outerBoundaryIndices[1])); sf::Vector2f ad = outerEdges[i]._outerBoundaryVectors[0]; sf::Vector2f bd = outerEdges[i]._outerBoundaryVectors[1]; sf::Vector2f intersectionOuter; // Handle antumbras as a seperate case if (rayIntersect(as, ad, bs, bd, intersectionOuter)) { sf::Vector2f asi = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(innerBoundaryIndices[0])); sf::Vector2f bsi = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(innerBoundaryIndices[1])); sf::Vector2f adi = innerBoundaryVectors[0]; sf::Vector2f bdi = innerBoundaryVectors[1]; LightSystem::clear(antumbraTempTexture, sf::Color::White); antumbraTempTexture.setView(view); sf::Vector2f intersectionInner; if (rayIntersect(asi, adi, bsi, bdi, intersectionInner)) { sf::ConvexShape maskShape; maskShape.setPointCount(3); maskShape.setPoint(0, asi); maskShape.setPoint(1, bsi); maskShape.setPoint(2, intersectionInner); maskShape.setFillColor(sf::Color::Black); antumbraTempTexture.draw(maskShape); } else { sf::ConvexShape maskShape; maskShape.setPointCount(4); maskShape.setPoint(0, asi); maskShape.setPoint(1, bsi); maskShape.setPoint(2, bsi + vectorNormalize(bdi) * shadowExtension); maskShape.setPoint(3, asi + vectorNormalize(adi) * shadowExtension); maskShape.setFillColor(sf::Color::Black); antumbraTempTexture.draw(maskShape); } // Add light back for antumbra/penumbras sf::VertexArray vertexArray; vertexArray.setPrimitiveType(sf::PrimitiveType::Triangles); vertexArray.resize(3); sf::RenderStates penumbraRenderStates; penumbraRenderStates.blendMode = sf::BlendAdd; penumbraRenderStates.shader = &unshadowShader; // Unmask with penumbras for (unsigned j = 0; j < penumbras.size(); j++) { unshadowShader.setParameter("lightBrightness", penumbras[j]._lightBrightness); unshadowShader.setParameter("darkBrightness", penumbras[j]._darkBrightness); vertexArray[0].position = penumbras[j]._source; vertexArray[1].position = penumbras[j]._source + vectorNormalize(penumbras[j]._lightEdge) * shadowExtension; vertexArray[2].position = penumbras[j]._source + vectorNormalize(penumbras[j]._darkEdge) * shadowExtension; vertexArray[0].texCoords = sf::Vector2f(0.0f, 1.0f); vertexArray[1].texCoords = sf::Vector2f(1.0f, 0.0f); vertexArray[2].texCoords = sf::Vector2f(0.0f, 0.0f); antumbraTempTexture.draw(vertexArray, penumbraRenderStates); } antumbraTempTexture.display(); // Multiply back to lightTempTexture sf::RenderStates antumbraRenderStates; antumbraRenderStates.blendMode = sf::BlendMultiply; sf::Sprite s; s.setTexture(antumbraTempTexture.getTexture()); lightTempTexture.setView(lightTempTexture.getDefaultView()); lightTempTexture.draw(s, antumbraRenderStates); lightTempTexture.setView(view); } else { sf::ConvexShape maskShape; maskShape.setPointCount(4); maskShape.setPoint(0, as); maskShape.setPoint(1, bs); maskShape.setPoint(2, bs + vectorNormalize(bd) * shadowExtension); maskShape.setPoint(3, as + vectorNormalize(ad) * shadowExtension); maskShape.setFillColor(sf::Color::Black); lightTempTexture.draw(maskShape); sf::VertexArray vertexArray; vertexArray.setPrimitiveType(sf::PrimitiveType::Triangles); vertexArray.resize(3); sf::RenderStates penumbraRenderStates; penumbraRenderStates.blendMode = sf::BlendMultiply; penumbraRenderStates.shader = &unshadowShader; // Unmask with penumbras for (unsigned j = 0; j < penumbras.size(); j++) { unshadowShader.setParameter("lightBrightness", penumbras[j]._lightBrightness); unshadowShader.setParameter("darkBrightness", penumbras[j]._darkBrightness); vertexArray[0].position = penumbras[j]._source; vertexArray[1].position = penumbras[j]._source + vectorNormalize(penumbras[j]._lightEdge) * shadowExtension; vertexArray[2].position = penumbras[j]._source + vectorNormalize(penumbras[j]._darkEdge) * shadowExtension; vertexArray[0].texCoords = sf::Vector2f(0.0f, 1.0f); vertexArray[1].texCoords = sf::Vector2f(1.0f, 0.0f); vertexArray[2].texCoords = sf::Vector2f(0.0f, 0.0f); lightTempTexture.draw(vertexArray, penumbraRenderStates); } } } for (unsigned i = 0; i < shapes.size(); i++) { LightShape* pLightShape = static_cast<LightShape*>(shapes[i]); if (pLightShape->_renderLightOverShape) { pLightShape->_shape.setFillColor(sf::Color::White); lightTempTexture.draw(pLightShape->_shape, &lightOverShapeShader); } else { pLightShape->_shape.setFillColor(sf::Color::Black); lightTempTexture.draw(pLightShape->_shape); } } lightTempTexture.display(); }