精华内容
下载资源
问答
  • 做了一个OSG离屏渲染,即将OSG渲染结果的图片纹理提取出来,提取到OpenCV并转化为Mat类型来显示,便于后续操作,还是比较有价值的工作。其中模型是动态的模型。 OSG 离屏渲染 上面这个视频中(b站链接在这里)...

    代码效果

    做了一个OSG离屏渲染,即将OSG渲染结果的图片纹理提取出来,提取到OpenCV并转化为Mat类型来显示,便于后续操作,还是比较有价值的工作。其中模型是动态的模型。

    OSG 离屏渲染

    上面这个视频中(b站链接在这里),左边是调用viewer.frame()进行渲染时自动显示的图像,是反的,这个无所谓了,不是我们要用的东西;右边是我将纹理提取到OpenCV的Mat中然后用imshow展示出来的,是便于在OpenCV中做进一步处理的。

    其实还是比较难做的,具体解释和做法详见下文。

    主要难点

    参考了很多资料,但是多数资料都只能把渲染后的图片纹理直接保存到本地,主要有两种思路:

    • 调用attach将OSG的camera与image连接起来,image就可以导出纹理到本地;
    • 读viewer的缓存,转化为图像。

    然而OSG有一个特性,即OSG中camera看到的图像是上下颠倒的,并且存储camera看到的图像的内存是会实时刷新的,这给离屏渲染造成了很大困扰,以上两种方法保存到本地都没有问题,但是如果要实时纹理提取,得到的纹理就是上下颠倒的。

    如果将得到的纹理再做一次上下反转,你会惊奇的发现你得到的纹理一直在闪烁。这是因为缓存是不断刷新的,总会有一部分被下一帧(颠倒的)覆盖掉。

    解决方案

    解决方案就是反向渲染,即进行渲染前先把背景反转一下。模型也反向渲染。
    当然还有一种取巧的办法,就是渲染时不上传背景图,只把模型渲染到默认幕布北京上,然后把幕布替换为我们的背景图。这种方法比较好写。本文走的是比较复杂的路子。。

    代码

    环境:win10, vs2015, opencv3.4.13, OSG3.6.5
    代码结构如下图:
    在这里插入图片描述
    其中 modelrend.h为:

    #pragma once
    
    #include <windows.h>
    #include <osg/Camera>
    #include <osg/PolygonMode>
    #include <osg/Texture2D>
    #include <osg/Geode>
    #include <osg/Geometry>
    
    #include <osgViewer/Viewer>
    #include <osgDB/ReadFile>
    #include <osgDB/WriteFile>
    #include <osg/PositionAttitudeTransform>
    #include <osgAnimation/BasicAnimationManager>         
    
    class VirtualCamera {
    public:
    	void createVirtualCamera(osg::ref_ptr<osg::Camera> cam, int width, int height);
    	void updatePosition(double r, double p, double h, double x, double y, double z);
    
    	double angle;
    	osg::Matrix rotation;
    	osg::Matrix translation;
    	osg::ref_ptr<osg::Camera> camera;
    	osg::ref_ptr<osg::Image> image;
    };
    
    class BackgroundCamera {
    public:
    	BackgroundCamera();
    	void update(uint8_t* data, int cols, int rows);
    	osg::Geode* createCameraPlane(int textureWidth, int textureHeight);
    	osg::Camera* createCamera(int textureWidth, int textureHeight);
    
    	osg::ref_ptr<osg::Image> img;
    };
    
    class Modelrender {
    public:
    	osgViewer::Viewer viewer;
    	BackgroundCamera bgCamera;
    	VirtualCamera vCamera;
    	double angleRoll;
    	int width, height;
    
    	Modelrender(int cols, int rows);
    	uint8_t* rend(uint8_t* inputimag);
    };
    
    

    modelrend.cpp为:

    #include "modelrend.h"
    
    #include <windows.h>
    #include <osgViewer/Viewer>
    #include <osgDB/ReadFile>
    #include <osgDB/WriteFile>
    #include <osg/PositionAttitudeTransform>
    #include <osgAnimation/BasicAnimationManager>
    
    #include <osgViewer/GraphicsWindow>
    #include <osg/Node>
    #include <osg/Geode>
    #include <osg/Group>
    #include <osg/Camera>
    #include <osg/Image>
    #include <osg/BufferObject>
    #include <osgUtil/Optimizer>
    #include <osgGA/GUIEventHandler>
    #include <osgGA/TrackballManipulator>
    
    osg::ref_ptr<osg::Image> _image;
    
    void VirtualCamera::createVirtualCamera(osg::ref_ptr<osg::Camera> cam, int width, int height)
    {
    	camera = cam;
    	// Initial Values
    	camera->setProjectionMatrixAsPerspective(320, 1., 1., 100.); //角度取了320,角度大于180时为反向渲染模型
    	camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER);
    	image = new osg::Image;
    	image->allocateImage(width, height, 1, GL_BGR, GL_UNSIGNED_BYTE);
    	camera->attach(osg::Camera::COLOR_BUFFER, image.get());
    }
    
    void VirtualCamera::updatePosition(double r, double p, double h, double x, double y, double z)
    { //模型旋转模块
    	osg::Matrixd myCameraMatrix;
    
    	// Update Rotation
    	rotation.makeRotate(
    		osg::DegreesToRadians(r), osg::Vec3(0, 1, 0), // roll
    		osg::DegreesToRadians(p), osg::Vec3(1, 0, 0), // pitch
    		osg::DegreesToRadians(h), osg::Vec3(0, 0, 1)); // heading
    
    													   // Update Translation
    	translation.makeTranslate(x, y, z);
    	myCameraMatrix = rotation * translation;
    	osg::Matrixd i = myCameraMatrix.inverse(myCameraMatrix);
    	camera->setViewMatrix(i*osg::Matrix::rotate(-(osg::PI_2), 1, -0, 0));
    }
    
    
    
    BackgroundCamera::BackgroundCamera() {
    	// Create OSG Image from CV Mat
    	img = new osg::Image;
    }
    
    void flipImageV(unsigned char* top, unsigned char* bottom, unsigned int rowSize, unsigned int rowStep)
    { //此函数用于在给输入的背景图片做反转
    	while (top<bottom)
    	{
    		unsigned char* t = top;
    		unsigned char* b = bottom;
    		for (unsigned int i = 0; i<rowSize; ++i, ++t, ++b)
    		{
    			unsigned char temp = *t;
    			*t = *b;
    			*b = temp;
    		}
    		top += rowStep;
    		bottom -= rowStep;
    	}
    }
    
    void BackgroundCamera::update(uint8_t* data, int width, int height)
    { //接收输入背景图像并做反转
    	// img->setImage(width, height, 3,
    	// 	GL_RGB, GL_BGR, GL_UNSIGNED_BYTE,
    	// 	data,
    	// 	osg::Image::AllocationMode::NO_DELETE, 1);
    	// img->dirty();
    	unsigned char* top = data;
    	unsigned char* bottom = top + (height - 1)*3*width;
    
    	flipImageV(top, bottom, width*3, width*3);
    
    	img->setImage(width, height, 3,
    		GL_RGB, GL_BGR, GL_UNSIGNED_BYTE,
    		data,
    		osg::Image::AllocationMode::NO_DELETE, 1);
    	img->dirty();
    }
    
    osg::Geode* BackgroundCamera::createCameraPlane(int textureWidth, int textureHeight)
    {
    	// CREATE PLANE TO DRAW TEXTURE
    	osg::ref_ptr<osg::Geometry> quadGeometry = osg::createTexturedQuadGeometry(osg::Vec3(0.0f, 0.0f, 0.0f),
    		osg::Vec3(textureWidth, 0.0f, 0.0f),
    		osg::Vec3(0.0, textureHeight, 0.0),
    		0.0f,
    		1.0f,
    		1.0f,
    		0.0f);
    	// PUT PLANE INTO NODE
    	osg::ref_ptr<osg::Geode> quad = new osg::Geode;
    	quad->addDrawable(quadGeometry);
    	// DISABLE SHADOW / LIGHTNING EFFECTS
    	int values = osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED;
    	quad->getOrCreateStateSet()->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), values);
    	quad->getOrCreateStateSet()->setMode(GL_LIGHTING, values);
    
    	osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
    	texture->setTextureSize(textureWidth, textureHeight);
    	texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
    	texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
    	texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
    	texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
    	texture->setResizeNonPowerOfTwoHint(false);
    
    	texture->setImage(img);
    
    	// Apply texture to quad
    	osg::ref_ptr<osg::StateSet> stateSet = quadGeometry->getOrCreateStateSet();
    	stateSet->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON);
    
    	return quad.release();
    }
    
    osg::Camera* BackgroundCamera::createCamera(int textureWidth, int textureHeight)
    {
    	osg::ref_ptr<osg::Geode> quad = createCameraPlane(textureWidth, textureHeight);
    	//Bind texture to the quadGeometry, then use the following camera:
    	osg::Camera* camera = new osg::Camera;
    	// CAMERA SETUP
    	camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
    	// use identity view matrix so that children do not get (view) transformed
    	camera->setViewMatrix(osg::Matrix::identity());
    	camera->setClearMask(GL_DEPTH_BUFFER_BIT);
    	camera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 1.0));
    	camera->setProjectionMatrixAsOrtho(0.f, textureWidth, 0.f, textureHeight, 1.0, 500.f);
    	// set resize policy to fixed
    	camera->setProjectionResizePolicy(osg::Camera::ProjectionResizePolicy::FIXED);
    	// we don't want the camera to grab event focus from the viewers main camera(s).
    	camera->setAllowEventFocus(false);
    	// only clear the depth buffer
    	camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    	//camera->setViewport( 0, 0, screenWidth, screenHeight );
    	camera->setRenderOrder(osg::Camera::NESTED_RENDER);
    	camera->addChild(quad);
    	return camera;
    }
    
    Modelrender::Modelrender(int cols, int rows)
    {
    	width = cols;
    	height = rows;
    	// OSG STUFF
    	// Create viewer
    	viewer.setUpViewInWindow(50, 50, width, height);
    
    	// Main Camera
    	osg::ref_ptr<osg::Camera>  camera = viewer.getCamera();
    	vCamera.createVirtualCamera(camera, width, height);
    
    	// Background-Camera (OpenCV Feed)
    	osg::Camera* backgroundCamera = bgCamera.createCamera(width, height);
    
    	// Load Truck Model as Example Scene
    	osg::ref_ptr<osg::Node> truckModel = osgDB::readNodeFile("avatar.osg"); //spaceship.osgt; º¬¶¯»­µÄ£º nathan.osg, avatar.osg, bignathan.osg,
    	osg::Group* truckGroup = new osg::Group();
    	// Position of truck
    	osg::PositionAttitudeTransform* position = new osg::PositionAttitudeTransform();
    
    	osgAnimation::BasicAnimationManager* anim =
    		dynamic_cast<osgAnimation::BasicAnimationManager*>(truckModel->getUpdateCallback());
    	const osgAnimation::AnimationList& list = anim->getAnimationList();
    	anim->playAnimation(list[0].get()); //模型动画的调用
    
    	truckGroup->addChild(position);
    	position->addChild(truckModel);
    
    	// Set Position of Model
    	osg::Vec3 modelPosition(0, 100, 0);
    	position->setPosition(modelPosition);
    
    	// Create new group node
    	osg::ref_ptr<osg::Group> group = new osg::Group;
    	osg::Node* background = backgroundCamera;
    	osg::Node* foreground = truckGroup;
    	background->getOrCreateStateSet()->setRenderBinDetails(1, "RenderBin");
    	foreground->getOrCreateStateSet()->setRenderBinDetails(2, "RenderBin");
    	group->addChild(background);
    	group->addChild(foreground);
    	background->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
    	foreground->getOrCreateStateSet()->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
    
    	// Add the groud to the viewer、
    	// _image = new osg::Image();
    	viewer.setSceneData(group.get());
    
    	angleRoll = 0.0;
    }
    
    uint8_t* Modelrender::rend(uint8_t * inputimage)
    {
    	bgCamera.update(inputimage, width, height);
    
    	//angleRoll += 0.5;
    
    	// Position Parameters: Roll, Pitch, Heading, X, Y, Z
    	vCamera.updatePosition(angleRoll, 0, 0, 0, 0, 0);
    	viewer.frame();
    	//vCamera.image->flipVertical();
    	return vCamera.image->data();
    }
    
    

    main.cpp为:

    #include <iostream>
    #include <algorithm>
    
    #include "modelrend.h"
    
    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/core/core.hpp"
    
    using namespace std;
    
    int main(int argc, char** argv)
    {
    	//cv::VideoCapture cap("movie.mkv");
    	cv::VideoCapture cap(0); //打开摄像头
    
    	if (!cap.isOpened())
    	{
    		std::cout << "Webcam cannot open!\n";
    		return 0;
    	}
    	int frameH = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
    	int frameW = cap.get(CV_CAP_PROP_FRAME_WIDTH);
    	int fps = cap.get(CV_CAP_PROP_FPS);
    	int numFrames = cap.get(CV_CAP_PROP_FRAME_COUNT);
    	printf("height=%d, width=%d, fps=%d, totalframes=%d", frameH, frameW, fps, numFrames);
    
    	Modelrender render(frameW, frameH);
    
    	while (1)
    	{
    		// Refresh Background Image
    		cv::Mat frame;
    		cap >> frame;
    
    		cv::Mat dst1 = cv::Mat(frame.size(), CV_8UC3, cv::Scalar(255, 255, 255));
    
    		dst1.data = render.rend(frame.data); //将摄像头采集到的图像作为背景输入进行渲染,然后取出纹理到dst1,完成离屏渲染
    
    		cv::imshow("test", dst1); //将dst1显示出来
    		cvWaitKey(5);
    	}
    	return 0;
    }
    
    
    
    展开全文
  • 延迟渲染,从这个名字来看就意味着渲染是被延迟的,直到所有几何对象都已经通过渲染管线处理后,在最后才应用着色(通过光照来决定最终的像素颜色)并产生最终的图像。 那么为什么要这样来处理呢?   ...

    如果你是一个游戏开发者,在你使用的图形引擎中或多或少都听说过forward rendering和deferred rendering。通常你必须在你的游戏中选择一种。但它们是什么,彼此之间有什么不同,我们又该如何选择呢?

    Modern Graphics Pipelines(现代图形管道)

    在开始之前,我们必须要知道一点现代可编程图形管线的一些知识。早些时候,我们被显卡的功能限制,不能去改变每个像素的绘制方式,除了发送一些不同的纹理外,不能去修改顶点的数据。现在时代已经改变,我们能够基于显卡的图形管线进行编程。我们能够发送代码到显卡去改变像素的外观(颜色),使用法线纹理(normal maps)改变它们外观使其变的突起,也可以添加反射(以及大量的现实主义)。

    此代码采用几何,顶点和片段着色器的形式,从本质上来说,它们控制显卡如何去渲染对象。

    可编程图形管道的简化视图

    Forward Rendering(正向渲染/前向渲染)

    Forward Rendering 是大多数渲染引擎使用的渲染技术。你给显卡提供几何对象,它将几何对象分解成顶点送入顶点着色器,然后把这些顶点数据插值后分别送入片元/像素着色器,然后在它们被送入屏幕前做最终的渲染处理(模板测试,混合等)。

    正向渲染:几何着色器到顶点着色器来分割着色器

    这是一个线性的流程,每个几何对象分别通过渲染管线一步步的处理下去并产生最终的图像。

    Deferred Rendering(延迟渲染)

    延迟渲染,从这个名字来看就意味着渲染是被延迟的,直到所有几何对象都已经通过渲染管线处理后,在最后才应用着色(通过光照来决定最终的像素颜色)并产生最终的图像。

    那么为什么要这样来处理呢?

     

    延迟渲染:几何到顶点到片段着色器。传递给多个渲染目标,然后用光照阴影。

    延迟照明是对延迟渲染的修改,通过在场景中使用更多遍来减少G缓冲区的大小。

    Lighting Performance(光照性能)

    标准前向渲染(Forward Rendering)光照的性能消耗也是为什么要另辟蹊径选择其他渲染方式的主要原因。在标准前向渲染(Forward Rendering)管线流程中,每个灯光都会在每个顶点/或片元上执行光照计算,这也就是常说的逐顶点光照和逐片元/像素光照。

    如果你在场景中有100个几何对象,并且每个几何对象有1000个顶点,你大约就有100000多变形(非常粗略的计算)。显卡还能够很轻松的处理,但是当这些多边形被发送到片元着色器时, 昂贵的对灯光消耗会使性能急剧下降。开发者可以尝试放置光照计算到顶点着色器减少片元着色器对光照的计算。

    不管它是不是此像素上最顶层的片元,还是被遮挡的片元,昂贵的光照计算都会在每个多边形的每个可见片元上执行。如果屏幕的分辨率是1024x768,你有将近800000个像素需要被渲染。你能很轻易的就达到每帧百万级的片元操作。并且大多数的片元还会被剔除(深度测试阶段),那么对于此片元的光照就算就白费了。

    如果你要对这样一个达到百万级片元的场景的每一灯光进行渲染,那么你在每一帧将跃升的一个灯光数量x1000000个片元的操作上!想象一下你有一个小镇的街道上面布满点光源!!!!!

    计算前向渲染(Forward Rendering)复杂度的公式参见: big O notatio,复杂度公式:O(num_geometry_fragments * num_lights)。你能看到这里的复杂度是和几何对象数量和灯光数量直接相关的。

    片元是一个最终可能在屏幕上成为像素的一个”待转像素“,如果在深度测试阶段不被剔除的话,它将在屏幕上成为屏幕的最终像素。现在一些引擎通过其他的方式优化了光照计算,比如:剔除非常远的灯光,组合灯管或使用 Light maps(非常流行的,但是只能是静态的物体)。如果你有大量的灯光需要动态光照的话,我们需要一个更好的解决方案。

    Deferred Rendering to the Rescue(前向渲染的救星–延迟渲染)

    延迟渲染(Deferred Rendering)是一个减少光照着色对象数量有趣的方法。尤其是对于总的片元对象来说,执行光照的片元数量直接由屏幕的分辨率决定。

    延迟渲染(Deferred Rendering)的复杂性,在big O notation中是O(screen_resolution * num_lights)。

    现在你能明白了,你有多少的光照数量是由你对灯光数量的使用来决定的。所以你能很高兴的增加你的灯光数量。(这不意味着你可以有无限的几何对象,它们还是要经过管线的及其他处理才能到G-Buffer中。)

    The Guts of Deferred Rendering(延迟渲染的细节)

    每个几何对象被渲染,但是没有使用光照,使用多目标渲染(multiple render targets),绘制出多个屏幕空间大小的Buffer。深度,法线和颜色分别写入各自的buffers(图像)。然后,这些Buffers和每个灯光像的素颜色进行合成,最后生成最终的图像。

     

    颜色,深度和正常缓冲区。(图片由astrofa,通过维基共享资源。)

     

    最终照明(阴影)使用三个缓冲区生成结果。(图片由astrofa,通过维基共享资源。)

    选择哪一个呢?

    一个最简短的回答是:如果你使用了大量灯光那么你就该使用延迟渲染(Deferred Rendering)了。但是延迟渲染(Deferred Rendering)也有一些明显的缺点:

    •  这个处理需要显卡支持多目标渲染,老的显卡是不支持的,所有不能在上面工作,对于这个是没有变通的方案的,除非强制要求客服换显卡。

    • 它需要高带宽的显卡,你要发送大的Buffer数据,老大的显卡可能处理不了。对于这个也没有变通的方案的,除非强制要求客服换显卡。

    • 你不能使用透明对象。(除非你联合 使用deferred rendering 和Forward Rendering )。

    • 没有抗锯齿。

    • 仅有一个类型的材质被允许,除非你使用了被叫做Deferred Lighting的延迟渲染修改。

    • 阴影依赖于光照的数量,延迟渲染没有解决任何阴影的问题。

    如果你没有大量的灯光或者你想能够在比较老的显卡上允许,你应该选择使用前向渲染(Forward Rendering)并且替换你的灯光使用静态光照贴图。这个结果看起来还是令人吃惊的。

    总结

    我希望摆脱一些光照的主题。在这里你的选择是解决渲染问题,但是在游戏开始之前就做出正确的选择是非常重要的,因为可以避免日后的修改。

    展开全文
  • Forward Rendering(正向渲染) 发生在渲染管线的顶点处理阶段,会计算所有的顶点的光照。全平台支持。 规则一:最亮的几个光源会被实现为像素光照 规则二:然后最多4个光源会被实现为顶点光照 规则三:剩下的...

    内容引自《Real Time Rendering 3rd》

    Forward Rendering(正向渲染)

     

    发生在渲染管线的顶点处理阶段,会计算所有的顶点的光照。全平台支持。

    • 规则一:最亮的几个光源会被实现为像素光照
    • 规则二:然后最多4个光源会被实现为顶点光照
    • 规则三:剩下的光源会被实现为效率较高的球面调谐光照(Spherical Hamanic),这是一种模拟光照

    规则一补充说明:

    • 最亮的那盏光一定是像素光照
    • Light的Render Mode是important的光一定是像素光照
    • 如果前面的两条加起来的像素光照小于Quality Setting里的Pixel Light Count(最大像素光照数量),那么从剩下的光源中找出最亮的那几盏光源,实现为像素光照。
    • 最后剩下的光源,按照规则2或3。
    • 在base pass里执行一盏像素光、所有的顶点光和球面调谐光照,并且进行阴影计算。
    • 其余的像素光每盏一个Additional Pass,并且这些pass里没有阴影计算。
    • 场景中看到的阴影,全是base pass里计算出最亮那盏像素光的阴影,其他像素光是不计算阴影的。

     

    延迟渲染( Deferred Rendering)

    在计算机图形学中,延迟渲染( Deferred Rendering) ,即延迟着色(Deferred Shading),是将着色计算延迟到深度测试之后进行处理的一种渲染方法。延迟着色技术的最大的优势就是将光源的数目和场景中物体的数目在复杂度层面上完全分开,能够在渲染拥有成百上千光源的场景的同时依然保持很高的帧率,给我们渲染拥有大量光源的场景提供了很多可能性。

     

    传统的正向渲染思路是,先进行着色,再进行深度测试。其的主要缺点就是光照计算跟场景复杂度和光源个数有很大关系。假设有n个物体,m个光源,且每个物体受所有光源的影响,那么复杂度就是O(m*n)。

    正向渲染简单直接,也很容易实现,但是同时它对程序性能的影响也很大,因为对每一个需要渲染的物体,程序都要对每个光源下每一个需要渲染的片段进行迭代,如果旧的片段完全被一些新的片段覆盖,最终无需显示出来,那么其着色计算花费的时间就完全浪费掉了。

    而延迟渲染的提出,就是为了解决上述问题而诞生了(尤其是在场景中存在大量光源的情况下)。

    延迟着色给我们优化拥有大量光源的场景提供了很多可能性,因为它能够在渲染拥有成百上千光源的场景的同时还能够保持能让人接受的帧率。

    发生在渲染管线的像素处理阶段,会对真正出现在屏幕上的像素进行光照计算。同时,光照计算的复杂度取决于屏幕的大小,而不是场景的复杂度。

    延迟渲染主要包含了两个Pass:

    1. 第一个Pass用于渲染G缓冲,在这个Pass中,不进行光照计算,仅仅计算哪些片元是可见的,如果一个片元是可见的,就把它的相关信息(漫反射颜色、高光反射颜色、法线、自发光和深度等信息)存储到G缓冲区中。对于每一个物体,这个Pass仅会执行一次。
    2. 第二个Pass用于计算真正的光照模型。该Pass会使用上一个Pass渲染的数据来计算最终的光照颜色,再存储到帧缓冲中。

     

    几何缓冲区 G-buffer
     

    G-Buffer,全称Geometric Buffer ,译作几何缓冲区,它主要用于存储每个像素对应的位置(Position),法线(Normal),漫反射颜色(Diffuse Color)以及其他有用材质参数。根据这些信息,就可以在像空间(二维空间)中对每个像素进行光照处理。

     

    缺点:

    • 读写G-buffer的内存带宽用量是性能瓶颈。
    • 不支持半透明
    • 不支持硬件抗锯齿(anti-aliasing)功能
    • 对显卡有一定要求。

    需要平台支持

    PC(Windows / Mac)需要Shader Model 3.0+支持。

    手机(iOS / Android)需要OpenGL ES 3.0,Metal支持

     

    延迟渲染的改进


    针对延迟渲染上述提到的缺点,下面简单列举一些降低 Deferred Rendering 存取带宽的改进方案。最简单也是最容易想到的就是将存取的 G-Buffer 数据结构最小化,这也就衍生出了 Light Pre-Pass(即Deferred Lighting) 方法。另一种方式是将多个光照组成一组,然后一起处理,这种方法衍生了 Tile-Based Deferred Rendering。

    现在主流的Deferred Rendering的改进是:分块延迟渲染 Tile-BasedDeferred Rendering

     

    分块延迟渲染 Tile-BasedDeferred Rendering


    作为传统Defferred Rendering的另一种主要改进,分块延迟渲染(Tile-Based Deferred Rendering,TBDR)旨在合理分摊开销(amortize overhead),自SIGGRAPH 2010上提出以来逐渐为业界所了解。

    实验数据表明TBDR在大量光源存在的情况下明显优于上文提到的Light Pre-Pass。

    我们知道,延迟渲染的瓶颈在于读写 G-buffer,在大量光源下,具体瓶颈将位于每个光源对 G-buffer的读取及与颜色缓冲区(color buffer)混合。这里的问题是,每个光源,即使它们的影响范围在屏幕空间上有重疉,因为每个光源是在不同的绘制中进行,所以会重复读取G-buffer中相同位置的数据,计算后以相加混合方式写入颜色缓冲。光源越多,内存带宽用量越大。

    分块延迟渲染的主要思想则是把屏幕分拆成一个个小的分块,例如每 32 × 32 像素作为一个分块(tile)。计算每个分块的深度范围(depth range),求得每个 tile 的 包围盒bounding box。然后,计算每个分块的包围盒bounding box会受到哪些光源影响,把那些光源的索引储存在分块的光源列表里。最后,逐个分块进行着色,对每像素读取 G-buffer 和光源列表及相关的光源信息。因此,G-buffer的数据只会被读取1次且仅1次,写入 color buffer也是1次且仅1次,大幅降低内存带宽用量。不过,这种方法需要计算光源会影响哪些分块,这个计算又称为光源剔除(light culling),可以在 CPU 或 GPU(通常以 compute shader 实现)中进行。用GPU计算的好处是,GPU 计算这类工作比 CPU 更快,也减少 CPU/GPU 数据传输。而且,可以计算每个分块的深度范围(depth range),作更有效的剔除。

     

    对比 Deferred Rendering,之前是对每个光源求取其作用区域 light volume,然后决定其作用的的 pixel,也就是说每个光源要求取一次。而使用 TBDR,只要遍历每个 pixel,让其所属 tile 与光线求交,来计算作用其上的 light,并利用 G-Buffer 进行 Shading。一方面这样做减少 了所需考虑的光源个数,另一方面与传统的 Deferred Rendering 相比,减少了存取的带宽。 

    展开全文
  • 【理解】神经立体渲染,NeRF

    千次阅读 2020-12-23 21:41:24
    这是我第一篇关于神经立体渲染的介绍,希望不断完善补充 2020年是神经立体渲染(neural volume rendering)爆发的一年。 更大的一个领域是神经渲染(Neural rendering),有一篇文章专门进行了介绍。 神经体积渲染是...

    参考自:https://dellaert.github.io/NeRF/

    这是我第一篇关于神经立体渲染的介绍,希望不断完善补充

    2020年是神经立体渲染(neural volume rendering)爆发的一年。

    更大的一个领域是神经渲染(Neural rendering),有一篇文章专门进行了介绍。

    神经体积渲染是指通过追踪光线进入场景并对光线长度进行积分来生成图像或视频的方法。
    一般来说,像多层感知器这样的神经网络会将一个函数从光线的三维坐标编码为密度和颜色等数量,然后将其整合以生成图像。

    展开全文
  • Vue中渲染内容的两种方式

    千次阅读 2019-02-21 15:55:29
    // 转换过来就是: 暂且可理解为是渲染App组件 // render:(function(x){ // return x(App); // }); }).$mount("#app"); 或者 new Vue({ el: '#app', router, render: h => h(App) // render: x => x(App) // ...
  • echarts 请求后台,返回数据渲染

    千次阅读 2020-04-22 22:20:30
    function initEchartY(divId,url){ var myChart = echarts.init(document.getElementById(divId)); myChart.showLoading({ text: '正在努力加载中...' }); ...
  • <el-date-picker v-model="form.validateTime" value-format="yyyy-MM-dd HH:mm:ss" type="daterange" range-separator="至" ... @change="$forceUpdate()" //强制渲染 ></el-date-picker> ...
  • 主要:nuxt.js服务器的渲染配置,在配置中注意的问题以及后台要安装配置哪些技术,和nginx反向代理配置和注意问题
  • Unity3D开发之更改材质的渲染模式

    千次阅读 2018-01-18 09:50:46
    在工业可视化的项目中,需要用到...Unity5.0版本出现的新版标准材质可以让我们直接在面板上更改渲染模式。不过代码来更改渲染模式确实很麻烦,要改的参数很多。 public enum RenderingMode { Opaque, Cutout, Fade
  • elementui select更改选中值后,无法渲染到页面中? 在select组件中添加了 @visible-change="$forceUpdate()" 方法,强制render当前组件 elementui-select组件 在对象里,一定要事先定义好原值,如果数据从...
  • 位图渲染 BitmapShader 简介( 1 ) 位图渲染综述 ( ① 三种方式 : Shader.TileMode.CLAMP | Shader.TileMode.REPEAT | Shader.TileMode.MIRROR | ② 流程 : 创建 Shader | 设置 Shader 到 Paint | 打开抗锯齿 | 绘制...
  • Redner的主要用途之一是通过梯度下降进行反向渲染(因此称为Redner)。 令红色更与众不同的是:1)通过适当考虑不连续性,它随机地计算正确的渲染梯度,而无需任何近似; 2)具有基于物理的模式-这意味着它可以模拟...
  • 点击上方“3D视觉工坊”,选择“星标”干货第一时间送达近日,商汤-港中文联合实验室提出基于风格化对抗生成器的人脸渲染器,用于取代传统图形学基于栅格化的渲染器来进行3D模型的重建。该方法构建...
  • 一些游戏用到的渲染技术

    千次阅读 2018-05-18 21:19:57
    在GPU和CPU有能力进行实时光线追踪(Ray Tracing,按照真实世界光线投射原理反向渲染的技术)之前,环境光遮蔽是当今光栅化渲染模式中最好、最高效的替代方案。环境光遮蔽通过计算光线在物体上的折射、衍射、散射和...
  • Django因其丰富的组件、高度的稳定性、强大的后台管理,在Python Web开发上占有绝大的市场份额与地位,2小时上手Django框架、帮助学员最快速的理解Web的运行原理和Django环境的快速搭建,并通过Django的Admin,一键...
  • 它提供了一个可微的渲染函数及其相关的反向模式微分函数(又名伴随函数),该函数提供了在渲染图像上定义的关于闪电、3D 顶点位置和顶点颜色的损失的导数。 核心三角形光栅化程序及其伴随程序是用 C 编写的以提高...
  • redner:无近似的可区分渲染redner是一种可区分的...Redner的主要用途之一是通过梯度下降进行反向渲染(因此称为Redner)。 设置红色的区别在于:1)通过适当考虑光盘,它可以随机计算正确的渲染渐变,而无需任何近似
  •   这算是第一次实打实遇到跨域问题,之前做的东西都是用后台MVC框架进行渲染前端页面,加上之前准备面试题都只是知道个大概是个什么东西,这才在这次的前后端分离练习中遇到了这个问题。 具体啥是跨域问题,...
  • Django框架基础教程(一):简单介绍Python Django框架

    万次阅读 多人点赞 2019-05-22 17:11:28
    每一次循环中,模板系统会渲染在 {% for %} 和 {% endfor %} 之间的所有内容。 {%  for  person  in  list %} <li>{{ person.name }} {% endfor %} 给标签增加一个 reversed 使得该列表被...
  • vue+elementUi多选框反选

    2020-07-06 09:31:36
  • 简介这是一篇没有什么实际作用的文章,因为没有任何shader效果实现,整篇文章到最后,我只实现了一个旋转的立方体(o(╯□╰)o),和Unity渲染的万紫千红的3D世界显得有很大落差,仿佛一切都回到了最初的起点。...
  • 基于SSM的校园二手交易平台的设计与实现

    万次阅读 多人点赞 2018-05-06 14:24:44
    PS: Java版本:1.7 数据库:MySQL 框架:Spring + Spring MVC + MyBatis 服务器:Tomcat 前端解析框架:Thymeleaf 开发工具:Idea 2017 版本管理工具:Maven 版本控制工具:GitHub ...一、设计概...
  • 本项目已由静态页面转为js渲染。 数据源为官方的API。 文件中已包含构建nginx反向代理服务器所需的配置文件及相关配置,如需全部拷贝运行请自行下载nginx安装,将本文件中的nginx / nginx.conf文件内容复制到您的...
  • 显示未遮罩图形:显示与未遮罩渲染区域关联的图形。 取消遮罩RaycastFilter 射线穿过未遮盖的矩形。 您可以单击背面的未屏蔽按钮。 演示版 安装 需求 Unity 5.5或更高版本 支持2017.x,2018.x,2019.x和2020.x.
  • URP渲染管线初步解析

    千次阅读 2020-01-12 13:46:40
    URP渲染管线初步解析 LWRP现在在unity2019已经成为默认的管线了,并更名为URP(通用渲染管线),替代了原来的builtin管线,以下是应用阶段的渲染流程顺序。 步骤分析 URP整个渲染的主入口在UniversalRenderPipeline...
  • Trickster Trickster是Prometheus HTTP APIv1的反向代理缓存,可极大地加快从Prometheus查询的任何系列的仪表板渲染时间。 工作原理1. Delta Proxy Mo Trickster是HTTP应用程序的HTTP反向代理/缓存,以及时间序列...
  • Unity渲染流程概述

    千次阅读 2019-12-04 19:58:29
    本篇的任务是回答:在Untiy的渲染流程中CPU和GPU分别做了什么。 渲染到设备屏幕显示的每一帧的画面,都经历几个阶段的加工过程: 应用程序阶段(CPU):识别出潜在可视的网格实例,并把他们及其材质提交给GPU以供...
  • 反向散射+骨干+ React TodoMVC Backscatter是一个微小的扩展,可帮助您跟踪整个Backbone模型树中的事件。 每当Backscatter从树中某个位置的模型... 这对于触发React渲染非常有用! 学习反向散射 是一个很好的起点。
  • 移动端云渲染的实现

    千次阅读 多人点赞 2018-11-22 17:58:44
    类似渲染云这种自然现象的时候,必须首先了解噪声这个概念。这个噪声指的是描述自然界规律的一些随机函数。例如大名鼎鼎的柏林噪声。Perlin噪声被大量用于云朵、火焰和地形等自然环境的模拟,而Worley噪声被提出用于...
  • 浅谈《原神》中的图形渲染技术

    千次阅读 多人点赞 2021-02-27 15:34:15
    从猜测的角度出发,谈谈《原神》中主要图形特效的渲染技术与优化方法。包括 LOD,PBR,环境光遮蔽,体积光,体积雾,视差,屏幕空间反射等常见的技术。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,233
精华内容 9,293
关键字:

反向渲染