// For each Direct3D sampler of either the pixel or vertex stage, // looks up the corresponding OpenGL texture image unit and texture type, // and sets the texture and its addressing/filtering state (or NULL when inactive). // Sampler mapping needs to be up-to-date on the program object before this is called. gl::Error RendererD3D::applyTextures(GLImplFactory *implFactory, const gl::ContextState &data, gl::SamplerType shaderType, const FramebufferTextureArray &framebufferTextures, size_t framebufferTextureCount) { ProgramD3D *programD3D = GetImplAs<ProgramD3D>(data.state->getProgram()); ASSERT(!programD3D->isSamplerMappingDirty()); unsigned int samplerRange = programD3D->getUsedSamplerRange(shaderType); for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) { GLenum textureType = programD3D->getSamplerTextureType(shaderType, samplerIndex); GLint textureUnit = programD3D->getSamplerMapping(shaderType, samplerIndex, *data.caps); if (textureUnit != -1) { gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); ASSERT(texture); gl::Sampler *samplerObject = data.state->getSampler(textureUnit); const gl::SamplerState &samplerState = samplerObject ? samplerObject->getSamplerState() : texture->getSamplerState(); // TODO: std::binary_search may become unavailable using older versions of GCC if (texture->getTextureState().isSamplerComplete(samplerState, data) && !std::binary_search(framebufferTextures.begin(), framebufferTextures.begin() + framebufferTextureCount, texture)) { ANGLE_TRY(setSamplerState(shaderType, samplerIndex, texture, samplerState)); ANGLE_TRY(setTexture(shaderType, samplerIndex, texture)); } else { // Texture is not sampler complete or it is in use by the framebuffer. Bind the incomplete texture. gl::Texture *incompleteTexture = getIncompleteTexture(implFactory, textureType); ANGLE_TRY(setSamplerState(shaderType, samplerIndex, incompleteTexture, incompleteTexture->getSamplerState())); ANGLE_TRY(setTexture(shaderType, samplerIndex, incompleteTexture)); } } else { // No texture bound to this slot even though it is used by the shader, bind a NULL texture ANGLE_TRY(setTexture(shaderType, samplerIndex, nullptr)); } } // Set all the remaining textures to NULL size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? data.caps->maxTextureImageUnits : data.caps->maxVertexTextureImageUnits; clearTextures(shaderType, samplerRange, samplerCount); return gl::NoError(); }
// attach attaches the api texture to sampling stage i // void APITexture::attach(unsigned flags) { if (!tex) setup(0, 0, 0); if (tex) { d3dd->SetTexture(0, tex); setSamplerState(0, flags); } }
//------------------------------------------------------------------------------ //## Basic TEST_F(Test_Shader_Shader, IndependentSamplerState) { auto shader1 = Shader::create(LN_ASSETFILE("Shader/IndependentSamplerState.fx")); auto vertexDecl1 = newObject<VertexLayout>(); vertexDecl1->addElement(0, VertexElementType::Float3, VertexElementUsage::Position, 0); vertexDecl1->addElement(0, VertexElementType::Float2, VertexElementUsage::TexCoord, 0); struct Vertex { Vector3 pos; Vector2 uv; }; Vertex v[] = { { { -1, 1, 0 }, { 0, 0 }, }, // 0.5 で中央の face からサンプリングする { { 0, 1, 0 }, { 1, 0 }, }, { { -1, 0, 0 }, { 0, 1 }, }, { { 0, 0, 0 }, { 1, 1 }, }, }; auto vb1 = newObject<VertexBuffer>(sizeof(v), v, GraphicsResourceUsage::Static); auto tex1 = newObject<Texture2D>(2, 2, TextureFormat::RGBA8); auto bmp1 = tex1->map(MapMode::Write); bmp1->setPixel32(0, 0, ColorI(255, 0, 0, 255)); bmp1->setPixel32(1, 0, ColorI(255, 0, 255, 255)); bmp1->setPixel32(0, 1, ColorI(0, 255, 0, 255)); bmp1->setPixel32(1, 1, ColorI(0, 0, 255, 255)); // TODO: まだ SamplerState 直接指定をサポートしていないので Texture に対してセットする方法でテストケースだけ用意しておく。 // 後でサポートするとき、shader1->findParameter("mySamplerState")->setSamplerState(samplerState); とかに書き換える。 auto samplerState = newObject<SamplerState>(); samplerState->setFilterMode(TextureFilterMode::Linear); tex1->setSamplerState(samplerState); shader1->findParameter("_Texture")->setTexture(tex1); auto ctx = Engine::graphicsContext(); TestEnv::resetGraphicsContext(ctx); ctx->setVertexLayout(vertexDecl1); ctx->setVertexBuffer(0, vb1); ctx->setIndexBuffer(nullptr); ctx->setShaderPass(shader1->techniques()[0]->passes()[0]); // * [ ] default { ctx->clear(ClearFlags::All, Color::White, 1.0f, 0); ctx->setPrimitiveTopology(PrimitiveTopology::TriangleStrip); ctx->drawPrimitive(0, 2); ASSERT_SCREEN(LN_ASSETFILE("Shader/Result/Test_Shader_Shader-IndependentSamplerState-1.png")); } }
// For each Direct3D sampler of either the pixel or vertex stage, // looks up the corresponding OpenGL texture image unit and texture type, // and sets the texture and its addressing/filtering state (or NULL when inactive). gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shaderType, const FramebufferTextureArray &framebufferTextures, size_t framebufferTextureCount) { gl::Program *program = data.state->getProgram(); unsigned int samplerRange = program->getUsedSamplerRange(shaderType); for (unsigned int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++) { GLenum textureType = program->getSamplerTextureType(shaderType, samplerIndex); GLint textureUnit = program->getSamplerMapping(shaderType, samplerIndex, *data.caps); if (textureUnit != -1) { gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType); ASSERT(texture); gl::SamplerState sampler = texture->getSamplerState(); gl::Sampler *samplerObject = data.state->getSampler(textureUnit); if (samplerObject) { samplerObject->getState(&sampler); } // TODO: std::binary_search may become unavailable using older versions of GCC if (texture->isSamplerComplete(sampler, data) && !std::binary_search(framebufferTextures.begin(), framebufferTextures.begin() + framebufferTextureCount, texture)) { gl::Error error = setSamplerState(shaderType, samplerIndex, texture, sampler); if (error.isError()) { return error; } error = setTexture(shaderType, samplerIndex, texture); if (error.isError()) { return error; } } else { // Texture is not sampler complete or it is in use by the framebuffer. Bind the incomplete texture. gl::Texture *incompleteTexture = getIncompleteTexture(textureType); gl::Error error = setTexture(shaderType, samplerIndex, incompleteTexture); if (error.isError()) { return error; } } } else { // No texture bound to this slot even though it is used by the shader, bind a NULL texture gl::Error error = setTexture(shaderType, samplerIndex, NULL); if (error.isError()) { return error; } } } // Set all the remaining textures to NULL size_t samplerCount = (shaderType == gl::SAMPLER_PIXEL) ? data.caps->maxTextureImageUnits : data.caps->maxVertexTextureImageUnits; clearTextures(shaderType, samplerRange, samplerCount); return gl::Error(GL_NO_ERROR); }
void ShadowsDemo::onDraw() { App::onDraw(); const auto device = graphicsDevice(); device->setClearColor(0.0f, 0.0f, 0.0f, 0.0f); device->clear(ciri::ClearFlags::Color | ciri::ClearFlags::Depth); device->setRasterizerState(_rasterState); device->restoreDefaultBlendState(); if( _spotlightShader->isValid() && _directionalShader->isValid() ) { const cc::Mat4f& cameraViewProj = _camera.getProj() * _camera.getView(); bool firstLight = true; Light::Type boundLightType = Light::Type::Invalid; for( auto& light : _lights ) { // compute light matrices //const cc::Mat4f& lightView = light.view(); //const cc::Mat4f& lightProj = light.proj();//cc::math::perspectiveRH(45.0f, 1.0f, 0.1f, light.range());//light.proj(); //const cc::Mat4f lightViewProj = lightProj * lightView; if( light.type() == Light::Type::Directional ) { //light.computeViewProjFromFrustum(BoundingFrustum(cameraViewProj)); light.computeViewProjFromFrustum(BoundingFrustum(_camera.getFov(), _camera.getAspect(), _camera.getNearPlane(), _camera.getFarPlane(), _camera.getPosition(), _camera.getFpsFront(), _camera.getUp())); //light.computeViewProjOrtho(_camera.getView(), _camera.getFov(), _camera.getAspect(), _camera.getNearPlane(), _camera.getFarPlane()); } const cc::Mat4f lightViewProj = light.proj() * light.view(); if( light.castShadows() ) { device->setDepthStencilState(device->getDefaultDepthStencilDefault()); // set and clear render target ciri::IRenderTarget2D* depthTarget = _shadowTarget.get(); device->setRenderTargets(&depthTarget, 1); device->setClearColor(0.0f, 0.0f, 0.0f, 0.0f); device->clear(ciri::ClearFlags::Color | ciri::ClearFlags::Depth); // apply depth shader device->applyShader(_depthShader); // set viewport to depth size device->setViewport(ciri::Viewport(0, 0, _shadowTarget->getDepth()->getWidth(), _shadowTarget->getDepth()->getHeight())); // render all models for( auto& mdl : _models ) { _depthConstants.xform = lightViewProj * mdl->getXform().getWorld(); _depthConstantsBuffer->setData(sizeof(DepthConstants), &_depthConstants); device->setVertexBuffer(mdl->getVertexBuffer()); if( mdl->getIndexBuffer() != nullptr ) { device->setIndexBuffer(mdl->getIndexBuffer()); device->drawIndexed(ciri::PrimitiveTopology::TriangleList, mdl->getIndexBuffer()->getIndexCount()); } else { device->drawArrays(ciri::PrimitiveTopology::TriangleList, mdl->getVertexBuffer()->getVertexCount(), 0); } } // reser viewport to screen device->setViewport(ciri::Viewport(0, 0, window()->getWidth(), window()->getHeight())); // restore default render targets device->restoreDefaultRenderTargets(); } switch( light.type() ) { case Light::Type::Directional: { if( boundLightType != Light::Type::Directional || light.castShadows() ) { boundLightType = Light::Type::Directional; device->applyShader(_directionalShader); device->setTexture2D(0, _shadowTarget->getDepth(), ciri::ShaderStage::Pixel); device->setSamplerState(0, _shadowSampler, ciri::ShaderStage::Pixel); } _directionalConstants.LightDirection = light.direction(); _directionalConstants.LightColor = light.diffuseColor(); _directionalConstants.LightIntensity = light.diffuseIntensity(); _directionalConstants.campos = _camera.getPosition(); _directionalConstants.CastShadows = light.castShadows(); _directionalConstants.lightViewProj = lightViewProj; for( auto& mdl : _models ) { if( !mdl->isValid() ) { continue; } _directionalConstants.world = mdl->getXform().getWorld(); _directionalConstants.xform = cameraViewProj * _directionalConstants.world; _directionalConstantsBuffer->setData(sizeof(DirectionalConstants), &_directionalConstants); device->setVertexBuffer(mdl->getVertexBuffer()); if( mdl->getIndexBuffer() != nullptr ) { device->setIndexBuffer(mdl->getIndexBuffer()); device->drawIndexed(ciri::PrimitiveTopology::TriangleList, mdl->getIndexBuffer()->getIndexCount()); } else { device->drawArrays(ciri::PrimitiveTopology::TriangleList, mdl->getVertexBuffer()->getVertexCount(), 0); } } break; } case Light::Type::Spot: { if( boundLightType != Light::Type::Spot || light.castShadows() ) { boundLightType = Light::Type::Spot; device->applyShader(_spotlightShader); device->setTexture2D(0, _shadowTarget->getDepth(), ciri::ShaderStage::Pixel); device->setSamplerState(0, _shadowSampler, ciri::ShaderStage::Pixel); } _spotlightConstants.LightPosition = light.position(); _spotlightConstants.LightDirection = light.direction(); _spotlightConstants.LightColor = light.diffuseColor(); _spotlightConstants.LightCosInner = light.cosConeInnerAngle(true); _spotlightConstants.LightCosOuter = light.cosConeOuterAngle(true); _spotlightConstants.LightIntensity = light.diffuseIntensity(); _spotlightConstants.LightRange = light.range(); _spotlightConstants.CastShadows = light.castShadows(); _spotlightConstants.lightViewProj = lightViewProj; for( auto& mdl : _models ) { _spotlightConstants.world = mdl->getXform().getWorld(); _spotlightConstants.xform = cameraViewProj * _spotlightConstants.world; _spotlightConstantsBuffer->setData(sizeof(SpotlightConstants), &_spotlightConstants); device->setVertexBuffer(mdl->getVertexBuffer()); if( mdl->getIndexBuffer() != nullptr ) { device->setIndexBuffer(mdl->getIndexBuffer()); device->drawIndexed(ciri::PrimitiveTopology::TriangleList, mdl->getIndexBuffer()->getIndexCount()); } else { device->drawArrays(ciri::PrimitiveTopology::TriangleList, mdl->getVertexBuffer()->getVertexCount(), 0); } } break; } } if( firstLight ) { firstLight = false; device->setBlendState(_additiveBlendState); } } } device->present(); }