been reading the "guide" at: viewtopic.php?f=25&t=83763&p=519279#p519340
and viewtopic.php?t=85410
When I took the code from the first, I converted the opengl -> direct as that is the only thing my ogre has for now and removed the texture buffer input etc.
So what it is supposed to do, the bare minimum is send the mvp matrix so I can do the simplist vertex shader. But either Im missunderstanding it totally or it does something wrong cause it always seems like my "mvp" forces the object rendered to be put "exactly" where the camera is (debugged both manually and with RenderingDoc)
Because of RenderingDoc it seems to both put the mvp in the constant buffer and read to correct one, its just that the "mvp" itself seems to not be correct?
I only post the "minimum" code here, for the HlmsBufferManager its the same one as in the first thread. I load it like him too.
Vertex shader
Code: Select all
cbuffer ModelViewProjectionCB : register( b0 )
{
matrix projection[1024];
};
struct VS_INPUT
{
float4 vertex : POSITION;
float3 normal : NORMAL;
//float2 uv0 : TEXCOORD;
uint drawId : DRAWID;
};
struct PS_INPUT
{
float4 gl_Position : SV_Position;
float3 normal : NORMAL;
//float2 uv0 : TEXCOORD;
};
float4 main( VS_INPUT input ):SV_Position
{
PS_INPUT outVs;
outVs.gl_Position = mul(input.vertex,projection[input.drawId]);
//mul(input.vertex,projection).xyz;
outVs.normal = input.normal;
//outVs.uv0 = input.uv0;
//return outVs;
return outVs.gl_Position;
}
Code: Select all
//////////////
// TYPEDEFS //
//////////////
struct PS_INPUT
{
//float4 gl_Position : SV_Position;
//float3 normal : NORMAL;
//float2 uv0 : TEXCOORD;
};
float4 main() : SV_Target
{
return float4(1,1,1,1);
}
Code: Select all
//////////////////////////////////////////////
// HlmsGround.h //
// //
// //
//////////////////////////////////////////////
#ifndef __HlmsGround
#define __HlmsGround
// Forward declarations
namespace Ogre
{
class VaoManager ;
class ConstBufferPacked ;
}
class OgreInitializer ;
#include "HlmsBufferManager.h"
#include <OgreHlmsDatablock.h>
#include <OgreMatrix4.h>
// This is a simple datablock. I am not sure what to put in there for now, but in this simple example it is not needed
class HlmsBlockDatablock : public Ogre::HlmsDatablock
{
private :
// Attributes
public :
// Constructor, destructor
HlmsBlockDatablock (Ogre::IdString name, Ogre::Hlms* creator, const Ogre::HlmsMacroblock* macroblock, const Ogre::HlmsBlendblock* blendblock, const Ogre::HlmsParamVec& params)
: HlmsDatablock(name, creator, macroblock, blendblock, params)
{
// Nothing to do
}
~HlmsBlockDatablock ()
{
// Nothing to do
}
} ;
// Here is the real class, inheriting from the BufferManager
class HlmsBlock : public HlmsBufferManager
{
private :
// Attributes
// The buffers used for the passes (one for every pass, we can't map the same accross different frames)
unsigned int _currentPassBuffer ;
std::vector<Ogre::ConstBufferPacked*> _passBuffers ;
// We want to give the WorldMat. This one will be calculated only once, so keep it there
Ogre::Matrix4 _passViewProj ;
// Sampler block we will use for the texture
const Ogre::HlmsSamplerblock* _samplerBlock ;
public :
// Constructor, destructor
HlmsBlock(Ogre::Archive* dataFolder, Ogre::ArchiveVec* libraryFolders, Ogre::VaoManager* vaoManager) ;
~HlmsBlock() ;
// HLMS functions
virtual const Ogre::HlmsCache* createShaderCacheEntry (Ogre::uint32 renderableHash, const Ogre::HlmsCache& passCache, Ogre::uint32 finalHash, const Ogre::QueuedRenderable& queuedRenderable) ;
virtual Ogre::HlmsCache preparePassHash (const Ogre::CompositorShadowNode* shadowNode, bool casterPass, bool dualParaboloid, Ogre::SceneManager* sceneManager) ;
virtual Ogre::uint32 fillBuffersFor (const Ogre::HlmsCache* cache, const Ogre::QueuedRenderable& queuedRenderable, bool casterPass, Ogre::uint32 lastCacheHash, Ogre::uint32 lastTextureHash) ;
virtual Ogre::uint32 fillBuffersFor (const Ogre::HlmsCache* cache, const Ogre::QueuedRenderable& queuedRenderable, bool casterPass, Ogre::uint32 lastCacheHash, Ogre::CommandBuffer* commandBuffer) ;
virtual void frameEnded () ;
virtual HlmsBlockDatablock* createDatablockImpl (Ogre::IdString datablockName, const Ogre::HlmsMacroblock* macroblock, const Ogre::HlmsBlendblock* blendblock, const Ogre::HlmsParamVec& paramVec) ;
} ;
#endif
Code: Select all
#include "pch.h"
//////////////////////////////////////////////
// HlmsGround.cpp //
// //
// //
//////////////////////////////////////////////
/// Defines ----------------------------------
// Buffer : Light direction + light's colour
// I put the total pass' size here, in values
#define GROUND_HLMS_PASS_BUFFER_SIZE 8
/// Includes ---------------------------------
// Locals
#include "material/HlmsBlock.h"
// Natives
#include <cstddef>
#include <iostream>
#include <OgreHlmsCommon.h>
#include <OgreLight.h>
#include <OgreCamera.h>
#include <OgreRenderable.h>
#include <OgreRenderQueue.h>
#include <OgreTextureManager.h>
#include <CommandBuffer/OgreCbShaderBuffer.h>
#include <CommandBuffer/OgreCbTexture.h>
#include <CommandBuffer/OgreCommandBuffer.h>
#include <Vao/OgreConstBufferPacked.h>
#include <Vao/OgreVaoManager.h>
/// Constructor, destructor ------------------
// Here you can see we give the name we want it to have, and its type
HlmsBlock::HlmsBlock(Ogre::Archive* dataFolder, Ogre::ArchiveVec* libraryFolders, Ogre::VaoManager* vaoManager)
: HlmsBufferManager (dataFolder, libraryFolders, vaoManager, "Block", Ogre::HLMS_USER0),
_currentPassBuffer (0),
_passBuffers (),
_passViewProj (Ogre::Matrix4::IDENTITY),
_samplerBlock (NULL)
{
// We register this HLMS class with the Ogre::HLMS_USER0 id. For another one, you could use HLMS_USER1, and so on
// Initiailize our sampler block for the texture
// We create a reference sampler block, to ask Ogre about the one used in intern. This is done in order to cache things and avoid having multiple blocks doing the same thing
// That's less API overhead as we won't switch for nothing
Ogre::HlmsSamplerblock samplerBlockRef ;
// You can change every parameter here. This is defining the sampler block you want from Ogre
// Let's put WRAP on U and V, it will repeat the texture (you can MIRROR, CLAMP...)
samplerBlockRef.mU = Ogre::TAM_WRAP ;
samplerBlockRef.mV = Ogre::TAM_WRAP ;
// Then, let's ask Ogre about its internal buffer. We will keep it and use it !
Ogre::HlmsManager* hlmsMan = Ogre::Root::getSingleton().getHlmsManager() ;
_samplerBlock = hlmsMan->getSamplerblock(samplerBlockRef) ;
}
HlmsBlock::~HlmsBlock()
{
// We have to delete our pass buffer
for (unsigned int i = 0 ; i < _passBuffers.size() ; i++)
_vaoManager->destroyConstBuffer(_passBuffers[i]) ;
}
/// HLMS functions ---------------------------
const Ogre::HlmsCache* HlmsBlock::createShaderCacheEntry (Ogre::uint32 renderableHash, const Ogre::HlmsCache& passCache, Ogre::uint32 finalHash, const Ogre::QueuedRenderable& queuedRenderable)
{
// First the parent one
const Ogre::HlmsCache* retVal = HlmsBufferManager::createShaderCacheEntry(renderableHash, passCache, finalHash, queuedRenderable) ;
// Here is where you can put the default values for the shaders.
// So we set the samplerId for our texture (to 0, let's be fair)
//retVal->pso.pixelShader->getDefaultParameters()->setNamedConstant("baseTex", 0) ;
// We have to switch the values in the program
mRenderSystem->_setPipelineStateObject(&retVal->pso) ;
// Doing it only with the pixel shader as it is the only one needing it
Ogre::GpuProgramParametersSharedPtr psParams = retVal->pso.pixelShader->getDefaultParameters() ;
mRenderSystem->bindGpuProgramParameters(Ogre::GPT_FRAGMENT_PROGRAM, psParams, Ogre::GPV_ALL) ;
// Would be this with the vertex shader
Ogre::GpuProgramParametersSharedPtr vsParams = retVal->pso.vertexShader->getDefaultParameters() ;
mRenderSystem->bindGpuProgramParameters(Ogre::GPT_VERTEX_PROGRAM, vsParams, Ogre::GPV_ALL);
// Done
return retVal ;
}
Ogre::HlmsCache HlmsBlock::preparePassHash (const Ogre::CompositorShadowNode* shadowNode, bool casterPass, bool dualParaboloid, Ogre::SceneManager* sceneManager)
{
// Let's call the parent again
Ogre::HlmsCache retVal = Hlms::preparePassHash (shadowNode, casterPass, dualParaboloid, sceneManager) ;
// Let's prepare our viewProj matrix (before the pass)
// You can get the camera from wherever you want, but we will take the current active camera here
Ogre::Camera* cam = sceneManager->getCameraInProgress() ;
Ogre::Matrix4 tempview = cam->getViewMatrix(true);
Ogre::Matrix4 projection = cam->getProjectionMatrixWithRSDepth() ;
Ogre::RenderTarget* rt = sceneManager->getCurrentViewport()->getTarget() ;
Ogre::Matrix4 identityProjMat;
mRenderSystem->_convertProjectionMatrix(Ogre::Matrix4::IDENTITY,
identityProjMat, true);
// Maybe we need to flip it (RTT at least)
if (rt->requiresTextureFlipping())
{
projection[1][0] = -projection[1][0] ;
projection[1][1] = -projection[1][1] ;
projection[1][2] = -projection[1][2] ;
projection[1][3] = -projection[1][3] ;
}
Ogre::Matrix4 viewProj = projection * tempview;
_passViewProj = viewProj;
return retVal ;
}
Ogre::uint32 HlmsBlock::fillBuffersFor (const Ogre::HlmsCache* cache, const Ogre::QueuedRenderable& queuedRenderable, bool casterPass, Ogre::uint32 lastCacheHash, Ogre::uint32 lastTextureHash)
{
// I didn't get any call for this one, but at least the console will tell us if it is so
std::cout << "fillBuffersFor Tex" << std::endl ;
return 0 ;
}
Ogre::uint32 HlmsBlock::fillBuffersFor (const Ogre::HlmsCache* cache, const Ogre::QueuedRenderable& queuedRenderable, bool casterPass, Ogre::uint32 lastCacheHash, Ogre::CommandBuffer* commandBuffer)
{
//We dont have any pass params, skip that and go directly to instance buffers
// We have now to fill the datas for an instance (and not a pass)
// The size of what we write to keep track of where we are
// We write only a mat4, so 16 values
Ogre::uint32 valuesToWrite = 16 ;
// Let's check if the buffer is big enough
bool bufferTooSmall = (_bufferCurrentIndex - _bufferStartIndex + valuesToWrite) > _bufferSize ;
if (bufferTooSmall)
{
// We have to ask for a new buffer, from the HlmsBufferManager parent
mapNextConstBuffer(commandBuffer) ;
}
//Special check for "unsupported" features that this material doesnt allow
bool useIdentityProjection = queuedRenderable.renderable->getUseIdentityProjection();
if (useIdentityProjection) {
cout << "useIdentityProjection" << endl;
throw std::runtime_error("asd");
}
#if OGRE_DOUBLE_PRECISION
cout << "Double prec used, need to throw" << endl;
throw std::runtime_error("asd");
#endif
// Fill the buffer then.
// Get the World mat
const Ogre::Matrix4& worldMat = queuedRenderable.movableObject->_getParentNodeFullTransform() ;
// We can then compute the final matrix
Ogre::Matrix4 mvpStandard = _passViewProj * worldMat ;
// Here I guess I had to transpose because it is OpenGL. Not sure though, as I saw transpose in the PBS one was done every time
Ogre::Matrix4 mvpMat = mvpStandard.transpose() ;
// We can push the matrix into our buffer
memcpy(_bufferCurrentIndex, &mvpMat, 16 * sizeof(float)) ;
// We have to update the offset for the next Item calling this function before its draw
_bufferCurrentIndex += valuesToWrite ;
// This drawId is important (see Dark_Sylinc's answer)
// Keep in mind that only the first one has to be correct, as Ogre's auto instancing will increment the base value automatically.
Ogre::uint32 drawId = ((_bufferCurrentIndex - _bufferStartIndex) / valuesToWrite) - 1 ;
return drawId ;
}
void HlmsBlock::frameEnded ()
{
// We have to call this one, it is resetting the constBuffer vars for us here
HlmsBufferManager::frameEnded() ;
// And as we added a pass component, we have to reset it ourself
_currentPassBuffer = 0 ;
_bufferStartIndex = 0;
_bufferCurrentIndex = 0;
_bufferSize = 0;
}
HlmsBlockDatablock* HlmsBlock::createDatablockImpl (Ogre::IdString datablockName, const Ogre::HlmsMacroblock* macroblock, const Ogre::HlmsBlendblock* blendblock, const Ogre::HlmsParamVec& paramVec)
{
// Only return the datablock
return OGRE_NEW HlmsBlockDatablock (datablockName, this, macroblock, blendblock, paramVec) ;
}
Note: Ive added the cases so I ensure Im not running double precision ogre, and Im not, neither does my rendable want the "identiyprojectionmatrix".
Best regards /Lan