Bonsoir à tous,
Après avoir découvert la magie du Raymarching avec un article de Iñigo Quilez (http://www.iquilezles.org/www/articl...marchingdf.htm), et lu un code exemple (http://www.openprocessing.org/sketch/25016), j'ai voulu implémenter cette technique.
J'ai donc commencé par une version CPU qui fonctionne correctement:
Et j'ai voulu ensuite passer à une impplémentation sur le gpu avec D3D11, pour avoir rendu bien accéléré.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 #include <SFML/Graphics.hpp> #include <kT/Math/Vector3.hpp> #include <kT/Math/Vector4.hpp> #include <kT/Math/Helpers.hpp> #include <sstream> #include <string> static unsigned width = 1680; static unsigned height = 1050; static float g_fTime = 0.f; static float g_fStepMultiplier = 0.9f; static unsigned g_MaxSteps = 100; static float g_fMinDist = 0.001f; static float g_fGradientEpsilon = 0.25f; static unsigned g_iResolution = 4;// tile size static int g_iNumRenderThreads = 1; static kT::Vector3f32 g_vecLightDir1; static kT::Vector3f32 g_vecLightDir2; static kT::Vector3f32 s_vecCamPos; static kT::Vector3f32 s_vecCamTo; static float s_fFov; static unsigned s_iStride; static kT::Vector3f32 s_vecFwd; static kT::Vector3f32 s_vecRight; static kT::Vector3f32 s_vecUp; float rmSphere( const kT::Vector3f32& f, float fRadius) { return f.Length() - fRadius; } float rmRoundedCube(float fX, float fY, float fZ, float fSize, float fRadius) { float fDX = kT::Max(abs(fX) - fSize + fRadius, 0.f); float fDY = kT::Max(abs(fY) - fSize + fRadius, 0.f); float fDZ = kT::Max(abs(fZ) - fSize + fRadius, 0.f); return sqrtf(fDX * fDX + fDY * fDY + fDZ * fDZ) - fRadius; } float getDistance(const kT::Vector3f32& vecPos) { float fSphereDist1 = rmSphere(vecPos - kT::Vector3f32( 5.f, 0.f, 0.f ), 4.f); float fSphereDist2 = rmSphere(vecPos + kT::Vector3f32( 5.f, 0.f, 0.f ), 4.f); float fSphereDist3 = rmSphere(vecPos - kT::Vector3f32( 0.f, 5.f, 0.f ), 4.f); float fSphereDist4 = rmSphere(vecPos + kT::Vector3f32( 0.f, 5.f, 0.f ), 4.f); float fSphereDist5 = rmSphere(vecPos - kT::Vector3f32( 0.f, 0.f, 5.f ), 4.f); float fSphereDist6 = rmSphere(vecPos + kT::Vector3f32( 0.f, 0.f, 5.f ), 4.f); float fMinSphereDist = kT::Min( kT::Min( kT::Min( fSphereDist1, fSphereDist2 ), fSphereDist3 ), kT::Min( kT::Min( fSphereDist4, fSphereDist5 ), fSphereDist6 )); float fCubeDist = rmRoundedCube(vecPos.x, vecPos.y, vecPos.z, 6, 2); return kT::Max(fCubeDist, -fMinSphereDist); } kT::Vector3f32 gradient(float fX, float fY, float fZ) { return kT::Vector3f32( getDistance(kT::Vector3f32(fX + g_fGradientEpsilon, fY, fZ)) -getDistance(kT::Vector3f32(fX - g_fGradientEpsilon, fY, fZ)), getDistance(kT::Vector3f32(fX, fY + g_fGradientEpsilon, fZ)) - getDistance(kT::Vector3f32(fX, fY - g_fGradientEpsilon, fZ)), getDistance(kT::Vector3f32(fX, fY, fZ + g_fGradientEpsilon)) - getDistance(kT::Vector3f32(fX, fY, fZ - g_fGradientEpsilon)) ); } struct RayMarchResult { RayMarchResult(float fDist, float fComplexity): m_fDist(fDist), m_fComplexity(fComplexity) {} float m_fDist; float m_fComplexity; }; RayMarchResult rayMarch(const kT::Vector3f32& vecPos, const kT::Vector3f32& vecDir) { kT::Vector3f32 vecCurrentPos = vecPos; float fDist = g_fMinDist; unsigned Step; for (Step = 1; Step < g_MaxSteps && fDist >= g_fMinDist; Step++) { fDist = getDistance(vecCurrentPos); // This is a bit of a hack that just so happens to work well with the current scenes by // stopping the rays from marching too far // Hacky.. but it gives a massive speed boost if(fDist > 100.f) return RayMarchResult(0.f, 0.f); kT::Vector3f32 vecStep = vecDir; vecStep *= (fDist * g_fStepMultiplier); vecCurrentPos += vecStep; } if (fDist < g_fMinDist) return RayMarchResult((vecPos-vecCurrentPos).Length(), 1.f/((float)Step)); else return RayMarchResult(0, 0); } kT::Uint32 shade(const kT::Vector3f32& vecContactPos, const kT::Vector3f32& vecCamRay, const RayMarchResult& rayMarchResult) { kT::Vector3f32 vecNorm = gradient(vecContactPos.x, vecContactPos.y, vecContactPos.z); float fR = 0, fG = 0, fB = 0; float fDiffTerm = kT::Clamp(vecNorm.Dot(g_vecLightDir1), 0.0f, 1.0f); fR += fDiffTerm * 1.5f; fG += fDiffTerm * 1.5f; fB += fDiffTerm * 1.5f; fR += 0.0f; fG += 0.0f; fB += 0.03f; // Ambient kT::Uint32 r = kT::Min(fR * 255.f, 255.f); kT::Uint32 g = kT::Min(fG * 255.f , 255.f); kT::Uint32 b = kT::Min(fB * 255.f, 255.f); kT::Uint32 out = r | (g << 8) | (b << 16) | 0xff000000; return out; } class RenderThread { public: RenderThread(unsigned iStartY, unsigned iRenderHeight): m_iStartY(iStartY), m_iRenderHeight(iRenderHeight), m_iPixel( iStartY * width ) {} unsigned m_iStartY; unsigned m_iRenderHeight; unsigned m_iPixel; void run( kT::Uint32* pixels ) { for (unsigned y = m_iStartY; y < height - g_iResolution + 1; y += g_iResolution) { for (unsigned x = 0; x < width - g_iResolution + 1; x += g_iResolution) { kT::Vector3f32 vecCamRight = s_vecRight; vecCamRight *= (((float)x / (float)(width) - 0.5f) * s_fFov); kT::Vector3f32 vecCamUp = s_vecUp; vecCamUp *= (((float)y / (float)(height) - 0.5f) * s_fFov); kT::Vector3f32 vecCamDir = vecCamRight; vecCamDir+=vecCamUp; vecCamDir+=(s_vecFwd); vecCamDir.Normalize(); RayMarchResult rayMarchResult = rayMarch(s_vecCamPos, vecCamDir); float fDistance = rayMarchResult.m_fDist; kT::Uint32 c; if (fDistance > 0.f) { // Ray hit our field - calculate the colour kT::Vector3f32 vecContactPos = vecCamDir; vecContactPos*=(fDistance); vecContactPos+=(s_vecCamPos); c = shade(vecContactPos, vecCamDir, rayMarchResult); } else { // Ray didn't hit anything - get background colour c = 122 + (0 * 255) + (255 * 65536) + 4278190080; } if (g_iResolution == 1) pixels[m_iPixel++] = c; else { for (unsigned i = 0; i < g_iResolution; i++) { for (unsigned j = 0; j < g_iResolution; j++) { pixels[m_iPixel + width * j ] = c; } m_iPixel++; } } } m_iPixel += s_iStride; } } }; void render( kT::Uint32* pixels ) { // Position camera s_vecCamPos = kT::Vector3f32(25.f * sin(g_fTime * 0.001f), 21.f * sin(g_fTime * 0.0002f), 25.f * cos(g_fTime * 0.001f)); s_vecCamTo = kT::Vector3f32(0.f, 0.f, 0.f); // Figure out view vectors from camera position s_vecFwd = s_vecCamTo; s_vecFwd-=(s_vecCamPos); s_vecFwd.Normalize(); s_vecUp = kT::Vector3f32(0.f, 1.f, 0.f); s_vecRight = s_vecFwd.Cross(s_vecUp); s_vecUp = s_vecRight.Cross(s_vecFwd); s_fFov = 1.0f; // Set up lights g_vecLightDir1 = kT::Vector3f32(-0.5f, -1.f, 0.f); g_vecLightDir1.Normalize(); g_vecLightDir2 = kT::Vector3f32(0.5f, -1.f, 0.f); g_vecLightDir2.Normalize(); // Create the render threads and start them running s_iStride = width * (g_iResolution - 1); int iRenderHeight = height / g_iNumRenderThreads; int iHeightRendered = height; RenderThread r(0, height); r.run( pixels ); } template< typename T > std::string toString( T i ) { // créer un flux de sortie std::ostringstream oss; // écrire un nombre dans le flux oss << i; // récupérer une chaîne de caractères return oss.str(); } int main() { sf::RenderWindow window(sf::VideoMode(width, height), "ray Marching"); width = window.getSize().x; height = window.getSize().y; kT::Uint32* pixels = new kT::Uint32[ width * height ]; sf::Texture backbuff; backbuff.create( window.getSize().x, window.getSize().y ); sf::Sprite screen(backbuff); sf::Font font; font.loadFromFile( "font.ttf" ); sf::Text renderTimeText("render time inknown", font); sf::Clock clock; while( window.isOpen() ) { sf::Event ev; while( window.pollEvent( ev ) ) { if( ev.type == sf::Event::Closed ) window.close(); } sf::Time elapsedTime = clock.getElapsedTime(); g_fTime = elapsedTime.asSeconds() * 1000.f; render( pixels ); backbuff.update( reinterpret_cast<kT::Uint8*>(pixels) ); window.draw( screen ); float renderTime = clock.getElapsedTime().asSeconds() * 1000.f - g_fTime; renderTimeText.setString("Render time: " + toString(renderTime) + "ms"); window.draw( renderTimeText ); window.display(); } delete[] pixels; return 0; }
Sauf que là - patatra - plus rien ne marche bien sûr!
En rapide: je rends un rectangle pour couvrir l'écran. Dans le pixel shader je suis sensé faire les calculs de RenderThread::run() de la version CPU.
Le code tient en trois fichiers:
Le main.cpp (je le mets au cas où l'erreur vienne de là, bien que je pense que ça vient plutôt du pixel shader).
Le vertex shader (tout court, promis):
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305 #include <kT/Core.hpp> #include <kT/Math.hpp> #include <kT/Window.hpp> #include <kT/Graphics/D3D11Device/D3D11Device.hpp> #include <kT/Graphics/D3D11Device/D3D11Shader.hpp> #include <kT/Graphics/D3D11Device/D3D11SwapChain.hpp> #include <kT/Graphics/D3D11Device/D3D11RasterizerState.hpp> #include <kT/Graphics/D3D11Device/D3D11ImmediateContext.hpp> #include <kT/Graphics/D3D11Device/D3D11DeviceTypes.hpp> #include <kT/Graphics/D3D11Device/D3D11SamplerState.hpp> #include <kT/Graphics/D3D11Device/D3D11Texture.hpp> #include <kT/Graphics/D3D11Device/D3D11DepthStencilBuffer.hpp> #include <D3D11.h> int main( int argc, char** argv ) { kT::FileLogger* logger = new kT::FileLogger; kT::VideoMode mode = kT::VideoMode::GetDesktopMode(); #ifdef NDEBUG kT::Window* window = new kT::Window("Ray", kT::Sizeui32(800, 800), kT::Window::Overlapped ); #else kT::Window* window = new kT::Window("Ray", kT::Sizeui32(800, 800), kT::Window::Overlapped ); #endif window->Show(); kT::D3D11Device* device; kT::D3D11ImmediateContext* immediateContext = 0; ID3D11Device* d3dDevice = 0; ID3D11DeviceContext* d3dImmediateContext = 0; try{ #ifndef NDEBUG try{ device = new kT::D3D11Device(kT::D3D11Device< kTD3D11DeviceTemplateListLineTypes >::HardwareProcessing, true); } catch( kT::Exception& e ) { device = new kT::D3D11Device(); } #else device = new kT::D3D11Device(); #endif immediateContext = device->GetImmediateContext(); d3dDevice = device->GetHandle(); d3dImmediateContext = immediateContext->GetHandle();; if( device->GetFeatureLevel() == D3D_FEATURE_LEVEL_11_0 ) logger->Log( kT::Logger::InfoMessage, "Feature level 11!" ); } catch( kT::Exception& e ) { logger->Log( kT::Logger::CriticalErrorMessage, "Can't create the device"); return -1; } kT::D3D11SwapChain* pSwapChain; try{ pSwapChain = new kT::D3D11SwapChain( d3dDevice, window, kT::PixelFormat::RGBA8_UNORM, window->GetSize(), true, 1 ); } catch( kT::Exception& e ) { logger->Log( kT::Logger::CriticalErrorMessage, "Can't create the swapchain" ); return -1; } ID3D11RenderTargetView* renderTargetView = pSwapChain->GetTexture()->GetRenderTargetView(); // Set the viewport D3D11_VIEWPORT vp; vp.Height = static_cast<float>(pSwapChain->GetTexture()->GetSize().Height); vp.Width = static_cast<float>(pSwapChain->GetTexture()->GetSize().Width); vp.TopLeftX = 0.f; vp.TopLeftY = 0.f; vp.MinDepth = 0.f; vp.MaxDepth = 1.f; d3dImmediateContext->RSSetViewports( 1, &vp ); /// /// Shaders setup /// kT::D3D11Shader* vs; // Load, compile, and create the vertex shader. try{ vs = kT::D3D11Shader::LoadFromFile( device->GetHandle(), "raymarching.vsh", kT::D3D11Shader::VertexShader, kT::D3D11Shader::Profile4, "vsMain" ); } catch( kT::Exception& e ) { logger->Log( kT::Logger::CriticalErrorMessage, e.what() ); return -10; } kT::D3D11Shader* ps; // Load, compile, and create the pixel shader. try{ ps = kT::D3D11Shader::LoadFromFile( device->GetHandle(), "raymarching.psh", kT::D3D11Shader::PixelShader, kT::D3D11Shader::Profile4, "psMain" ); }catch( std::exception& e ) { logger->Log( kT::Logger::CriticalErrorMessage, e.what() ); return -10; } /// /// Shader setup end. /// /// /// Geometry setup /// kT::Vector3f32 vertices[] = { kT::Vector3f32( -1.f, 1.f, 0.5f ), kT::Vector3f32( 1.f, 1.f, 0.5f ), kT::Vector3f32( 1.f, -1.f, 0.5f ), kT::Vector3f32( -1.f, -1.f, 0.5f ) }; kT::D3D11HardwareBuffer* vb = device->CreateBuffer( kT::D3D11HardwareBuffer::VertexBuffer, kT::D3D11HardwareBuffer::ImmutableBuffer, 0, sizeof(kT::Vector3f32) * 4, vertices ); unsigned short indices[] = { 0, 1, 2, 0, 2, 3 }; kT::D3D11HardwareBuffer* ib = device->CreateBuffer( kT::D3D11HardwareBuffer::IndexBuffer, kT::D3D11HardwareBuffer::ImmutableBuffer, 0, sizeof(unsigned short) * 6, indices ); kT::InputElementDesc layout[] = { { 0, kT::PositionElement, 0, kT::PixelFormat::RGB32_FLOAT, 0, kT::PerVertex } }; kT::InputLayoutDesc layoutDesc = { 1, layout, }; kT::D3D11InputLayout* inputLayout = device->CreateLayout( vs, layoutDesc ); size_t strides[16]; inputLayout->ComputeStrides( strides ); size_t offsets[16]; memset( offsets, 0, sizeof(size_t) * 16 ); /// /// /// /// General constants buffers float GradientEpsilon = 0.25f; struct WindowConstantBufferPS { kT::Vector3f32 dx; float minDist; kT::Vector3f32 dy; kT::Uint32 maxSteps; kT::Vector3f32 dz; float stepMultiplier; }; WindowConstantBufferPS cbuffContentps; cbuffContentps.dx = kT::Vector3f32( GradientEpsilon, 0.f, 0.f ); cbuffContentps.minDist = 0.001f; cbuffContentps.dy = kT::Vector3f32( 0.f, GradientEpsilon, 0.f ); cbuffContentps.maxSteps = 100; cbuffContentps.dz = kT::Vector3f32( 0.f, 0.f, GradientEpsilon ); cbuffContentps.stepMultiplier = 0.9f; kT::D3D11HardwareBuffer* windowConstants = device->CreateBuffer( kT::D3D11HardwareBuffer::ConstantBuffer, kT::D3D11HardwareBuffer::DefaultBuffer, 0, sizeof(WindowConstantBufferPS), reinterpret_cast<void*>(&cbuffContentps)); d3dImmediateContext->UpdateSubresource( windowConstants->GetHandle(), 0, 0, &cbuffContentps, 0, 0); // Light constants buffer struct LightBufferPS { kT::Vector3f32 LightDir; float pad; kT::Vector4f32 padl; kT::Vector4f32 padl1; kT::Vector4f32 padl2; }; LightBufferPS lContentps; lContentps.LightDir = kT::Vector3f32(-0.5f, -1.f, 0.f).Normalize(); kT::D3D11HardwareBuffer* lightConstants = device->CreateBuffer( kT::D3D11HardwareBuffer::ConstantBuffer, kT::D3D11HardwareBuffer::DefaultBuffer, 0, sizeof(LightBufferPS), reinterpret_cast<void*>(&lContentps)); d3dImmediateContext->UpdateSubresource( lightConstants->GetHandle(), 0, 0, &lContentps, 0, 0); // Camera constants buffer struct CameraBuffer { kT::Vector3f32 vecRight; kT::Vector3f32 vecUp; kT::Vector3f32 vecFwd; kT::Vector3f32 vecCamPos; float fov; kT::Vector3f32 pad; }; CameraBuffer camContentps; // Position camera kT::Vector3f32 vecCamTo = kT::Vector3f32(0.f, 0.f, 0.f); // Figure out view vectors from camera position camContentps.vecUp = kT::Vector3f32(0.f, 1.f, 0.f); camContentps.fov = 1.0f; kT::D3D11HardwareBuffer* camConstants = device->CreateBuffer( kT::D3D11HardwareBuffer::ConstantBuffer, kT::D3D11HardwareBuffer::DefaultBuffer, 0, sizeof(CameraBuffer), reinterpret_cast<void*>(&camContentps.vecRight.x)); bool opened = true; kT::Clock clock; window->EnableKeyRepeat(true); while( opened ) { float dt = (float)clock.GetTimeElapsed(); clock.Reset(); window->ProcessEvents(); kT::GUIEvent evt; while( window->GetEvent(evt) ) { if( evt.Type == kT::GUIEvent::Closed || (evt.Type == kT::GUIEvent::KeyPressed && evt.Key.Code == kT::Key::Escape) ) opened = false; } // Position camera float g_fTime = clock.GetTimeElapsed() * 1000.f; camContentps.vecCamPos = kT::Vector3f32(25.f * sin(g_fTime * 0.001f), 21.f * sin(g_fTime * 0.0002f), 25.f * cos(g_fTime * 0.001f)); // Figure out view vectors from camera position camContentps.vecFwd = (vecCamTo-camContentps.vecCamPos).Normalize(); camContentps.vecRight = camContentps.vecFwd.Cross(camContentps.vecUp); camContentps.vecUp = camContentps.vecRight.Cross(camContentps.vecFwd); d3dImmediateContext->UpdateSubresource( camConstants->GetHandle(), 0, 0, &camContentps.vecRight.x, 0, 0); float color[4] = { 0.f, 0.f, 0.f, 0.f }; d3dImmediateContext->ClearRenderTargetView( renderTargetView, color ); immediateContext->IASetInputLayout( inputLayout ); immediateContext->IASetPrimitiveTopology( kT::PrimitiveTopology::TriangleList ); immediateContext->VSSetShader( vs ); immediateContext->PSSetShader( ps ); immediateContext->PSSetConstantBuffers( 0, 1, &windowConstants ); immediateContext->PSSetConstantBuffers( 1, 1, &lightConstants ); immediateContext->PSSetConstantBuffers( 2, 1, &camConstants ); immediateContext->IASetIndexBuffer( ib, kT::PixelFormat::R16_UINT, 0 ); immediateContext->IASetVertexBuffers( 0, 1, &vb, strides, offsets ); immediateContext->DrawIndexed( 6, 0, 0 ); pSwapChain->Present(); } immediateContext->ClearState(); delete inputLayout; delete ib; delete vb; delete ps; delete vs; delete pSwapChain; delete device; delete logger; delete window; return 0; }
raymarch.vsh:
le pixel shader (beaucoup plus long)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 struct VS_OUTPUT { float4 Pos: SV_POSITION; float2 uv : TEXCOORD0; }; VS_OUTPUT vsMain( float4 Pos : POSITION ) { VS_OUTPUT output; output.Pos = Pos; output.uv = 0.5f * Pos + 0.5f; output.uv.y = 1.0f - output.uv.y; return output; }
raymarch.psh
J'ai remarqué (en débuguant avec PIX et GPUPerfStudio) que même si l'on passe dans la branche que j'ai noté Branche A de rayMarch(), on arrive jamais dans la branche B de render(), le problème vient de là. (la branche B est la celle à pouvoir affecter autre chose que la couleur du fond).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 cbuffer WindowConstantBufferPS { float3 dx; float minDist; float3 dy; uint maxSteps; float3 dz; float stepMultiplier; }; cbuffer LightBuffer { float3 vecLightDir1; float padl; float4 padl1; float4 padl2; float4 padl3; }; cbuffer CameraBuffer { float3 s_vecRight; float3 s_vecUp; float3 s_vecFwd; float3 s_vecCamPos; float s_fFov; float3 pad1; }; float rmSphere( in float3 f, in float fRadius ) { return length(f) - fRadius; } float rmRoundedCube( in float3 f, in float fSize, in float fRadius ) { float3 fD = max( abs(f) - fSize + fRadius, float3( 0.0f, 0.0f, 0.0f ) ); return length( fD ) - fRadius; } float getDistance( in float3 vecPos) { float fSphereDist1 = rmSphere(vecPos - float3( 5.f, 0.f, 0.f ), 4.f); float fSphereDist2 = rmSphere(vecPos + float3( 5.f, 0.f, 0.f ), 4.f); float fSphereDist3 = rmSphere(vecPos - float3( 0.f, 5.f, 0.f ), 4.f); float fSphereDist4 = rmSphere(vecPos + float3( 0.f, 5.f, 0.f ), 4.f); float fSphereDist5 = rmSphere(vecPos - float3( 0.f, 0.f, 5.f ), 4.f); float fSphereDist6 = rmSphere(vecPos + float3( 0.f, 0.f, 5.f ), 4.f); float fMinSphereDist = min( min( min( fSphereDist1, fSphereDist2 ), fSphereDist3 ), min( min(fSphereDist4, fSphereDist5), fSphereDist6 ) ); float fCubeDist = rmRoundedCube(vecPos.xyz, 6.f, 2.f); return max(fCubeDist, -fMinSphereDist); } float3 gradient( in float3 f) { return float3( getDistance(f + dx) - getDistance(f - dx), getDistance(f + dy) - getDistance(f - dy), getDistance(f + dz) - getDistance(f - dz) ); } // r.x : fDist // r.y complexity float2 rayMarch( in float3 vecPos, in float3 vecDir ) { float3 vecCurrentPos = vecPos; float fDist = minDist; uint Step; for (Step = 0; (Step < maxSteps) && (fDist >= minDist); Step++ ) { fDist = getDistance( vecCurrentPos ); vecCurrentPos += (fDist * stepMultiplier) * vecDir; if(fDist > 100.f) return float2( 0.0f, 0.0f ); } if ( fDist < minDist ) { /////////////// Branche A return float2( length(vecPos-vecCurrentPos), 1.f/float(Step) ); } else return float2( 0.f, 0.f ); } float3 shade( in float3 contactPos, in float3 camRay, in float2 rayMarchResult) { float3 norm = gradient( contactPos ); float fDiffTerm = saturate( dot( norm, vecLightDir1 ) ); float3 f = fDiffTerm * float3( 1.5f, 1.5f, 1.5f ) + float3( 0.f, 0.f, 0.3f ); return saturate( f ); } float3 render( in float2 uv ) { float3 vecCamRight = (( uv.x - 0.5f) * s_fFov) * s_vecRight; float3 vecCamUp = ((uv.y - 0.5f) * s_fFov) * s_vecUp; float3 vecCamDir = vecCamRight + vecCamUp + s_vecFwd; vecCamDir = normalize( vecCamDir ); float2 rayMarchResult = rayMarch( s_vecCamPos, vecCamDir ); float fDistance = rayMarchResult.x; float3 c; if ( fDistance > 0.f ) { ///////////////// Branche B // Ray hit our field - calculate the colour float3 vecContactPos = s_vecCamPos + (fDistance * vecCamDir); c = shade(vecContactPos, vecCamDir, rayMarchResult); } else { // Ray didn't hit anything - get background colour c = float3( 0.5f, 0.f, 1.0f ); } return c; } struct VS_OUTPUT { float4 Pos: SV_POSITION; float2 uv : TEXCOORD0; }; float4 psMain( VS_OUTPUT output ) : SV_Target { float3 c = render( output.uv ); return float4( c.x, c.y, c.z, 1.f ); return float4( output.uv.x, output.uv.y, 0.f, 1.f ); }
Est-ce que vous auriez une idée?
Toute idée est la bien venue
Merci!
Partager