软模拟光栅化渲染器
时间:2022-09-27 08:30:01
软模拟光栅渲染器实现了统一的引擎渲染接口。现在可以用了opengl,ogles,d3d9,d3d分别渲染11和软模拟。
不支持多流。多流的目的是减少缓冲区数据的更新。软模拟没有从内存更新到显存的步骤,因此实现多流是没有意义的。然而,为了与原始接口统一,多流仍然可以设置在这里,多流将在渲染前合并。
因为不需要多流量,同样灵活的顶点格式对提高速度毫无意义。在这里使用固定的顶点格式,所有所需的数据都可以按固定的顺序放入,只占用更多的内存。
当顶点不太多时,速度瓶颈主要出现在光栅阶段。光栅阶段复杂shader可引入多线程处理,简单shader引入多线程优化不明显,内存读取瓶颈。
不同于硬件渲染,软模拟UI绘制更耗时,因为它相当于光栅化。相反,当占据屏幕像素很少时,模型的绘制速度更快。
和d3d、ogl与渲染管道相比,前世界空间与观察空间矩阵转换基本没有太大区别,投影矩阵结构差异较大。
这里使用的投影矩阵是右手系,depth与z成正比而不是像opengl那样和1/z成正比,这样深度测试精度更高,还可以辅助透视修正,缺点是反投影计算多了一步。
mat[0] = 1.0f/x; mat[4] = 0.0; mat[8] = 0.0; mat[12] = 0.0;
mat[1] = 0.0; mat[5] = 1.0f/y; mat[9] = 0.0; mat[13] = 0.0;
mat[2] = 0.0; mat[6] = 0.0; mat[10] = -1.0f/(zfar-znear); mat[14] =-znear/(zfar-znear);
mat[3] = 0.0; mat[7] = 0.0; mat[11] = -1.0; mat[15] = 0.0;
在vsshader不要除以中等深度计算w。
考虑到速度,只做了顶点光。
d3d渲染图片:
软模拟渲染图片:
用软模拟渲染之前的游戏,帧速有点差
源码:
//======================================================== // @Date: 2016.05 // @File: Include/Render/RendDriverSoft.h // @Brief: RendDriverSoft // @Author: LouLei // @Email: twopointfive@163.com // @Copyright (Crapell) - All Rights Reserved //======================================================== #ifndef __RendDriverSoft__H__ #define __RendDriverSoft__H__ #include "Render/RendDriver.h" struct VSInput { VSInput(); vec3 pos; vec4 color; vec3 normal; vec2 texcoord; }; //d3d VertexShaderOutput == ogl Fragment struct VSOutput { //Gouraud shading (per-vertex) pass [posH、color、texcoord] to pixel shader vec4 posH; //homogenous position vec4 color; vec2 texcoord; //Phong shading (per-pixel) additional pass [posW、normalW] 或 [posV、normalV] vec3 posW; vec3 normalW; vec3 posV; //有时可以简化传递视觉空间的位置ps计算 //vec3 normalV; }; typedef VSOutput Fragment; struct PSInput { int pixelX; int pixelY; vec4 color; vec2 texcoord; //vec3 normal; }; class FragmentEdge { public: const Fragment *Fragment1, *Fragment2; float dx, dy, dz, dw; float dr, dg, db, da; float ds, dt; bool valid; public: void Set(const Fragment *fragment1, const Fragment *fragment2); }; //扫描线 class FragmentSpan { public: const Fragment *Fragment1, *Fragment2; float dx, dy, dz, dw; float dr, dg, db, da; float ds, dt; public: void Set(const Fragment *fragment1, const Fragment *fragment2); }; //灯光 class LightSoft:public Light { friend class SoftRendDriver; public: LightSoft(); virtual void Bind(); virtual void UnBind(); bool operator==(LightSoft& Light) const; float diffuseIntensity; float specularIntensity; bool isEnabled; }; class SoftRendTexture; class MaterialSoft; class SoftVertexBuffer; class SoftIndexBuffer; class Camera; class SoftRendDriver:public RendDriver { friend class Rasterizer; friend class FragmentEdge; friend class LightSoft; friend class SoftVertexBuffer; friend class SoftIndexBuffer; public: SoftRendDriver(); ~SoftRendDriver(); virtual int Create(void* context); virtual void Close(); //! 设置矩阵 virtual void Perspective(float fovDegY=0, float znear=0, float zfar=0); virtual void Ortho (int x,int y,int w,int h, float znear=0, float zfar=0); //! 设置视口 virtual void SetViewPortf(float x,float y,float width,float height); virtual void SetViewPort(int x,int y,int width,int height); ! 开始2D渲染 virtual void BeginUI(int x=0, int y=0, int w = 0, int h = 0); //virtual void EndUI(){}; virtual void SetClipRect(const RectF &clipRect); virtual void SetClipRect(const RectF &clipRect,const RectF &fullRendTargetRect); virtual void ClearClipRect(); virtual void SetRenderStateEnable(RenderStateType rendstate,bool on,bool force=false); virtual void SetRenderStateEnable(LightName rendstate,bool on,bool force=false); virtual void CullFace (DrawBufferMode mode); virtual void BlendFunc (BlendingFactor sfactor,BlendingFactor dfactor,bool force=false); virtual void BlendFunc (BlendingType blendingType,bool force=false); //vrtual void Prepare();
virtual void RendClear(int mode,const Color& color);
virtual void FillMode(bool wire);
virtual void RendBegin(PrimitiveType mode);
virtual void RendEnd();
virtual void Vertex2f ( float x, float y );
virtual void Vertex3f ( float x, float y, float z );
virtual void Vertex3fv( const float* v);
virtual void TexCoord2f ( float x, float y );
virtual void TexCoord3f ( float s, float t, float r );
virtual void TexCoord3fv( const float* v );
virtual void Color3f ( float r, float g, float b);
virtual void Color3fv( const float* v );
virtual void Color4f ( float r, float g, float b, float a);
virtual void Color4fv( const float* v );
virtual void Normal3f ( float x, float y, float z );
virtual void Normal3fv( const float* v );
//virtual void SetMatrixMode(MatrixMode mode);
virtual void PushMatrix();
virtual void PopMatrix();
//virtual void LoadIdentity();
//virtual void MultMatrix(float* mat);
//virtual void Translatef( float x, float y, float z );
//virtual void Rotatef( float ang,float x, float y, float z );
//virtual void Scalef( float x, float y, float z );
virtual void SetMatrixToDrive(MatrixMode mode);
virtual void SwapBuffer();
virtual void ReadPixels (int x, int y, int width, int height, PixelFormat format, DataType type, void *pixels);
virtual vec3 UnProject(const vec2& pos,float depth=-1);
virtual vec3 Project(const vec3& pos);
//跳过正交投影及光栅化
virtual void DrawTextureRect(const RectF& tar);
virtual void DrawTextureRect (const RectF& tar,const RectF& scr,int depthTest=-1);
//virtual void DrawTextureRect (const RectF& tar,const RectF& scr,const vec2& cen,const mat3& rot);
virtual void DrawRect (const RectF& tar);
//virtual void DrawRect (const RectF& tar,const vec2& cen,const mat3& rot);
virtual void DrawPoint(int x, int y);
virtual void DrawLine (const vec2& start,const vec2& end);
//virtual void RendTrigon (int trigonNum,vec3* vVertex,vec2* tVertex,vec4* cVertex=NULL,vec3* nVertex=NULL,IndexInt* indexs=NULL,int vertexNum=0);
virtual void LookAt( float eyex, float eyey, float eyez,
float centerx, float centery, float centerz,
float upx, float upy, float upz);
virtual VertexBuffer* CreateVB();
virtual IndexBuffer* CreateIB();
virtual RendTexture* CreateTexture();
virtual RenderTarget* CreateRenderTarget();
virtual Light* CreateLight();
virtual Material* CreateMaterial();
virtual const char* GetLastError(){return "";};
virtual void OnSize();
void SetPresenter(Presenter* presenter);
void SetRendTexture(SoftRendTexture* pTex);
//startIndex=0
void DrawIndexedPrimitive(PrimitiveType type,int primCount);
void DrawTriangles(int primCount);
void DrawPoints (int primCount);
protected:
//c++ 模拟shader
inline vec4 VertexShader_Lighting(const vec3& vPosW,const vec3& vNormalW);
inline void VertexShader (const VSInput& inVertex,VSOutput& outVertex);
inline void PixelShader_Triangle(const PSInput& inVertex);
inline void PixelShader_Point (const PSInput& inVertex);
protected:
void HomoSpaceClipping_Triangles(const IndexInt* const pIB,int indexCount);
void HomoSpaceClipping_Points (const IndexInt* const pIB,int indexCount);
void RasterizeTriangles();
void RasterizePoints();
//!可以多线程 多个管道并行处理,所以规定不能取targetbuffer因为它是不确定的
void RasterizeTriangle (const VSOutput& vsOutput1,const VSOutput& vsOutput2,const VSOutput& vsOutput3);
void RasterizeBetweenEdges(const FragmentEdge *edgeL, const FragmentEdge *edgeS);
void RasterizeSpan (const FragmentSpan *span, int y);
inline void F_SetDepth (int x, int y,float z);
inline bool F_DepthTest (int x,int y,float srcZ);
inline void F_BlendPixel(const vec4*src, vec4*dst);
public:
//矩阵 渲染状态等 类似寄存器变量 加快速度
vec3 m_eyePos;
//有的矩阵在基类中已经维护了
mat4 m_modelMatrix;
mat4 m_viewMatrix;
mat4 m_projectMatrix;
//mat4 m_modelViewMatrix;
//mat4 m_viewProjectMatrix;
//mat4 m_modelViewProjectMatrix;
float* m_textureMatrix[8];
protected:
Presenter* m_presenter;
DrawBufferMode m_cullFace;
float* m_depthBuffer;
vec4* m_colorBuffer;//0~1
高光贴图等 在ShaderMgr中有保存
//Texture* m_curTexture[8];
//RenderTarget* m_curTargetTexture[8];
//todo
//SoftRenderTarget* m_colorBuffer;
//注意基类中也有此成员, 此处可以省略
SoftVertexBuffer* m_curVertexBuffer;
SoftIndexBuffer* m_curIndexBuffer;
SoftRendTexture* m_curRendTexture;
bool m_lightEnable;
LightSoft m_lights[MaxValidLightNum];
//世界空间 world space VertexBuffer
//投影空间 projection space
//齐次空间 homogeous space,通过vertexshader、geometryshader后后的vertexbuff
VSOutput* m_vertexBufferHomoSpace;
//通过齐次空间裁剪后的索引
int* m_indexBufferHomoClipped;
int m_indexNumHomoClipped;
//屏幕空间,光栅化后将进入pixelshader的fragment,vertices attribute have been interpolated
PSInput* m_fragmentsRasterized;
int m_fragmentsNum;
};
class SoftRendTexture:public RendTexture
{
public:
friend class SoftRendDriver;
SoftRendTexture();
~SoftRendTexture();
virtual void Create();
virtual void Create(int internalColorFormat, int width, int height, int colorFormat, const void *pixels);
virtual void Release();
virtual int Bind();
virtual void RefreshFromData(int width, int height,const unsigned char * imageData,int format);
//just ppm
bool CreateFromFile(const char* filename);
bool SaveToFile(const char* filePath, bool bOverrideExistedFile);
int GetWidth();
int GetHeight();
void SetPixel(int x, int y,const vec4& color);
void GetPixel(int x, int y,vec4& color);
//to Sampler
inline void SamplePixel(float u, float v,vec4& color);
private:
vec4* m_pColorBuffer;
};
class SoftRenderTarget :public RenderTarget
{
public:
SoftRenderTarget();
virtual ~SoftRenderTarget();
virtual void Create(ColorType fmt,int width, int height);
virtual void Release();
virtual int BeginTarget();
virtual void EndTarget();
virtual int BindTexture();
virtual void BltToCurTarget(bool depthTest=false);
virtual void SavetoFile(const char* filename);
protected:
void CreateEmptyTexture();
void CopyTexImage();
SoftRendTexture* m_texture;
};
class SoftDepthBuffer :public DepthBuffer
{
public:
SoftDepthBuffer();
virtual ~SoftDepthBuffer();
virtual void Create (int width, int height);
virtual void Release();
virtual int BeginBuffer();
virtual void EndBuffer ();
float* m_depthBuffer;
};
class SoftStencilBuffer :public StencilBuffer
{
public:
SoftStencilBuffer();
virtual ~SoftStencilBuffer();
virtual void Create(int width, int height);
virtual void Release();
virtual int BeginBuffer();
virtual void EndBuffer ();
float* m_stencilBuffer;
};
class SoftVertexBuffer:public VertexBuffer
{
public:
friend class SoftRendDriver;
SoftVertexBuffer();
virtual ~SoftVertexBuffer();
virtual bool Create(BufferMode mode,int fvfMode,unsigned long NumVertices,long VertexSize);
virtual bool Free();
virtual bool IsLoaded();
virtual bool Set(unsigned long FirstVertex, unsigned long NumVertices, void *VertexList);
virtual bool Bind (int streamIndex);
virtual bool UnBind();
virtual bool Lock (unsigned long FirstVertex = 0, unsigned long NumVertices = 0);
virtual bool Unlock();
private:
int m_bufferId;
void* m_pVB;
};
class SoftIndexBuffer:public IndexBuffer
{
public:
friend class SoftRendDriver;
SoftIndexBuffer();
virtual ~SoftIndexBuffer();
virtual bool Create(BufferMode mode,unsigned long NumIndexes);
virtual bool Free();
virtual bool IsLoaded();
virtual bool Bind (VertexDeclaration* decl);
virtual bool UnBind();
virtual bool Set(unsigned long FirstVertex, unsigned long NumIndexes, void *VertexList);
//virtual bool Render(unsigned long FirstVertex, unsigned long NumPrimitives, DWORD Type);
virtual bool Render(unsigned long FirstVertex, unsigned long NumPrimitives, PrimitiveType Type);
virtual bool Lock (unsigned long FirstVertex = 0, unsigned long NumIndexes = 0);
virtual bool Unlock();
private:
int m_bufferId;
IndexInt* m_pIB;
};
class MaterialSoft:public Material
{
public:
MaterialSoft();
virtual void Bind();
};
extern SoftRendDriver* G_SoftDriver;
#endif
//========================================================
// @Date: 2016.05
// @File: Include/Render/RendDriverSoft.cpp
// @Brief: RendDriverSoft
// @Author: LouLei
// @Email: twopointfive@163.com
// @Copyright (Crapell) - All Rights Reserved
//========================================================
#include "General/Pch.h"
#include "General/Window.h"
#include "General/List.h"
#include "General/Option.h"
#include "Math/MathLibAdvance.h"
#include "Render/Camera.h"
#include "Render/RendDriverSoft.h"
#include "Render/ShaderSoft.h"
//#include
#include
#include "Math/MathLibIncDbg.h"
#include "General/Pce.h"
SoftRendDriver* G_SoftDriver=NULL;
//#define DebugNotValidNum
#define MaxRenderVertex 36000 //5096
#define MaxQuads 6000 //849 //5096/4 5096/6
SoftVertexBuffer* G_VertexsPNCT3 = NULL;
SoftIndexBuffer* G_TiangleIndexs = NULL;
static VSInput* G_pVertexPNCT3 = NULL;
static int G_CachedVertexNum = 0;
#define MaxFragments 2359296 //1024*768*3, 限制单次drawcall最多约300%屏幕像素刷新率(覆盖3遍屏幕)
#define MaxIndex 65535 //最大索引short index
static bool RenderState[1024];
SoftRendDriver::SoftRendDriver()
:m_presenter(NULL)
,m_colorBuffer(NULL)
,m_depthBuffer(NULL)
,m_fragmentsRasterized(NULL)
,m_vertexBufferHomoSpace(NULL)
,m_indexBufferHomoClipped(NULL)
{
m_driverType = SOFTDRIVER;
G_SoftDriver = this;
m_indexNumHomoClipped = 0;
m_backBufferWidth = 100;
m_backBufferHeight = 100;
m_curTexture = 0;//NULL;//wait for user to set
m_eyePos = vec3( 0,0,0 );
m_lightEnable = true;
for (int i = 0;i < MaxValidLightNum;++i)
memset(&m_lights[i],0,sizeof(LightSoft));
m_curIndexBuffer = NULL;
m_curVertexBuffer = NULL;
}
SoftRendDriver::~SoftRendDriver()
{
Close();
}
int SoftRendDriver::Create(void* context)
{
if (!RendDriver::Create(context))
{
return false;
}
m_context = context;
int bufferWidth;
int bufferHeight;
if(G_Window->m_bFullScreen)
{
//G_d3dpp.Windowed = false;
bufferWidth = 1024;
bufferHeight = 768;
//bufferFormat = D3DFMT_X8R8G8B8;
}
else
{
//固定的不随窗口改变
bufferWidth = G_Window->m_iWidth;
bufferHeight = G_Window->m_iHeight;
if (bufferWidth<800)
{
bufferWidth = 800;
}
if (bufferHeight<600)
{
bufferHeight = 600;
}
}
m_backBufferWidth = bufferWidth;
m_backBufferHeight = bufferHeight;
m_colorBuffer = new vec4 [m_backBufferHeight*m_backBufferWidth];
m_depthBuffer = new float[m_backBufferHeight*m_backBufferWidth];
m_fragmentsRasterized = new PSInput[MaxFragments];
m_vertexBufferHomoSpace = new VSOutput[MaxIndex];
m_indexBufferHomoClipped = new int[MaxIndex];
G_VertexsPNCT3 = (SoftVertexBuffer*)CreateVB();
G_TiangleIndexs = (SoftIndexBuffer*)CreateIB();
G_VertexsPNCT3->Create(STATIC_DRAW_ARB,0,MaxRenderVertex,sizeof(VSInput));
G_TiangleIndexs->Create(STATIC_DRAW_ARB,MaxRenderVertex);
G_TiangleIndexs->Lock();
IndexInt* ptr = (IndexInt*)G_TiangleIndexs->GetLockedPtr();
for (int i=0;iUnlock();
G_VertexsPNCT3->Lock();
G_pVertexPNCT3 = (VSInput*)G_VertexsPNCT3->GetLockedPtr();
G_VertexsPNCT3->Unlock();
CullFace(RS_BACK);
CreateAllRenderTarget();
SetFogParms(Color(0,0,1,1),500,5000);
m_defaultMaterial = CreateMaterial();
return true;
}
void SoftRendDriver::Close()
{
RendDriver::Close();
SafeDelete(G_VertexsPNCT3);
SafeDelete(G_TiangleIndexs);
SafeDeleteArray(m_colorBuffer);
SafeDeleteArray(m_depthBuffer);
SafeDeleteArray(m_fragmentsRasterized);
SafeDeleteArray(m_vertexBufferHomoSpace);
SafeDeleteArray(m_indexBufferHomoClipped);
}
// 渲染前的准备工作
void SoftRendDriver::RendClear(int mode,const Color& clearColor)
{
int pixNum = m_backBufferWidth*m_backBufferHeight;
//color buffer
if(RS_COLOR_BUFFER_BIT&mode)
{
vec4* color = m_colorBuffer;
for (int i = 0;i < pixNum;++i)
{
color->r = clearColor.r;
color->g = clearColor.g;
color->b = clearColor.b;
color->a = clearColor.a;
color++;
}
}
//Depth Buffer
if(RS_DEPTH_BUFFER_BIT&mode)
{
float* depth = m_depthBuffer;
for (int i = 0;i < pixNum;++i)
{
*depth = 1.0f;
depth++;
}
}
}
void SoftRendDriver::FillMode(bool wire)
{
m_bWire = wire;
}
void SoftRendDriver::BlendFunc (BlendingFactor sfactor,BlendingFactor dfactor,bool force)
{
if (sfactor==RS_ONE||dfactor==RS_ONE)
{
m_opacityType = Blend_Additive;
}
else
{
m_opacityType = Blend_Filter;
}
}
void SoftRendDriver::BlendFunc (BlendingType blendingType,bool force)
{
m_opacityType = blendingType;
}
void SoftRendDriver::RendBegin(PrimitiveType mode)
{
m_curRendMode = mode;
G_CachedVertexNum = 0;
G_VertexsPNCT3->Lock();
G_pVertexPNCT3 = (VSInput*)G_VertexsPNCT3->GetLockedPtr();
}
void SoftRendDriver::RendEnd()
{
if (m_curRendMode == RS_Invalid)
{
Assert(0,"need RendBegin before RendEnd!");
return;
}
if (G_CachedVertexNum>0)
{
G_VertexsPNCT3->Bind(0);
G_TiangleIndexs->Bind(NULL);
int primtiveNum = 1;
switch(m_curRendMode)
{
case RS_POINTS:
{
primtiveNum = G_CachedVertexNum;
DrawPoints(primtiveNum);
break;
}
//case RS_LINES:
// {
// //v1~v2 ,v3~v4
// primtiveNum = G_CachedVertexNum/2;
// m_pD3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, primtiveNum, &G_VertexsPNCT3[0].x, sizeof(Vertex));
// break;
// }
case RS_TRIANGLES:
{
primtiveNum = G_CachedVertexNum/3;
DrawTriangles(primtiveNum);
break;
}
//case RS_QUADS:
// {
// //两个三角形模拟一个quad,原生不支持
// primtiveNum = G_CachedVertexNum/2;
// m_pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0,G_CachedVertexNum,primtiveNum, &G_QuadsIndexs[0],D3DFMT_INDEX32,&G_VertexsPNCT3[0].x, sizeof(Vertex));
// break;
// }
}
G_CachedVertexNum = 0;
G_pVertexPNCT3 = (VSInput*)G_VertexsPNCT3->GetLockedPtr();
CallStatistic_(DrawCallNum,1);
CallStatistic_(DrawPrimtiveNum,primtiveNum);
}
m_curRendMode = RS_Invalid;
G_VertexsPNCT3->Unlock();
}
void SoftRendDriver::Vertex2f( float x, float y )
{
}
void SoftRendDriver::Vertex3f( float x, float y, float z )
{
if (G_CachedVertexNum>=MaxRenderVertex)
{
return;
}
VSInput* vertex = G_pVertexPNCT3;
vertex->pos.x = x;
vertex->pos.y = y;
vertex->pos.z = z;
G_CachedVertexNum++;
G_pVertexPNCT3++;
VSInput* vertexNext = G_pVertexPNCT3;
vertexNext->normal.x = vertex->normal.x;
vertexNext->normal.y = vertex->normal.y;
vertexNext->normal.z = vertex->normal.z;
vertexNext->texcoord.x = vertex->texcoord.x;
vertexNext->texcoord.y = vertex->texcoord.y;
vertexNext->color = vertex->color;
}
void SoftRendDriver::Vertex3fv( const float* v)
{
Vertex3f(v[0],v[1],v[2]);
}
void SoftRendDriver::TexCoord2f( float u, float v )
{
VSInput* vertex = G_pVertexPNCT3;
vertex->texcoord.x = u;
vertex->texcoord.y = v;
}
void SoftRendDriver::TexCoord3f( float s, float t, float r )
{
VSInput* vertex = G_pVertexPNCT3;
vertex->texcoord.x = s;
vertex->texcoord.y = t;
}
void SoftRendDriver::TexCoord3fv( const float* v)
{
TexCoord3f(v[0],v[1],v[2]);
}
void SoftRendDriver::Color3f( float r, float g, float b)
{
Color4f(r, g, b, 1);
}
void SoftRendDriver::Color3fv( const float* v)
{
Color4f(v[0],v[1],v[2],1);
}
void SoftRendDriver::Color4fv( const float* v)
{
Color4f(v[0],v[1],v[2],v[3]);
}
void SoftRendDriver::Color4f( float r, float g, float b, float a)
{
m_curColor.r = r;
m_curColor.g = g;
m_curColor.b = b;
m_curColor.a = a;
VSInput* vertex = G_pVertexPNCT3;
vertex->color.x = r;
vertex->color.y = g;
vertex->color.z = b;
vertex->color.w = a;
}
void SoftRendDriver::Normal3f( float x, float y, float z )
{
VSInput* vertex = G_pVertexPNCT3;
vertex->normal.x = x;
vertex->normal.y = y;
vertex->normal.z = z;
}
void SoftRendDriver::Normal3fv( const float* v)
{
Normal3f(v[0],v[1],v[2]);
}
//void SoftRendDriver::FillMode(bool wire)
//{
// //assert(0 && __FUNCDNAME__ && "not impleted!");
//}
void SoftRendDriver::SetViewPortf(float x,float y,float width,float height)
{
//视口被改变
int w,h;
if(0)//GetRenderTargetNum()>0)
{
w = 400;//G_Window->m_iWidth;
h = 300;//G_Window->m_iHeight;
}
else
{
w = G_Window->m_iWidth;
h = G_Window->m_iHeight;
}
m_viewPort = RectI
(
x*w +0.5f,
y*h +0.5f,
(x+width) *w +0.5f,
(y+height)*h +0.5f
);
}
void SoftRendDriver::SetViewPort(int x,int y,int width,int height)
{
//视口被改变
m_viewPort = RectI
(
x,
y,
x+width,
y+height
);
}
// 开始2D渲染
void SoftRendDriver::BeginUI(int x, int y, int _width, int _height)
{
if (m_projectMode==PS_UI)
{
return;
}
m_projectMode = PS_UI;
if(_width==0 || _height==0)
{
_width = m_viewPort.GetWidth();
_height = m_viewPort.GetHeight();
}
SetMatrixMode(MT_PROJECTION);
PushMatrix();
Ortho(x,y,_width,_height);
SetMatrixMode(MT_VIEW);
PushMatrix();
LoadIdentity();
Translatef(0,0,-100); //看点在-100
SetMatrixMode(MT_WORLD);
PushMatrix();
LoadIdentity();
}
void SoftRendDriver::SetClipRect(const RectF &clipRect)//相对于视口
{
//比使用视口裁剪速度要快
//return RendDriver::SetClipRect(clipRect);
if (m_projectMode==PS_Scene)
{
return;
}
m_clipRect = clipRect;
}
void SoftRendDriver::SetClipRect(const RectF &clipRect,const RectF &fullRendTargetRect)
{
//return RendDriver::SetClipRect(clipRect,fullRendTargetRect);
if (m_projectMode==PS_Scene)
{
return;
}
m_clipRect = clipRect;
}
void SoftRendDriver::ClearClipRect()
{
RectF rect(0, 0, G_Window->m_iWidth, G_Window->m_iHeight);
SetClipRect(rect);
}
// 设置矩阵
void SoftRendDriver::Perspective(float fovDegY, float znear, float zfar)
{
if (fovDegY<=0)
fovDegY = m_fov;
if (znear<=0)
znear = m_nearPlane;
if (zfar<=0)
zfar = m_farPlane;
m_fov = fovDegY;
m_nearPlane = znear;
m_farPlane = zfar;
double aspect;
if (m_viewPort.GetHeight() == 0)
{
aspect = 1.0;
}
else
{
aspect = double(m_viewPort.GetWidth())/m_viewPort.GetHeight();
}
mat4 matProj;
//近节点设的太小如0.0001f会产生闪烁
//matProj.PerspectiveSoft(
// fovDegY,
// aspect,
// znear,
// zfar);
//void mat4::PerspectiveSoft(float fovDegY, float aspect, float znear, float zfar)
{
float* mat = matProj.mat;
const float y = tan(fovDegY * DEG2RAD / 2.0f);
const float x = y * aspect;
//D3DXMatrixPerspectiveFovRH
//mat[0] = 1.0f/x; mat[4] = 0.0; mat[8] = 0.0; mat[12] = 0.0;
//mat[1] = 0.0; mat[5] = 1.0f/y; mat[9] = 0.0; mat[13] = 0.0;
//mat[2] = 0.0; mat[6] = 0.0; mat[10] = -zfar/(zfar-znear); mat[14] = -(zfar*znear)/(zfar-znear);
//mat[3] = 0.0; mat[7] = 0.0; mat[11] = -1.0; mat[15] = 0.0;
//depth = far/(far-near) + (far*near)/(z*(far-near)); 必须除以w depth和1/z成正比(深度测试精度不够?)
//z=-near时d=0,z=-far时d=1
DonotDevW
posH.z 不能除以w,unproject多了一步
//左手系和右手系 mat[10] mat[11]正负变号
//ogl 右手系
mat[0] = 1.0f/x; mat[4] = 0.0; mat[8] = 0.0; mat[12] = 0.0;
mat[1] = 0.0; mat[5] = 1.0f/y; mat[9] = 0.0; mat[13] = 0.0;
mat[2] = 0.0; mat[6] = 0.0; mat[10] = -1.0f/(zfar-znear); mat[14] =-znear/(zfar-znear);
mat[3] = 0.0; mat[7] = 0.0; mat[11] = -1.0; mat[15] = 0.0;
posH.z = posV.z*(-1/(zfar-znear)) - znear/(zfar-znear);
= -(posV.z + znear) / (zfar-znear)
posH.w = -posV.z
posH.x/pos.w = -1/x/posV.z; //近大远小
depth = posH.z 没有除以w depth和z成正比(深度测试精度更高,还可以辅助透视校正)
z=-near时d=0,z=-far时d=1,
//d3d 左手系 面向z正, lookat 的eye和tar反了,摄像机移动也反了
//mat[0] = 1.0f/x; mat[4] = 0.0; mat[8] = 0.0; mat[12] = 0.0;
//mat[1] = 0.0; mat[5] = 1.0f/y; mat[9] = 0.0; mat[13] = 0.0;
//mat[2] = 0.0; mat[6] = 0.0; mat[10] = 1.0f/(zfar-znear); mat[14] =-znear/(zfar-znear);
//mat[3] = 0.0; mat[7] = 0.0; mat[11] = 1.0; mat[15] = 0.0;
};
SetMatrixMode(MT_PROJECTION);
LoadMatrix(matProj);
SetMatrixMode(MT_WORLD);
}
void SoftRendDriver::Ortho(int x, int y, int _width, int _height,float znear, float zfar)
{
//RendDriver::Ortho(x, y, _width, _height, znear, zfar);
if(_width==0 || _height==0)
return;
if (znear<=0)
znear = -1.0f;
if (zfar<=0)
zfar = F3D_DEPTH;
SetMatrixMode(MT_PROJECTION);
mat4 matProj;
matProj.Ortho(x,x+_width,y,y+_height,znear,zfar);
LoadMatrix(matProj);
SetMatrixMode(MT_WORLD);
}
void SoftRendDriver::LookAt( float eyex, float eyey, float eyez, float centerx, float centery, float centerz, float upx, float upy, float upz )
{
//投影矩阵参考系不同会影响这里
方法一
//mat4 matTran;
//mat4 matRot;
先对齐原点
//matTran.FromTranslate(-mPosition.x, -mPosition.y, -mPosition.z);
然后用 yawpitchroll的逆阵 转到view空间
//matRot.FromEulerAngle(vec3(mRotateX_Pitch,mRotateY_Yaw, mRotateZ_Roll));
正交矩阵的转置是逆
//matRot.Transpose();
先平移,再旋转 (column vector)
//mat4 mMatrixView= (matRot*matTran);
//
vec3 vEyePt( eyex,eyey,eyez);
vec3 vLookatPt(centerx,centery,centerz);
vec3 vUpVec( upx,upy,upz);
mat4 matView;
//vUpVec.y *= -1;
matView.LookAt(vEyePt, vLookatPt, vUpVec );
SetMatrixMode(MT_VIEW);
LoadMatrix(matView);
SetMatrixMode(MT_WORLD);
}
void SoftRendDriver::SetRenderStateEnable(RenderStateType rendstate,bool on,bool force)
{
switch(rendstate)
{
case RS_TEXTURE_2D:
{
m_textureEnable = on;
break;
}
}
if(rendstate>=0)
{
RenderState[rendstate-RS_LINE_SMOOTH] = on;
}
}
void SoftRendDriver::CullFace(DrawBufferMode mode)
{
m_cullFace = mode;
}
void SoftRendDriver::SetRenderStateEnable(LightName rendstate,bool on,bool force)
{
//(rendstate-RS_LIGHT0,true);
m_lightEnable = on;
}
void SoftRendDriver::SwapBuffer()
{
if(m_presenter)
m_presenter->Present(m_backBufferWidth,m_backBufferHeight,&m_colorBuffer->r);
}
VertexBuffer* SoftRendDriver::CreateVB()
{
return new SoftVertexBuffer;
}
IndexBuffer* SoftRendDriver::CreateIB()
{
return new SoftIndexBuffer;
}
RendTexture* SoftRendDriver::CreateTexture()
{
return new SoftRendTexture;
}
RenderTarget* SoftRendDriver::CreateRenderTarget()
{
if (G_Option->m_renderTargetEnable==false)
{
return NULL;
}
return new SoftRenderTarget;
}
Light* SoftRendDriver::CreateLight()
{
return new LightSoft;
}
Material* SoftRendDriver::CreateMaterial()
{
return new MaterialSoft;
}
inline float fractionPart(float f)
{
return f - float(int(f));
}
//#define F_SetDepth(x,y, z)
inline void SoftRendDriver::F_SetDepth(int x, int y, float z)
{
m_depthBuffer[y*m_backBufferWidth + x]=z;
}
//#define F_DepthTest(x,y, testZ)
inline bool SoftRendDriver::F_DepthTest(int x, int y, float srcZ)
{
float& dstZ = m_depthBuffer[y*m_backBufferWidth + x];
if (srcZ <= dstZ
&& srcZ>0.0f //?
)
{
dstZ = srcZ;
return true;
}
else
{
return false;
}
}
//inline void SoftRendDriver::F_BlendPixel(const vec4*_src, vec4*_dst)
#define F_BlendPixel(_src, _dst)\
{ \
if (m_opacityType==Blend_Disable /*|| (_src)->a>0.9f*/ ) \
{ \
(_dst)->r = (_src)->r; \
(_dst)->g = (_src)->g; \
(_dst)->b = (_src)->b; \
(_dst)->a = (_src)->a; \
} \
else if (m_opacityType==Blend_Additive) \
{ \
(_dst)->r += (_src)->r; \
(_dst)->g += (_src)->g; \
(_dst)->b += (_src)->b; \
(_dst)->a = (_src)->a; \
} \
else \
{ \
const float srcAlpha = (_src)->a; \
const float oneMinusSrcAlpha = 1-srcAlpha; \
(_dst)->r *= oneMinusSrcAlpha; \
(_dst)->g *= oneMinusSrcAlpha; \
(_dst)->b *= oneMinusSrcAlpha; \
/*(_dst)->a = (_src)->a;*/ \
\
(_dst)->r += (_src)->r*srcAlpha; \
(_dst)->g += (_src)->g*srcAlpha; \
(_dst)->b += (_src)->b*srcAlpha; \
(_dst)->a = (_src)->a; \
} \
}
//==================^_^==================^_^==================^_^==================^_^
inline vec4 SoftRendDriver::VertexShader_Lighting(const vec3& vPosW, const vec3& vNormalW)
{
PROSTATISTIC("SoftRendDriver::VertexShader_Lighting()");
//Gouraud Shading 顶点数较少时,此处不是瓶颈
Color outColor( 0.0f,0.0f,0.0f,1.0f );
for (int i = 0;i < MaxValidLightNum;++i)
{
LightSoft* light = &m_lights[i];
if (light->isEnabled == true)
{
vec3 vertexNormal = vNormalW;
NormalizeFastVec3(vertexNormal);
vec3 dirToLight = -light->m_dir;
//环境光
Color currentAmbient = m_curMaterial->m_colorAmbient.Mult(light->m_colorAmbient) ;
//漫反射
Color currentDiffuse( 0.0f,0.0f,0.0f,1.0f );
float NdotL = DotVec3(dirToLight,vertexNormal);
//正面 背面只有环境光
if (NdotL > 0.0f)
{
currentDiffuse = light->m_colorDiffuse*m_curMaterial->m_colorDiffuse * light->diffuseIntensity;
}
//高光
Color currentSpecular( 0.0f,0.0f,0.0f,1.0f);
vec3 dirToEye = m_eyePos - vPosW;
NormalizeFastVec3(dirToEye);
vec3 H = dirToLight+dirToEye;
NormalizeFastVec3(H);
float NdotH = DotVec3(vertexNormal,H);
Color specularColor = light->m_colorSpecular*10*m_curMaterial->m_colorSpecular* pow(max(NdotH, 0.0f), m_curMaterial->m_shininess);
//*10 必须clamp
ClampColor1(specularColor);
//高光要用叠加而不是乘法混合,否则黑色纹理无高光
outColor.r = currentAmbient.r+currentDiffuse.r+currentSpecular.r;
outColor.g = currentAmbient.g+currentDiffuse.g+currentSpecular.g;
outColor.b = currentAmbient.b+currentDiffuse.b+currentSpecular.b;
}
}
return vec4(outColor.r,outColor.g,outColor.b,outColor.a);
//return outColor;
}
inline void SoftRendDriver::VertexShader(const VSInput& inVertex,VSOutput& outVertex)
{
PROSTATISTIC("SoftRendDriver::VertexShader()");
//位置 方法一
vec4 posL(inVertex.pos.x, inVertex.pos.y, inVertex.pos.z, 1.0f);
Mat4xVec4(outVertex.posH,m_modelViewProjectMatrix,posL);
if(outVertex.posH.w>0)//posV.z < 0 //右手系 posH.w=-posV.z
{
outVertex.posH.x /= (outVertex.posH.w); // 除z 近大远小
outVertex.posH.y /= (outVertex.posH.w);
//DonotDevW
//outVertex.posH.z /= (outVertex.posH.w);
}
Mat4xVec4(outVertex.posW,m_modelMatrix ,posL); //gpu编程为了减少带宽,一般在ps中根据深度反推世界位置。这里直接传递插值更快。
Mat4xVec4(outVertex.posV,m_modelViewMatrix,posL);
//法线 World-Inverse-Transpose
//mat4 matNormal = G_RendDriver->GetModelMatrix();
//matNormal.Inverse4();
//matNormal.Transpose();
//等比缩放时可以简化如下
Mat4xNormal(outVertex.normalW,m_modelMatrix,inVertex.normal);
//纹理坐标变换
{
//mat4& matTex = GetTextureMatrix(0);
//outVertex.texcoord = matTex * inVertex.texcoord;
float* mat = m_textureMatrix[0];
outVertex.texcoord.x = mat[0] * inVertex.texcoord.x + mat[4] * inVertex.texcoord.y + mat[12]; //mat[8];
outVertex.texcoord.y = mat[1] * inVertex.texcoord.x + mat[5] * inVertex.texcoord.y + mat[13]; //mat[9];
}
//颜色
if (m_lightEnable)
{
outVertex.color = VertexShader_Lighting(outVertex.posW, outVertex.normalW);
//混合材质色
MultVec4(outVertex.color,outVertex.color,inVertex.color);
}
else
{
CopyVec4(outVertex.color,inVertex.color);
}
}
//没有更快
//int(float) 直接去小数部分,向零舍入到整数
#define float2int(x) (reinterpret_cast(__d=x + 6755399441055744.0))
inline void SoftRendTexture::SamplePixel(float u, float v,vec4& color)
{
PROSTATISTIC("SoftRendDriver::SamplePixel()");
v = 1-v;
//wrap-mode; linear or nearest; //-1.2 - -1 = -0.2
u -= (int)u;
v -= (int)v;
//double __d;
//u -= float2int(u);
//v -= float2int(v);
if(u < 0.0f) u += 1.0f; //-0.2+1=0.8
if(v < 0.0f) v += 1.0f;
int pixelX = (m_iWidth * u);
int pixelY = (m_iHeight * v);
//不使用线性采样,降低效率
const vec4* c = &m_pColorBuffer[pixelY*m_iWidth + pixelX];
color.r = c->x;
color.g = c->y;
color.b = c->z;
color.a = c->w;
}
#define Sample2D(texture, u_, v_, color) \
if(texture) \
{ \
float u = u_; \
float v = v_; \
v = 1-v; \
u -= (int)u; \
v -= (int)v; \
if(u < 0.0f) u += 1.0f; \
if(v < 0.0f) v += 1.0f; \
int pixelX = (texture->m_iWidth * u); \
int pixelY = (texture->m_iHeight * v); \
const vec4* c = &texture->m_pColorBuffer[pixelY*texture->m_iWidth + pixelX]; \
color.r = c->x; \
color.g = c->y; \
color.b = c->z; \
color.a = c->w; \
}
inline void SoftRendDriver::PixelShader_Triangle(const PSInput& inVertex)
{
//PROSTATISTIC("SoftRendDriver::PixelShader_Triangle()");
vec4 outColor;
//8 个 sampler
vec4 texSampleColor;
//if (m_curRendTexture)//&&texture2d enable
// m_curRendTexture->SamplePixel(inVertex.texcoord.x, inVertex.texcoord.y,texSampleColor);
//if (texture2d enable) //宏内联提速有限
Sample2D(m_curRendTexture,inVertex.texcoord.x, inVertex.texcoord.y,texSampleColor);
//不使用float(0~255) 代替float(0~1)来提高速度:*255 影响不大 且255截取有问题 不能用char 还要float来存储
MultVec4(outColor,inVertex.color,texSampleColor);
ClampColor1(outColor);
vec4* dst = &m_colorBuffer[inVertex.pixelY*m_backBufferWidth + inVertex.pixelX];
vec4* src = &outColor;
F_BlendPixel(src,dst);
ClampColor1(*dst);
}
inline void SoftRendDriver::PixelShader_Point(const PSInput & inVertex)
{
PROSTATISTIC("SoftRendDriver::PixelShader_Point()");
int size = 4;
//draw a bigger point (2x2 pixel)
int px1 = inVertex.pixelX - size;
int px2 = inVertex.pixelX + size;
int py1 = inVertex.pixelY - size;
int py2 = inVertex.pixelY + size;
//Clamp(px1, 0, m_backBufferWidth -1);
//Clamp(px2, 0, m_backBufferWidth -1);
//Clamp(py1, 0, m_backBufferHeight-1);
//Clamp(py2, 0, m_backBufferHeight-1);
if (px1 < 0) px1=0; else if (px1 >= m_backBufferWidth ) px1=m_backBufferWidth -1;
if (px2 < 0) px2=0; else if (px2 >= m_backBufferWidth ) px2=m_backBufferWidth -1;
if (py1 < 0) py1=0; else if (py1 >= m_backBufferHeight) py1=m_backBufferHeight-1;
if (py2 < 0) py2=0; else if (py2 >= m_backBufferHeight) py2=m_backBufferHeight-1;
for (int y = py1;y < py2;y++)
{
int dy = y-inVertex.pixelY;
for (int x = px1;x < px2;x++)
{
int dx = x-inVertex.pixelX;
if (dx*dx+dy*dy > 8)
{
//F_BlendPixel(&inVertex.color,&m_colorBuffer[j*mBufferWidth +i]);
vec4& outColor = m_colorBuffer[y*m_backBufferWidth +x];
outColor.r = inVertex.color.r;
outColor.g = inVertex.color.g;
outColor.b = inVertex.color.b;
outColor.a = inVertex.color.a;
}
}
}
}
void SoftRendDriver::HomoSpaceClipping_Triangles(const IndexInt* const pIB,int indexCount)
{
PROSTATISTIC("SoftRendDriver::HomoSpaceClipping_Triangles()");
//齐次空间剪裁 homogeous space clipping
//如果在这里将超出视口的三角形拆分,index可能会增加,所以不做拆分,在光栅化时再处理越界
//提前在世界空间视椎体裁剪?
int i = 0;
while(i < indexCount/*-3*/)
{
int idx1 = pIB[i];
int idx2 = pIB[i+1];
int idx3 = pIB[i+2];
const vec4& v1 = m_vertexBufferHomoSpace[idx1].posH;
const vec4& v2 = m_vertexBufferHomoSpace[idx2].posH;
const vec4& v3 = m_vertexBufferHomoSpace[idx3].posH;
//bool skip = false;
if(m_cullFace!=RS_NONE)
{
float a = 0.0f;
a += v1.x * v2.y - v2.x * v1.y;
a += v2.x * v3.y - v3.x * v2.y;
a += v3.x * v1.y - v1.x * v3.y;
if(m_cullFace==RS_FRONT && a >= 0)
{
i += 3;
continue;
//skip = true;
}
else if(m_cullFace== RS_BACK && a <= 0)
{
i += 3;
continue;
//skip = true;
}
}
//这里z的范围也是[-1,1] 不是[0,1]
//分离轴太复杂 直接用三角形的aabb 只有6个分离面 更严格的剔除 还要加上三角形法线 和9条叉积轴
if ( (v1.x>1.0f && v2.x>1.0f && v3.x>1.0f)
||(v1.y>1.0f && v2.x>1.0f && v3.x>1.0f)
||(v1.z>1.0f && v2.x>1.0f && v3.x>1.0f)
||(v1.x<-1.0f && v2.x<-1.0f && v3.x<-1.0f)
||(v1.y<-1.0f && v2.x<-1.0f && v3.x<-1.0f)
||(v1.z<-1.0f && v2.x<-1.0f && v3.x<-1.0f)
)
{
//skip
}
else
{
m_indexBufferHomoClipped[m_indexNumHomoClipped++] = idx1;
m_indexBufferHomoClipped[m_indexNumHomoClipped++] = idx2;
m_indexBufferHomoClipped[m_indexNumHomoClipped++] = idx3;
}
i += 3;
}
}
void SoftRendDriver::HomoSpaceClipping_Points(const IndexInt* const pIB,int indexCount)
{
PROSTATISTIC("SoftRendDriver::HomoSpaceClipping_Points()");
int i = 0;
while(i < indexCount)
{
int idx = pIB[i];
const vec4& v1 = m_vertexBufferHomoSpace[idx].posH;
bool bOutOfBox = v1.x <= -1.0f || v1.x >= 1.0f ||
v1.y <= -1.0f || v1.y >= 1.0f ||
v1.z <= -1.0f || v1.z >= 1.0f;
//
if (!bOutOfBox)
{
m_indexBufferHomoClipped[m_indexNumHomoClipped++] = idx;
}
++i;
}
}
void SoftRendDriver::OnSize()
{
RendDriver::OnSize();
m_backBufferWidth = G_Window->m_iWidth;
m_backBufferHeight = G_Window->m_iHeight;
delete[] m_colorBuffer;
delete[] m_depthBuffer;
m_colorBuffer = new vec4[m_backBufferHeight*m_backBufferWidth];
m_depthBuffer = new float[m_backBufferHeight*m_backBufferWidth];
}
void SoftRendDriver::SetRendTexture(SoftRendTexture * pTex)
{
m_curRendTexture = pTex;
}
void SoftRendDriver::SetPresenter(Presenter* presenter)
{
m_presenter = presenter;
}
void SoftRendDriver::SetMatrixToDrive(MatrixMode mode_)
{
m_eyePos = G_Camera->GetEyePos();
}
void SoftRendDriver::RasterizeTriangles()
{
PROSTATISTIC("SoftRendDriver::RasterizeTriangles()");
const int ColorBufferWidth = m_backBufferWidth;
const int ColorBufferHeight = m_backBufferHeight;
const int ViewPortX = m_viewPort.left;
const int ViewPortY = m_viewPort.top;
const int ViewPortW = m_viewPort.GetWidth();
const int ViewPortH = m_viewPort.GetHeight();
//homo space[-1,1] convert to screen space
const int vCount = m_curVertexBuffer->m_vertexNum;
VSOutput* vh = m_vertexBufferHomoSpace;
for (int i = 0;i < vCount;++i,++vh)
{
vh->posH.x = (vh->posH.x * 0.5f + 0.5f) * ViewPortW + ViewPortX;
vh->posH.y = (vh->posH.y * -0.5f + 0.5f) * ViewPortH + ViewPortY;
}
//通过geometryshader后 增加
int trigonNum = m_indexNumHomoClipped/3;
int* pIndex = m_indexBufferHomoClipped;
for (int tri = 0;tri0
Edge2.Set(&vsOutput2, &vsOutput3);
Edge3.Set(&vsOutput3, &vsOutput1);
FragmentEdge *LongEdge = &Edge1;
FragmentEdge *ShortEdge1 = &Edge2;
FragmentEdge *ShortEdge2 = &Edge3;
if(Edge2.dy > LongEdge->dy)
{
LongEdge = &Edge2;
ShortEdge1 = &Edge3;
ShortEdge2 = &Edge1;
}
if(Edge3.dy > LongEdge->dy)
{
LongEdge = &Edge3;
ShortEdge1 = &Edge1;
ShortEdge2 = &Edge2;
}
/* /
/\ \ /
/ \ \/
/
*/
//长边(y轴投影)分别对应两个短边,组成上三角和下三角
if (LongEdge->valid && ShortEdge1->valid)
RasterizeBetweenEdges(LongEdge, ShortEdge1);
if (LongEdge->valid && ShortEdge2->valid)
RasterizeBetweenEdges(LongEdge, ShortEdge2);
}
void SoftRendDriver::RasterizeBetweenEdges(const FragmentEdge *edgeL, const FragmentEdge *edgeS)
{
PROSTATISTIC("SoftRendDriver::RasterizeBetweenEdges()");
if(edgeL->dy == 0.0f || edgeS->dy == 0.0f)
return;
int iy1 = (int)edgeS->Fragment1->posH.y;
int iy2 = (int)edgeS->Fragment2->posH.y;
if(iy1 < 0)
iy1 = 0;
if(iy2 >= m_backBufferHeight)
iy2 = m_backBufferHeight - 1;
if (iy1= m_clipRect.y+m_clipRect.height)
iy2 = m_clipRect.y+m_clipRect.height - 1;
float fy;
float factor1, factor2;
const float ode1dy = 1.0f / edgeL->dy;
const float ode2dy = 1.0f / edgeS->dy;
VSOutput Fragment1, Fragment2;
FragmentSpan Span;
//透视插值修正factor
float odLW1 = 1/edgeL->Fragment1->posH.w;
float odLW2 = 1/edgeL->Fragment2->posH.w;
float odSW1 = 1/edgeS->Fragment1->posH.w;
float odSW2 = 1/edgeS->Fragment2->posH.w;
float odZ1;
float odZ2;
float s1;
float s2;
for(int y = iy1; y <= iy2; y++)
{
fy = y + 0.5f;
factor1 = (fy - edgeL->Fragment1->posH.y) * ode1dy;
if(factor1 < 0.0f || factor1 > 1.0f)
continue;
factor2 = (fy - edgeS->Fragment1->posH.y) * ode2dy;
if(factor2 < 0.0f || factor2 > 1.0f)
continue;
//#define PerspectiveCorrect false
#define PerspectiveCorrect true
if(!PerspectiveCorrect)
{
//无透视修正, 大块斜三角形插值错误
Fragment1.posH.x = edgeL->Fragment1->posH.x + edgeL->dx * factor1;
Fragment1.posH.y = edgeL->Fragment1->posH.y + edgeL->dy * factor1;
Fragment1.posH.z = edgeL->Fragment1->posH.z + edgeL->dz * factor1;
Fragment1.posH.w = edgeL->Fragment1->posH.w + edgeL->dw * factor1;
Fragment1.color.r = edgeL->Fragment1->color.r + edgeL->dr * factor1;
Fragment1.color.g = edgeL->Fragment1->color.g + edgeL->dg * factor1;
Fragment1.color.b = edgeL->Fragment1->color.b + edgeL->db * factor1;
Fragment1.color.a = edgeL->Fragment1->color.a + edgeL->da * factor1;
Fragment1.texcoord.x = edgeL->Fragment1->texcoord.x + edgeL->ds * factor1;
Fragment1.texcoord.y = edgeL->Fragment1->texcoord.y + edgeL->dt * factor1;
Fragment2.posH.x = edgeS->Fragment1->posH.x + edgeS->dx * factor2;
Fragment2.posH.y = edgeS->Fragment1->posH.y + edgeS->dy * factor2;
Fragment2.posH.z = edgeS->Fragment1->posH.z + edgeS->dz * factor2;
Fragment2.posH.w = edgeS->Fragment1->posH.w + edgeS->dw * factor2;
Fragment2.color.r = edgeS->Fragment1->color.r + edgeS->dr * factor2;
Fragment2.color.g = edgeS->Fragment1->color.g + edgeS->dg * factor2;
Fragment2.color.b = edgeS->Fragment1->color.b + edgeS->db * factor2;
Fragment2.color.a = edgeS->Fragment1->color.a + edgeS->da * factor2;
Fragment2.texcoord.x = edgeS->Fragment1->texcoord.x + edgeS->ds * factor2;
Fragment2.texcoord.y = edgeS->Fragment1->texcoord.y + edgeS->dt * factor2;
}
else
{
//设点A的深度为Z1,点B的深度为Z2。C为AB上的插值点,投影面上的插值比为s。根据Z1、Z2、s来求得线性空间下的插值比t,再根据t对顶点属性进行插值,
//最后得出的插值公式如下:
//提前在观察空间中裁剪图元是耗时的!
//线段两端w一正一负时有问题,或者当w跑到摄像机背后时更加错误(投影位置已经无意义)。
//透视插值修正, 1/z 的透视校正 1/w可以在屏幕空间线性插值 w和z是成线性关系的
//裁剪空间坐标的w分量记录了观察空间下顶点的深度值,
//x -50163.02 float
//y -258449.5 float
//z -0.029273 float
//w -174.6117 float
//x 240.75304 float
//y 290.44684 float
//z 0.0527610 float
//w 317.51324 float
//x 798.61462 float
//y -2075.807 float
//z 0.0179880 float
//w 108.91015 float
//x 472.23068 float
//y 294.95343 float
//z 0.1000225 float
//w 601.03516 float
//透视修正后的depth
//透视插值修正, 1/z 的透视校正 1/w可以在屏幕空间线性插值 w和z是承线性关系的
//裁剪空间坐标的w分量记录了观察空间下顶点的深度值,
//float odZ1 = (1-factor1)/edgeL->Fragment1->posH.w;
//float odZ2 = ( factor1)/edgeL->Fragment2->posH.w;
//float odSum = 1.0f/(odZ1+odZ2);
//Fragment1.r = (edgeL->Fragment1->color.r *odZ1 + edgeL->Fragment2->color.r *odZ2) * odSum;
odZ1 = (1-factor1)*odLW1;
odZ2 = ( factor1)*odLW2;
s1 = odZ1/(odZ1+odZ2);
s2 = 1-s1;
Fragment1.posH.x = edgeL->Fragment1->posH.x + edgeL->dx * factor1;//x、y在屏幕空间插值=》对应其它属性在齐次空间插值
Fragment1.posH.y = edgeL->Fragment1->posH.y + edgeL->dy * factor1;
Fragment1.posH.z = edgeL->Fragment1->posH.z *s1 + edgeL->Fragment2->posH.z *s2;
Fragment1.posH.w = edgeL->Fragment1->posH.w *s1 + edgeL->Fragment2->posH.w *s2;
Fragment1.color.r = edgeL->Fragment1->color.r *s1 + edgeL->Fragment2->color.r *s2;
Fragment1.color.g = edgeL->Fragment1->color.g *s1 + edgeL->Fragment2->color.g *s2;
Fragment1.color.b = edgeL->Fragment1->color.b *s1 + edgeL->Fragment2->color.b *s2;
Fragment1.color.a = edgeL->Fragment1->color.a *s1 + edgeL->Fragment2->color.a *s2;
Fragment1.texcoord.x = edgeL->Fragment1->texcoord.x*s1 + edgeL->Fragment2->texcoord.x*s2;
Fragment1.texcoord.y = edgeL->Fragment1->texcoord.y*s1 + edgeL->Fragment2->texcoord.y*s2;
//Fragment1.posW.x = edgeL->Fragment1->posW.x *s1 + edgeL->Fragment2->posW.x *s2;
//Fragment1.posW.y = edgeL->Fragment1->posW.y *s1 + edgeL->Fragment2->posW.y *s2;
//Fragment1.posW.z = edgeL->Fragment1->posW.z *s1 + edgeL->Fragment2->posW.z *s2;
//Fragment1.normalW.x = edgeL->Fragment1->normalW.x *s1 + edgeL->Fragment2->normalW.x *s2;
//Fragment1.normalW.y = edgeL->Fragment1->normalW.y *s1 + edgeL->Fragment2->normalW.y *s2;
//Fragment1.normalW.z = edgeL->Fragment1->normalW.z *s1 + edgeL->Fragment2->normalW.z *s2;
odZ1 = (1-factor2)*odSW1;
odZ2 = ( factor2)*odSW2;
s1 = odZ1/(odZ1+odZ2);
s2 = 1-s1;
Fragment2.posH.x = edgeS->Fragment1->posH.x + edgeS->dx * factor2;
Fragment2.posH.y = edgeS->Fragment1->posH.y + edgeS->dy * factor2;
Fragment2.posH.z = edgeS->Fragment1->posH.z *s1 + edgeS->Fragment2->posH.z *s2;
Fragment2.posH.w = edgeS->Fragment1->posH.w *s1 + edgeS->Fragment2->posH.w *s2;
Fragment2.color.r = edgeS->Fragment1->color.r *s1 + edgeS->Fragment2->color.r *s2;
Fragment2.color.g = edgeS->Fragment1->color.g *s1 + edgeS->Fragment2->color.g *s2;
Fragment2.color.b = edgeS->Fragment1->color.b *s1 + edgeS->Fragment2->color.b *s2;
Fragment2.color.a = edgeS->Fragment1->color.a *s1 + edgeS->Fragment2->color.a *s2;
Fragment2.texcoord.x = edgeS->Fragment1->texcoord.x*s1 + edgeS->Fragment2->texcoord.x*s2;
Fragment2.texcoord.y = edgeS->Fragment1->texcoord.y*s1 + edgeS->Fragment2->texcoord.y*s2;
//Fragment2.posW.x = edgeS->Fragment1->posW.x *s1 + edgeS->Fragment2->posW.x *s2;
//Fragment2.posW.y = edgeS->Fragment1->posW.y *s1 + edgeS->Fragment2->posW.y *s2;
//Fragment2.posW.z = edgeS->Fragment1->posW.z *s1 + edgeS->Fragment2->posW.z *s2;
//Fragment2.normalW.x = edgeS->Fragment1->normalW.x *s1 + edgeS->Fragment2->normalW.x *s2;
//Fragment2.normalW.y = edgeS->Fragment1->normalW.y *s1 + edgeS->Fragment2->normalW.y *s2;
//Fragment2.normalW.z = edgeS->Fragment1->normalW.z *s1 + edgeS->Fragment2->normalW.z *s2;
}
if (Fragment1.color.a <0.1f && Fragment2.color.a <0.1f
//&&blend=filter && depthtest=false
)
{
//Skip;
}
else
{
Span.Set(&Fragment1, &Fragment2);
RasterizeSpan(&Span, y);
}
}
}
void SoftRendDriver::RasterizeSpan(const FragmentSpan *span, int y)
{
PROSTATISTIC("SoftRendDriver::RasterizeSpan()");
int DepthBufferWidth = m_backBufferWidth;
int ColorBufferWidth = m_backBufferWidth;
if(span->dx == 0.0f)
return;
int ix1 = (int)span->Fragment1->posH.x;
int ix2 = (int)span->Fragment2->posH.x;
if(ix2 == ColorBufferWidth)
ix2--;
if (ix1 < 0)
ix1 = 0;
if (ix2 >= ColorBufferWidth)
ix2 = ColorBufferWidth-1;
if (ix1 < m_clipRect.x)
ix1 = m_clipRect.x;
if(ix2 >= m_clipRect.x+m_clipRect.width)
ix2 = m_clipRect.x+m_clipRect.width - 1;
float factor;
float odsdx = 1.0f / span->dx;
//float w;
float r, g, b,a;
float s, t;
float depth;
int DepthBufferIndex = DepthBufferWidth * y + ix1;
//透视插值修正factor
float odW1 = 1/span->Fragment1->posH.w;
float odW2 = 1/span->Fragment2->posH.w;
float odZ1;
float odZ2;
float s1;
float s2;
for(int x = ix1; x <= ix2; x++)
{
factor = (x + 0.5f - span->Fragment1->posH.x) * odsdx;
if(factor >= 0.0f && factor <= 1.0f)
{
//透视修正后的depth
//透视插值修正, 1/z 的透视校正 1/w可以在屏幕空间线性插值 w和z是承线性关系的
//裁剪空间坐标的w分量记录了观察空间下顶点的深度值,
//float odZ1 = (1-factor)/span->Fragment1->posH.w;
//float odZ2 = ( factor)/span->Fragment2->posH.w;
//float odSum = 1.0f/(odZ1+odZ2);
//r = (span->Fragment1->color.r *odZ1 + span->Fragment2->color.r *odZ2) * odSum;
if(!PerspectiveCorrect)
{
depth = span->Fragment1->posH.z + span->dz * factor;
}
else
{
odZ1 = (1-factor)*odW1;
odZ2 = ( factor)*odW2;
s1 = odZ1/(odZ1+odZ2);
s2 = 1-s1;
depth = span->Fragment1->posH.z *s1 + span->Fragment2->posH.z *s2;
}
// depth test
//if (F_DepthTest(x,y,Depth))
if(depth <= m_depthBuffer[DepthBufferIndex])
{
PSInput& outFragment = m_fragmentsRasterized[m_fragmentsNum];
m_fragmentsNum++;
if(m_fragmentsNum>=MaxFragments)
{
return;
}
//F_SetDepth
m_depthBuffer[DepthBufferIndex++] = depth;
if(!PerspectiveCorrect)
{
//无透视修正, 大块斜三角形插值错误
//w = (Span->Fragment1->posH.w + Span->dw * factor);
r = (span->Fragment1->color.r + span->dr * factor);
g = (span->Fragment1->color.g + span->dg * factor);
b = (span->Fragment1->color.b + span->db * factor);
a = (span->Fragment1->color.a + span->da * factor);
s = (span->Fragment1->texcoord.x + span->ds * factor);
t = (span->Fragment1->texcoord.y + span->dt * factor);
}
else
{
//z = Span->Fragment1->posH.z *s1 + Span->Fragment2->posH.z *s2;
//w = Span->Fragment1->posH.w *s1 + Span->Fragment2->posH.w *s2;
r = span->Fragment1->color.r *s1 + span->Fragment2->color.r *s2;
g = span->Fragment1->color.g *s1 + span->Fragment2->color.g *s2;
b = span->Fragment1->color.b *s1 + span->Fragment2->color.b *s2;
a = span->Fragment1->color.a *s1 + span->Fragment2->color.a *s2;
s = span->Fragment1->texcoord.x*s1 + span->Fragment2->texcoord.x*s2;
t = span->Fragment1->texcoord.y*s1 + span->Fragment2->texcoord.y*s2;
}
outFragment.pixelX = x;
outFragment.pixelY = y;
outFragment.color.r = r;
outFragment.color.g = g;
outFragment.color.b = b;
outFragment.color.a = a;
outFragment.texcoord.x = s;
outFragment.texcoord.y = t;
}
else
{
DepthBufferIndex++;
}
}
else
{
DepthBufferIndex++;
}
}
}
void SoftRendDriver::RasterizePoints()
{
const int ColorBufferWidth = m_backBufferWidth;
const int ColorBufferHeight = m_backBufferHeight;
for (int i = 0;i < m_indexNumHomoClipped ;++i)
{
int idx = (m_indexBufferHomoClipped)[i];
const VSOutput& v1 = m_vertexBufferHomoSpace[idx];
vec2 v1_pixel;
//homo space[-1,1] convert to pixel space
v1_pixel.x = (v1.posH.x * 0.5f + 0.5f) * ColorBufferWidth;
v1_pixel.y = (v1.posH.y * -0.5f + 0.5f) * ColorBufferWidth;
//clip in pixel space
if (v1_pixel.x >= ColorBufferWidth || v1_pixel.y >= ColorBufferHeight)
{
continue;
}
//if (v1_pixel.x < m_clipRect.x || v1_pixel.x >= m_clipRect.x+m_clipRect.width
// ||v1_pixel.y < m_clipRect.y || v1_pixel.y >= m_clipRect.y+m_clipRect.height)
//{
// continue;
//}
//depth test
float depth = v1.posH.z;
if (F_DepthTest(int(v1_pixel.x), int(v1_pixel.y), depth) == false)
continue;
PSInput& outFragment = m_fragmentsRasterized[m_fragmentsNum];
m_fragmentsNum++;
if(m_fragmentsNum>=MaxFragments)
{
return;
}
outFragment.pixelX = int(v1_pixel.x);
outFragment.pixelY = int(v1_pixel.y);
F_SetDepth(outFragment.pixelX, outFragment.pixelY, depth);
outFragment.color = v1.color;
outFragment.texcoord = v1.texcoord;
}
}
void SoftRendDriver::ReadPixels(int x, int y, int width, int height, PixelFormat format, DataType type, void *pixels_)
{
if(x<0 || y<0 || width<=0 || width<=0 || x >=m_backBufferWidth || x>m_backBufferHeight)
{
return;
}
int dw = width;
if (x+width>m_backBufferWidth)
{
width = m_backBufferWidth-x;
}
if (y+height>m_backBufferHeight)
{
height = m_backBufferHeight - y;
}
if (format==RS_BGR)
{
unsigned char* pixels = (unsigned char*)pixels_;
for(int i = 0; i < width; ++i)
{
for(int j = 0; j < height; ++j)
{
vec4* c = &m_colorBuffer[(m_backBufferHeight-j-1)*m_backBufferWidth+i];
unsigned char* d = pixels+ (j*dw+i)*3;
d[0] = c->b*255;
d[1] = c->g*255;
d[2] = c->r*255;
}
}
}
else if (format==RS_DEPTH_COMPONENT)
{
float* pixels = (float*)pixels_;
for(int i = 0; i < width; ++i)
{
for(int j = 0; j < height; ++j)
{
float* c = &m_depthBuffer[(m_backBufferHeight-j-1)*m_backBufferWidth+i];
float* d = pixels+ (j*dw+i)*3;
d[0] = *c;
}
}
}
}
vec3 SoftRendDriver::UnProject(const vec2 &pos, float depth)
{
//投影矩阵
//mat[0] = 1.0f/x; mat[4] = 0.0; mat[8] = 0.0; mat[12] = 0.0;
//mat[1] = 0.0; mat[5] = 1.0f/y; mat[9] = 0.0; mat[13] = 0.0;
//mat[2] = 0.0; mat[6] = 0.0; mat[10] = -1.0f/(zfar-znear); mat[14] =-znear/(zfar-znear);
//mat[3] = 0.0; mat[7] = 0.0; mat[11] = -1.0; mat[15] = 0.0;
//posH.z = posV.z*(-1/(zfar-znear)) - znear/(zfar-znear);
// = -(posV.z + znear) / (zfar-znear)
//posH.w = -posV.z
//posH.x/pos.w = -1/x *posV.x/posV.z; //近大远小
//depth = posH.z 没有除以w depth和z成正比(深度测试精度更高,还可以辅助透视校正)
//z=-near时d=0,z=-far时d=1,
int viewport[4];
viewport[0] = m_viewPort.left;
viewport[1] = m_viewPort.top;
viewport[2] = m_viewPort.GetWidth();
viewport[3] = m_viewPort.GetHeight();
//depth:0表示近裁剪面上的点,1对应远裁剪面上的点
if (depth<-1)//0.000001f
{
depth = 1;//0.000001f;
//float depth_[2];
//ReadPixels(pos.x,viewport[3]- pos.y,1,1,RS_DEPTH_COMPONENT,RS_FLOAT,depth_);
//depth = depth_[0];
}
//
float x,y,z;
vec4 posH, posV,posW;
//posH = 齐次空间下 除以w的结果
posH.x = (pos.x - viewport[0]) * 2 / viewport[2] - 1.0;
posH.y = ((G_Window->m_iHeight-pos.y) - viewport[1]) * 2 / viewport[3] - 1.0;
posH.z = depth;//2 * depth - 1.0; //DonotDevW 无法正确反投影???
posH.w = 1.0;
//{
// mat4 matP = GetProjectMatrix();
// posV.z = posH.z*(1-6000)-1;
// posV.x = posH.x*posV.z/-matP.mat[0];
// posV.y = posH.y*posV.z/-matP.mat[5];
// posV.w = 1;
//}
{
mat4 matVI = GetViewMatrix();
matVI.Inverse4();
mat4 matP = GetProjectMatrix();
mat4 matPI = GetProjectMatrix();
matPI.Inverse4();
posV = matPI * posH;
if (posV.w != 0.0)
{
posV.x *= -posV.w;
posV.y *= -posV.w;
//DonotDevW
posV.z *= -posV.w;
}
posV.w = 1; //归1
posW = matVI * posV;
}
//下面结果不正确,如果后期特效需要大量unproject时,还是要修改投影矩阵以便使用下面的简化算法
//mat4 mat = GetViewProjectMatrix();
//mat.Inverse4();
//posW = mat * posH;
if (posW.w != 0.0)
//{
// posW.x *= -posW.w;
// posW.y *= -posW.w;
// //DonotDevW
// posW.z *= -posW.w;
//}
return vec3(posW.x,posW.y,posW.z);
}
vec3 SoftRendDriver::Project(const vec3 &pos)
{
vec4 posH = GetModelViewProjectMatrix()*vec4(pos,1);
if(posH.w)
{
posH.x /= posH.w;
posH.y /= posH.w;
//DonotDevW
//posH.z /= posH.w;
}
posH *= 0.5f;
posH += vec4(0.5f,0.5f,0.5f,0.5f);
posH.x *= m_viewPort.GetWidth();
posH.y *= m_viewPort.GetHeight();
posH.y = m_viewPort.GetHeight() - posH.y;
return vec3(posH);
}
inline void SoftRendDriver::DrawPoint(int x, int y)
{
PROSTATISTIC("SoftRendDriver::DrawPoint()");
// vec4& color = m_curColor;
vec4 color(m_curColor.r,m_curColor.g,m_curColor.b,m_curColor.a);
if(
0<=x && x=1;
//2. abs(slope)<=1;
float offset = 0.0f;
if (abs(k) <= 1.0f)
{
int i = x1;
while(i!=x2)
{
DrawPoint(i, y1 + int(offset));
//F_BlendPixel(i, y1 + int(offset)+ 1, fractionPart(offset),color);
offset += k;//dy = dx * k;
if (x2 > x1)
++i;
else
--i;
}
}
else
{
int j = y1;
while(j!=y2)
{
DrawPoint(x1+int(offset), j);
//F_BlendPixel(x1+int(offset) +1,j, fractionPart(offset),color);
offset += (k_inv);
if (y2 > y1)
++j;
else
--j;
}
}
}
}
void SoftRendDriver::DrawRect(const RectF& tar)
{
PROSTATISTIC("SoftRendDriver::DrawRect()");
RectF newTar;
//todo clamp viewport
newTar.FromIntersect(tar,RectF(0,0,m_backBufferWidth-1,m_backBufferHeight-1));
newTar.FromIntersect(newTar,m_clipRect);
if (newTar.IsValidRect()==false)
{
return;
}
const int vLeft = newTar.x;
const int vRight = newTar.x+newTar.width;
const int vTop = newTar.y;
const int vBottom = newTar.y+newTar.height;
vec4 color = vec4(m_curColor.r,m_curColor.g,m_curColor.b,m_curColor.a);
vec4* _src = &color;
for (int y=vTop; y<=vBottom; ++y)
{
vec4* _dst = m_colorBuffer+(y*m_backBufferWidth);
for (int x=vLeft; x<=vRight; ++x)
{
F_BlendPixel(_src,_dst);
_dst++;
}
}
CallStatistic_(DrawCallNum,1);
CallStatistic_(DrawPrimtiveNum,2);
};
void SoftRendDriver::DrawTextureRect(const RectF& tar)
{
DrawTextureRect(tar,RectF(0,0,1,1));
}
void SoftRendDriver::DrawTextureRect(const RectF& tar,const RectF& scr,int depthTest)
{
PROSTATISTIC("SoftRendDriver::DrawTextureRect()");
if (m_curRendTexture==NULL)
{
return;
}
RectF newTar;
//todo clamp viewport
newTar.FromIntersect(tar,RectF(0,0,m_backBufferWidth-1,m_backBufferHeight-1));
newTar.FromIntersect(newTar,m_clipRect);
if (newTar.IsValidRect()==false)
{
return;
}
RectF newScr(scr.x+ (newTar.x - tar.x)*scr.width /tar.width,
scr.y+ (newTar.y - tar.y)*scr.height/tar.height,
(newTar.width )*scr.width /tar.width,
(newTar.height)*scr.height/tar.height);
const int vLeft = newTar.x;
const int vRight = newTar.x+newTar.width;
const int vTop = newTar.y;
const int vBottom = newTar.y+newTar.height;
const int mWidth = m_curRendTexture->m_iWidth;
const int mHeight = m_curRendTexture->m_iHeight;
const float tLeft = newScr.x*mWidth;
const float tRight = newScr.GetRight()*mWidth;
const float tTop = newScr.y*mHeight;
const float tBottom = newScr.GetBottom()*mHeight;
const float texStepX = (tRight-tLeft)/(vRight-vLeft);
const float texStepY = (tBottom-tTop)/(vBottom-vTop);
const vec4 curColor = vec4(m_curColor.r,m_curColor.g,m_curColor.b,m_curColor.a);
const vec4* pColorBuffer = m_curRendTexture->m_pColorBuffer;
vec4 color(1, 0, 0,0);
float picCoordY = tTop;
for (int y=vTop; y=0?_y:(mHeight-_y);
_y *= mWidth;
float picCoordX = tLeft;
vec4* dst = m_colorBuffer+(y*m_backBufferWidth + vLeft);
for (int x=vLeft ; xGetPixel(picCoordX, picCoordY,color);
{
int _x = int(picCoordX)%mWidth;
_x = _x>=0?_x:(mWidth -_x);
const vec4* c = &pColorBuffer[_y + _x];
color.r = c->x;
color.g = c->y;
color.b = c->z;
color.a = c->w;
}
color.r *= curColor.r;
color.g *= curColor.g;
color.b *= curColor.b;
color.a *= curColor.a;
//F_BlendPixel(&color,dst);
{