void GPUProgramManager::removeUnused() { #ifdef C_CODE std::map<std::string, GPUProgram*>::iterator it = _programs.begin(); while (it != _programs.end()) { if (it->second->getNReferences() == 0) { ILogger::instance()->logInfo("Deleting program %s", it->second->getName().c_str() ); delete it->second; _programs.erase(it++); } else{ ++it; } } #endif #ifdef JAVA_CODE java.util.Iterator it = _programs.entrySet().iterator(); while (it.hasNext()) { java.util.Map.Entry pairs = (java.util.Map.Entry)it.next(); GPUProgram program = (GPUProgram) pairs.getValue(); if (program.getNReferences() == 0) { ILogger.instance().logInfo("Deleting program %s", program.getName() ); it.remove(); } } #endif }
//----------------------------------------------------------------------------------------------------------------------------------------------------- Ptr<GPUProgram> Context::CreateGPUProgram( Ptr<VertexShader> pVertexShader, Ptr<FragmentShader> pFragmentShader ) { GPUProgram* pProgram = new GPUProgram(this); if (pVertexShader) pProgram->Attach(pVertexShader); if (pFragmentShader) pProgram->Attach(pFragmentShader); return pProgram; }
void GCL::RenderComponent::Render(const Matrix44 &proj) { const RenderObject *tempRenderObject = mObj; if (tempRenderObject->IsVisible()) { const Material &tempMaterial = tempRenderObject->GetMaterial(); tempMaterial.Bind(); const Matrix44 &transform = mParentActor->GetTransform(); GPUProgram *tempProgram = tempMaterial.GetShader(); tempProgram->SetProjectionMatrix(proj); tempProgram->SetModelViewMatrix(transform); tempRenderObject->GetVBO().Render(); } }
bool GPUProgramManager::loadGPUProgram(const char* name, const char* vertexProgram, const char* fragmentProgram, const char* geometryProgram, int GS_inputPrimitiveType, int GS_outputPrimitiveType, int GS_maxVerticesOut) { bool ret = false; //load the gpu program using vertex and fragment shader source GPUProgram* gpup = new GPUProgram(); if(gpup->load(vertexProgram,fragmentProgram,geometryProgram,GS_inputPrimitiveType,GS_outputPrimitiveType,GS_maxVerticesOut)) { this->gpuPrograms[name] = gpup; ret = true; } else delete gpup; return ret; }
void FramebufferObject::bindRenderablesToOutput (GraphicAPI * api) { GPUProgram* program = api->getCurrentProgram(); // TODO: remove the hard coded 16 std::vector<Texture2D*> textures(16); if(program == NULL) return; int boundNames = 0; std::map<std::string,Texture2D*>::iterator it; for(it = renderables.begin(); it != renderables.end(); it++) { int location = program->getOutputLocation(it->first); if(location != -1) { textures[location] = it->second; boundNames++; } } textures.resize(boundNames); useRenderables(textures); }
void VPLShaderManager::drawBackground(const Sensor *sensor, const Transform &projectionTransform, Float scaleFactor) { if (m_backgroundProgram == NULL) return; const Transform &trafo = sensor->getWorldTransform()->eval(0); Transform clipToWorld = trafo * Transform::scale(Vector(-1, 1, -1)) * projectionTransform.inverse(); GPUProgram *prog = m_backgroundProgram; int tuOffset = 0; prog->bind(); m_backgroundDependencies.bind(prog, m_backgroundDependencies, tuOffset); if (sensor->getType() & Sensor::EOrthographicCamera) { Vector d = trafo(Vector(0.0f, 0.0f, 1.0f)); prog->setParameter(m_backgroundParam_camDirection, d); } else { Point p = trafo(Point(0.0f)); prog->setParameter(m_backgroundParam_camPosition, p); } prog->setParameter(m_backgroundParam_emitterScale, scaleFactor); prog->setParameter(m_backgroundParam_clipToWorld, clipToWorld); m_renderer->blitQuad(false); prog->unbind(); m_backgroundDependencies.unbind(); }
GPUProgram* GPUProgramManager::getCompiledProgram(int uniformsCode, int attributesCode) { #ifdef C_CODE for (std::map<std::string, GPUProgram*>::iterator it = _programs.begin(); it != _programs.end(); ++it) { //#warning GPUProgram getUniformsCode avoid call GPUProgram* p = it->second; if (p->getUniformsCode() == uniformsCode && p->getAttributesCode() == attributesCode) { return p; } } #endif #ifdef JAVA_CODE for (final GPUProgram p : _programs.values()) { if ((p.getUniformsCode() == uniformsCode) && (p.getAttributesCode() == attributesCode)) { return p; } } #endif return NULL; }
GPUProgram* GPUProgramManager::getProgram(GL* gl, int uniformsCode, int attributesCode) { GPUProgram* p = getCompiledProgram(uniformsCode, attributesCode); if (p == NULL) { p = getNewProgram(gl, uniformsCode, attributesCode); if (p == NULL) { ILogger::instance()->logError("Problem at compiling program."); return NULL; } //#warning AVOID getAttributesCode and getUniformsCode calls if (p->getAttributesCode() != attributesCode || p->getUniformsCode() != uniformsCode) { //#warning GIVE MORE DETAIL ILogger::instance()->logError("New compiled program does not match GL state."); } } p->addReference(); return p; }
void Sprite::Render(const Matrix44 &proj) { if (!IsVisible()) return; //RenderPipe::BufferCommands(); const RenderObject *tempRenderObject = mObj; const Material &tempMaterial = tempRenderObject->GetMaterial(); tempMaterial.Bind(); const Texture ¤tTexture = *(mTextureList[0]); currentTexture.Bind(); const Matrix44 &transform = mTransform; GPUProgram *tempProgram = tempMaterial.GetShader(); tempProgram->SetProjectionMatrix(proj); tempProgram->SetModelViewMatrix(transform); tempProgram->SetUniform("CurrentFrame", (long)mCurrentFrame); tempProgram->SetUniform("Dimension", Point2<long>(long(mHeader.width), long(mHeader.height))); tempProgram->SetUniform("FrameCount", (long)mHeader.frameCount); tempProgram->SetUniform("TextureSize", Point2<long>((long)currentTexture.GetResourceWidth(), (long)currentTexture.GetResourceHeight())); tempProgram->SetTextureSampler(currentTexture); tempRenderObject->GetVBO().Render(); //RenderPipe::FlushCommands(); }
void VPLShaderManager::setScene(const Scene *scene) { if (scene == m_scene || (scene && m_scene && scene->getShapes() == m_scene->getShapes())) { m_scene = scene; return; /* This is still the same scene! Do nothing.. */ } if (m_scene) { /* Unregister any content from the previous scene (which was uploaded to the GPU) */ const ref_vector<Shape> &oldShapes = m_scene->getShapes(); for (size_t i=0; i<oldShapes.size(); ++i) { const Shape *shape = oldShapes[i].get(); if (shape->getClass()->getName() == "Instance") { const Instance *instance = static_cast<const Instance *>(shape); const std::vector<const Shape *> &instantiatedShapes = instance->getShapeGroup()->getKDTree()->getShapes(); for (size_t j=0; j<instantiatedShapes.size(); ++j) { shape = instantiatedShapes[j]; if (!m_renderer->unregisterGeometry(shape)) continue; const BSDF *bsdf = shape->getBSDF(); if (!bsdf) bsdf = const_cast<Shape *>(shape)->createTriMesh()->getBSDF(); m_renderer->unregisterShaderForResource(bsdf); } } else { const BSDF *bsdf = shape->getBSDF(); if (!bsdf) bsdf = const_cast<Shape *>(shape)->createTriMesh()->getBSDF(); if (!m_renderer->unregisterGeometry(shape)) continue; m_renderer->unregisterShaderForResource(bsdf); } } const ref_vector<Emitter> &emitters = m_scene->getEmitters(); for (size_t i=0; i<emitters.size(); ++i) m_renderer->unregisterShaderForResource(emitters[i].get()); /* Release all active GPU programs */ std::map<std::string, VPLConfiguration>::iterator it = m_configurations.begin(); for (; it != m_configurations.end(); ++it) { GPUProgram *program = (*it).second.program; program->cleanup(); program->decRef(); } m_configurations.clear(); if (m_backgroundProgram) { m_backgroundProgram->cleanup(); m_backgroundProgram = NULL; } } m_scene = scene; m_vplIndex = 0; if (!scene) return; const ref_vector<Shape> &shapes = scene->getShapes(); m_geometry.clear(); m_geometry.reserve(shapes.size()); m_opaqueGeometry.clear(); m_opaqueGeometry.reserve(shapes.size()); m_animatedGeometry.clear(); Matrix4x4 identityTrafo; identityTrafo.setIdentity(); /* Upload all geometry to the GPU, create shaders for scattering models */ for (size_t i=0; i<shapes.size(); ++i) { const Shape *shape = shapes[i].get(); if (shape->getClass()->getName() == "Instance") { const Instance *instance = static_cast<const Instance *>(shape); const std::vector<const Shape *> &instantiatedShapes = instance->getShapeGroup()->getKDTree()->getShapes(); const AnimatedTransform *atrafo = instance->getWorldTransform(); const Matrix4x4 &trafo = atrafo->eval(0).getMatrix(); for (size_t j=0; j<instantiatedShapes.size(); ++j) { shape = instantiatedShapes[j]; GPUGeometry *gpuGeo = m_renderer->registerGeometry(shape); if (!gpuGeo) continue; const BSDF *bsdf = shape->getBSDF(); if (!bsdf) bsdf = gpuGeo->getTriMesh()->getBSDF(); Shader *shader = m_renderer->registerShaderForResource(bsdf); if (shader && !shader->isComplete()) { m_renderer->unregisterShaderForResource(bsdf); shader = NULL; } gpuGeo->setShader(shader); ssize_t geometryIndex = (ssize_t) m_geometry.size(), opaqueGeometryIndex = -1; m_geometry.push_back(std::make_pair(gpuGeo, trafo)); if (shader && !(shader->getFlags() & Shader::ETransparent)) { opaqueGeometryIndex = (ssize_t) m_opaqueGeometry.size(); m_opaqueGeometry.push_back(std::make_pair(gpuGeo, trafo)); } if (!atrafo->isStatic()) { m_animatedGeometry.push_back(AnimatedGeometryRecord(atrafo, geometryIndex, opaqueGeometryIndex)); } } } else { GPUGeometry *gpuGeo = m_renderer->registerGeometry(shape); if (!gpuGeo) continue; const BSDF *bsdf = shape->getBSDF(); if (!bsdf) bsdf = gpuGeo->getTriMesh()->getBSDF(); Shader *shader = m_renderer->registerShaderForResource(bsdf); if (shader && !shader->isComplete()) { m_renderer->unregisterShaderForResource(bsdf); shader = NULL; } gpuGeo->setShader(shader); m_geometry.push_back(std::make_pair(gpuGeo, identityTrafo)); if (shader && !(shader->getFlags() & Shader::ETransparent)) m_opaqueGeometry.push_back(std::make_pair(gpuGeo, identityTrafo)); } } const ref_vector<Emitter> &emitters = scene->getEmitters(); for (size_t i=0; i<emitters.size(); ++i) m_renderer->registerShaderForResource(emitters[i].get()); if (scene->hasEnvironmentEmitter()) { Shader *shader = m_renderer->getShaderForResource(m_scene->getEnvironmentEmitter()); m_backgroundDependencies = DependencyNode(shader); int id = 0; std::ostringstream oss; std::string evalName = m_backgroundDependencies.generateCode(oss, id); std::string marker = SUPPLEMENTAL_CODE_MARKER; std::string code = sh_background_frag; size_t insertionPos = code.find(marker); Assert(insertionPos != std::string::npos); code.replace(insertionPos, marker.length(), oss.str()); ref<GPUProgram> prog = m_renderer->createGPUProgram("Background program"); prog->setSource(GPUProgram::EVertexProgram, sh_background_vert); prog->setSource(GPUProgram::EFragmentProgram, code.c_str()); prog->define("BACKGROUND_EVAL_NAME", evalName + "_background"); if (scene->getSensor()->getType() & Sensor::EOrthographicCamera) prog->define("DIRECTIONAL_CAMERA"); prog->init(); id = 0; m_backgroundDependencies.resolve(prog, id); m_backgroundProgram = prog; m_backgroundParam_camPosition = prog->getParameterID("camPosition", false); m_backgroundParam_camDirection = prog->getParameterID("camDirection", false); m_backgroundParam_clipToWorld = prog->getParameterID("clipToWorld", false); m_backgroundParam_emitterScale = prog->getParameterID("emitterScale", false); } std::vector<size_t> geometryPermutation(m_geometry.size()), opaqueGeometryPermutation(m_opaqueGeometry.size()); for (size_t i=0; i<m_geometry.size(); ++i) geometryPermutation[i] = i; for (size_t i=0; i<m_opaqueGeometry.size(); ++i) opaqueGeometryPermutation[i] = i; /// Sort using the MaterialOrder to reduce material changes/pipeline flushes std::sort(geometryPermutation.begin(), geometryPermutation.end(), MaterialOrder(m_geometry)); std::sort(opaqueGeometryPermutation.begin(), opaqueGeometryPermutation.end(), MaterialOrder(m_opaqueGeometry)); if (!m_animatedGeometry.empty()) { std::vector<size_t> geometryPermutationInv(m_geometry.size()), opaqueGeometryPermutationInv(m_opaqueGeometry.size()); for (size_t i=0; i<m_geometry.size(); ++i) geometryPermutationInv[geometryPermutation[i]] = i; for (size_t i=0; i<m_opaqueGeometry.size(); ++i) opaqueGeometryPermutationInv[opaqueGeometryPermutation[i]] = i; for (size_t i=0; i<m_animatedGeometry.size(); ++i) { AnimatedGeometryRecord &agRec = m_animatedGeometry[i]; if (agRec.geometryIndex >= 0) agRec.geometryIndex = geometryPermutationInv[agRec.geometryIndex]; if (agRec.opaqueGeometryIndex >= 0) agRec.opaqueGeometryIndex = opaqueGeometryPermutationInv[agRec.opaqueGeometryIndex]; } } permute_inplace(&m_geometry[0], geometryPermutation); permute_inplace(&m_opaqueGeometry[0], opaqueGeometryPermutation); }
void VPLShaderManager::bind(const VPL &vpl, const BSDF *bsdf, const Sensor *sensor, const Emitter *emitter, const Matrix4x4 &instanceTransform, bool faceNormals) { Shader *bsdfShader = m_renderer->getShaderForResource(bsdf); Shader *vplShader = (vpl.type == EPointEmitterVPL || vpl.type == EDirectionalEmitterVPL) ? m_renderer->getShaderForResource(vpl.emitter) : m_renderer->getShaderForResource(vpl.its.getBSDF()); Shader *emitterShader = (emitter == NULL) ? NULL : m_renderer->getShaderForResource(emitter); /* Find situations in which we won't be able to render the object properly ... Case 1: one of the shaders is missing */ bool unsupported = bsdfShader == NULL || vplShader == NULL || (emitter != NULL && emitterShader == NULL); /* The material uses face normals (which have to be generated on the fly), and: case 2: anisotropy is active as well case 3: the graphics card does not support geometry shaders */ if (faceNormals) unsupported |= (bsdf->getType() & BSDF::EAnisotropic) || !m_renderer->getCapabilities()->isSupported( RendererCapabilities::EGeometryShaders); if (unsupported) { std::map<std::string, VPLConfiguration>::iterator it = m_configurations.find("unsupported"); m_targetConfiguration = VPLConfiguration(); if (it != m_configurations.end()) { /* A program for this configuration has been created previously */ m_currentProgram = (*it).second; } else { m_currentProgram = VPLConfiguration(); ref<GPUProgram> prog = m_renderer->createGPUProgram("Unsupported material program"); prog->setSource(GPUProgram::EVertexProgram, sh_unsupported_vert); prog->setSource(GPUProgram::EFragmentProgram, sh_unsupported_frag); prog->init(); prog->incRef(); m_currentProgram.program = prog; m_currentProgram.param_instanceTransform = prog->getParameterID("instanceTransform", false); m_configurations["unsupported"] = m_currentProgram; } GPUProgram *prog = m_currentProgram.program; prog->bind(); prog->setParameter(m_currentProgram.param_instanceTransform, instanceTransform); return; } m_targetConfiguration = VPLConfiguration(vplShader, bsdfShader, emitterShader, faceNormals); m_alpha = bsdfShader->getAlpha(); /* Generate a fingerprint of this shader chain, and check if it is known */ std::string fingerprint = m_targetConfiguration.toString(); if (m_diffuseSources) fingerprint += ", ds"; if (m_diffuseReceivers) fingerprint += ", dr"; std::map<std::string, VPLConfiguration>::iterator it = m_configurations.find(fingerprint); bool directionalCamera = false; if (sensor->getType() & Sensor::EOrthographicCamera) { directionalCamera = true; } else if (!(sensor->getType() & Sensor::EPerspectiveCamera)) { /* Sensor is neither a perspective nor orthographic camera */ Log(EError, "Unsupported sensor type!"); } if (it != m_configurations.end()) { /* A program for this configuration has been created previously */ m_currentProgram = (*it).second; } else { std::ostringstream oss; std::string vplEvalName, bsdfEvalName, emitterEvalName; m_targetConfiguration.generateCode(oss, vplEvalName, bsdfEvalName, emitterEvalName); m_currentProgram = m_targetConfiguration; ref<GPUProgram> prog = m_renderer->createGPUProgram(fingerprint); prog->setSource(GPUProgram::EVertexProgram, sh_render_vert); if (faceNormals) { prog->setSource(GPUProgram::EGeometryProgram, sh_render_geom); prog->setInputGeometryType(GPUProgram::ETriangles); prog->setOutputGeometryType(GPUProgram::ETriangleStrips); prog->setMaxVertices(3); } std::string code(sh_render_frag); std::string marker(SUPPLEMENTAL_CODE_MARKER); size_t insertionPos = code.find(marker); Assert(insertionPos != std::string::npos); code.replace(insertionPos, marker.length(), oss.str()); prog->setSource(GPUProgram::EFragmentProgram, code); if (bsdf->getType() & BSDF::EAnisotropic) prog->define("ANISOTROPIC"); if (fingerprint.find("VertexColor") != std::string::npos) prog->define("VERTEX_COLORS"); if (m_shadowMapType == ShadowMapGenerator::EDirectional) prog->define("DIRECTIONAL_VPL"); else if (m_shadowMapType == ShadowMapGenerator::EParaboloid) prog->define("PARABOLOIDAL_VPL"); else prog->define("CUBEMAP_VPL"); if (directionalCamera) prog->define("DIRECTIONAL_CAMERA"); if (faceNormals) prog->define("FACE_NORMALS"); if (vpl.type == EDirectionalEmitterVPL || vpl.type == EPointEmitterVPL) { prog->define("EMITTER_VPL"); prog->define("VPL_EVAL_NAME", vplEvalName + "_dir"); } else { if (m_diffuseSources) prog->define("VPL_EVAL_NAME", vplEvalName + "_diffuse"); else prog->define("VPL_EVAL_NAME", vplEvalName); } if (vpl.type == ESurfaceVPL || (vpl.type == EPointEmitterVPL && vpl.emitter->getType() & Emitter::EOnSurface)) prog->define("VPL_ON_SURFACE"); if (emitterShader) { prog->define("EMITTER_AREA_EVAL_NAME", emitterEvalName + "_area"); prog->define("EMITTER_DIR_EVAL_NAME", emitterEvalName + "_dir"); } if (m_diffuseReceivers) prog->define("BSDF_EVAL_NAME", bsdfEvalName + "_diffuse"); else prog->define("BSDF_EVAL_NAME", bsdfEvalName); prog->init(); prog->incRef(); m_currentProgram.program = prog; m_currentProgram.param_camPosition = prog->getParameterID("camPosition", false); m_currentProgram.param_camDirection = prog->getParameterID("camDirection", false); m_currentProgram.param_vplPosition = prog->getParameterID("vplPosition", false); m_currentProgram.param_vplDirection = prog->getParameterID("vplDirection", false); m_currentProgram.param_vplPower = prog->getParameterID("vplPower", false); m_currentProgram.param_vplTransform = prog->getParameterID("vplTransform", false); m_currentProgram.param_vplFrame = prog->getParameterID("vplFrame", false); m_currentProgram.param_vplUV = prog->getParameterID("vplUV", false); m_currentProgram.param_vplWi = prog->getParameterID("vplWi", false); m_currentProgram.param_minDistSqr = prog->getParameterID("minDistSqr", false); m_currentProgram.param_emitterScale = prog->getParameterID("emitterScale", false); m_currentProgram.param_depthRange = prog->getParameterID("depthRange", false); m_currentProgram.param_instanceTransform = prog->getParameterID("instanceTransform", false); m_currentProgram.param_shadowMap = prog->getParameterID("shadowMap", false); m_currentProgram.resolve(prog); m_configurations[fingerprint] = m_currentProgram; statsMaxResidentShaders.recordMaximum(m_configurations.size() + m_shadowGen->getShaderCount()); } GPUProgram *prog = m_currentProgram.program; prog->bind(); Float minDist = m_nearClip + (m_farClip - m_nearClip) * m_clamping; prog->setParameter(m_currentProgram.param_instanceTransform, instanceTransform); prog->setParameter(m_currentProgram.param_vplTransform, m_shadowMapTransform); prog->setParameter(m_currentProgram.param_depthRange, Vector2(m_nearClip, m_farClip)); prog->setParameter(m_currentProgram.param_vplPower, vpl.P); prog->setParameter(m_currentProgram.param_vplFrame, Matrix3x3(vpl.its.shFrame.s, vpl.its.shFrame.t, vpl.its.shFrame.n)); prog->setParameter(m_currentProgram.param_vplUV, vpl.its.uv); prog->setParameter(m_currentProgram.param_vplWi, vpl.its.wi); prog->setParameter(m_currentProgram.param_shadowMap, m_shadowMap); prog->setParameter(m_currentProgram.param_minDistSqr, minDist*minDist); prog->setParameter(m_currentProgram.param_emitterScale, vpl.emitterScale); if (directionalCamera) { Vector d = sensor->getWorldTransform()->eval(0)(Vector(0.0f, 0.0f, 1.0f)); prog->setParameter(m_currentProgram.param_camDirection, d); } else { Point p = sensor->getWorldTransform()->eval(0).transformAffine(Point(0.0f)); prog->setParameter(m_currentProgram.param_camPosition, p); } if (m_shadowMapType == ShadowMapGenerator::EDirectional) prog->setParameter(m_currentProgram.param_vplDirection, vpl.its.shFrame.n); else prog->setParameter(m_currentProgram.param_vplPosition, vpl.its.p); m_targetConfiguration.bind(m_currentProgram, 1); }
/* * FIXME: Stupid argument ordering */ void GenericRenderer::set_auto_uniforms_on_shader(GPUProgram& program, CameraID camera, Renderable &subactor) { //Calculate the modelview-projection matrix Mat4 modelview_projection; Mat4 modelview; const Mat4 model = subactor.final_transformation(); const Mat4& view = window().camera(camera)->view_matrix(); const Mat4& projection = window().camera(camera)->projection_matrix(); kmMat4Multiply(&modelview, &view, &model); kmMat4Multiply(&modelview_projection, &projection, &modelview); if(program.uniforms().uses_auto(SP_AUTO_VIEW_MATRIX)) { program.uniforms().set_mat4x4( program.uniforms().auto_variable_name(SP_AUTO_VIEW_MATRIX), view ); } if(program.uniforms().uses_auto(SP_AUTO_MODELVIEW_PROJECTION_MATRIX)) { program.uniforms().set_mat4x4( program.uniforms().auto_variable_name(SP_AUTO_MODELVIEW_PROJECTION_MATRIX), modelview_projection ); } if(program.uniforms().uses_auto(SP_AUTO_MODELVIEW_MATRIX)) { program.uniforms().set_mat4x4( program.uniforms().auto_variable_name(SP_AUTO_MODELVIEW_MATRIX), modelview ); } if(program.uniforms().uses_auto(SP_AUTO_PROJECTION_MATRIX)) { program.uniforms().set_mat4x4( program.uniforms().auto_variable_name(SP_AUTO_PROJECTION_MATRIX), projection ); } if(program.uniforms().uses_auto(SP_AUTO_INVERSE_TRANSPOSE_MODELVIEW_MATRIX)) { Mat3 inverse_transpose_modelview; kmMat4ExtractRotationMat3(&modelview, &inverse_transpose_modelview); kmMat3Inverse(&inverse_transpose_modelview, &inverse_transpose_modelview); kmMat3Transpose(&inverse_transpose_modelview, &inverse_transpose_modelview); program.uniforms().set_mat3x3( program.uniforms().auto_variable_name(SP_AUTO_INVERSE_TRANSPOSE_MODELVIEW_MATRIX), inverse_transpose_modelview ); } /* if(pass.uses_auto_uniform(SP_AUTO_MATERIAL_AMBIENT)) { pass.program()->uniforms().set_colour( pass.auto_uniform_variable_name(SP_AUTO_MATERIAL_AMBIENT), pass.ambient() ); } if(pass.uses_auto_uniform(SP_AUTO_MATERIAL_DIFFUSE)) { pass.program()->uniforms().set_colour( pass.auto_uniform_variable_name(SP_AUTO_MATERIAL_DIFFUSE), pass.diffuse() ); } if(pass.uses_auto_uniform(SP_AUTO_MATERIAL_SPECULAR)) { pass.program()->uniforms().set_colour( pass.auto_uniform_variable_name(SP_AUTO_MATERIAL_SPECULAR), pass.specular() ); } if(pass.uses_auto_uniform(SP_AUTO_MATERIAL_SHININESS)) { pass.program()->uniforms().set_float( pass.auto_uniform_variable_name(SP_AUTO_MATERIAL_SHININESS), pass.shininess() ); } if(pass.uses_auto_uniform(SP_AUTO_MATERIAL_ACTIVE_TEXTURE_UNITS)) { pass.program()->uniforms().set_int( pass.auto_uniform_variable_name(SP_AUTO_MATERIAL_ACTIVE_TEXTURE_UNITS), pass.texture_unit_count() ); }*/ }
void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, const Luminaire *luminaire, const Point &camPos, bool faceNormals) { Shader *bsdfShader = m_renderer->getShaderForResource(bsdf); Shader *vplShader = (vpl.type == ELuminaireVPL) ? m_renderer->getShaderForResource(vpl.luminaire) : m_renderer->getShaderForResource(vpl.its.shape->getBSDF()); Shader *lumShader = (luminaire == NULL) ? NULL : m_renderer->getShaderForResource(luminaire); std::ostringstream oss; if (bsdfShader == NULL || vplShader == NULL || (luminaire != NULL && lumShader == NULL)) { /* Unsupported! */ m_renderer->setColor(Spectrum(0.0f)); return; } bool anisotropic = bsdf->getType() & BSDF::EAnisotropic; m_targetConfig = VPLProgramConfiguration(vplShader, bsdfShader, lumShader, faceNormals); m_targetConfig.toString(oss); std::string configName = oss.str(); std::map<std::string, ProgramAndConfiguration>::iterator it = m_programs.find(configName); GPUProgram *program = NULL; if (it != m_programs.end()) { /* A program for this configuration has been created previously */ m_current = (*it).second; program = m_current.program; } else { /* No program for this particular combination exists -- create one */ program = m_renderer->createGPUProgram(configName); if (faceNormals) { /* Generate face normals in a geometry shader */ if (!m_renderer->getCapabilities()->isSupported( RendererCapabilities::EGeometryShaders)) Log(EError, "Face normals require geometry shader support!"); if (anisotropic) Log(EError, "Anisotropy and face normals can't be combined at the moment"); oss.str(""); oss << "#version 120" << endl << "#extension GL_EXT_geometry_shader4 : enable" << endl << "varying in vec3 lightVec_vertex[3], camVec_vertex[3];" << endl << "varying in vec2 uv_vertex[3];" << endl << "varying in vec3 vertexColor_vertex[3];" << endl << "varying out vec3 normal;" << endl << "varying out vec3 lightVec, camVec;" << endl << "varying out vec2 uv;" << endl << "varying out vec3 vertexColor;" << endl << endl << "void main() {" << endl << " vec3 edge1 = camVec_vertex[0]-camVec_vertex[1];" << endl << " vec3 edge2 = camVec_vertex[0]-camVec_vertex[2];" << endl << " normal = normalize(cross(edge1, edge2));" << endl << " gl_Position = vec4(0.0);" << endl << " lightVec = camVec = vec3(0.0);" << endl << " for (int i=0; i<gl_VerticesIn; ++i) {" << endl << " gl_Position = gl_PositionIn[i];" << endl << " uv = uv_vertex[i];" << endl << " vertexColor = vertexColor_vertex[i];" << endl << " lightVec = lightVec_vertex[i];" << endl << " camVec = camVec_vertex[i];" << endl << " EmitVertex();" << endl << " }" << endl << " EndPrimitive();" << endl << "}" << endl; program->setMaxVertices(3); program->setSource(GPUProgram::EGeometryProgram, oss.str()); } /* Vertex program */ oss.str(""); oss << "#version 120" << endl; if (anisotropic) oss << "varying vec3 tangent;" << endl; oss << "uniform vec3 vplPos, camPos;" << endl; if (!faceNormals) { oss << "varying vec3 lightVec, camVec;" << endl << "varying vec2 uv;" << endl << "varying vec3 normal;" << endl << "varying vec3 vertexColor;" << endl << endl << "void main() {" << endl << " uv = gl_MultiTexCoord0.xy;" << endl << " camVec = camPos - gl_Vertex.xyz;" << endl << " lightVec = vplPos - gl_Vertex.xyz;" << endl << " gl_Position = ftransform();" << endl << " vertexColor = gl_Color.rgb;" << endl << " normal = gl_Normal;" << endl; } else { oss << "varying vec3 lightVec_vertex, camVec_vertex;" << endl << "varying vec2 uv_vertex;" << endl << "varying vec3 vertexColor_vertex;" << endl << endl << "void main() {" << endl << " uv_vertex = gl_MultiTexCoord0.xy;" << endl << " camVec_vertex = camPos - gl_Vertex.xyz;" << endl << " lightVec_vertex = vplPos - gl_Vertex.xyz;" << endl << " gl_Position = ftransform();" << endl << " vertexColor_vertex = gl_Color.rgb;" << endl; } if (anisotropic) oss << " tangent = gl_MultiTexCoord1.xyz;" << endl; oss << "}" << endl; program->setSource(GPUProgram::EVertexProgram, oss.str()); oss.str(""); oss << "#version 120" << endl << endl << "/* Uniform inputs */" << endl << "uniform samplerCube shadowMap;" << endl << "uniform vec3 vplPower, vplS, vplT, vplN, vplWi;" << endl << "uniform float nearClip, invClipRange, minDist, alpha;" << endl << "uniform vec2 vplUV;" << endl << "uniform bool diffuseSources, diffuseReceivers;" << endl << "varying vec3 vertexColor;" << endl << endl << "/* Inputs <- Vertex program */" << endl << "varying vec3 normal, lightVec, camVec;" << endl << "varying vec2 uv;" << endl; if (anisotropic) oss << "varying vec3 tangent;" << endl; oss << endl << "/* Some helper functions for BSDF implementations */" << endl << "float cosTheta(vec3 v) { return v.z; }" << endl << "float sinTheta2(vec3 v) { return 1.0-v.z*v.z; }" << endl << "float sinTheta(vec3 v) { float st2 = sinTheta2(v); if (st2 <= 0) return 0.0; else return sqrt(sinTheta2(v)); }" << endl << "float tanTheta(vec3 v) { return sinTheta(v)/cosTheta(v); }" << endl << "float sinPhi(vec3 v) { return v.y/sinTheta(v); }" << endl << "float cosPhi(vec3 v) { return v.x/sinTheta(v); }" << endl << "const float pi = 3.141592653589;" << endl << "const float inv_pi = 0.318309886183791;" << endl << endl; std::string vplEvalName, bsdfEvalName, lumEvalName; m_targetConfig.generateCode(oss, vplEvalName, bsdfEvalName, lumEvalName); oss << "void main() {" << endl << " /* Set up an ONB */" << endl << " vec3 N = normalize(normal);" << endl; if (anisotropic) { oss << " vec3 S = normalize(tangent - dot(tangent, N)*N);" << endl; } else { oss << " vec3 S;" << endl << " if (abs(N.x) > abs(N.y)) {" << endl << " float invLen = 1.0 / sqrt(N.x*N.x + N.z*N.z);" << endl << " S = vec3(-N.z * invLen, 0.0, N.x * invLen);" << endl << " } else {" << endl << " float invLen = 1.0 / sqrt(N.y*N.y + N.z*N.z);" << endl << " S = vec3(0.0, -N.z * invLen, N.y * invLen);" << endl << " }" << endl; } oss << " vec3 T = cross(N, S);" << endl << endl << " /* Compute shadows */" << endl << " float d = length(lightVec);" << endl << " vec3 nLightVec = lightVec/d, absLightVec = abs(lightVec);" << endl << " float depth = max(max(absLightVec.x, absLightVec.y), absLightVec.z);" << endl << " depth = (depth-nearClip) * invClipRange - 0.005;" << endl << " float shadow = textureCube(shadowMap, nLightVec).r > depth ? 1.0 : 0.0;" << endl << endl << " /* Shading */" << endl << " vec3 nCamVec = normalize(camVec);" << endl << " vec3 wo = vec3(dot(S, nLightVec)," << endl << " dot(T, nLightVec)," << endl << " dot(N, nLightVec));" << endl << " vec3 wi = vec3(dot(S, nCamVec)," << endl << " dot(T, nCamVec)," << endl << " dot(N, nCamVec));" << endl << " vec3 vplWo = -vec3(dot(vplS, nLightVec)," << endl << " dot(vplT, nLightVec)," << endl << " dot(vplN, nLightVec));" << endl << " vec3 contrib = vplPower;" << endl << " if (!diffuseSources)" << endl << " contrib *= " << vplEvalName; if (vpl.type == ESurfaceVPL) oss << "(vplUV, vplWi, vplWo);" << endl; else oss << "_dir(vplWo);" << endl; if (vpl.type == ESurfaceVPL) oss << " else contrib *= max(0, cosTheta(vplWo));" << endl; oss << " if (d < minDist) d = minDist;" << endl << " if (!diffuseReceivers)" << endl << " contrib *= "<< bsdfEvalName << "(uv, wi, wo);" << endl << " else" << endl << " contrib *= " << bsdfEvalName << "_diffuse(uv, wi, wo);" << endl << " gl_FragColor.rgb = contrib"; if (vpl.type == ELuminaireVPL && (vpl.luminaire->getType() & Luminaire::EOnSurface)) oss << " * (shadow * abs(cosTheta(vplWo)) / (d*d))"; else oss << " * (shadow / (d*d))"; if (luminaire != NULL) { oss << endl; oss << " + " << lumEvalName << "_area(uv)" << " * " << lumEvalName << "_dir(wi);" << endl; } else { oss << ";" << endl; } oss << " gl_FragColor.a = alpha;" << endl << "}" << endl; program->setSource(GPUProgram::EFragmentProgram, oss.str()); try { program->init(); } catch (const std::exception &) { Log(EWarn, "Unable to compile the following VPL program:\n%s", oss.str().c_str()); throw; } m_targetConfig.resolve(program); m_targetConfig.param_shadowMap = program->getParameterID("shadowMap", false); m_targetConfig.param_vplPos = program->getParameterID("vplPos", false); m_targetConfig.param_camPos = program->getParameterID("camPos", false); m_targetConfig.param_vplPower = program->getParameterID("vplPower", false); m_targetConfig.param_vplN = program->getParameterID("vplN", false); m_targetConfig.param_vplS = program->getParameterID("vplS", false); m_targetConfig.param_vplT = program->getParameterID("vplT", false); m_targetConfig.param_vplWi = program->getParameterID("vplWi", false); m_targetConfig.param_vplUV = program->getParameterID("vplUV", false); m_targetConfig.param_nearClip = program->getParameterID("nearClip", false); m_targetConfig.param_invClipRange = program->getParameterID("invClipRange", false); m_targetConfig.param_minDist = program->getParameterID("minDist", false); m_targetConfig.param_diffuseSources = program->getParameterID("diffuseSources", false); m_targetConfig.param_diffuseReceivers = program->getParameterID("diffuseReceivers", false); m_targetConfig.param_alpha = program->getParameterID("alpha", false); m_current.program = program; m_current.config = m_targetConfig; m_programs[configName] = m_current; program->incRef(); } program->bind(); m_shadowMap->bind(0); const VPLProgramConfiguration &config = m_current.config; program->setParameter(config.param_shadowMap, m_shadowMap); program->setParameter(config.param_vplPos, vpl.its.p); program->setParameter(config.param_camPos, camPos); program->setParameter(config.param_vplN, vpl.its.shFrame.n); program->setParameter(config.param_vplS, vpl.its.shFrame.s); program->setParameter(config.param_vplT, vpl.its.shFrame.t); program->setParameter(config.param_alpha, bsdfShader->getFlags() & Shader::ETransparent ? 0.5f : 1.0f); if (vpl.type == ESurfaceVPL) { program->setParameter(config.param_vplWi, vpl.its.wi); program->setParameter(config.param_vplUV, vpl.its.uv); program->setParameter(config.param_diffuseSources, m_diffuseSources); } Spectrum power = vpl.P; if (m_diffuseSources && vpl.type == ESurfaceVPL) power *= vpl.its.shape->getBSDF()->getDiffuseReflectance(vpl.its) * INV_PI; program->setParameter(config.param_vplPower, power); program->setParameter(config.param_diffuseReceivers, m_diffuseReceivers); program->setParameter(config.param_nearClip, m_nearClip); program->setParameter(config.param_invClipRange, m_invClipRange); program->setParameter(config.param_minDist, m_minDist); int textureUnitOffset = 1; m_targetConfig.bind(program, config, textureUnitOffset); }