Introi
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
A 3D streaming system is a system that collects 3D data and dynamically renders it.
|
||||
The previous chapter voluntarily remained vague about what \emph{3D data} actually is.
|
||||
This chapter presents in detail what 3D data is and how it is reenderer, and give insights about interaction and streaming by comparing the 3D case to the video one.
|
||||
|
||||
\section{What is a 3D model?}
|
||||
|
||||
Before talking about 3D streaming, we need to define what is a 3D model and how it is rendered.
|
||||
|
||||
\subsection{Content of a 3D model}
|
||||
\subsection{3D data}
|
||||
A 3D model consists in a set of data.
|
||||
|
||||
\begin{itemize}
|
||||
@@ -19,7 +21,7 @@ A 3D model encoded in the OBJ format typically consists in two files: the materi
|
||||
\paragraph{}
|
||||
The materials file declare all the materials that the object file will reference.
|
||||
A material consists in name, and other photometric properties such as ambient, diffuse and specular colors, as well as texture maps.
|
||||
Each face correspond to a material and a renderer can use the material's information to render the faces.
|
||||
Each face correspond to a material and a renderer can use the material's information to render the faces in a specific way.
|
||||
A simple material file is visible on Listing~\ref{i:mtl}.
|
||||
|
||||
\paragraph{}
|
||||
@@ -63,26 +65,94 @@ An example of object file is visible on Listing~\ref{i:obj}.
|
||||
|
||||
\subsection{Rendering a 3D model\label{i:rendering}}
|
||||
|
||||
To be able to render a model, it is first required to send the data (vertices, textures coordinates, normals, faces and textures) to the GPU, and then only the rendering can be done.
|
||||
Then, to render a 3D model, the objects from the model are traversed, the materials and textures are bound to the target on which the rendering will be done, and then, \texttt{glDrawArray} or \texttt{glDrawElements} function is called.
|
||||
To understand how performance is impacted by the structure of the model, we need to realize two things:
|
||||
A typical 3D renderer follows Algorithm~\ref{f:renderer}.
|
||||
|
||||
\newcommand\mycommfont[1]{\footnotesize\ttfamily\textcolor{blue}{#1}}
|
||||
\SetCommentSty{mycommfont}
|
||||
\SetNoFillComment%
|
||||
|
||||
\begin{algorithm}[th]
|
||||
\SetKwData{Texture}{texture}
|
||||
\SetKwData{Object}{object}
|
||||
\SetKwData{Geometry}{geometry}
|
||||
\SetKwData{Textures}{all\_textures}
|
||||
\SetKwData{Object}{object}
|
||||
\SetKwData{Scene}{scene}
|
||||
\SetKwData{True}{true}
|
||||
\SetKwFunction{LoadGeometry}{load\_geometry}
|
||||
\SetKwFunction{LoadTexture}{load\_texture}
|
||||
\SetKwFunction{BindTexture}{bind\_texture}
|
||||
\SetKwFunction{Draw}{draw}
|
||||
|
||||
\tcc{Initialization}
|
||||
\For{\Object\in\Scene}{%
|
||||
\LoadGeometry(\Object.\Geometry)\;
|
||||
\LoadTexture(\Object.\Texture)\;
|
||||
}
|
||||
\BlankLine%
|
||||
\BlankLine%
|
||||
\tcc{Render loop}
|
||||
\While{\True}{%
|
||||
\For{\Object\in\Scene}{%
|
||||
\BindTexture{\Object.\Texture}\;
|
||||
\Draw{\Object.\Geometry}\;
|
||||
}
|
||||
}
|
||||
|
||||
\caption{A rendering algorithm\label{f:renderer}}
|
||||
\end{algorithm}
|
||||
|
||||
The first task the renderer needs to perform is sending the data to the GPU\@: this is done in the loading loop at the beginning.
|
||||
This step can be slow, but it is generally acceptable since it only occurs once at the beginning of the program.
|
||||
Then, the renderer starts the rendering loop: at each frame, it renders the whole scene.
|
||||
During the rendering loop, there are two things to consider regarding performances:
|
||||
\begin{itemize}
|
||||
\item calling many times \texttt{glDrawArray} on small arrays is considerably slower than calling it once on a big array;
|
||||
\item calling \texttt{glDrawArray} on a small array is faster than calling it on a big array.
|
||||
\item obviously, the more faces a geometry contains, the slower the \texttt{draw} call is;
|
||||
\item the more objects in the scene, the more overhead at each step of the loop.
|
||||
\end{itemize}
|
||||
|
||||
However, due to the way the materials and textures work, we are forced to call \texttt{glDrawArray} at least as many times as there are materials in the model.
|
||||
Minimizing the numbers of materials used in a 3D model is thus critical for rendering performances.
|
||||
The way the loop works forces objects with different textures to be rendered separately.
|
||||
An efficient renderer keeps the number of objects in a scene low to avoid introducing overhead.
|
||||
|
||||
Another way to improve the performance of rendering is \textbf{frustum culling}.
|
||||
Frustum culling is a technique that consists in avoiding drawing objects that are not in the field of view of the user's camera.
|
||||
It is particularly efficient when they are many objects in a scene since it gives potential for skips.
|
||||
However, an important feature of 3D engine regarding performance is frustum culling.
|
||||
The frustum is the viewing volume of the camera.
|
||||
Frustum culling consists in avoiding rendering objects that are outside the viewing volume of the camera.
|
||||
Algorithm~\ref{f:frustum-culling} is a variation of Algorithm~\ref{f:renderer} with frustum culling.
|
||||
|
||||
These two aspects are somehow contradictory, and to have greatest performance for 3D rendering, one must ensure that:
|
||||
\begin{itemize}
|
||||
\item the least amount of materials are used, and most objects that share materials are drawn together in a single \texttt{glDrawArray} call;
|
||||
\item objects are not all drawn together and grouped together depending on their location to keep the frustum culling efficient.
|
||||
\end{itemize}
|
||||
\begin{algorithm}[th]
|
||||
\SetKwData{Texture}{texture}
|
||||
\SetKwData{Object}{object}
|
||||
\SetKwData{Geometry}{geometry}
|
||||
\SetKwData{Textures}{all\_textures}
|
||||
\SetKwData{Object}{object}
|
||||
\SetKwData{Scene}{scene}
|
||||
\SetKwData{True}{true}
|
||||
\SetKwData{CameraFrustum}{camera\_frustum}
|
||||
\SetKwFunction{LoadGeometry}{load\_geometry}
|
||||
\SetKwFunction{LoadTexture}{load\_texture}
|
||||
\SetKwFunction{BindTexture}{bind\_texture}
|
||||
\SetKwFunction{Draw}{draw}
|
||||
|
||||
\tcc{Initialization}
|
||||
\For{$\Object\in\Scene$}{%
|
||||
\LoadGeometry(\Object.\Geometry)\;
|
||||
\LoadTexture(\Object.\Texture)\;
|
||||
}
|
||||
\BlankLine%
|
||||
\BlankLine%
|
||||
\tcc{Render loop}
|
||||
\While{\True}{%
|
||||
\For{$\Object\in\Scene$}{%
|
||||
\If{$\Object\cap\CameraFrustum\neq\emptyset$}{%
|
||||
\BindTexture{\Object.\Texture}\;
|
||||
\Draw{\Object.\Geometry}\;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\caption{A rendering algorithm with frustum culling\label{f:frustum-culling}}
|
||||
\end{algorithm}
|
||||
|
||||
A renderer that uses a single object avoids the overhead, but fails to benefit from frustum culling.
|
||||
A better renderer ensures to have objects that do not spread across the whole scene, since that would lead to a useless frustum culling, and many objects to avoid rendering the whole scene at each frame, but not too many objects to avoid suffering from the overhead.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user