irrlicht/examples/28.CubeMapping/tutorial.html

214 lines
61 KiB
HTML
Raw Blame History

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Tutorial 28: CubeMapping</title>
<html xmlns="http://www.w3.org/1999/xhtml">
<!-- Wanted to avoid copying .css to each folder, so copied default .css from doxyen in here, kicked out most stuff we don't need for examples and modified some a little bit.
Target was having a single html in each example folder which is created from the main.cpp files and needs no files besides some images below media folder.
Feel free to improve :)
-->
<style>
body, table, div, p, dl {
font: 400 14px/22px;
}
body {
background-color: #F0F0F0;
color: black;
margin-left: 5%;
margin-right: 5%;
}
p.reference, p.definition {
font: 400 14px/22px;
}
.title {
font: 400 14px/28px;
font-size: 150%;
font-weight: bold;
margin: 10px 2px;
}
h1, h2, h3, h4, h5, h6 {
-webkit-transition: text-shadow 0.5s linear;
-moz-transition: text-shadow 0.5s linear;
-ms-transition: text-shadow 0.5s linear;
-o-transition: text-shadow 0.5s linear;
transition: text-shadow 0.5s linear;
margin-right: 15px;
}
caption {
font-weight: bold;
}
h3.version {
font-size: 90%;
text-align: center;
}
a {
color: #3D578C;
font-weight: normal;
text-decoration: none;
}
.contents a:visited {
color: #4665A2;
}
a:hover {
text-decoration: underline;
}
a.el {
font-weight: bold;
}
a.code, a.code:visited, a.line, a.line:visited {
color: #4665A2;
}
a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
color: #4665A2;
}
pre.fragment {
border: 1px solid #C4CFE5;
background-color: #FBFCFD;
padding: 4px 6px;
margin: 4px 8px 4px 2px;
overflow: auto;
word-wrap: break-word;
font-size: 9pt;
line-height: 125%;
font-family: monospace, fixed;
font-size: 105%;
}
div.fragment {
padding: 0px;
margin: 4px 8px 4px 2px;
background-color: #FBFCFD;
border: 1px solid #C4CFE5;
}
div.line {
font-family: monospace, fixed;
font-size: 13px;
min-height: 13px;
line-height: 1.0;
text-wrap: unrestricted;
white-space: -moz-pre-wrap; /* Moz */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: pre-wrap; /* CSS3 */
word-wrap: break-word; /* IE 5.5+ */
text-indent: -53px;
padding-left: 53px;
padding-bottom: 0px;
margin: 0px;
-webkit-transition-property: background-color, box-shadow;
-webkit-transition-duration: 0.5s;
-moz-transition-property: background-color, box-shadow;
-moz-transition-duration: 0.5s;
-ms-transition-property: background-color, box-shadow;
-ms-transition-duration: 0.5s;
-o-transition-property: background-color, box-shadow;
-o-transition-duration: 0.5s;
transition-property: background-color, box-shadow;
transition-duration: 0.5s;
}
div.contents {
margin-top: 10px;
margin-left: 12px;
margin-right: 8px;
}
div.center {
text-align: center;
margin-top: 0px;
margin-bottom: 0px;
padding: 0px;
}
div.center img {
border: 0px;
}
span.keyword {
color: #008000
}
span.keywordtype {
color: #604020
}
span.keywordflow {
color: #e08000
}
span.comment {
color: #800000
}
span.preprocessor {
color: #806020
}
span.stringliteral {
color: #002080
}
span.charliteral {
color: #008080
}
blockquote {
background-color: #F7F8FB;
border-left: 2px solid #9CAFD4;
margin: 0 24px 0 4px;
padding: 0 12px 0 16px;
}
hr {
height: 0px;
border: none;
border-top: 1px solid #4A6AAA;
}
address {
font-style: normal;
color: #2A3D61;
}
div.header {
background-image:url('nav_h.png');
background-repeat:repeat-x;
background-color: #F9FAFC;
margin: 0px;
border-bottom: 1px solid #C4CFE5;
}
div.headertitle {
padding: 5px 5px 5px 10px;
}
.image {
text-align: center;
}
.caption {
font-weight: bold;
}
div.zoom {
border: 1px solid #90A5CE;
}
tr.heading h2 {
margin-top: 12px;
margin-bottom: 4px;
}
</style>
</head>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--END TITLEAREA-->
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
</div><!-- top -->
<div class="header">
<div class="headertitle">
<div class="title">Tutorial 28: CubeMapping </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><div class="image">
<img src="../../media/example_screenshots/028shot.jpg" alt="028shot.jpg"/>
</div>
<p>Shows usage of cubemap textures and how to do some simple environment mapping. Cubemap textures have images for all 6 directions of a cube in a single texture. Environment is used to reflect the environment around an object onto the object. Cubemaps only work with shader materials which are written to support cube mapping.</p>
<dl class="section author"><dt>Author</dt><dd>Michael Zeilfelder, based on EnvCubeMap example from irrSpintz engine.</dd></dl>
<p>Start with the usual includes. </p><div class="fragment"><div class="line"><span class="preprocessor">#ifdef _MSC_VER</span></div><div class="line"><span class="preprocessor">#pragma comment(lib, &quot;Irrlicht.lib&quot;)</span></div><div class="line"><span class="preprocessor">#endif</span></div><div class="line"></div><div class="line"><span class="preprocessor">#include &lt;irrlicht.h&gt;</span></div><div class="line"><span class="preprocessor">#include &quot;driverChoice.h&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;exampleHelper.h&quot;</span></div><div class="line"></div><div class="line"><span class="keyword">using namespace </span>irr;</div></div><!-- fragment --><p> A callback class for our cubemap shader. We need a shader material which maps the cubemap texture to the polygon vertices of objects. </p><div class="fragment"><div class="line"><span class="keyword">class </span>CubeMapReflectionCallback : <span class="keyword">public</span> video::IShaderConstantSetCallBack</div><div class="line">{</div><div class="line"><span class="keyword">public</span>:</div><div class="line"> CubeMapReflectionCallback(scene::ISceneManager* smgr, <span class="keywordtype">int</span> styleUVW)</div><div class="line"> : SceneMgr(smgr)</div><div class="line"> , StyleUVW(styleUVW), Roughness(0.f)</div><div class="line"> , styleUvwID(-1) , worldViewProjID(-1), worldID(-1), cameraPosID(-1)</div><div class="line"> {}</div></div><!-- fragment --><p> Setting the style to map vertex UV-coordinates to the cubemap textures.</p><ul>
<li>Specular style is typically used for mirrors and highlight reflections.</li>
<li>Diffuse style is commonly used in image based lighting calculations and often in combination with a higher roughness. Think of it as the sum of all light which reaches a point on your object.</li>
<li>Using model vertices directly for UV's is just nice for testing sometimes. Maybe has more uses? Experiment around :-) <div class="fragment"><div class="line"><span class="keywordtype">void</span> SetStyleUVW(<span class="keywordtype">int</span> style)</div><div class="line">{</div><div class="line"> StyleUVW = style;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> GetStyleUVW()<span class="keyword"> const</span></div><div class="line"><span class="keyword"></span>{</div><div class="line"> <span class="keywordflow">return</span> StyleUVW;</div><div class="line">}</div></div><!-- fragment --> We could also call this sharpness as the rougher a material the less sharp the reflections of a cubemap are (light for rough materials spreads out more while smooth materials reflect it more like a mirror). Roughness is calculated using the mipmaps of the cubemap texture. Note that rendertarget cubemap textures won't have mipmaps, so unfortunately it won't work for those. Also currently only OpenGL is able to interpolate seamless over cubemap borders. On Direct3D9 you will only smooth per side, but not over side-borders. <div class="fragment"><div class="line"><span class="keywordtype">void</span> SetRoughness(<span class="keywordtype">float</span> roughness)</div><div class="line">{</div><div class="line"> Roughness = roughness;</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">float</span> getRoughness()<span class="keyword"> const</span></div><div class="line"><span class="keyword"></span>{</div><div class="line"> <span class="keywordflow">return</span> Roughness;</div><div class="line">}</div></div><!-- fragment --> Typical code which passes a few values from c++ to shader. <div class="fragment"><div class="line"> <span class="keyword">virtual</span> <span class="keywordtype">void</span> OnSetMaterial(<span class="keyword">const</span> video::SMaterial&amp; material)</div><div class="line"> {}</div><div class="line"></div><div class="line"> <span class="keyword">virtual</span> <span class="keywordtype">void</span> OnSetConstants(video::IMaterialRendererServices* services, s32 userData)</div><div class="line"> {</div><div class="line"> video::IVideoDriver* driver = services-&gt;getVideoDriver();</div><div class="line"></div><div class="line"> <span class="keywordflow">if</span> ( worldViewProjID &lt; 0 ) <span class="comment">// first update</span></div><div class="line"> {</div><div class="line"> styleUvwID = services-&gt;getVertexShaderConstantID(<span class="stringliteral">&quot;StyleUVW&quot;</span>);</div><div class="line"> <span class="keywordflow">if</span>( driver-&gt;getDriverType() == video::EDT_DIRECT3D9 )</div><div class="line"> {</div><div class="line"> worldViewProjID = services-&gt;getVertexShaderConstantID(<span class="stringliteral">&quot;WorldViewProj&quot;</span>);</div><div class="line"> }</div><div class="line"> worldID = services-&gt;getVertexShaderConstantID(<span class="stringliteral">&quot;World&quot;</span>);</div><div class="line"> cameraPosID = services-&gt;getVertexShaderConstantID(<span class="stringliteral">&quot;CameraPos&quot;</span>);</div><div class="line"> roughnessID = services-&gt;getPixelShaderConstantID(<span class="stringliteral">&quot;Roughness&quot;</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"> services-&gt;setVertexShaderConstant(styleUvwID, &amp;StyleUVW, 1 );</div><div class="line"></div><div class="line"> irr::core::matrix4 world = driver-&gt;getTransform(irr::video::ETS_WORLD);</div><div class="line"> services-&gt;setVertexShaderConstant(worldID, world.pointer(), 16);</div><div class="line"></div><div class="line"> <span class="keywordflow">if</span>( driver-&gt;getDriverType() == video::EDT_DIRECT3D9 )</div><div class="line"> {</div><div class="line"> irr::core::matrix4 worldViewProj;</div><div class="line"> worldViewProj = driver-&gt;getTransform(irr::video::ETS_PROJECTION);</div><div class="line"> worldViewProj *= driver-&gt;getTransform(irr::video::ETS_VIEW);</div><div class="line"> worldViewProj *= world;</div><div class="line"> services-&gt;setVertexShaderConstant(worldViewProjID, worldViewProj.pointer(), 16);</div><div class="line"> }</div><div class="line"></div><div class="line"> core::vector3df cameraPos = SceneMgr-&gt;getActiveCamera()-&gt;getAbsolutePosition();</div><div class="line"> services-&gt;setVertexShaderConstant(cameraPosID, &amp;cameraPos.X, 3 );</div><div class="line"> services-&gt;setPixelShaderConstant(roughnessID, &amp;Roughness, 1 );</div><div class="line"> }</div><div class="line"></div><div class="line"><span class="keyword">private</span>:</div><div class="line"> scene::ISceneManager* SceneMgr;</div><div class="line"></div><div class="line"> <span class="keywordtype">int</span> StyleUVW; <span class="comment">// 0 = specular, 1=diffuse, 2 = use model vertex coordinates for uvw.</span></div><div class="line"> <span class="keywordtype">float</span> Roughness; <span class="comment">// cubemap 0 = specular ... highest value depends on number of mipmaps in the texture</span></div><div class="line"></div><div class="line"> irr::s32 styleUvwID;</div><div class="line"> irr::s32 worldViewProjID;</div><div class="line"> irr::s32 worldID;</div><div class="line"> irr::s32 cameraPosID;</div><div class="line"> irr::s32 roughnessID;</div><div class="line">};</div></div><!-- fragment --> To keep the example compact our event-receiver acts also like a main application class. So it handles user input, updates the dynamic parts of the UI and it keeps some 3d nodes around. <div class="fragment"><div class="line"><span class="keyword">class </span>MyEventReceiver : <span class="keyword">public</span> IEventReceiver</div><div class="line">{</div><div class="line"><span class="keyword">public</span>:</div><div class="line"> MyEventReceiver() : Driver(0), Shader(0)</div><div class="line"> ,BackgroundSkybox(0), BackgroundCube(0)</div><div class="line"> , CubemapUpdates(2)</div><div class="line"> , CurrentStyleUVW(0), CurrentRoughness(0)</div><div class="line"> , NeedCubemapUpdate(true)</div><div class="line"> {</div><div class="line"> StyleNamesUVW.push_back( L<span class="stringliteral">&quot;specular&quot;</span> );</div><div class="line"> StyleNamesUVW.push_back( L<span class="stringliteral">&quot;diffuse&quot;</span> );</div><div class="line"> StyleNamesUVW.push_back( L<span class="stringliteral">&quot;model coordinates&quot;</span> );</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Handle the key input</span></div><div class="line"> <span class="keyword">virtual</span> <span class="keywordtype">bool</span> OnEvent(<span class="keyword">const</span> SEvent&amp; event)</div><div class="line"> {</div><div class="line"> <span class="keywordflow">if</span> (event.EventType == EET_KEY_INPUT_EVENT &amp;&amp; event.KeyInput.PressedDown == <span class="keyword">false</span>)</div><div class="line"> {</div><div class="line"> <span class="keywordflow">switch</span>(event.KeyInput.Key )</div><div class="line"> {</div><div class="line"> <span class="keywordflow">case</span> KEY_SPACE:</div><div class="line"> <span class="comment">// Switch between different texture mapping styles</span></div><div class="line"> <span class="keywordflow">if</span> ( Shader )</div><div class="line"> {</div><div class="line"> Shader-&gt;SetStyleUVW((Shader-&gt;GetStyleUVW()+1)%StyleNamesUVW.size());</div><div class="line"> updateStyleUVW();</div><div class="line"> }</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_KEY_B:</div><div class="line"> <span class="comment">// Switch between our 2 different backgrounds</span></div><div class="line"> <span class="keywordflow">if</span> ( BackgroundSkybox &amp;&amp; BackgroundCube )</div><div class="line"> {</div><div class="line"> <span class="keywordflow">if</span> ( BackgroundSkybox-&gt;isVisible() )</div><div class="line"> {</div><div class="line"> BackgroundSkybox-&gt;setVisible(<span class="keyword">false</span>);</div><div class="line"> BackgroundCube-&gt;setVisible(<span class="keyword">true</span>);</div><div class="line"> }</div><div class="line"> <span class="keywordflow">else</span></div><div class="line"> {</div><div class="line"> BackgroundSkybox-&gt;setVisible(<span class="keyword">true</span>);</div><div class="line"> BackgroundCube-&gt;setVisible(<span class="keyword">false</span>);</div><div class="line"> }</div><div class="line"> NeedCubemapUpdate = <span class="keyword">true</span>;</div><div class="line"> }</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_KEY_I:</div><div class="line"> <span class="comment">// Show/hide the info text nodes</span></div><div class="line"> <span class="keywordflow">for</span> (u32 i=0; i&lt;InfoTextNodes.size(); ++i )</div><div class="line"> InfoTextNodes[i]-&gt;setVisible(!InfoTextNodes[i]-&gt;isVisible());</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_KEY_S:</div><div class="line"> <span class="comment">// Enable/disable seamless smoothing of mipmaps over cube borders</span></div><div class="line"> <span class="keywordflow">if</span> ( Driver )</div><div class="line"> {</div><div class="line"> Driver-&gt;disableFeature(video::EVDF_TEXTURE_CUBEMAP_SEAMLESS, Driver-&gt;queryFeature(video::EVDF_TEXTURE_CUBEMAP_SEAMLESS) );</div><div class="line"> updateSeamless();</div><div class="line"> }</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_KEY_U:</div><div class="line"> <span class="comment">// Switch dynamic cubemap updates on/off.</span></div><div class="line"> CubemapUpdates = (CubemapUpdates+1) % 3;</div><div class="line"> updateCubemapUpdates();</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_PLUS:</div><div class="line"> <span class="keywordflow">case</span> KEY_ADD:</div><div class="line"> <span class="comment">// Make material rougher</span></div><div class="line"> <span class="keywordflow">if</span> ( Shader )</div><div class="line"> {</div><div class="line"> Shader-&gt;SetRoughness( Shader-&gt;getRoughness() + 0.5f );</div><div class="line"> updateRoughness();</div><div class="line"> }</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_MINUS:</div><div class="line"> <span class="keywordflow">case</span> KEY_SUBTRACT:</div><div class="line"> {</div><div class="line"> <span class="comment">// Make material smoother</span></div><div class="line"> <span class="keywordflow">if</span> ( Shader )</div><div class="line"> {</div><div class="line"> <span class="keywordtype">float</span> roughness = Shader-&gt;getRoughness() - 0.5f;</div><div class="line"> <span class="keywordflow">if</span> ( roughness &gt;= 0.f )</div><div class="line"> {</div><div class="line"> Shader-&gt;SetRoughness(roughness);</div><div class="line"> updateRoughness();</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> }</div><div class="line"> <span class="keywordflow">default</span>:</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keywordflow">return</span> <span class="keyword">false</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Some helper functions to update the UI</span></div><div class="line"> <span class="keywordtype">void</span> updateStyleUVW()</div><div class="line"> {</div><div class="line"> <span class="keywordflow">if</span> ( CurrentStyleUVW &amp;&amp; Shader)</div><div class="line"> CurrentStyleUVW-&gt;setText(StyleNamesUVW[Shader-&gt;GetStyleUVW()].c_str());</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keywordtype">void</span> updateRoughness()</div><div class="line"> {</div><div class="line"> <span class="keywordflow">if</span> ( CurrentRoughness &amp;&amp; Shader )</div><div class="line"> {</div><div class="line"> CurrentRoughness-&gt;setText( irr::core::stringw(Shader-&gt;getRoughness()).c_str() );</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keywordtype">void</span> updateSeamless()</div><div class="line"> {</div><div class="line"> <span class="keywordflow">if</span> ( CurrentSeamlessCubemap &amp;&amp; Driver )</div><div class="line"> {</div><div class="line"> CurrentSeamlessCubemap-&gt;setText( Driver-&gt;queryFeature(video::EVDF_TEXTURE_CUBEMAP_SEAMLESS) ? L<span class="stringliteral">&quot;ON&quot;</span> : L<span class="stringliteral">&quot;OFF&quot;</span> );</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keywordtype">void</span> updateCubemapUpdates()</div><div class="line"> {</div><div class="line"> <span class="keywordflow">if</span> ( CurrentCubemapUpdates )</div><div class="line"> {</div><div class="line"> <span class="keywordflow">switch</span> ( CubemapUpdates )</div><div class="line"> {</div><div class="line"> <span class="keywordflow">case</span> 0: CurrentCubemapUpdates-&gt;setText( L<span class="stringliteral">&quot;static&quot;</span>); <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> 1: CurrentCubemapUpdates-&gt;setText( L<span class="stringliteral">&quot;dynamic&quot;</span> ); <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> 2: CurrentCubemapUpdates-&gt;setText( L<span class="stringliteral">&quot;dynamic+mips&quot;</span> ); <span class="keywordflow">break</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Check if the cubemap textures should be updated with new screenshots</span></div><div class="line"> <span class="comment">// return 0 for no update, 1 for update, 2 for update and fix mip-maps</span></div><div class="line"> <span class="keywordtype">int</span> checkCubemapUpdate()</div><div class="line"> {</div><div class="line"> <span class="keywordflow">if</span> ( NeedCubemapUpdate || CubemapUpdates == 2)</div><div class="line"> {</div><div class="line"> NeedCubemapUpdate = <span class="keyword">false</span>;</div><div class="line"> <span class="keywordflow">return</span> 2;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keywordflow">return</span> CubemapUpdates;</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">// Add some text-node floating above it&#39;s parent node.</span></div><div class="line"> <span class="keywordtype">void</span> addInfoTextNode(irr::gui::IGUIFont* font, <span class="keyword">const</span> <span class="keywordtype">wchar_t</span>* text, irr::scene::ISceneNode* parent)</div><div class="line"> {</div><div class="line"> <span class="keywordflow">if</span> ( parent )</div><div class="line"> {</div><div class="line"> <span class="keyword">const</span> video::SColor infoTextCol(250, 70, 90, 90);</div><div class="line"> core::dimension2du dim(font-&gt;getDimension(text));</div><div class="line"> core::dimension2df dimf((f32)dim.Width, (f32)dim.Height);</div><div class="line"> scene::IBillboardTextSceneNode* infoNode = parent-&gt;getSceneManager()-&gt;addBillboardTextSceneNode( font, text, parent, dimf, core::vector3df(0, 120, 0), -1, infoTextCol, infoTextCol);</div><div class="line"> InfoTextNodes.push_back(infoNode);</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> irr::video::IVideoDriver* Driver;</div><div class="line"> CubeMapReflectionCallback* Shader;</div><div class="line"></div><div class="line"> scene::ISceneNode* BackgroundSkybox;</div><div class="line"> scene::ISceneNode* BackgroundCube;</div><div class="line"> irr::core::array&lt;scene::ISceneNode*&gt; InfoTextNodes;</div><div class="line"></div><div class="line"> <span class="keywordtype">int</span> CubemapUpdates; <span class="comment">// 0 = static, 1 = dynamic, 2 = dynamic with rtt</span></div><div class="line"></div><div class="line"> irr::core::array&lt;irr::core::stringw&gt; StyleNamesUVW;</div><div class="line"></div><div class="line"> irr::gui::IGUIStaticText* CurrentStyleUVW;</div><div class="line"> irr::gui::IGUIStaticText* CurrentRoughness;</div><div class="line"> irr::gui::IGUIStaticText* CurrentSeamlessCubemap;</div><div class="line"> irr::gui::IGUIStaticText* CurrentCubemapUpdates;</div><div class="line"></div><div class="line"><span class="keyword">private</span>:</div><div class="line"> <span class="keywordtype">bool</span> NeedCubemapUpdate;</div><div class="line">};</div></div><!-- fragment --> Workaround for OpenGL's upside-down images. Texture origins (0,0) in OpenGL are usually at the left-bottom instead of the more common left-top image formats. Irrlicht internally uses textures with left-top origin and then corrects the texture-matrices in the fixed-function pipeline. For shader materials it's left to the users to handle those UV-flips for the texture-matrix. Render target textures (RTT's) in OpenGL are rendered with left-bottom origin and Irrlicht can't change that, so all RTT textures in memory are upside-down (unlike all other Irrlicht textures). In the fixed function pipeline Irrlicht handles this by flipping the RTT's texture matrix once more and for shaders it's again left to the users to handle it. Cubemap textures are different from other textures in OpenGL. Each cube side has left-top as the origin. So not flipping Irrlicht textures for those would be fine. Except - OpenGL RTT's still render left-bottom - even when the target is a cubemap RTT. I found no good way around this so far - it just seems messed up as we get a left-handed/right handed coordinate system change that way.</li>
</ul>
<p>So... the following 2 defines are two different workarounds I found. Both are ugly, which one is better in reality depends probably on the scene. Only use one of those: CUBEMAP_UPSIDE_DOWN_GL_PROJECTION is relatively fast as it just changes the project matrix. The problem is that changing the projection matrix means changing front/backside culling. So every node rendered has to flip the material flags for those.</p>
<p>CUBEMAP_USPIDE_DOWN_RTT will change the texture memory itself and flip the image upside-down. While easier to do, this involves texture-locking and is very slow. </p><div class="fragment"><div class="line"><span class="preprocessor">#define CUBEMAP_UPSIDE_DOWN_GL_PROJECTION</span></div><div class="line"><span class="comment">//#define CUBEMAP_USPIDE_DOWN_RTT</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="comment">// Flip frontface/backface culling for all nodes</span></div><div class="line"><span class="preprocessor">#ifdef CUBEMAP_UPSIDE_DOWN_GL_PROJECTION</span></div><div class="line"><span class="keywordtype">void</span> flipCullingFlags(<span class="keyword">const</span> core::array&lt;scene::ISceneNode*&gt;&amp; nodes)</div><div class="line">{</div><div class="line"> <span class="keywordflow">for</span> ( irr::u32 n=0; n &lt; nodes.size(); ++n )</div><div class="line"> {</div><div class="line"> scene::ISceneNode* node = nodes[n];</div><div class="line"> <span class="keyword">const</span> irr::u32 matCount = node-&gt;getMaterialCount();</div><div class="line"> <span class="keywordflow">for</span> ( irr::u32 m=0; m &lt; matCount; ++m)</div><div class="line"> {</div><div class="line"> video::SMaterial&amp; mat = node-&gt;getMaterial(m);</div><div class="line"> mat.BackfaceCulling = !mat.BackfaceCulling;</div><div class="line"> mat.FrontfaceCulling = !mat.FrontfaceCulling;</div><div class="line"> }</div><div class="line"> }</div><div class="line">}</div><div class="line"><span class="preprocessor">#endif</span></div></div><!-- fragment --><p> Render the environment around a node into a cubemap texture. </p><div class="fragment"><div class="line"><span class="keywordtype">void</span> renderEnvironmentCubeMap(irr::video::IVideoDriver* driver, irr::scene::ICameraSceneNode* cubeMapCamera, irr::scene::ISceneNode* cubeCenterNode, video::IRenderTarget* cubeMapRT, video::ITexture* dynamicCubeMapRTT, video::ITexture* depthStencilRTT)</div><div class="line">{</div><div class="line"> <span class="comment">// Change to the cubemap camera which has a few specific render-settings</span></div><div class="line"> scene::ISceneManager* smgr = cubeMapCamera-&gt;getSceneManager();</div><div class="line"> scene::ICameraSceneNode * oldCam = smgr-&gt;getActiveCamera();</div><div class="line"> smgr-&gt;setActiveCamera( cubeMapCamera );</div></div><!-- fragment --><p> We want to see everything around the center node, so hide the node itself, otherwise it would be in the way. Then set the camera to that node's position. </p><div class="fragment"><div class="line">cubeCenterNode-&gt;setVisible( <span class="keyword">false</span> );</div><div class="line"><span class="keyword">const</span> core::vector3df center( cubeCenterNode-&gt;getAbsolutePosition() );</div><div class="line">cubeMapCamera-&gt;setPosition( center );</div></div><!-- fragment --><p> Render all 6 directions. Which means simple setting the camera target/up vector to all 6 directions and then render the full scene each time. So yeah - updating an environment cube-map means 6 full renders for each object which needs an environment map. In other words - you generally only want to do that in pre-processing, not in realtime. </p><div class="fragment"><div class="line"> <span class="keyword">const</span> core::vector3df targetVecs[6] = {</div><div class="line"> core::vector3df(1.f, 0.f, 0.f),</div><div class="line"> core::vector3df(-1.f, 0.f, 0.f),</div><div class="line"> core::vector3df(0.f, 1.f, 0.f),</div><div class="line"> core::vector3df(0.f, -1.f, 0.f),</div><div class="line"> core::vector3df(0.f, 0.f, 1.f),</div><div class="line"> core::vector3df(0.f, 0.f, -1.f)</div><div class="line"> };</div><div class="line"></div><div class="line"> <span class="keyword">const</span> core::vector3df upVecs[6] = {</div><div class="line"> core::vector3df( 0,1,0 ),</div><div class="line"> core::vector3df( 0,1,0 ),</div><div class="line"> core::vector3df( 0,0,-1 ),</div><div class="line"> core::vector3df( 0,0,1 ),</div><div class="line"> core::vector3df( 0,1,0 ),</div><div class="line"> core::vector3df( 0,1,0 )</div><div class="line"> };</div><div class="line"> <span class="keywordflow">for</span> ( <span class="keywordtype">int</span> s=0; s&lt;6; ++s )</div><div class="line"> {</div><div class="line"> cubeMapCamera-&gt;setUpVector( upVecs[s] );</div><div class="line"> cubeMapCamera-&gt;setTarget( center + targetVecs[s] );</div><div class="line"> <span class="comment">// Here we tell into which side of the cubemap texture we want to write</span></div><div class="line"> cubeMapRT-&gt;setTexture(dynamicCubeMapRTT, depthStencilRTT, (video::E_CUBE_SURFACE)(video::ECS_POSX + s));</div><div class="line"> driver-&gt;setRenderTargetEx(cubeMapRT, video::ECBF_ALL);</div><div class="line"> smgr-&gt;drawAll();</div><div class="line"></div><div class="line"><span class="preprocessor">#ifdef CUBEMAP_USPIDE_DOWN_RTT</span></div><div class="line"> <span class="comment">// This works because the lock for rtt&#39;s always flips in Irrlicht.</span></div><div class="line"> <span class="comment">// So in this case lock() unlock will result in a flipped texture</span></div><div class="line"> <span class="comment">// But be warned - it&#39;s very, very slow!</span></div><div class="line"> driver-&gt;setRenderTarget(0); <span class="comment">// to avoid accessing active rt</span></div><div class="line"> dynamicCubeMapRTT-&gt;lock(video::ETLM_READ_WRITE, 0, s, video::ETLF_FLIP_Y_UP_RTT);</div><div class="line"> dynamicCubeMapRTT-&gt;unlock();</div><div class="line"><span class="preprocessor">#endif</span></div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="comment">//dynamicCubeMapRTT-&gt;regenerateMipMapLevels(); // Unfortunately we can&#39;t seem to have mipmaps for rtt&#39;s</span></div><div class="line"></div><div class="line"> driver-&gt;setRenderTarget(0);</div><div class="line"> cubeCenterNode-&gt;setVisible( <span class="keyword">true</span> );</div><div class="line"> smgr-&gt;setActiveCamera( oldCam );</div><div class="line">}</div></div><!-- fragment --><p> Typical setup at the main start. </p><div class="fragment"><div class="line"><span class="keywordtype">int</span> main()</div><div class="line">{</div><div class="line"> <span class="comment">// Ask user for driver</span></div><div class="line"> video::E_DRIVER_TYPE driverType = driverChoiceConsole();</div><div class="line"> <span class="keywordflow">if</span> (driverType==video::EDT_COUNT)</div><div class="line"> <span class="keywordflow">return</span> 1;</div><div class="line"></div><div class="line"> <span class="comment">// Create device</span></div><div class="line"> MyEventReceiver eventReceiver;</div><div class="line"> <span class="keyword">const</span> core::dimension2d&lt;u32&gt; dimDevice(1024, 768);</div><div class="line"> IrrlichtDevice* device = createDevice( driverType, dimDevice, 32, <span class="keyword">false</span>, <span class="keyword">false</span>, <span class="keyword">false</span>, &amp;eventReceiver );</div><div class="line"> <span class="keywordflow">if</span> (!device)</div><div class="line"> <span class="keywordflow">return</span> 1;</div><div class="line"></div><div class="line"> <span class="keyword">const</span> io::path mediaPath = getExampleMediaPath();</div><div class="line"> video::IVideoDriver* driver = device-&gt;getVideoDriver();</div><div class="line"> scene::ISceneManager* smgr = device-&gt;getSceneManager();</div><div class="line"> gui::IGUIEnvironment* env = device-&gt;getGUIEnvironment();</div><div class="line"> eventReceiver.Driver = driver;</div><div class="line"></div><div class="line"> <span class="comment">// Set window title</span></div><div class="line"> core::stringw strCaption(L<span class="stringliteral">&quot;Cubemap example - Irrlicht Engine [&quot;</span>);</div><div class="line"> strCaption += driver-&gt;getName();</div><div class="line"> strCaption += L<span class="stringliteral">&quot;]&quot;</span>;</div><div class="line"> device-&gt;setWindowCaption(strCaption.c_str());</div><div class="line"></div><div class="line"> <span class="comment">// set a nicer font</span></div><div class="line"> gui::IGUISkin* skin = env-&gt;getSkin();</div><div class="line"> gui::IGUIFont* font = env-&gt;getFont(mediaPath + <span class="stringliteral">&quot;fonthaettenschweiler.bmp&quot;</span>);</div><div class="line"> <span class="keywordflow">if</span> (font)</div><div class="line"> skin-&gt;setFont(font);</div></div><!-- fragment --><p> Create a shader material for cube mapping </p><div class="fragment"><div class="line">video::IGPUProgrammingServices* gpu = driver-&gt;getGPUProgrammingServices();</div><div class="line">s32 cubeMapReflectionMaterial = 0;</div><div class="line"><span class="keywordflow">if</span>( gpu )</div><div class="line">{</div><div class="line"> <span class="comment">// Decide on shader to use based on active driver</span></div><div class="line"> irr::io::path vsFileName;</div><div class="line"> irr::io::path psFileName;</div><div class="line"> <span class="keywordflow">switch</span>( driverType )</div><div class="line"> {</div><div class="line"> <span class="keywordflow">case</span> video::EDT_DIRECT3D9:</div><div class="line"> vsFileName = mediaPath + <span class="stringliteral">&quot;cubeMapReflectionVS.hlsl&quot;</span>;</div><div class="line"> psFileName = mediaPath + <span class="stringliteral">&quot;cubeMapReflectionPS.hlsl&quot;</span>;</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"></div><div class="line"> <span class="keywordflow">case</span> video::EDT_OPENGL:</div><div class="line"> vsFileName = mediaPath + <span class="stringliteral">&quot;cubeMapReflection.vert&quot;</span>;</div><div class="line"> psFileName = mediaPath + <span class="stringliteral">&quot;cubeMapReflection.frag&quot;</span>;</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> }</div><div class="line"></div><div class="line"> CubeMapReflectionCallback* cubeMapCB = <span class="keyword">new</span> CubeMapReflectionCallback(smgr, 2);</div><div class="line"> cubeMapReflectionMaterial = gpu-&gt;addHighLevelShaderMaterialFromFiles(</div><div class="line"> vsFileName, <span class="stringliteral">&quot;VS&quot;</span>, video::EVST_VS_1_1,</div><div class="line"> psFileName, <span class="stringliteral">&quot;PS&quot;</span>, video::EPST_PS_3_0,</div><div class="line"> cubeMapCB, video::EMT_SOLID );</div><div class="line"> <span class="keywordflow">if</span> ( cubeMapReflectionMaterial &gt;= 0 )</div><div class="line"> eventReceiver.Shader = cubeMapCB;</div><div class="line"> cubeMapCB-&gt;drop();</div><div class="line">}</div><div class="line"></div><div class="line"><span class="comment">// add fps camera</span></div><div class="line">scene::ICameraSceneNode* camera = smgr-&gt;addCameraSceneNodeFPS(0, 100.f, 1.f);</div><div class="line">camera-&gt;setPosition( core::vector3df( 0,10,-200 ) );</div><div class="line">device-&gt;getCursorControl()-&gt;setVisible(<span class="keyword">false</span>);</div></div><!-- fragment --><p> Get 6 images forming a cubemap. The coordinate system used in those images seemed to be different than the one in Irrlicht. I decided to leave it like that because it's pretty common that way. If you get cubemap textures which seem to have x/y/z axis named different you'll just have to experiment until you figured out the correct order. </p><div class="fragment"><div class="line">core::array&lt;video::IImage*&gt; cubeMapImages;</div><div class="line">cubeMapImages.push_back(driver-&gt;createImageFromFile( mediaPath + <span class="stringliteral">&quot;cubemap_posx.jpg&quot;</span> ));</div><div class="line">cubeMapImages.push_back(driver-&gt;createImageFromFile( mediaPath + <span class="stringliteral">&quot;cubemap_negx.jpg&quot;</span> ));</div><div class="line">cubeMapImages.push_back(driver-&gt;createImageFromFile( mediaPath + <span class="stringliteral">&quot;cubemap_posy.jpg&quot;</span> ));</div><div class="line">cubeMapImages.push_back(driver-&gt;createImageFromFile( mediaPath + <span class="stringliteral">&quot;cubemap_negy.jpg&quot;</span> ));</div><div class="line">cubeMapImages.push_back(driver-&gt;createImageFromFile( mediaPath + <span class="stringliteral">&quot;cubemap_posz.jpg&quot;</span> ));</div><div class="line">cubeMapImages.push_back(driver-&gt;createImageFromFile( mediaPath + <span class="stringliteral">&quot;cubemap_negz.jpg&quot;</span> ));</div></div><!-- fragment --><p> Create a cubemap texture from those images. Note that 6 images become a single texture now.</p><div class="fragment"><div class="line">video::ITexture* cubeMapStaticTex = 0;</div><div class="line">cubeMapStaticTex = driver-&gt;addTextureCubemap(<span class="stringliteral">&quot;cm&quot;</span>, cubeMapImages[0], cubeMapImages[1], cubeMapImages[2], cubeMapImages[3], cubeMapImages[4], cubeMapImages[5]);</div><div class="line"><span class="keywordflow">for</span> ( u32 i=0; i&lt;cubeMapImages.size(); ++i )</div><div class="line"> <span class="keywordflow">if</span> ( cubeMapImages[i] )</div><div class="line"> cubeMapImages[i]-&gt;drop();</div><div class="line">cubeMapImages.clear();</div></div><!-- fragment --><p> Create a render target, cubemap render-target-textures and a camera with settings for cube mapping</p><div class="fragment"><div class="line">video::IRenderTarget* cubeMapRT = driver-&gt;addRenderTarget();</div><div class="line">video::ITexture* dynamicCubeMapRTT = 0;</div><div class="line">video::ITexture* depthStencilRTT = 0;</div><div class="line">video::ITexture* dynamicCubeMapRTT_intermediate = 0; <span class="comment">// just for rendering, but not used in material</span></div><div class="line">video::ITexture* dynamicCubeMapTex = 0; <span class="comment">// dynamic and with mipmaps</span></div><div class="line">scene::ICameraSceneNode* cubeMapCamera = 0;</div><div class="line"><span class="keywordflow">if</span>( driver-&gt;queryFeature( video::EVDF_RENDER_TO_TARGET ) )</div><div class="line">{</div><div class="line"> <span class="comment">// Create cube map textures and render target cubemap textures.</span></div><div class="line"> <span class="keyword">const</span> u32 dynamicCubeMapSize = 512;</div><div class="line"> dynamicCubeMapRTT = driver-&gt;addRenderTargetTextureCubemap(dynamicCubeMapSize, <span class="stringliteral">&quot;cube_rtr&quot;</span>);</div><div class="line"> depthStencilRTT = driver-&gt;addRenderTargetTexture(irr::core::dimension2du(dynamicCubeMapSize, dynamicCubeMapSize), <span class="stringliteral">&quot;cubemap_ds&quot;</span>, irr::video::ECF_D24S8);</div><div class="line"></div><div class="line"> dynamicCubeMapRTT_intermediate = driver-&gt;addRenderTargetTextureCubemap(dynamicCubeMapSize, <span class="stringliteral">&quot;cube_rtr&quot;</span>);</div><div class="line"> dynamicCubeMapTex = driver-&gt;addTextureCubemap(dynamicCubeMapSize, <span class="stringliteral">&quot;cube_tex&quot;</span>);</div><div class="line"></div><div class="line"> <span class="comment">// Camera for creating an environment cubemap</span></div><div class="line"> cubeMapCamera = smgr-&gt;addCameraSceneNode();</div><div class="line"> cubeMapCamera-&gt;setFOV(core::PI* 0.5f); <span class="comment">// 90<39> view angle</span></div><div class="line"> cubeMapCamera-&gt;setAspectRatio(1.f); <span class="comment">// it&#39;s a cube... all sides have the same length</span></div><div class="line"> smgr-&gt;setActiveCamera( camera );</div><div class="line">}</div></div><!-- fragment --><p> Add sphere-nodes which will be using the cubemaps as materials. You may also want to experiment with other node-types here! </p><div class="fragment"><div class="line">scene::ISceneNode* sphereNode = 0;</div><div class="line">scene::ISceneNode* sphereNode2 = 0;</div><div class="line">scene::ISceneNode* sphereNode3 = 0;</div><div class="line">scene::IMesh* sphereMesh = smgr-&gt;getGeometryCreator()-&gt;createSphereMesh(100.f);</div><div class="line"><span class="keywordflow">if</span>( sphereMesh )</div><div class="line">{</div><div class="line"> <span class="comment">// Nothing really special here except they need the shader material to display cubemaps.</span></div><div class="line"> sphereNode = smgr-&gt;addMeshSceneNode( sphereMesh );</div><div class="line"> sphereNode-&gt;setPosition( core::vector3df(-250,0,0) );</div><div class="line"> sphereNode-&gt;updateAbsolutePosition();</div><div class="line"> sphereNode-&gt;setMaterialFlag( video::EMF_LIGHTING, <span class="keyword">false</span> );</div><div class="line"> sphereNode-&gt;setMaterialTexture( 0, dynamicCubeMapRTT );</div><div class="line"> sphereNode-&gt;setMaterialType( (video::E_MATERIAL_TYPE)cubeMapReflectionMaterial );</div><div class="line"> eventReceiver.addInfoTextNode(font, L<span class="stringliteral">&quot;Cubemap dynamic rtt, no mip-maps&quot;</span>, sphereNode);</div><div class="line"></div><div class="line"> <span class="keywordflow">if</span> ( dynamicCubeMapTex )</div><div class="line"> {</div><div class="line"> sphereNode3 = smgr-&gt;addMeshSceneNode( sphereMesh );</div><div class="line"> sphereNode3-&gt;setPosition( core::vector3df(0,0,250) );</div><div class="line"> sphereNode3-&gt;updateAbsolutePosition();</div><div class="line"> sphereNode3-&gt;setMaterialFlag( video::EMF_LIGHTING, <span class="keyword">false</span> );</div><div class="line"> sphereNode3-&gt;setMaterialTexture( 0, dynamicCubeMapTex );</div><div class="line"> sphereNode3-&gt;getMaterial(0).TextureLayer[0].TrilinearFilter = <span class="keyword">false</span>; <span class="comment">// this is default anyway. It would be faster - but you can only access integer mip-levels - no filtering between mip-levels.</span></div><div class="line"> sphereNode3-&gt;setMaterialType( (video::E_MATERIAL_TYPE)cubeMapReflectionMaterial );</div><div class="line"> eventReceiver.addInfoTextNode(font, L<span class="stringliteral">&quot;Cubemap dynamic with mip-maps&quot;</span>, sphereNode3);</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keywordflow">if</span> ( cubeMapStaticTex )</div><div class="line"> {</div><div class="line"> sphereNode2 = smgr-&gt;addMeshSceneNode( sphereMesh );</div><div class="line"> sphereNode2-&gt;setPosition( core::vector3df(250,0,0) );</div><div class="line"> sphereNode2-&gt;updateAbsolutePosition();</div><div class="line"> sphereNode2-&gt;setMaterialFlag( video::EMF_LIGHTING, <span class="keyword">false</span> );</div><div class="line"> sphereNode2-&gt;setMaterialTexture( 0, cubeMapStaticTex );</div><div class="line"> sphereNode2-&gt;getMaterial(0).TextureLayer[0].TrilinearFilter = <span class="keyword">true</span>; <span class="comment">// this way smoothing happens between different mip-levels.</span></div><div class="line"> sphereNode2-&gt;setMaterialType( (video::E_MATERIAL_TYPE)cubeMapReflectionMaterial );</div><div class="line"> eventReceiver.addInfoTextNode(font, L<span class="stringliteral">&quot;Cubemap fixed images&quot;</span>, sphereNode2);</div><div class="line"> }</div><div class="line"></div><div class="line"> sphereMesh-&gt;drop();</div><div class="line">}</div></div><!-- fragment --><p> Add some background which will show up in the environment maps. For first one we use the same textures as used in the spheres. Note the difference between a skybox and a cubemap is that the skybox really uses 6 different textures. While the cubemap uses a single texture created from 6 images.</p><div class="fragment"><div class="line">eventReceiver.BackgroundSkybox = smgr-&gt;addSkyBoxSceneNode(</div><div class="line"> driver-&gt;getTexture(mediaPath + <span class="stringliteral">&quot;cubemap_posy.jpg&quot;</span>), <span class="comment">// top</span></div><div class="line"> driver-&gt;getTexture(mediaPath + <span class="stringliteral">&quot;cubemap_negy.jpg&quot;</span>), <span class="comment">// bottom</span></div><div class="line"> driver-&gt;getTexture(mediaPath + <span class="stringliteral">&quot;cubemap_posz.jpg&quot;</span>), <span class="comment">// left</span></div><div class="line"> driver-&gt;getTexture(mediaPath + <span class="stringliteral">&quot;cubemap_negz.jpg&quot;</span>), <span class="comment">// right</span></div><div class="line"> driver-&gt;getTexture(mediaPath + <span class="stringliteral">&quot;cubemap_posx.jpg&quot;</span>), <span class="comment">// front</span></div><div class="line"> driver-&gt;getTexture(mediaPath + <span class="stringliteral">&quot;cubemap_negx.jpg&quot;</span>)); <span class="comment">// back</span></div></div><!-- fragment --><p> Another background for comparison and to make it more obvious when the spheres reflect the environment and when they use static cubemaps.</p><div class="fragment"><div class="line"> scene::IMesh * cubeMesh = smgr-&gt;getGeometryCreator()-&gt;createCubeMesh( core::vector3df(10.f, 10.f, 10.f), scene::ECMT_6BUF_4VTX_NP);</div><div class="line"> smgr-&gt;getMeshManipulator()-&gt;scale(cubeMesh, core::vector3df(-1, 1, 1));</div><div class="line"> <span class="keywordflow">if</span>( cubeMesh )</div><div class="line"> {</div><div class="line"> smgr-&gt;getMeshManipulator()-&gt;setVertexColors( cubeMesh-&gt;getMeshBuffer(0), video::SColor(255, 240, 10, 10) );</div><div class="line"> smgr-&gt;getMeshManipulator()-&gt;setVertexColors( cubeMesh-&gt;getMeshBuffer(1), video::SColor(255, 240, 130, 10) );</div><div class="line"> smgr-&gt;getMeshManipulator()-&gt;setVertexColors( cubeMesh-&gt;getMeshBuffer(2), video::SColor(255, 50, 250, 10) );</div><div class="line"> smgr-&gt;getMeshManipulator()-&gt;setVertexColors( cubeMesh-&gt;getMeshBuffer(3), video::SColor(255, 70, 10, 250) );</div><div class="line"> smgr-&gt;getMeshManipulator()-&gt;setVertexColors( cubeMesh-&gt;getMeshBuffer(4), video::SColor(255, 240, 250, 10) );</div><div class="line"> smgr-&gt;getMeshManipulator()-&gt;setVertexColors( cubeMesh-&gt;getMeshBuffer(5), video::SColor(255, 85, 250, 250) );</div><div class="line"></div><div class="line"> eventReceiver.BackgroundCube = smgr-&gt;addMeshSceneNode( cubeMesh );</div><div class="line"> cubeMesh-&gt;drop();</div><div class="line"></div><div class="line"> eventReceiver.BackgroundCube-&gt;setScale( core::vector3df( 200, 200, 200 ) );</div><div class="line"> eventReceiver.BackgroundCube-&gt;setMaterialFlag( video::EMF_LIGHTING, <span class="keyword">false</span> );</div><div class="line"> eventReceiver.BackgroundCube-&gt;setVisible(<span class="keyword">false</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"><span class="preprocessor">#ifdef CUBEMAP_UPSIDE_DOWN_GL_PROJECTION</span></div><div class="line"> <span class="keywordflow">if</span> ( driverType == video::EDT_OPENGL )</div><div class="line"> {</div><div class="line"> <span class="comment">// Flip projection matrix (note this also flips front/backface culling)</span></div><div class="line"> core::matrix4 matProj = cubeMapCamera-&gt;getProjectionMatrix();</div><div class="line"> matProj[4] = -matProj[4];</div><div class="line"> matProj[5] = -matProj[5];</div><div class="line"> matProj[6] = -matProj[6];</div><div class="line"> matProj[7] = -matProj[7];</div><div class="line"> cubeMapCamera-&gt;setProjectionMatrix(matProj);</div><div class="line"> }</div><div class="line"><span class="preprocessor">#endif</span></div></div><!-- fragment --><p> Add some moving node to show the difference between static/dynamic environment maps </p><div class="fragment"><div class="line">scene::IMeshSceneNode * movingNode = smgr-&gt;addCubeSceneNode(30.f);</div><div class="line">movingNode-&gt;getMaterial(0).Lighting = <span class="keyword">false</span>;</div><div class="line">smgr-&gt;getMeshManipulator()-&gt;setVertexColors( movingNode-&gt;getMesh()-&gt;getMeshBuffer(0), video::SColor(255, 230, 200, 150));</div><div class="line">scene::ISceneNodeAnimator* circleAnimator = smgr-&gt;createFlyCircleAnimator(core::vector3df(-125, -50.f, 125), 300.f, 0.0005f);</div><div class="line">movingNode-&gt;addAnimator(circleAnimator);</div><div class="line">circleAnimator-&gt;drop();</div></div><!-- fragment --><p> Add some UI</p><div class="fragment"><div class="line"><span class="keywordflow">if</span> ( eventReceiver.Shader )</div><div class="line">{</div><div class="line"> skin-&gt;setColor(gui::EGDC_3D_FACE, video::SColor(50, 160, 120, 120));</div><div class="line"></div><div class="line"> u32 top = dimDevice.Height - 200;</div><div class="line"> <span class="keyword">const</span> u32 left = dimDevice.Width - 350;</div><div class="line"> <span class="keyword">const</span> u32 right = dimDevice.Width - 10;</div><div class="line"> irr::gui::IGUIStaticText * stextUVW = env-&gt;addStaticText(L<span class="stringliteral">&quot; Style of generating texture coordinates:\n Change with (space)&quot;</span>, core::recti(left, top, right, top+35), <span class="keyword">false</span>, <span class="keyword">true</span>, 0, -1, <span class="keyword">true</span>);</div><div class="line"> top += 40;</div><div class="line"> stextUVW-&gt;setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_UPPERLEFT);</div><div class="line"> eventReceiver.CurrentStyleUVW = env-&gt;addStaticText(L<span class="stringliteral">&quot;&quot;</span>, core::recti(240,0, 400, 20), <span class="keyword">false</span>, <span class="keyword">false</span>, stextUVW);</div><div class="line"> eventReceiver.updateStyleUVW();</div><div class="line"></div><div class="line"> irr::gui::IGUIStaticText * stextRoughness = env-&gt;addStaticText(L<span class="stringliteral">&quot; Roughness:\n Change with (+) and (-)&quot;</span>, core::recti(left, top, right, top+35), <span class="keyword">false</span>, <span class="keyword">true</span>, 0, -1, <span class="keyword">true</span>);</div><div class="line"> top += 40;</div><div class="line"> eventReceiver.CurrentRoughness = env-&gt;addStaticText( L<span class="stringliteral">&quot;&quot;</span>, core::recti(240,0, 400, 20), <span class="keyword">false</span>, <span class="keyword">false</span>, stextRoughness);</div><div class="line"> eventReceiver.updateRoughness();</div><div class="line"></div><div class="line"> irr::gui::IGUIStaticText * stextSeamlessCupemap = env-&gt;addStaticText(L<span class="stringliteral">&quot; Seamless cubemap (with roughness):\n Change with (s)&quot;</span>, core::recti(left, top, right, top+35), <span class="keyword">false</span>, <span class="keyword">true</span>, 0, -1, <span class="keyword">true</span>);</div><div class="line"> top += 40;</div><div class="line"> eventReceiver.CurrentSeamlessCubemap = env-&gt;addStaticText( L<span class="stringliteral">&quot;&quot;</span>, core::recti(240,0, 400, 20), <span class="keyword">false</span>, <span class="keyword">false</span>, stextSeamlessCupemap);</div><div class="line"> eventReceiver.updateSeamless();</div><div class="line"></div><div class="line"> irr::gui::IGUIStaticText * stextUpdates = env-&gt;addStaticText(L<span class="stringliteral">&quot; Cubemap updates:\n Change with (u)&quot;</span>, core::recti(left, top, right, top+35), <span class="keyword">false</span>, <span class="keyword">true</span>, 0, -1, <span class="keyword">true</span>);</div><div class="line"> top += 40;</div><div class="line"> eventReceiver.CurrentCubemapUpdates = env-&gt;addStaticText( L<span class="stringliteral">&quot;&quot;</span>, core::recti(240,0, 400, 20), <span class="keyword">false</span>, <span class="keyword">false</span>, stextUpdates);</div><div class="line"> eventReceiver.updateCubemapUpdates();</div><div class="line"></div><div class="line"> env-&gt;addStaticText(L<span class="stringliteral">&quot; Change background with (b)&quot;</span>, core::recti(left, top, right, top+15), <span class="keyword">false</span>, <span class="keyword">true</span>, 0, -1, <span class="keyword">true</span>);</div><div class="line"> top += 20;</div><div class="line"></div><div class="line"> env-&gt;addStaticText(L<span class="stringliteral">&quot; Show/hide info nodes with (i)&quot;</span>, core::recti(left, top, right, top+15), <span class="keyword">false</span>, <span class="keyword">true</span>, 0, -1, <span class="keyword">true</span>);</div><div class="line">}</div></div><!-- fragment --><p> Main loop</p><div class="fragment"><div class="line"><span class="keywordflow">while</span>(device-&gt;run())</div><div class="line">{</div><div class="line"> <span class="keywordflow">if</span> (device-&gt;isWindowActive())</div><div class="line"> {</div><div class="line"> driver-&gt;beginScene(<span class="keyword">true</span>, <span class="keyword">true</span>, video::SColor(255, 127, 127, 255));</div></div><!-- fragment --><p> Check if we want to update the environment maps. Usually not something you'll do every frame, but either once at the star or maybe updating an environment map once in a while. </p><div class="fragment"><div class="line"> <span class="keywordtype">int</span> updateCubemaps = eventReceiver.checkCubemapUpdate();</div><div class="line"> <span class="keywordflow">if</span>( dynamicCubeMapRTT &amp;&amp; sphereNode &amp;&amp; updateCubemaps &gt; 0 )</div><div class="line"> {</div><div class="line"><span class="preprocessor">#ifdef CUBEMAP_UPSIDE_DOWN_GL_PROJECTION</span></div><div class="line"> core::array&lt;scene::ISceneNode*&gt; allNodes;</div><div class="line"> <span class="keywordflow">if</span> ( driverType == video::EDT_OPENGL )</div><div class="line"> {</div></div><!-- fragment --><p> Flipping projection matrix flips front/backface culling. We only have a skybox so in this case this still would be fast, with more objects it's getting more ugly. </p><div class="fragment"><div class="line"> smgr-&gt;getSceneNodesFromType(scene::ESNT_ANY, allNodes);</div><div class="line"> flipCullingFlags(allNodes);</div><div class="line"> }</div><div class="line"><span class="preprocessor">#endif</span></div></div><!-- fragment --><p> If rendered just once then this node has still a white (or even undefined) texture at this point Just hiding it and render the background when rendering the cubemap for the other node is less noticable than having a big white dot in the environment texture. Render order can matter if you want several environment maps in your scene. </p><div class="fragment"><div class="line"><span class="keywordflow">if</span> (sphereNode3)</div><div class="line"> sphereNode3-&gt;setVisible(<span class="keyword">false</span>);</div><div class="line"></div><div class="line">renderEnvironmentCubeMap(driver, cubeMapCamera, sphereNode, cubeMapRT, dynamicCubeMapRTT, depthStencilRTT);</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> ( sphereNode3)</div><div class="line">{</div><div class="line"> <span class="keywordflow">if</span> ( updateCubemaps == 2 )</div><div class="line"> {</div></div><!-- fragment --><p> Our rtt's unfortunately don't have mipmaps (sorry, not sure if we can get that somehow...) So if we want mipmaps in the dynamic cubemap we have to copy it to a non-rtt texture. Warning: Very, very slow. Far slower than just creating an environment map as this will copy the texture from GPU to main memory - copy it to a new texture, create mip-maps and upload the result back to the GPU. </p><div class="fragment"><div class="line"> renderEnvironmentCubeMap(driver, cubeMapCamera, sphereNode3, cubeMapRT, dynamicCubeMapRTT_intermediate, depthStencilRTT);</div><div class="line"> <span class="keywordflow">for</span> ( <span class="keywordtype">int</span> i=0; i&lt;6; ++i)</div><div class="line"> {</div><div class="line"> <span class="keywordtype">void</span> * rtData = dynamicCubeMapRTT_intermediate-&gt;lock(video::ETLM_READ_ONLY, 0, i, video::ETLF_NONE);</div><div class="line"> <span class="keywordtype">void</span> * tData = dynamicCubeMapTex-&gt;lock(video::ETLM_READ_WRITE, 0, i);</div><div class="line"> memcpy(tData, rtData, dynamicCubeMapTex-&gt;getPitch()*dynamicCubeMapTex-&gt;getSize().Width);</div><div class="line"> dynamicCubeMapRTT_intermediate-&gt;unlock();</div><div class="line"> dynamicCubeMapTex-&gt;unlock();</div><div class="line"> dynamicCubeMapTex-&gt;regenerateMipMapLevels();</div><div class="line"> }</div><div class="line"> }</div><div class="line"> sphereNode3-&gt;setVisible(<span class="keyword">true</span>);</div><div class="line"> }</div><div class="line"></div><div class="line"><span class="preprocessor">#ifdef CUBEMAP_UPSIDE_DOWN_GL_PROJECTION</span></div><div class="line"> <span class="keywordflow">if</span> ( driverType == video::EDT_OPENGL )</div><div class="line"> {</div><div class="line"> flipCullingFlags(allNodes);</div><div class="line"> }</div><div class="line"><span class="preprocessor">#endif</span></div><div class="line"> }</div><div class="line"></div><div class="line"> smgr-&gt;drawAll();</div><div class="line"> env-&gt;drawAll();</div><div class="line"></div><div class="line"> driver-&gt;endScene();</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> device-&gt;drop();</div><div class="line"></div><div class="line"> <span class="keywordflow">return</span> 0;</div><div class="line">}</div></div><!-- fragment --> </div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.13-->
<!-- start footer part -->
<p>&nbsp;</p>
</body>
</html>