Files
F3DEX3/camera.html
2024-06-19 22:05:45 +00:00

135 lines
7.4 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.11.0"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>F3DEX3: Camera</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<script type="text/javascript" src="clipboard.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="cookie.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript" src="darkmode_toggle.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="doxygen-awesome.css" rel="stylesheet" type="text/css"/>
<link href="doxygen-awesome-sidebar-only.css" rel="stylesheet" type="text/css"/>
<link href="doxygen-extra.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<td id="projectalign">
<div id="projectname">F3DEX3
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.11.0 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
var searchBox = new SearchBox("searchBox", "search/",'.html');
/* @license-end */
</script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(function() { codefold.init(0); });
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(function() {
initMenu('',true,false,'search.php','Search',true);
$(function() { init_search(); });
});
/* @license-end */
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(function(){initNavTree('camera.html',''); initResizable(true); });
/* @license-end */
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<div id="MSearchResults">
<div class="SRPage">
<div id="SRIndex">
<div id="SRResults"></div>
<div class="SRStatus" id="Loading">Loading...</div>
<div class="SRStatus" id="Searching">Searching...</div>
<div class="SRStatus" id="NoMatches">No Matches</div>
</div>
</div>
</div>
</div>
<div><div class="header">
<div class="headertitle"><div class="title">Camera</div></div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>For any game, the idea is to send the camera world position to the RSP whenever you send / apply the view matrix. For OoT, this is not trivial because the game allocates the view matrix at the beginning of the frame and runs gSPMatrix, but at the end of the frame it updates the camera and then rewrites the allocated view matrix, changing it retroactively for the frame. So, we have to similarly save a pointer to the camera position, set at the beginning of the frame, and update it at the end of the frame.</p>
<p>In z64view.h, in the definition of the View struct, after Mtx* viewingPtr </p><div class="fragment"><div class="line">PlainVtx* cameraWorldPosPtr;</div>
</div><!-- fragment --><p>In z_view.c somewhere towards the top </p><div class="fragment"><div class="line">void View_SetCameraWorld(PlainVtx* cameraWorldPos, View* view){</div>
<div class="line"> cameraWorldPos-&gt;c.pos[0] = (s16)view-&gt;eye.x;</div>
<div class="line"> cameraWorldPos-&gt;c.pos[1] = (s16)view-&gt;eye.y;</div>
<div class="line"> cameraWorldPos-&gt;c.pos[2] = (s16)view-&gt;eye.z;</div>
<div class="line">}</div>
<div class="line">PlainVtx* View_CreateCameraWorld(View* view){</div>
<div class="line"> PlainVtx* cameraWorldPos = Graph_Alloc(view-&gt;gfxCtx, sizeof(PlainVtx));</div>
<div class="line"> View_SetCameraWorld(cameraWorldPos, view);</div>
<div class="line"> return cameraWorldPos;</div>
<div class="line">}</div>
</div><!-- fragment --><p>After each place in the functions in z_view.c where view-&gt;viewingPtr gets set </p><div class="fragment"><div class="line">PlainVtx* cameraWorldPos = View_CreateCameraWorld(view);</div>
<div class="line">view-&gt;cameraWorldPosPtr = cameraWorldPos;</div>
</div><!-- fragment --><p>In those same functions, right after the calls to <code>gSPMatrix(GFX, viewing, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_PROJECTION)</code> where <code>GFX</code> is <code>POLY_OPA_DISP++</code>, <code>POLY_XLU_DISP++</code>, <code>OVERLAY_DISP++</code>, or <code>gfx++</code> </p><div class="fragment"><div class="line">gSPCameraWorld(GFX, cameraWorldPos);</div>
</div><!-- fragment --><p>The important part: in View_UpdateViewingMatrix </p><div class="fragment"><div class="line">View_SetCameraWorld(view-&gt;cameraWorldPosPtr, view);</div>
</div><!-- fragment --><p>The same issue happens (in the vanilla game) for lookat vectors&ndash;they are computed during the frame based on the camera position and direction, but these are updated at the end of the frame so the lookat vectors are one frame behind. You can see this when going into C-up next to an object with hilite or env map&ndash; it's wrong for one frame and then is fixed. You could solve this by either tracking all lookat vectors created during the frame and updating them at the end as we did here. Another option is to only send lookat once at the start of each frame (and update it at the end of the frame), rather than once per object using it. This is not exactly the same for objects not in the middle of the screen, but the difference is minor. </p>
</div></div><!-- contents -->
</div><!-- PageDoc -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="navelem"><a class="el" href="md_docs_2code.html">Code</a></li>
<li class="footer">Generated by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.11.0 </li>
</ul>
</div>
</body>
</html>