#SlimDX
Explore tagged Tumblr posts
anachrosims · 3 days ago
Text
Can someone please send me a working version of TSRW? (Or recommend a fix?)
I tried using this version from @greenplumbboblover but I keep getting the following error any time I try to clone anything for TS3:
Tumblr media
Which is weird, because I have all the needed .Net frameworks (3.5 having 2.0 and 3.0 on it, and also 4.0 is just part of Windows 11).
It's a shame, because this version is the only one that lets me see fireplaces for TS3!!
Other versions of TSRW work for me (mostly) but I can't see fireplaces, or I can't even clone clothing.
I've tried uninstalling and reinstalling both TSRW and SlimDX and now I'm just really annoyed.
(We are so damn lucky to have TS4Studio. I do not miss the days of the internet where everything was as janky as TSRW still is.)
EDIT: 3.5 is set to 'on' but NOT the bits in the dropdown menu of optionalfeatures soooo, I did the thing, reinstalled TSRW... still getting that error.
4 notes · View notes
sapphim · 6 years ago
Note
I know you're not supper into modding anymore but I wanted to ask if you knew where one could get their hands on Slimdx now? It looks like it's still necessary for DAI Mod Maker, but the site itself has gone offline.
Huh, it sure has. I guess that was inevitable since the project has been defunct for 7 years now. I pulled up the SlimDX site in the wayback machine and found a link on the front page to their google code project for you, which is still up! :)
2 notes · View notes
mediumohio599 · 3 years ago
Text
Download Hacked Gamepad For Pc
Tumblr media
Download and Update Xbox 360 Controller Driver for Windows 10 PC.
PSP Gamepad For PC v1.0.
Free Fortnite Hacks Download Softaim Aimbot 2022.
Download gta 5 7z file.
Brawl Stars Hack Apk Download Pc.
Download Hacked on PC | GameLoop Official.
🏆 Hack Among Us PC DOWNLOAD | ESP + Unlocks all cosmetics and.
IWantC - Hacks Cheats and Aimbots for PC Games.
Download XBOX 360 controller emulator for PC games.
PC Cheats, Hacks, and Aimbot IWantCheats 2022.
Hacked Gamepad BY SAMRANI | U.
Apex Legends Hack Wallhack & Aimbot Free Download Pc Undetected Cheat.
Xbox 360 Controller Emulator (x360ce) for PC gaming. - S-Config.
Download and Update Xbox 360 Controller Driver for Windows 10 PC.
Download Keysticks. Keysticks is free, open source software released under the Eclipse Public License v1.0. To download the latest version of Keysticks, click the Download button on the right. When the installer program has finished downloading, run it and follow the instructions in the install wizard. Keysticks uses the SlimDX Runtime, so the. Connect your gamepad controller to your PC to begin the settings. Open the emulator you downloaded. Clicking the create icon when it appears along the dialogue box create a Xinput Click "Search automatically for settings". Click the "Auto" icon to fill up the controller in order to prepare it for settings. Carry out the settings. Welcome to PrivateCheatz all of our Hacks & Cheats are unique private builds only for PrivateCheatz Customers. Stay safe & undetected with our Aimbot, ESP, Wallhack, Radar, No recoil, & HWID Spoofer with lowest detection rates. We offer 24/7 365 live chat support for all users if have a question or a technical issue. Read our 119 reviews.
PSP Gamepad For PC v1.0.
Instinct Pro. Check Price. 6. Razer. Wolverine Ultimate. Check Price. Grab the best PC controller and game from the comfort of your couch. (Image credit: Future) The best PC controller is.
Free Fortnite Hacks Download Softaim Aimbot 2022.
Aug 26, 2021 · How to download Octopus - Gamepad, Mouse, Keyboard Keymapper on PC. ① Download and install MuMu Player on your PC. ② Start MuMu Player and complete Google sign-in to access the Play Store. ③ Search Octopus - Gamepad, Mouse, Keyboard Keymapper in App center. Monect PC Remote is a free app that allows you to control PC over Wi-Fi or Bluetooth locally or remotely. Key Features: - Play all kinds of PC games with on board sensors and specifically designed button layouts and you can edit them as you wish - Transfer screen and camera of PC to phone in real time and vice verse - Add up to 4 virtual.
Download gta 5 7z file.
Every console has a different style of controller. So the exact way that you connect to the controller will depend on the system that you are working with. But in general, most buttons are wired up the same way. The button is a normally open momentary switch. One side of the switch is wired to ground. Mar 17, 2019 · 22 Remap. Via Some games - not all - give you the option to customize the button configuration for your controller. Many players do this for FPS and sports games to maintain consistency (a great example is the different shooting buttons for FIFA and Pro Evo games).
Brawl Stars Hack Apk Download Pc.
Here is the link to the PDF file that includes all GTA 3 cheats for PC: Download it here. Although the franchise had always included a variety of cheats in its games, the ones in GTA 3 were much. Free, Working OurWorld Hacks - F June 8, 2015 After months and months of hard work, we've managed to update our fully functional, free OurWorld Hack v3.5.1 OurWorld Flow Hack, OurWorld Coins Hack, OurWorld Gems Hack, OurWorld Resident Hack, and a working and tested OurWorld Zoe's Club Hack without having to download a. Evil Controllers, the leader in modded and custom gaming controllers, creates personalized pro, eSports ready and modded controllers for Playstation 5, Xbox Series X, Xbox One, and Playstation 4.
Download Hacked on PC | GameLoop Official.
Our Popular Game Cheats. We work constantly to upgrade our Undetected Hacks for Video Games so they are undetectable through all the Video Games and the upgrades launched by developers: WARZONE HACKS. COLD WAR HACKS. APEX HACKS. VALORANT HACKS. RUST HACKS. SIX SIEGE HACKS. PUBG HACKS. Feb 03, 2018 · The x360ce (Xbox 360 Controller Emulator) may not need any introduction to many in the gaming community. But we feel it should deserve a noteworthy review and basics as to the hows and why that this software exists. The reason why this software is handy and at times almost essential to play certain games is due to the way they are programmed.
🏆 Hack Among Us PC DOWNLOAD | ESP + Unlocks all cosmetics and.
Jun 12, 2022 · Currently the DRC (GamePad), Pro Controller and Classic Controller is emulated. Wiimotes are emulated as well (including native support). Keyboard input + USB controllers as input devices are supported. GamePad touch input can be controlled via left mouse click. Gyro functionality is emulated with limitations and can be controlled via right. The Evil SHIFT’s Weapon Hotkey Feature is a competitive enhancement for Fortnite. This allows you to make 2 of your 4 Paddles, perform as hotkeys for selecting weapons 1 and 5. Simply press an assigned hotkey paddle and the controller will always select the proper weapon for you. The Evil SHIFT works just like a keyboard, providing extra.
IWantC - Hacks Cheats and Aimbots for PC Games.
..
Download XBOX 360 controller emulator for PC games.
Introduction VitaPad allows you to use your PSVITA as a wireless PC controller. It supports Windows (both 32 and 64 bit) and Linux (port made by nyorem). In the future i'm planning to add also Mac Os X support and also add a proper fiddler for vJoy. Footage (thanks to kood k) Usage Install. Oct 10, 2018 click on "Settings (Game setting)" - "System", scroll down until you see search and tick the "Enable cheats". Ppsspp need for speed underground 2 android apk download. Go back, after this, you will be able to see "Cheats" option on the menu of ppsspp, if not then try to restart the game. On the menu choose 'Cheats.
PC Cheats, Hacks, and Aimbot IWantCheats 2022.
How to Download Xbox 360 Controller Emulator (X360ce) To download you just have to follow these steps that will be listed below. First of all, open your web browser; Search for x360ce; There you will see various download options " download for all games", "download for the 32-bit game" " download for the 64-bit game" The next thing..
Hacked Gamepad BY SAMRANI | U.
Download Gamepad Software. Advertisement. Gamepad Map v.1.3.1 Map gamepad input to keyboard and mouse actions. Compatible with any XInput controller including Xbox One and XBox 360 controllers. Works with virtually all games for Windows or on the web. GamePad 4 Flash v.1.0 GamePad 4 Flash enables you to play flash games with a gamepad or joystick.
Apex Legends Hack Wallhack & Aimbot Free Download Pc Undetected Cheat.
Click the " DOWNLOAD • for 32-bit games " link and start the download process. Once its downloaded, extract its content to wherever you would like. Plug your controller/gamepad, then start the program on administrator mode. The first thing you'll see after launching the program is would be the warning pop-up. In this part, I will recommend 3 popular N64 emulators for PC to you. 1. Project 64. Project 64 is the king of Nintendo 64 emulation. When it comes to best N64 emulator for PC, the first software people will think of is Project 64. Project 64 started out as a closed-source project with a plugin system. But back in April 2013, Zilmar disclosed.
Xbox 360 Controller Emulator (x360ce) for PC gaming. - S-Config.
Download. Drone-Hacks for free. Drone-Hacks Desktop supports Linux or Windows 10, simply select your OS to begin the download. Windows: DO NOT USE WINDOWS 7 or 8!!!! This OS versions are outdated and DOES NOT work properly. Many things will not work and unpredictable issues WILL appear. Jul 13, 2020 · Chasing. elite*gold: 0. The Black Market: 175 /0/ 0. Join Date: Mar 2013. Posts: 5,951. Received Thanks: 1,183. Depends on the hack (cheat), but most of them should work with a controller. You could ask the provider about it, there are a lot of them here on epvp. Read Or Download Gallery of fivem mod menu for pc download free trainer 2021 - Fivem Free Mod Menu | how to download install fivem mod fivem cartel dubai burj khalifas, fivem mod menu for pc download free trainer 2021, download kiddions menu v0 8 kiddion s modest menu grand theft auto, fivem mod menu 10 06 update youtube,.
Other content:
Download Helvetica Font For Photoshop
Football Manager 2015 Cd Key Generator
Sniper Pc Game Free Download Full Version
Dragon Ball Af Episode 2
Driver Solution Pack 14 Free Download
Tumblr media
1 note · View note
loadcard201 · 4 years ago
Text
Trip Mode For Mac
Tumblr media
Home » Mac » Utilities » TripMode
JackTrip Documentation. About JackTrip JackTrip: A System for High-Quality Audio Network Performance over the Internet. JackTrip is a Linux and Mac OS X-based system used for multi-machine network performance over the Internet. It supports any number of channels (as many as the computer/network can handle) of bidirectional, high quality, uncompressed audio signal steaming.
TripMode 2 allows mobile users to save data, save money, and surf faster. The award-winning data saving app for Mac has been released in a new version, TripMode 2, two years after its initial release in May 2015. It provides peace of mind for users on the go, in the form of a simple setup-and-forget utility. Available today for $7.99, Buy it now.
Start Download Now
TripMode.pkg | 5.42 MB
Tumblr media
PriceFree to tryVersion1.0.5Release DateFebruary 25, 2016CategoryUtilitiesOperating SystemsOS XPublisher
TripMode
https://www.tripmode.ch
Publisher's Description
TripMode is the best way to stop updates and other background processes from consuming your mobile data.
Block unwanted traffic
Only apps that you’ve selected are allowed to access the Internet when TripMode is ON. The rest is blocked.
Save data automatically
Fusion provides a simple yet customizable way to install multiple operating systems on your Mac. New in Fusion is updated support for the Open Virtualization Format which includes an effortless installation walkthrough of the VMware vCenter Server Appliance OVA. Download VMware Fusion 12 and let your Mac run Windows, Linux or Mac OS X Server. Run the most demanding Mac and Windows applications side-by-side at maximum speeds without rebooting. Mac-fusion is a small but extremely capable full-service Apple Store. We’ve been helping small to mid-size businesses stay up and running on their Mac for 17 years. If your company needs help with their Apple productss, we are here to meet your needs. Download Fusion. Download MyStyle. Download Spark Updater. Download Update Agent. Download Ignition Updater for Mac. Download CS/CTS Drivers. Download Evolution Drivers. Download Superchips Spark Drivers. Download SlimDX for data log playback. Fusion for mac free. VMware Fusion delivers the best way to run Windows on the Mac, and the ultimate development and testing tool for building apps to run on any platform. Ready for macOS 11.0 Big Sur, Fusion 12 supports macOS 10.15 Catalina and includes new features for developers, IT admins and everyday users.
TripMode activates itself on networks where you used it before. No need to fiddle in menus. It’s super easy.
Track your data usage
See how much data was used per app and per session, day, or month. Spot the data hungry apps.
Tripmode is turned on mechanically when your mac is attached to a mobile hotspot. When it’s far on, it prevents all your mac apps from getting access to the net however those which have been whitelisted with the aid of your self.
Related Apps
I recently had to go on a trip where my wifi was super limited. Core keygen for mac. We were allocated 2gb of data a week over wifi. Now I don’t know if you’ve ever really paid attention to your data usage on your laptop/desktop, but you’ll eat through that FAST. It feels like everything on your laptop is calling home, trying to update, etc. I was trying to find a way to really limit my data usage. I did some googlefu and stubbled across an app for macOS called TripMode.
TripMode allows you to limit network access to only the apps/processes that you want. I limited mine to pretty much only the services I needed. If I needed something I turned it on and then immediately turned it off. It worked wonderfully. It will even alert you when an unauthorized app has tried to connect to something. TripMode recognized that the network I was on the one that needed to be metered, and auto turned itself on.
Tripmode For Mac
While you have the app turned on you can tell how much data I have used for the session, day, week, or month. When the app is metering data, you can have it alert you after you’ve used a certain amount. I had an alert set up when I passed 1gb, so I knew to be extra careful.
Download Tripmode For Mac
TripMode was well worth the money if you are ever in a situation where you need to really limit your data usage. It would be great when using a wifi hotspot, travel where data is limited, or if you just are really a stickler about your data usage. It was well worth my $7.99.
Tumblr media
0 notes
sims3tutorialhub · 4 years ago
Note
When downloading the portable version of TSRW, it throws up an error message about missing a "SlimDX dll". Any idea what's going on there?
It requires the SlimDX directX to run. Just download and install it or download a normal version of tsrw and it will install it with it.
1 note · View note
munrad · 6 years ago
Text
nVIDIA GeForce Game Ready Driver / 381.65 Keygen Serial
nVIDIA GeForce Game Ready Driver / 381.65 Keygen Serial
Tumblr media
nVIDIA GeForce Game Ready Driver / 381.65 Keygen Download
NVIDIA PhysX PhysX Wrapper Library Wrapper PhysX Wrapper Wrap Library. – SlimDX (September 2008). To compile nVIDIA GeForce Game Ready Driver / Patch you need the following:.
nVIDIA GeForce Game Ready Driver / Serial.Net was designed to be a wrapper for NVIDIA’s PhysX (2.8.1) library. Game Ready Drivers provide the best possible gaming…
View On WordPress
0 notes
akhanubis · 13 years ago
Photo
Tumblr media Tumblr media
Estoy haciendo un .obj/.mtl loader para el framework. Todavía me falta habilitar alpha blending, pero ya casi está. Cuando esté listo lo subo con los comentarios pertinentes que fui anotando :P.
A Team Fortress 2 map (converted to .obj/.mtl with Blender) used for testing my scene loader for SlimDX and DirectX 11. At this moment is lacking of alpha blending, but I hope to add this in the next few days. As soon as it's done, I'll be posting the source code.
12 notes · View notes
akhanubis-eng · 13 years ago
Text
SlimDX - DirectX 11 - Frustum corners, sphere and shader
Source code (take a look at CicloBase.HandleInput() for the controls)
Just like the previous post, I'll show you three different approaches for obtaining, in this case, the vertices of the frustum. Then, I'll breafly talk about it's boundingsphere and vertex shader.
Corners
Taking into account that the volume has reflection symmetry around both XZ and YZ planes in View Space, we only need to find one corner of the far plane and one of the near plane, and then find the other six using the symmetry planes.
In case you don't remember, in View Space the X, Y and Z axis are the camera's right, up, and backward (I'm working with right handed matrices) directions, and the camera is at the origin.
The yellow dots in the following image show the corners we are going to find with each method.
Extracting the corners using trigonometry
The position P of the far right top corner can be decomposed in the three vectors/components drawed in red in the image.
The Z coordinate can be obtained straigthforward because it is equal to the distance from the camera to the far plane (far distance). Sice we are using a right handed coordinate system, it's signed value will be -farDistance.
From the right triangle whose legs are farDistance and the Y vector, we can calculate the length of the last one. The angle between the top plane and the bottom plane is called vertical field of view, and thus the angle between the top plane and the -Z axis will be FOV_Y / 2.
\[\large{tan(\frac{fov_{y}}{2})=\frac{y}{Z_{far}}\Rightarrow y=Z_{far} tan(\frac{fov_{y}}{2})}\]
Similarly, the X coordinate can be obtained as:
\[\large{tan(\frac{fov_{x}}{2})=\frac{x}{Z_{far}}\Rightarrow x=Z_{far} tan(\frac{fov_{x}}{2})}\]
Or even better, considering that \(aspectRatio = \frac {width} {height}\):
\[\large x=aspectRatio \times y \Rightarrow x= aspectRatio \times Z_{far} tan(\frac{fov_{y}}2)\]
For the near corner, the algorythm remains unchanged except that we change \(Z_{far}\) with \(Z_{near}\).
It's being pretty easy so far, but how we extract the values of FOV_X, FOV_Y, farDistance and nearDistance from the projection matrix? Normally, we will using only one frustum in our app corresponding to the active camera, so we could save the values of the constants used when setting up our projection matrix. Anyway, knowing how to get them from the matrix can't hurt us.
As msdn states, Matrix.PerspectiveFovRH() returns the following matrix:
\[\begin{bmatrix}\frac 1{aspectRatio \times tan\left (\frac{fov_y}2 \right )}& 0 & 0 & 0 \\\ 0 & \frac 1 {tan\left (\frac{fov_y}2  \right )} & 0 & 0 \\\ 0 & 0 & \frac {Z_{far}}{Z_{near}-Z_{far}} & -1 \\\ 0 & 0 &  \frac{Z_{near} Z_{far}}{Z_{near}-Z_{far}}  & 0 \end{bmatrix}\]
We can then get the values with:
float tanY = 1f / inProjection.M22; float tanX = 1f / inProjection.M11; float fNear = inProjection.M43 / inProjection.M33; float fFar = fNear * inProjection.M33 / (1f + inProjection.M33);
tanX equals \(aspectRatio \times tan\left (\frac{fov_y}2 \right )\) because:
\[\left (width = 2Z_{far}tan\left (\frac {fov_x} 2  \right )    \right ) \wedge \left (height= 2Z_{far}tan\left (\frac {fov_y} 2  \right )  \right ) \\\ \left (2Z_{far} = \frac{width}{tan\left (\frac {fov_x} 2  \right )}   \right ) \wedge \left (2Z_{far} = \frac{height}{tan\left (\frac {fov_y} 2  \right )}  \right ) \\\ \frac{width}{tan\left (\frac {fov_x} 2  \right )} = \frac{height}{tan\left (\frac {fov_y} 2  \right )} \]
\(\large{aspectRatio = \frac{width}{height} = \frac{tan\left (\frac {fov_x} 2  \right )}{tan\left (\frac {fov_y} 2  \right )} \\\ tan\left (\frac {fov_x} 2  \right ) = aspectRatio \times tan\left (\frac {fov_y} 2  \right )}\)
Finally, adding the 3 coordinates for each corner:
Vector3 extremoFar = new Vector3(tanX, tanY, -1) * fFar; Vector3 extremoNear = new Vector3(tanX, tanY, -1) * fNear;
Extracting the corners using plane intersections
A point can be defined as the intersection of 3 planes. Although resolving the intersection of 3 planes may seem cumbersome (it involves a 3x3 linear system), the frustum planes are particularly simple (normals with null components and planes that contain the origin (\(D=0\))).
For example, in order to get the far top right corner, we will be using the far, top and right planes:
\(\large{N_{far,z} z + D = 0 \\\ N_{top,y} y + N_{top,z} z = 0 \\\ N_{right,x} x + N_{right,z} z =0}\)
Z can be extracted directly from the first equation and the other coordinates from the second and third ones using the Z value obtained:
extremoFar.Z = -far.D / far.Normal.Z; extremoFar.X = -right.Normal.Z * extremoFar.Z / right.Normal.X; extremoFar.Y = -top.Normal.Z * extremoFar.Z / top.Normal.Y; extremoNear.Z = -near.D / near.Normal.Z; extremoNear.X = -right.Normal.Z * extremoNear.Z / right.Normal.X; extremoNear.Y = -top.Normal.Z * extremoNear.Z / top.Normal.Y;
Extracting the corners by transforming them from Clip Space
The idea behind this method is the same as the one described in my previous post. To generate the vector in Clip Space and then transform it back to View Space using the inverse of the projection matrix. Remembering that the viewing volume in Clip Space is an AABB, the corners can be found with:
Matrix inverseProjection = Matrix.Invert(inProjection); Vector3 extremoFar = Vector3.TransformCoordinate(new Vector3(1f, 1f, 1f), inverseProjection); Vector3 extremoNear = Vector3.TransformCoordinate(new Vector3(1f, 1f, 0f), inverseProjection);
Vertex Buffer and Vertex Shader
Using extremoFar, extremoNear and the reflection symmetry, we can then write the 8 vertices/corners to the vertex buffer:
d.Write(extremoFar); //Far Right Top d.Write(new Vector3(extremoFar.X, -extremoFar.Y, extremoFar.Z)); //Far Right Bottom d.Write(new Vector3(-extremoFar.X, -extremoFar.Y, extremoFar.Z)); //Far Left Bottom d.Write(new Vector3(-extremoFar.X, extremoFar.Y, extremoFar.Z)); //Far Left Top d.Write(extremoNear); //Near Right Top d.Write(new Vector3(extremoNear.X, -extremoNear.Y, extremoNear.Z)); //Near Right Bottom d.Write(new Vector3(-extremoNear.X, -extremoNear.Y, extremoNear.Z)); //Near Left Bottom d.Write(new Vector3(-extremoNear.X, extremoNear.Y, extremoNear.Z)); //Near Left Top d.Write(Vector3.Zero); //Eye
The vertex shader we will be using is the "hello world" shader which multiplies the input by the World, View and Projection matrices. Considering that the input vertices which correspond to the corners of the frustum are in View Space, the world matrix will be the inverse of the view matrix A related to the frustum we are rendering. By the other side, the view and projection matrices will be the ones related to the active camera B:
inEffect.SetearParametro("MatricesBuffer", "matViewProjection", inViewProjection_cámaraB); inEffect.SetearParametro("MatricesBuffer", "matWorld", inverseView_cámaraA);
Bounding Sphere
Despite of the fact that the bounding sphere could be generated using BoundingSphere.FromPoints(), it's center and radius can be found as:
centroVS = new Vector3(0, 0, (extremoFar.Z + extremoNear.Z) * 0.5f); boundingSphereWS.Radius = (centroVS - extremoFar).Length();
At last!
That's all about frustum culling. The next topic will be normal mapping with multiple point lights and generation of tangents and bitangents (and maybe a post in the middle about a project I'm doing for the unniversity involving QR code detection in an image).
A video showing the initial camera frustum and another frustum just laying there:
3 notes · View notes
mydirectx12demo-blog · 9 years ago
Text
Further Learning
Well, as I come closer to the end of this month, I’ll take a little pause here, and dive more deeper into real time rendering specifically DirectX by exploring few advanced areas like collision detection, clipping, multi-threading, post-processing effect, and tessellation by looking into DirectX12 Development book by Frank Luna. So, hence the learning doesn't end here. After few more days of research and getting a good hand on DirectX12 libraries, I’ll post my learning’s too. And yes, in this journey of learning, I came across many resourceful books, one of them is Real-Time rendering, that gives good general background of components involved in 3D graphics, and then Frank Luna has amazing in-depth view of DirectX. The experience of dealing with SlimDX was handy, as of how comfortable it was to use high-end class libraries provided in c#, but it has its own advantages and disadvantages, when it comes to dealing with DirectX.
0 notes
akhanubis · 13 years ago
Text
SlimDX y DirectX 11 - Cache de shaders compilados
Dado que la solución estaba tardando casi 5 minutos en compilar por culpa de unos compute shaders que estoy usando para comparar performance, armé una pequeña clase que se encarga de cachear los shaders. Si el código fuente de un shader no fue modificado respecto del utilizado para compilarlo en la ejecución anterior, no se compila y se utiliza el bytecode almacenado.
El código fuente de la solución entera no lo subo porque tengo que ordenar varias partes, pero dejo todo el código de la clase ShaderCache al final del post.
Pseudo-pseudocódigo:
public static Effect ObtenerEffect(string fileName) { if (BuscarShaderEnCacheYActualizar(fileName)) { bytecode = Leer bytecode desde filename + ".cache" } else { bytecode = CompilarBytecode(fileName) Almacenar bytecode en disco en filename + ".cache" } return CrearEfecto(bytecode) } private static bool BuscarShaderEnCacheYActualizar(string fullFilePath) { md5 = CalcularMD5(fileName, fileBaseDir); Buscar fullFilePath en cacheEntries.txt if (No se encontró) { Agregar la entrada "fullFilePath \t md5" return false; //Nuevo shader, habrá que compilar el bytecode } else { Comparar md5 contra MD5 almacenado if (Son iguales) { return true; //Utilizar bytecode cacheado } else { Actualizar el MD5 almacenado con md5 return false; //Shader modificado, habrá que compilar el bytecode } } } private static string CalcularMD5(string fileName, string fileBaseDir) { md5 = GenerarMD5(fileBaseDir + fileName) //Recursivamente concatenar los MD5 de los #include para detectar cambios en estos foreach (#include que haya en el shader) md5 += CalcularMD5(includeFileName, fileBaseDir) return md5; }
CacheEntries
Para detectar si un shader fue modificado, se mantiene en disco una tabla cuyos registros son de la forma (ruta al archivo del shader \t MD5 de su código fuente). Esta tabla no es más que un archivo de texto tabulado, ubicado en Framework\Resources\ShadersCache\cacheEntries.txt.
MD5
El cálculo del MD5 se realiza utilizando el método MD5CryptoServiceProvider.ComputeHash(Stream) y se aplica recursivamente concatenando el hash de un archivo con el hash de sus #include.
private static string ComputeShaderFileMD5(string fileName, string fileBaseDir) { string md5; using (FileStream fs = new FileStream(fileBaseDir + fileName, FileMode.Open)) { md5 = BitConverter.ToString(new MD5CryptoServiceProvider().ComputeHash(fs)); fs.Position = 0; using (TextReader tr = new StreamReader(fs)) { string line = tr.ReadLine(); while (line != null) { if (line.StartsWith("#include \"")) { string includeName = line.Substring("#include \"".Length, line.Length - "#include \"".Length - "\"".Length); //Recursively compute the MD5 of the include file md5 += ComputeShaderFileMD5(includeName, fileBaseDir); } line = tr.ReadLine(); } } } return md5; }
Ejemplo de cacheEntries.txt:
D:\SlimDX\Framework\Framework\Resources\fxVarios.fx 45-43-29-04-00-39-4E-85-CA-3C-4B-97-7F-68-D5-77 D:\SlimDX\Framework\Framework\Resources\CSvsPSGaussianBlur\PSGaussianFilter.fx A9-81-CA-05-14-DD-1F-AE-06-C7-1E-AE-99-6F-1D-2147-4D-90-CD-5B-F6-35-A0-8E-51-50-35-78-71-E3-BD D:\SlimDX\Framework\Framework\Resources\CSvsPSGaussianBlur\CSGaussianFilterF3.fx 33-63-EF-D9-46-34-C3-0C-25-59-C1-FC-5C-3C-E0-CD46-E7-1E-D8-16-76-CA-5F-3E-BE-E8-9F-A7-4F-59-AA47-4D-90-CD-5B-F6-35-A0-8E-51-50-35-78-71-E3-BD
En el ejemplo se observa que el shader PSGaussianFilter.fx hace #include de un archivo X (su MD5 empieza con 47 y termina con BD) y CSGaussianFilterF3.fx de un archivo Y (46-...-AA) que a su vez incluye a X.
Shaderfile.cache
Una vez detectada una modificación en un archivo, se compila el ShaderBytecode y el mismo se graba en el disco en la misma carpeta que el archivo original, con el nombre original seguido de ".cache".
private static Effect CompileEffect(string fileName, string profile, ShaderFlags shaderFlags, EffectFlags effectFlags, ShaderMacro[] macros, Include includeHandler) { Debug.WriteLine("Compiling shader: " + fileName); using (ShaderBytecode shaderCode = ShaderBytecode.CompileFromFile(fileName, profile, shaderFlags, effectFlags, macros, includeHandler)) { using (FileStream fs = new FileStream(fileName + ".cache", FileMode.Create)) { using (BinaryWriter bw = new BinaryWriter(fs)) { bw.Write(shaderCode.Data.ReadRange((int)shaderCode.Data.Length)); } } return new Effect(Recursos.Device, shaderCode); } }
Pequeña limitación
Dado que no se realiza ningún tipo de lectura de macros o directivas al preprocesador (exceptuando el #include), si un archivo X se modifica dentro de un bloque #if #endif (o #ifdef #endif) y un archivo Y incluye a X, entonces Y se recompilará aún cuando no cumpla la condición de #if presente en X y la modificación hecha le sea trasparente.
ShaderCache.cs
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; using SlimDX; using SlimDX.D3DCompiler; using SlimDX.Direct3D11; using Debug = System.Diagnostics.Debug; using Recursos = Framework.Base; namespace Framework { /// <summary> /// A static class used for storing ShaderBytecode and avoiding compiling shaders that weren't modified /// </summary> public static class ShaderCache { /// <summary> /// Looks for the shader's bytecode cache. If found, returns a new Effect created from the bytecode. If not, compiles the Effect, stores it's bytecode and updates the cache entry. /// </summary> /// <param name="fileName">Full path of the shader file</param> /// <param name="profile">Target profile</param> /// <param name="shaderFlags">ShaderFlags (default ShaderFlags.WarningsAreErrors)</param> /// <param name="effectFlags">EffectFlags (default EffectFlags.None)</param> /// <param name="macros">Array of ShaderMacro (default null)</param> /// <param name="includeHandler">An include handler (default null)</param> /// <returns>The compiled Effect</returns> public static Effect CheckCacheAndCompileEffect(string fileName, string profile, ShaderFlags shaderFlags = ShaderFlags.WarningsAreErrors, EffectFlags effectFlags = EffectFlags.None, ShaderMacro[] macros = null, Include includeHandler = null) { if (CheckAndUpdateCache(fileName)) { byte[] byteCode; using (FileStream fs = new FileStream(fileName + ".cache", FileMode.Open)) { using (BinaryReader br = new BinaryReader(fs)) { byteCode = br.ReadBytes((int)fs.Length); } using (DataStream ds = new DataStream(byteCode, true, false)) { using (ShaderBytecode shaderCode = new ShaderBytecode(ds)) { return new Effect(Recursos.Device, shaderCode); } } } } else return CompileEffect(fileName, profile, shaderFlags, effectFlags, macros, includeHandler); } #region Private methods /// <summary> /// Compiles an Effect and writes its bytecode to the hard drive. /// </summary> /// <param name="fileName">Full path of the shader file</param> /// <param name="profile">Target profile</param> /// <param name="shaderFlags">ShaderFlags (default ShaderFlags.WarningsAreErrors)</param> /// <param name="effectFlags">EffectFlags (default EffectFlags.None)</param> /// <param name="macros">Array of ShaderMacro (default null)</param> /// <param name="includeHandler">An include handler (default null)</param> /// <returns>The compiled Effect</returns> private static Effect CompileEffect(string fileName, string profile, ShaderFlags shaderFlags, EffectFlags effectFlags, ShaderMacro[] macros, Include includeHandler) { Debug.WriteLine("Compiling shader: " + fileName); using (ShaderBytecode shaderCode = ShaderBytecode.CompileFromFile(fileName, profile, shaderFlags, effectFlags, macros, includeHandler)) { using (FileStream fs = new FileStream(fileName + ".cache", FileMode.Create)) { using (BinaryWriter bw = new BinaryWriter(fs)) { bw.Write(shaderCode.Data.ReadRange<byte>((int)shaderCode.Data.Length)); } } return new Effect(Recursos.Device, shaderCode); } } /// <summary> /// Generates the MD5 of the shader, compares it against the value stored in the cache entry, and updates the entry if necessary. /// </summary> /// <param name="fileName">Full path of the shader file</param> /// <returns>True if the bytecode stored in the cache is valid.</returns> private static bool CheckAndUpdateCache(string fullFilePath) { string fileBaseDir = fullFilePath.Substring(0, fullFilePath.LastIndexOf('\\') + 1); string fileName = fullFilePath.Substring(fullFilePath.LastIndexOf('\\') + 1); string md5 = ComputeShaderFileMD5(fileName, fileBaseDir); string[] entries; try { entries = File.ReadAllLines(Recursos.ResourcesDir + "ShadersCache\\cacheEntries.txt"); } catch (FileNotFoundException) { File.Create(Recursos.ResourcesDir + "ShadersCache\\cacheEntries.txt").Dispose(); entries = File.ReadAllLines(Recursos.ResourcesDir + "ShadersCache\\cacheEntries.txt"); } int i; for (i = 0; i < entries.Length && !entries[i].Contains(fullFilePath); i++) /*Not an extra semicolon*/; if (i == entries.Length) { Debug.WriteLine("Shader added to cache: " + fullFilePath); List<string> aux = entries.ToList(); aux.Add(fullFilePath + "\t" + md5); entries = aux.ToArray(); } else { string[] split = entries[i].Split(new char[] { '\t' }); if (split[1] == md5) { Debug.WriteLine("Shader found on cache: " + fullFilePath); return true; } else { Debug.WriteLine("Shader updated on cache: " + fullFilePath); entries[i] = fullFilePath + "\t" + md5; } } File.WriteAllLines(Recursos.ResourcesDir + "ShadersCache\\cacheEntries.txt", entries); return false; } /// <summary> /// Computes the MD5 of a shader file concatenated with the MD5 of each of the included files (#include) /// </summary> /// <param name="fileName">Full path of the shader file</param> /// <returns>MD5 as a string</returns> private static string ComputeShaderFileMD5(string fileName, string fileBaseDir) { string md5; using (FileStream fs = new FileStream(fileBaseDir + fileName, FileMode.Open)) { md5 = BitConverter.ToString(new MD5CryptoServiceProvider().ComputeHash(fs)); fs.Position = 0; using (TextReader tr = new StreamReader(fs)) { string line = tr.ReadLine(); while (line != null) { if (line.StartsWith("#include \"")) { string includeName = line.Substring("#include \"".Length, line.Length - "#include \"".Length - "\"".Length); //Recursively compute the MD5 of the include file md5 += ComputeShaderFileMD5(includeName, fileBaseDir); } line = tr.ReadLine(); } } } return md5; } /// <summary> /// Computes the MD5 of a file /// </summary> /// <param name="fileName">Name of the file</param> /// <param name="fileDir">Directory of the file (ending with \\)</param> /// <returns>MD5 of the file</returns> private static string ComputeFileMD5(string fileName, string fileDir) { using (FileStream fs = new FileStream(fileDir + fileName, FileMode.Open)) { return BitConverter.ToString(new MD5CryptoServiceProvider().ComputeHash(fs)); } } #endregion } }
6 notes · View notes
akhanubis-eng · 13 years ago
Text
SlimDX - DirectX 11 - Extracting frustum planes
Extracting the planes from the colums of the projection matrix
My method is based in the implementation proposed in http://crazyjoke.free.fr/doc/3D/plane%20extraction.pdf. Looking at how a point int View Space is transformed to Clip Space, it's possible to obtain the equations related to the planes from the colums of the projection matrix.
Something worthed pointing out is that the coordinate space of the resulting planes depends on the matrix used for the extraction. Quoting the paper:
If the matrix used is the projection matrix P, then the algorithm gives the clipping planes in view space (i.e., camera space).
If the matrix used is equal to the combined view and projection matrices, then the algorithm gives the clipping planes in world space.
If the matrix used is equal to the combined world, view, and projection matrices, then the algorithm gives the clipping planes in object space.
I adapted to C# the example provided in C by the author:
private void GenerarPlanos_columnasmatriz(Matrix inProjection) { //Basado en http://crazyjoke.free.fr/doc/3D/plane%20extraction.pdf planesVS = new Plane[6]; planesVS[(int)FrustumPlane.Near] = Plane.Normalize(new Plane(inProjection.get_Columns(2))); planesVS[(int)FrustumPlane.Far] = Plane.Normalize(new Plane(inProjection.get_Columns(3) - inProjection.get_Columns(2))); planesVS[(int)FrustumPlane.Left] = Plane.Normalize(new Plane(inProjection.get_Columns(3) + inProjection.get_Columns(0))); planesVS[(int)FrustumPlane.Right] = Plane.Normalize(new Plane(inProjection.get_Columns(3) - inProjection.get_Columns(0))); planesVS[(int)FrustumPlane.Top] = Plane.Normalize(new Plane(inProjection.get_Columns(3) - inProjection.get_Columns(1))); planesVS[(int)FrustumPlane.Bottom] = Plane.Normalize(new Plane(inProjection.get_Columns(3) + inProjection.get_Columns(1))); }
Extracting the planes from the vertices of the frustum
I didn't write this algorithm, but it should be very simple. Each plane is constructed using 3 points (vertices of the frustum) that are contained in it. Each face of the frustum has 4 vertices of which we will choose 3. Then, it's just a matter of using the constructor:
new Plane(point1, point2, point3);
Probably, this method generates two vectors from the given point and compute their cross product to obtain the plane normal. Then, in order to obtain D, it should replace the X,Y,Z variables of the equation of the plane with the coordinates of any of the points.
When using this method, we need to keep in mind that 3 points actually define 2 planes with opposite normals depending on the order of the arguments of the constructor. The sphere-frustum collision test that I implemented requires that the 6 planes are facing inwards the frustum in order to work properly.
Extracting the planes by transforming them from Clip Space
The following image (taken from msdn) illustrates how the transformation from View Space to Clip Space works:
When transformed, the frustum becomes an AABB(axis aligned bounding box). This volume is much easier to work with so if we could define the planes in Clip Space and find a way of transforming them back to View Space, the problem would be solved.
Given an inversible transformation matrix \(M\) which goes from a coordinate system \(A\) to a coordinate system \(B\), its inverse(\(M^{-1}\)) will transform a vector backwards. Therefore, we will be using the inverse projectin matrix, which will transform a vector in Clip Space to View Space.
Furthermore, the planes of an AABB are really simple to determine. Their normals have two null components, and D equals 1 for every plane except the near plane (D=0).
Finally, the planes in Clip Space are hardcoded and then transformed to View Space using inverseProjection:
private void GenerarPlanos_clipspace(Matrix inProjection) { Matrix inverseProjection = Matrix.Invert(inProjection); planesVS = new Plane[6]; //Z + 0 = 0 planesVS[(int)FrustumPlane.Near] = Plane.Normalize(Plane.Transform(new Plane(0f, 0f, 1f, 0f), inverseProjection)); //-Z + 1 = 0 planesVS[(int)FrustumPlane.Far] = Plane.Normalize(Plane.Transform(new Plane(0f, 0f, -1f, 1f), inverseProjection)); //X + 1 = 0 planesVS[(int)FrustumPlane.Left] = Plane.Normalize(Plane.Transform(new Plane(1f, 0f, 0f, 1f), inverseProjection)); //-X + 1 = 0 planesVS[(int)FrustumPlane.Right] = Plane.Normalize(Plane.Transform(new Plane(-1f, 0f, 0f, 1f), inverseProjection)); //-Y + 1 = 0 planesVS[(int)FrustumPlane.Top] = Plane.Normalize(Plane.Transform(new Plane(0f, -1f, 0f, 1f), inverseProjection)); //Y + 1 = 0 planesVS[(int)FrustumPlane.Bottom] = Plane.Normalize(Plane.Transform(new Plane(0f, 1f, 0f, 1f), inverseProjection)); }
In terms of speed, the first method is the fastest (the title of the paper is "Fast Extraction..." :P). Nevertheless, I'm staying with the third one because it's more abstract and can be generalized (we will use this again in order to obtain the vertices of the frustum). Also, the viewing frustum sould be generated only once at the beginning, so the time spent on it it's irrelevant.
1 note · View note
mydirectx12demo-blog · 9 years ago
Text
Testing 2D Tile Based Game World
In this section, I would like to share few issues I'm facing with regards to testing input from the joystick, sadly for some reason I’m not able to move my player and after few seconds of execution, SlimDX application points out that it is not able to accept the input key press. I’m still in process of digging into the functionality. I’m trying to look into the book, but code seems to be good, there is some issue with linking of classes. Online reference for SlimDX and DirectX is also sparse. But surprisingly, I was able to capture how it looked like, here is the glimpse.
Tumblr media
0 notes
akhanubis · 13 years ago
Text
SlimDX y DirectX 11 - Query
Algo simple pero bastante útil.
Una query se basa en obtener stats del pipeline desde la placa de video como, por ejemplo, invocaciones a cada shader, primitivas renderizadas, tiempo transcurrido, etc. Hay una query en particular denominada occlusion query que es sumamente útil para occlusion culling (al menos eso tengo entendido: GPU Gems).
El encapsulamiento que hace SlimDX del manejo de las queries mapea prácticamente uno a uno contra las llamadas a la API de DX11, por lo que con la documentación de msdn alcanza y sobra para poder trabajar.
PipelineStatistics
Para el ejemplo, voy a utilizar una query que brinda datos generales sobre cada etapa del pipeline.
pipelineStatisticsQuery = new Query(device, new QueryDescription(QueryType.PipelineStatistics, QueryFlags.None));
El intervalo en el que se obtienen los datos de la query se define mediante los métodos Begin(query) y End(query). Algunas, sin embargo, sólo requieren de End(query).
context.Begin(pipelineStatisticsQuery); prueba.Render(elapsed); context.End(pipelineStatisticsQuery); swapChain.Present(0, PresentFlags.None);
Una vez obtenida la información, se debe verificar si la misma está disponible para luego proceder a su lectura:
while (!context.IsDataAvailable(pipelineStatisticsQuery)) ; PipelineStatistics pipelineStatistics = context.GetData<PipelineStatistics>(pipelineStatisticsQuery);
Si bien esto funciona, el usar un while para esperar a que se pueda leer el resultado de la query en cada frame disminuye bastante la performance. Me parece más sensato desacoplar el ciclo de actualización de la query respecto del de renderizado:
if (queryIsReadable) context.Begin(pipelineStatisticsQuery); prueba.Render(elapsed); if (queryIsReadable) context.End(pipelineStatisticsQuery); swapChain.Present(0, PresentFlags.None); if (context.IsDataAvailable(pipelineStatisticsQuery)) { pipelineStatistics = context.GetData<PipelineStatistics>(pipelineStatisticsQuery); queryIsReadable = true; } else queryIsReadable = false;
Así, una vez capturada la información, se intenta en cada ciclo leer la misma y no se vuelve a capturar hasta no lograrlo. Notar qué pasaría si directamente se reemplazase el while inicial por un if: nunca estaría disponible para leer porque, si bien no se bloquearía esperando, en cada ciclo se volvería a capturar y procesar.
Código fuente
El código fuente lo subo en el próximo post, en donde voy a mostrar mi primera incursión en Geometry Shaders con un shader que simplemente expande puntos a quads.
6 notes · View notes
akhanubis · 13 years ago
Text
SlimDX y DirectX 11 - Tessellation (Hull Shader y Domain Shader)
Código fuente y ejecutable de la solución
Tessellation
Subdivisión de un triángulo, un quad o una isolínea en triángulos (, puntos o líneas) más pequeños para generar un modelo de mayor cantidad de primitivas (msdn). Esto permite reducir el ancho de banda necesario al usar como input al pipeline un modelo low-poly, realizar cálculos por patch en lugar de por primitiva final (siempre y cuando se pueda interpolar después), adaptar la calidad del modelo en función de distancia a cámara o screen space, aplicar eficientemente técnicas como displacement mapping, etc.
Para implementarlo por hardware, DirectX 11 incorpora tres etapas más al pipeline: Hull Shader, Tessellation Stage y Domain Shader.
Hull Shader
Este shader recibe como inputs los puntos de control y genera como output puntos de control que definen un patch (superficie) a subdividir junto con parámetros constantes por cada patch relativos a la forma en que se realiza la subdivisión.
Patch Constant Function
Para definir los parámetros de tessellation o cualquier otro output constante por patch se utiliza una función que se ejecuta por patch y tiene como input todos los puntos de control originales. La información que posee cada punto y la cantidad de puntos que conforman al patch se define en el header de la función, más precisamente en el input del tipo InputPatch.
struct HS_OUTPATCH { float Edges[3] : SV_TessFactor; float Inside : SV_InsideTessFactor; }; HS_OUTPATCH HSPatchFunction(InputPatch<HS_INPOSTXR, 3> PatchPoints, uint PatchID : SV_PrimitiveID) { HS_OUTPATCH Out; Out.Edges[0] = Out.Edges[1] = Out.Edges[2] = Out.Inside = tessFactor; return Out; }
Mínimamente, la salida debe definir SV_TessFactor y SV_InsideTessFactor, y el índice de cada array asociado dependerá del dominio (tipo de patch). Por ejemplo, un triángulo requiere de 3 SV_TessFactor (uno por lado) y un SV_InsideTessFactor, mientras que un quad de 4 y 2 respectivamente.
Estos factores determinan la cantidad de subdivisiones a realizar. Cabe mencionar que si algún factor es igual a 0 el patch no pasa a las etapas siguientes, por lo que se puede realizar algún tipo de culling en esta etapa.
Backface culling
Si el patch/triángulo no se encuentra mirando a la cámara, se setea el factor de tessellation en 0 para que sea descartado en la próxima etapa y evitar subdividir algo que de todas formas no se vería finalmente. Básicamente, si el producto escalar entre la normal de la superficie y el vector superficie->cámara es mayor a 0 (en realidad un epsilon muy pequeño), se descarta. Google lo explica mejor.
HS_OUTPATCH HSPatchFunctionBFCulling(InputPatch<HS_INPOSTXR, 3> PatchPoints, uint PatchID : SV_PrimitiveID) { HS_OUTPATCH Out; float3 patchNormal = normalize(cross(PatchPoints[1].Pos - PatchPoints[0].Pos, PatchPoints[2].Pos - PatchPoints[0].Pos)); if (BackFaceCull(dot(patchNormal, normalize(PatchPoints[0].Pos - viewPos)), dot(patchNormal, normalize(PatchPoints[1].Pos - viewPos)), dot(patchNormal, normalize(PatchPoints[2].Pos - viewPos)), 0.1)) Out.Edges[0] = Out.Edges[1] = Out.Edges[2] = Out.Inside = 0; else Out.Edges[0] = Out.Edges[1] = Out.Edges[2] = Out.Inside = tessFactor; return Out; }
Comparación entre Backface culling ON (izquierda) y OFF (derecha) seteando el rasterizer en CullNone:
Shader
EL hull shader propiamente dicho genera cada punto de control de salida a partir de la información relativa a todos los puntos de control de input y un ID del punto de control a generar (interno al patch). Además, se deben configurar parámetros requeridos por la Tessellation Stage que indican cómo realizar la subdivision.
[domain("tri")] [partitioning("integer")] [outputtopology("triangle_cw")] [outputcontrolpoints(3)] [patchconstantfunc("HSPatchFunction")] HS_OUTPOINTPOSTXR HSTessellation(InputPatch<HS_INPOSTXR, 3> PatchPoints, uint PatchID : SV_PrimitiveID, uint PointID : SV_OutputControlPointID) { HS_OUTPOINTPOSTXR Out; Out.Pos = PatchPoints[PointID].Pos; Out.Txr = PatchPoints[PointID].Txr; return Out; }
domain indica el tipo de patch de entrada, partitioning el algoritmo a utilizar para subdividir, outputtopology el tipo de primitiva de salida, outputcontrolpoints la cantidad de control points de salida, y patchconstantfunc el nombre de la función que genera la información por patch.
Tessellator Stage
Esta etapa se encarga de realizar la subdivisión de los patchs. Es fixed, por lo que no se programa nada y sólo se setean los parámetros en el HS (msdn).
Domain Shader
A nivel funcionalidad se podría pensar como el Vertex Shader si las primitivas generadas hubiesen sido directamente mandadas como input del pipeline y no hubiese tessellation. En el DS se calcula la posición final de cada vértice (output point) generado por la TS utilizando como entrada la ubicación de los puntos de control (generada por el HS), la información constante per patch (generada por la patch constant function del HS), y las coordenadas del vértice generada dentro del patch.
Estas coordenadas se obtienen a partir de la system value SV_DomainLocation y su tipo de dato depende del tipo de patch. Para un quad, se utiliza un float2 que indica las coordenadas internas UV (símil coordenadas de textura), para un triángulo (el caso de ejemplo que hice) un float3 que representa las coordenadas baricéntricas, y para una línea un float2 que no sé que representa.
[domain("tri")] PS_INPOSTXR DSTessellation (HS_OUTPATCH PatchData, float3 BariPos : SV_DomainLocation, const OutputPatch<HS_OUTPOINTPOSTXR, 3> PatchPoints) { PS_INPOSTXR Out; //Interpolación baricéntrica en función de los 3 control points (vértices del triángulo/patch original) float4 pos = float4(PatchPoints[0].Pos * BariPos.x + PatchPoints[1].Pos * BariPos.y + PatchPoints[2].Pos * BariPos.z, 1.0f); Out.Pos = mul(pos, matViewProjection); Out.Txr = PatchPoints[0].Txr * BariPos.x + PatchPoints[1].Txr * BariPos.y + PatchPoints[2].Txr * BariPos.z; return Out; }
Video
Coming up
Lo próximo que haga sea probablemente displacement mapping. Parece interesante y relativamente simple.
4 notes · View notes
akhanubis · 13 years ago
Text
SlimDX y DirectX 11 - Point to Quad Geometry Shader
Solución
Para no armar una solución/proyecto por cada cosa que haga en SlimDX, hice un form Base.cs desde donde se elige y lanza (creando un thread) la prueba a ejecutar. De paso la uso para mostrar stats y demás sin recurrir a DirectWrite :P
Recién me entero de que activando el unmanaged code debugging en las propiedades del proyecto se pueden ver en la ventana de Output warnings y mensajes de error de DX, por lo que probablemente más adelante me proponga como tarea arreglar el código para no dejar recursos colgando :P
El código lo subo en el próximo post (igual copio textual el GS en este).
Pipeline de DX 10
Geometry Shader
Shader que trabaja a nivel de primitiva, el cual permite crear nuevas primitivas y/o descartarlas. Su input es un array de outputs del Domain Shader (Vertex Shader si no hubiere HS-Tesselator-DS) (dado que para trabajar sobre un triángulo, por ejemplo, requeriría de sus 3 vértices), y su output uno o más buffers símiles a los vertex buffers.
[maxvertexcount(4)] void GShaderGSExpandPointToQuad(point GS_INPOS Input[1], inout TriangleStream<PS_INPOSTXR> outStream) { Shader code... }
El header es bastante simple. Se define la cantidad máxima de vértices de salida por ejecución del GS (maxvertexcount), el tipo de primitiva de entrada (point) con su struct asociada, la cantidad de vértices a leer antes de ejecutar el GS (por ser point: Input[1]), y el tipo de primitiva de salida (TriangleStream).
Ejemplo de GS: Point to Quad/Sprite
Es casi el Hello World de los GSs. Ni siquiera hace uso del Stream Output (sobre el cual voy a escribir en el próximo post).
Este GS recibe un array de puntos y, por cada uno, genera un Triangle Strip formado por 2 triángulos que le dan forma a un Screen Aligned Quad. Cada vértice de salida se agrega al Stream utilizando la función Append(vertex) y, si bien en este shader no hace falta, si hiciese falta resetear el Strip de salida se usaría la función RestartStrip().
[maxvertexcount(4)] void GShaderGSExpandPointToQuad(point GS_INPOS Input[1], inout TriangleStream<PS_INPOSTXR> outStream) { PS_INPOSTXR Output; float fQuadDimensionX = fQuadDimensionsCS.x * (cos(Input[0].Pos.z + fTimeTotal) + 1.0); float fQuadDimensionY = fQuadDimensionsCS.y * (cos(Input[0].Pos.z + fTimeTotal) + 1.0); Output.Pos.z = 0.0; Output.Pos.w = 1.0; Output.Col = Input[0].Col; Output.Pos.xy = Input[0].Pos.xy + float2(-fQuadDimensionX, fQuadDimensionY); Output.Txr = float2(0.0,0.0); outStream.Append(Output); Output.Pos.xy = Input[0].Pos.xy + float2(-fQuadDimensionX, -fQuadDimensionY); Output.Txr = float2(0.0,1.0); outStream.Append(Output); Output.Pos.xy = Input[0].Pos.xy + float2(fQuadDimensionX, fQuadDimensionY); Output.Txr = float2(1.0,0.0); outStream.Append(Output); Output.Pos.xy = Input[0].Pos.xy + float2(fQuadDimensionX, -fQuadDimensionY); Output.Txr = float2(1.0,1.0); outStream.Append(Output); } technique11 GSExpandPointToQuad { pass P0 { SetVertexShader(CompileShader(vs_5_0, VShaderGSExpandPointToQuad())); SetGeometryShader(CompileShader(gs_5_0, GShaderGSExpandPointToQuad())); SetPixelShader(CompileShader(ps_5_0, PShaderGSExpandPointToQuad())); } }
Por cada punto (Input[0]), voy creando cada vértice del quad usando la posición y el tamaño en Clip Space y agregándolo al Stream. Pos.z almacena un valor random generado al momento de crear los vertex buffers que modifica la fase de expansión del quad para que no estén todos sincronizados :P
Del lado de la aplicación no hay que codificar absolutamente nada ya que el GS se carga al cargar el efecto entero (si no se usase Effect habría que compilarlo usando new GeometryShader()).
1 note · View note
akhanubis · 13 years ago
Text
SlimDX y DirectX 11 - Normal Mapping y múltiples Point Lights
Código fuente y ejecutable de la solución 
Controles
WASDQE: Mueve la cámara.
TFGHRY: Mueve las tres luces a la vez.
Shift + TFGHRY: Mueve la luz roja.
Ctrl + TFGHRY: Mueve la luz verde.
Alt + TFGHRY: Mueve la luz azul.
UJ: Rota a Altair.
IK: Escala a Altair.
1: Habilita/deshabilita Frustum Culling.
2: Habilita/deshabilita renderizar las Bounding Spheres.
3: Alterna entre distintos shaders para Altair y los cubos.
Legibilidad del código
Para hacer un poco más entendible el código, agregué un summary por cada método (en inglés) y le pasé Stylecop a la solución. Tal vez ahora sí se pueda entender aunque sea algo.
/// <summary> /// Rotates (adds to the actual rotation) the model given an arbitrary axis and angle /// </summary> /// <param name="inAxis">Rotation axis</param> /// <param name="inAngle">Rotation angle in radians</param>
Normal Mapping
Normal Mapping se basa en reemplazar la normal utilizada en las fórmulas de iluminación por una leída desde una textura (Normal Map). Esto permite simular relieve sin alterar la geometría del modelo.
Dado que el relieve es dependiente de la textura (Diffuse Map) sobre la que se aplica y no del objeto sobre el que se aplica esa textura, las normales almacenadas están en un espacio de coordenadas propio de la textura y no del objeto: Tangent Space.
Tangent Space
El Tangent Space es un sistema de coordenadas cuyos ejes son la normal de la superficie (normal), un versor cuya dirección es igual a la dirección en la que aumenta la coordenada de textura U (tangente) y un versor cuya dirección bla bla bla la coordenada de textura V (bitangente (también llamado binormal)). Hay mil explicaciones en Internet mejores que la que acabo de dar. :P
Para que se entienda un poco mejor, las siguientes imágenes muestran el valor de cada vector en WS para simples cubos. La imagen de arriba a la izquierda muestra una textura en la que se ve la dirección de los vectores U y V de cada cubo. A su derecha se muestran las normales en WS. Abajo a la izquierda los vectores tangentes (en WS), y a la derecha los bitangentes (en WS).
Por ejemplo, el vector tangente de la cara +Z del cuadrado de la derecha tiene la dirección de +Y (verde clarito), que coincide con la que figura para U en la textura.
Generación de tangentes y bitangentes
Dado que la normal a muestrear desde el normal map estará en TS, hará falta pasar  los vectores Light Dir y Eye a TS, o la normal a WS. Cualquiera sea el caso, se va a necesitar una matriz compuesta por la base del TS que son los tres vectores ya mencionados.
El algoritmo para la generación de la tangente y bitangente de un vértice lo saqué de acá. De todas formas, seguramente haya hecho algo mal ya que tuve que modificar la obtención de la bitangente ortogonal para obtener el mismo resultado que muestra el shader de ejemplo Show Binormals de RenderMonkey.
while (line != null && line.StartsWith("f ")) { Vector2[] texcoordsFace = new Vector2[3]; Vector3[] verticesFace = new Vector3[3]; string[] indicesFaces = new string[3]; fields = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < 3; i++) { indicesFace = fields[i + 1].Split(new[] { '/' }, StringSplitOptions.None); indicesFaces[i] = indicesFace[0]; meshAux.Indices.Add(ReadInt(indicesFace[0]) - 1 - indexOffset); indAbsolutoTex[ReadInt(indicesFace[0]) - 1 - indexOffset] = ReadInt(indicesFace[1]) - 1; verticesFace[i] = meshAux.Positions[ReadInt(indicesFace[0]) - 1 - indexOffset]; texcoordsFace[i] = texcoordsTotales[ReadInt(indicesFace[1]) - 1]; } int i0 = ReadInt(indicesFaces[0]) - 1 - indexOffset; int i1 = ReadInt(indicesFaces[1]) - 1 - indexOffset; int i2 = ReadInt(indicesFaces[2]) - 1 - indexOffset; float a0 = AnguloDeVertice(verticesFace[0], verticesFace[1], verticesFace[2]); float a1 = AnguloDeVertice(verticesFace[1], verticesFace[2], verticesFace[0]); float a2 = AnguloDeVertice(verticesFace[2], verticesFace[0], verticesFace[1]); Vector3 v10 = verticesFace[0] - verticesFace[1]; Vector3 v12 = verticesFace[2] - verticesFace[1]; Vector3 normal = Vector3.Normalize(Vector3.Cross(v12, v10)); normalAcumuladaPorVertice[i0] += normal * a0; normalAcumuladaPorVertice[i1] += normal * a1; normalAcumuladaPorVertice[i2] += normal * a2; v10 = verticesFace[1] - verticesFace[0]; v12 = verticesFace[2] - verticesFace[0]; Vector2 texCoordsRelativas1 = texcoordsFace[1] - texcoordsFace[0]; Vector2 texCoordsRelativas2 = texcoordsFace[2] - texcoordsFace[0]; float unoSobreDeterminante = 1f / (texCoordsRelativas1.X * texCoordsRelativas2.Y - texCoordsRelativas2.X * texCoordsRelativas1.Y); Vector3 tangente, bitangente; tangente.X = v10.X * texCoordsRelativas2.Y - v12.X * texCoordsRelativas1.Y; tangente.Y = v10.Y * texCoordsRelativas2.Y - v12.Y * texCoordsRelativas1.Y; tangente.Z = v10.Z * texCoordsRelativas2.Y - v12.Z * texCoordsRelativas1.Y; tangente *= unoSobreDeterminante; bitangente.X = v10.X * texCoordsRelativas1.X - v12.X * texCoordsRelativas2.X; bitangente.Y = v10.Y * texCoordsRelativas1.X - v12.Y * texCoordsRelativas2.X; bitangente.Z = v10.Z * texCoordsRelativas1.X - v12.Z * texCoordsRelativas2.X; bitangente *= unoSobreDeterminante; tangenteAcumuladaPorVertice[i0] += tangente * a0; tangenteAcumuladaPorVertice[i1] += tangente * a1; tangenteAcumuladaPorVertice[i2] += tangente * a2; bitangenteAcumuladaPorVertice[i0] += bitangente * a0; bitangenteAcumuladaPorVertice[i1] += bitangente * a1; bitangenteAcumuladaPorVertice[i2] += bitangente * a2; line = reader.ReadLine(); } for (int i = 0; i < meshAux.Positions.Count; i++) { normalAcumuladaPorVertice[i].Normalize(); tangenteAcumuladaPorVertice[i].Normalize(); bitangenteAcumuladaPorVertice[i].Normalize(); /*Gram-Smichdt*/ tangenteOrto = Vector3.Normalize(tangenteAcumuladaPorVertice[i] - Vector3.Dot(normalAcumuladaPorVertice[i], tangenteAcumuladaPorVertice[i]) * normalAcumuladaPorVertice[i]); //float hand = (Vector3.Dot(Vector3.Cross(normalAcumuladaPorVertice[i], tangenteAcumuladaPorVertice[i]), bitangenteAcumuladaPorVertice[i]) < 0.0f) ? -1.0f : 1.0f; float hand = -1.0f; bitangenteOrto = Vector3.Normalize(Vector3.Cross(normalAcumuladaPorVertice[i], tangenteOrto) * hand); meshAux.TextureCoordinates.Add(texcoordsTotales[indAbsolutoTex[i]]); meshAux.Normals.Add(normalAcumuladaPorVertice[i]); meshAux.Tangents.Add(tangenteOrto); meshAux.Bitangents.Add(bitangenteOrto); //meshAux.Tangents.Add(tangenteAcumuladaPorVertice[i]); //meshAux.Bitangents.Add(bitangenteAcumuladaPorVertice[i]); }
Known bug: si el .obj primero define todos los vértices y luego todos los cuerpos en lugar de intercalar, todos los cuerpos de la escena tendrán el mismo vertex buffer, desperdiciando espacio y generando para cada uno una misma BoundingSphere que termina englobando a la escena entera. Nada terrible, más adelante lo arreglaré.
Lighting
El modelo de iluminación del shader se basa en el que trae embebido DX9 (msdn), con la diferencia de que no implementa emmisive lightning.
No hay mucha diferencia con el modelo para una sola luz, simplemente se debe calcular cada término de la fórmula por cada luz.
float4 ComputeAmbientLight(float4 materialColor, float4 lightColor, float attenuation) { return materialColor * lightColor * attenuation; } float4 ComputeDiffuseLight(float4 materialColor, float4 lightColor, float3 normal, float3 lightDirection, float attenuation) { return materialColor * lightColor * saturate(dot(normal, lightDirection)) * attenuation; } float4 ComputeSpecularLight(float4 materialColor, float4 lightColor, float3 normal, float3 lightDirection, float3 viewDirection, float attenuation) { float3 vReflect = reflect(-lightDirection, normal); return materialColor * lightColor * saturate(pow(max(0, dot(vReflect, viewDirection)), fMatSpecularPower)) * attenuation; } float4 PShaderTexturedNormalPointLight(VS_OUTPOSTXREYELUZ Input) : SV_TARGET { float3 normal = normalize(normalMap.Sample(samLinearWrap, Input.Txr).xyz * 2.0 - 1.0); float4 colorAD = float4(0,0,0,1); float4 colorS = float4(0,0,0,1); float3 lightDir; for (int i=0; i < iCantLights; i++) { lightDir = normalize(Input.LDir[i].xyz); colorAD += ComputeAmbientLight(cMatAmbient, cAmbient[i], Input.LDir[i].w) + ComputeDiffuseLight(cMatDiffuse, cDiffuse[i], normal, lightDir, Input.LDir[i].w); colorS += ComputeSpecularLight(cMatSpecular, cSpecular[i], normal, lightDir, Input.Eye, Input.LDir[i].w); } return diffuseMap.Sample(samLinearWrap, Input.Txr) * saturate(colorAD) + colorS; }
La clase PointLight que desarrollé almacena las constantes de la luz en un Constant Buffer para setear todos los parámetros a la vez, pero lamentablemente no existen los arrays de Constants Buffers por lo que, al trabajar con N luces, tuve que setear cada parámetro por separado (setear N * parámetros/luz parámetros, en lugar de setear N constant buffers).
Video
1 note · View note