// Copyright (C) 2009-2020, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #include #include #include #include #include namespace anki { TraditionalDeferredLightShading::TraditionalDeferredLightShading(Renderer* r) : RendererObject(r) { } TraditionalDeferredLightShading::~TraditionalDeferredLightShading() { } Error TraditionalDeferredLightShading::init() { // Init progs { ANKI_CHECK(getResourceManager().loadResource("shaders/TraditionalDeferredShading.ankiprog", m_lightProg)); for(U32 specular = 0; specular <= 1; ++specular) { ShaderProgramResourceVariantInitInfo variantInitInfo(m_lightProg); variantInitInfo.addMutation("LIGHT_TYPE", 0); variantInitInfo.addMutation("SPECULAR", specular); const ShaderProgramResourceVariant* variant; m_lightProg->getOrCreateVariant(variantInitInfo, variant); m_plightGrProg[specular] = variant->getProgram(); variantInitInfo.addMutation("LIGHT_TYPE", 1); m_lightProg->getOrCreateVariant(variantInitInfo, variant); m_slightGrProg[specular] = variant->getProgram(); variantInitInfo.addMutation("LIGHT_TYPE", 2); m_lightProg->getOrCreateVariant(variantInitInfo, variant); m_dirLightGrProg[specular] = variant->getProgram(); } } // Init meshes ANKI_CHECK(getResourceManager().loadResource("engine_data/Plight.ankimesh", m_plightMesh, false)); ANKI_CHECK(getResourceManager().loadResource("engine_data/Slight.ankimesh", m_slightMesh, false)); return Error::NONE; } void TraditionalDeferredLightShading::bindVertexIndexBuffers(MeshResourcePtr& mesh, CommandBufferPtr& cmdb, U32& indexCount) { // Attrib U32 bufferBinding; Format fmt; PtrSize relativeOffset; mesh->getVertexAttributeInfo(VertexAttributeLocation::POSITION, bufferBinding, fmt, relativeOffset); cmdb->setVertexAttribute(0, 0, fmt, relativeOffset); // Vert buff BufferPtr buff; PtrSize offset, stride; mesh->getVertexBufferInfo(bufferBinding, buff, offset, stride); cmdb->bindVertexBuffer(0, buff, offset, stride); // Idx buff IndexType idxType; mesh->getIndexBufferInfo(buff, offset, indexCount, idxType); cmdb->bindIndexBuffer(buff, offset, idxType); } void TraditionalDeferredLightShading::drawLights(TraditionalDeferredLightShadingDrawInfo& info) { // Set common state for all lights CommandBufferPtr& cmdb = info.m_commandBuffer; cmdb->setBlendFactors(0, BlendFactor::ONE, BlendFactor::ONE); cmdb->setViewport(info.m_viewport.x(), info.m_viewport.y(), info.m_viewport.z(), info.m_viewport.w()); // Dir light if(info.m_directionalLight) { ANKI_ASSERT(info.m_directionalLight->m_uuid && info.m_directionalLight->m_shadowCascadeCount == 1); cmdb->bindShaderProgram(m_dirLightGrProg[info.m_computeSpecular]); DeferredDirectionalLightUniforms* unis = allocateAndBindUniforms( sizeof(DeferredDirectionalLightUniforms), cmdb, 0, 1); unis->m_inputTexUvScale = info.m_gbufferTexCoordsScale; unis->m_inputTexUvBias = info.m_gbufferTexCoordsBias; unis->m_fbUvScale = info.m_lightbufferTexCoordsScale; unis->m_fbUvBias = info.m_lightbufferTexCoordsBias; unis->m_invViewProjMat = info.m_invViewProjectionMatrix; unis->m_camPos = info.m_cameraPosWSpace.xyz(); unis->m_diffuseColor = info.m_directionalLight->m_diffuseColor; unis->m_lightDir = info.m_directionalLight->m_direction; unis->m_lightMatrix = info.m_directionalLight->m_textureMatrices[0]; unis->m_near = info.m_cameraNear; unis->m_far = info.m_cameraFar; if(info.m_directionalLight->m_shadowCascadeCount > 0) { unis->m_effectiveShadowDistance = info.m_directionalLight->m_shadowRenderQueues[0]->m_effectiveShadowDistance; } else { unis->m_effectiveShadowDistance = 0.0f; } drawQuad(cmdb); } // Set other light state cmdb->setCullMode(FaceSelectionBit::FRONT); // Do point lights U32 indexCount; bindVertexIndexBuffers(m_plightMesh, cmdb, indexCount); cmdb->bindShaderProgram(m_plightGrProg[info.m_computeSpecular]); for(const PointLightQueueElement& plightEl : info.m_pointLights) { // Update uniforms DeferredVertexUniforms* vert = allocateAndBindUniforms(sizeof(DeferredVertexUniforms), cmdb, 0, 0); Mat4 modelM(plightEl.m_worldPosition.xyz1(), Mat3::getIdentity(), plightEl.m_radius); vert->m_mvp = info.m_viewProjectionMatrix * modelM; DeferredPointLightUniforms* light = allocateAndBindUniforms(sizeof(DeferredPointLightUniforms), cmdb, 0, 1); light->m_inputTexUvScale = info.m_gbufferTexCoordsScale; light->m_inputTexUvBias = info.m_gbufferTexCoordsBias; light->m_fbUvScale = info.m_lightbufferTexCoordsScale; light->m_fbUvBias = info.m_lightbufferTexCoordsBias; light->m_invViewProjMat = info.m_invViewProjectionMatrix; light->m_camPos = info.m_cameraPosWSpace.xyz(); light->m_position = plightEl.m_worldPosition; light->m_oneOverSquareRadius = 1.0f / (plightEl.m_radius * plightEl.m_radius); light->m_diffuseColor = plightEl.m_diffuseColor; // Draw cmdb->drawElements(PrimitiveTopology::TRIANGLES, indexCount); } // Do spot lights bindVertexIndexBuffers(m_slightMesh, cmdb, indexCount); cmdb->bindShaderProgram(m_slightGrProg[info.m_computeSpecular]); for(const SpotLightQueueElement& splightEl : info.m_spotLights) { // Compute the model matrix // Mat4 modelM(splightEl.m_worldTransform.getTranslationPart().xyz1(), splightEl.m_worldTransform.getRotationPart(), 1.0f); // Calc the scale of the cone Mat4 scaleM(Mat4::getIdentity()); scaleM(0, 0) = tan(splightEl.m_outerAngle / 2.0f) * splightEl.m_distance; scaleM(1, 1) = scaleM(0, 0); scaleM(2, 2) = splightEl.m_distance; modelM = modelM * scaleM; // Update vertex uniforms DeferredVertexUniforms* vert = allocateAndBindUniforms(sizeof(DeferredVertexUniforms), cmdb, 0, 0); vert->m_mvp = info.m_viewProjectionMatrix * modelM; // Update fragment uniforms DeferredSpotLightUniforms* light = allocateAndBindUniforms(sizeof(DeferredSpotLightUniforms), cmdb, 0, 1); light->m_inputTexUvScale = info.m_gbufferTexCoordsScale; light->m_inputTexUvBias = info.m_gbufferTexCoordsBias; light->m_fbUvScale = info.m_lightbufferTexCoordsScale; light->m_fbUvBias = info.m_lightbufferTexCoordsBias; light->m_invViewProjMat = info.m_invViewProjectionMatrix; light->m_camPos = info.m_cameraPosWSpace.xyz(); light->m_position = splightEl.m_worldTransform.getTranslationPart().xyz(); light->m_oneOverSquareRadius = 1.0f / (splightEl.m_distance * splightEl.m_distance); light->m_diffuseColor = splightEl.m_diffuseColor; light->m_outerCos = cos(splightEl.m_outerAngle / 2.0f); light->m_lightDir = -splightEl.m_worldTransform.getZAxis().xyz(); light->m_innerCos = cos(splightEl.m_innerAngle / 2.0f); // Draw cmdb->drawElements(PrimitiveTopology::TRIANGLES, indexCount); } // Restore state cmdb->setBlendFactors(0, BlendFactor::ONE, BlendFactor::ZERO); cmdb->setCullMode(FaceSelectionBit::BACK); } } // end namespace anki