Recent Questions - Computer Graphics Stack Exchange most recent 30 from computergraphics.stackexchange.com 2023-11-29T16:36:55Z https://computergraphics.stackexchange.com/feeds https://creativecommons.org/licenses/by-sa/4.0/rdf https://computergraphics.stackexchange.com/q/13832 0 Alpha calculation for anti aliased line Tom Huntington https://computergraphics.stackexchange.com/users/20902 2023-11-29T05:27:10Z 2023-11-29T05:27:10Z <p>Seems like there are two techniques</p> <ul> <li><p><code>Interpolation</code>: Interpolate the minimum distance from the canter of the pixel to the line.</p> </li> <li><p><code>Coverage</code>: The fraction of the pixel covered by the line</p> </li> </ul> <p>Are the results the same?</p> <p>For interpolation, are the edges always linearly interpolated?</p> <p>What about for the intersection of two lines? I imagine coverage would make better sense?</p> https://computergraphics.stackexchange.com/q/13829 0 Confusion about different sampling strategies in Monte Carlo Path Tracing bim https://computergraphics.stackexchange.com/users/7869 2023-11-28T17:15:52Z 2023-11-28T17:15:52Z <p>I am studying Monte Carlo Path Tracing from different sources. However, I have some confusion about the <code>sampling</code> part and dare to post here for experts' clarification.</p> <p>Most of the <a href="https://www.scratchapixel.com/lessons/3d-basic-rendering/global-illumination-path-tracing/introduction-global-illumination-path-tracing.html" rel="nofollow noreferrer">sources</a> present path tracing as figure below:</p> <p><a href="https://i.stack.imgur.com/qGWLom.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/qGWLom.png" alt="enter image description here" /></a></p> <p>This represents, the light ray starts from the camera/eye, has 3 bounces (whatever is the predefined bounce number), and then hits the light source (<code>L_e &gt;0</code>). If I am not wrong, when a ray hits the surface, it has surface information like <code>normal</code> and <code>material</code>. So if it hits a diffuse surface, it will flow the output angle wrt. the normal anywhere in the scene until the next hit (below figure).</p> <p>I assume in this figure above, I have one sample per pixel, and that sample is traveling throughout the scene (the deep orange color ray). The rest of the 5 rays are randomly generated reflected rays over the hemisphere (point <code>P</code> in the above figure).</p> <p><a href="https://i.stack.imgur.com/2wSpum.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/2wSpum.png" alt="enter image description here" /></a></p> <blockquote> <p><strong>Question:</strong> Can I call this one primary ray to 5 other reflected ray creation <code>ray splitting</code>? How do I define these 5 random <code>splitting</code>? Is it the <code>hemisphere sampling</code>? with some pseudorandom number generation like <code>LCG, TEA</code>?</p> </blockquote> <p>Now come to the second confusing point, according to <code>pbr book</code>, each sample is a complete path in the path tracing algorithm. If that is true, according to the first figure, I am just shooting one sample (one path) like below. but the first figure shows I am actually creating <code>6*6*6 =216</code> paths within 3 bounces. How that could be possible?</p> <p><a href="https://i.stack.imgur.com/oZXESs.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/oZXESs.png" alt="enter image description here" /></a></p> <p>Now, if I shoot multiple samples per pixel, like the figure below, I guess that should follow some pattern as well (lets say, adaptive sampling)</p> <p><a href="https://i.stack.imgur.com/Hf9D3s.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Hf9D3s.png" alt="enter image description here" /></a></p> <p><a href="https://i.stack.imgur.com/IctW4m.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/IctW4m.png" alt="enter image description here" /></a></p> <p>Now, instead of shooting at a point, the <code>light rays</code> will hit in a similar area and finally the average the <code>final color</code> value.</p> <blockquote> <p><strong>Question</strong> How this <code>pixel sampling</code> is different than the hemisphere sampling?</p> </blockquote> <p>My whole understanding is like this, I guess if I shoot 5 primary rays, they will hit the surface in 5 different points (similar area), and reflect according to the material and attenuation. However, I need to create <code>hemisphere sampling</code> separately for the hemisphere and determine, how many random points I am going to create over the hemisphere. <strong>Am I right?</strong></p> <p>Instead of these two types of sampling, I also see there are <code>material sampling</code>, <code>light sampling</code>, etc. Is there any other type of sampling?</p> https://computergraphics.stackexchange.com/q/13827 3 Profile GPU performance in Direct3D 11 leone ruggiero https://computergraphics.stackexchange.com/users/18529 2023-11-28T15:17:29Z 2023-11-29T09:35:24Z <p>I'm trying to profile a d3d11 application using queries (pretty much exactly as described <a href="https://therealmjp.github.io/posts/profiling-in-dx11-with-queries/" rel="nofollow noreferrer">here</a>).</p> <p>I noticed something strange with the data I was getting from the queries and I think I managed to isolate the issue: <a href="https://i.stack.imgur.com/lb0ZA.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/lb0ZA.png" alt="enter image description here" /></a></p> <p>The green line (<em>Cpu</em>) represent the time between two consecutive <code>swapChain-&gt;Present</code>, while the blue one represents the time to complete some gpu work for the current frame (measured using queries as explained above). The GPU work is always the same, however, as the time interval between two <code>Present</code> becomes bigger, the measured GPU time increases too.</p> <p>I guess this could be a way to reduce power consumption, however, I don't know if that's the case. Is this something you'd expect from the GPU?</p> <p>Is there a way to prevent this from happening?</p> <p><strong>EDIT:</strong> Apparently, this is the answer to my question (at least on NVidia GPUs): <a href="https://developer.nvidia.com/blog/advanced-api-performance-setstablepowerstate/" rel="nofollow noreferrer">https://developer.nvidia.com/blog/advanced-api-performance-setstablepowerstate/</a> <a href="https://i.stack.imgur.com/1nM5S.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/1nM5S.png" alt="enter image description here" /></a></p> https://computergraphics.stackexchange.com/q/13824 0 Texture coordinates ODA https://computergraphics.stackexchange.com/users/20899 2023-11-28T12:33:28Z 2023-11-29T02:39:51Z <p>Consider the square shown below on the left, which has been textured with the image shown on the right. What are the texture coordinates of the vertices a, b, c, and d?</p> <p>Does anyone know how to answer this?</p> <p><a href="https://i.stack.imgur.com/Umtrl.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Umtrl.png" alt="Question" /></a></p> https://computergraphics.stackexchange.com/q/13823 0 Geometry Shader Not Working TFamIdoing https://computergraphics.stackexchange.com/users/20888 2023-11-26T10:23:35Z 2023-11-28T19:04:59Z <p>So I seem to have some trouble getting a geometry shader working with &quot;glDrawArrays(GL_LINE_STRIP, 0, 4);&quot;. When I omit the geometry shader and make some minor variable changes, the vertex and fragment shader outputs the line strips properly, but adding the geometry shader somehow doesn't output anything (there doesn't seem to be any compile issues).</p> <p>I have also tried modifying the geometry shader to be a passthrough shader, and even that fails to output anything.</p> <p>Code attached below. Intention of the pipeline is to interpolate 4 colors across corners of a quad given as 4 vertices, so geometry shader is for coalescing data. Note that &quot;pos&quot; in &quot;GS_OUT&quot; in the fragment shader is unused right now because code has been heavily modified after testing.</p> <p>Vertex Shader:</p> <pre><code>#version 460 core in vec2 in_Position; in vec3 in_Color; out VS_OUT { vec2 position; vec3 color; } vs_out; void main(void) { vs_out.position = in_Position; vs_out.color = in_Color; gl_Position = vec4(in_Position, 0.0, 1.0); } </code></pre> <p>Geometry Shader:</p> <pre><code>#version 460 core layout (lines_adjacency) in; layout (triangle_strip, max_vertices = 4) out; in VS_OUT { vec2 position; vec3 color; } gs_in; // tl, tr, bl, br out GS_OUT { flat vec2 pos; flat vec3 rgb; } gs_out; void main() { for (int i = 0; i &lt; 4; i++) { for (int j = 0; j &lt; 4; j++) { gs_out.pos[j] = gs_in[j].position; gs_out.rgb[j] = gs_in[j].color; } gl_Position = gl_in[i].gl_Position; EmitVertex(); } EndPrimitive(); } </code></pre> <p>Fragment Shader:</p> <pre><code>#version 460 core precision highp float; // tl, tr, bl, br in GS_OUT { flat vec2 pos; flat vec3 rgb; } fs_in; out vec4 fragColor; void main(void) { fragColor = vec4(fs_in.rgb, 1.0); } </code></pre> https://computergraphics.stackexchange.com/q/13821 0 Raycasting wall slice height issue abcdef https://computergraphics.stackexchange.com/users/20870 2023-11-24T12:30:11Z 2023-11-24T19:13:07Z <p>I am having an issue with wall heights in my 2D raycasting playground I made for practice.</p> <h2>Problem</h2> <p><i>Test code in P5.js editor:</i> <a href="https://editor.p5js.org/tomekp/sketches/6fKPIAHNx" rel="nofollow noreferrer">https://editor.p5js.org/tomekp/sketches/6fKPIAHNx</a> (WASD to move, Left/Right arrow to turn)<br/> In the code above, I have an implementation of 2D raycasting, it is the best I have so far in that the walls are mostly the correct height depending on the player's position. The core of the logic is in <b>sketch.js</b> (you may need to open the sidebar menu if it doesn't open by default). <br/> However, <b>the problem</b> is that when you are standing directly in front of a wall (or walls), just far back enough to see the top and bottom of the wall slices you are looking at, the top and bottom of the lines that are being drawn vary in size just enough to make the wall look sort of concave.<br/> I've also attached an image at the bottom from the P5 link above to illustrate the issue further.</p> <h2>What I've tried</h2> <p>I've read the Lodev's tutorial (<a href="https://lodev.org/cgtutor/raycasting.html" rel="nofollow noreferrer">https://lodev.org/cgtutor/raycasting.html</a>), and a number of other articles online that explain the maths behind raycasting. I learned that I should be using <code>cos(rayAngle) * rayLength</code> to get the perpendicular distance from wall to player. And after trying various code changes &amp; studying up on my maths I still can't seem to grasp what's going wrong.</p> <p>I think the issue is that despite the perpendicular distance being used there are still small variations in that distance causing the concave effect on the walls that you are directly perpendicular to, but not sure.</p> <p>Any help/pointers would be appreciated, for context, I've been been mainly focusing on trigonometry when brushing up on my maths so I wonder if I am maybe just missing some required bit of maths to understand what I am doing wrong or if it's a case of misunderstanding how the computer renders rects/lines at specific canvas sizes. I think I basically don't know what I don't know to solve this problem.</p> <h3>Image of issue</h3> <p><a href="https://i.stack.imgur.com/i88wD.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/i88wD.png" alt="Example of concave wall issue" /></a></p> https://computergraphics.stackexchange.com/q/13819 0 Gregory triangle patch, calculating $b_{i,j,k}$ Thomas https://computergraphics.stackexchange.com/users/13273 2023-11-23T08:31:22Z 2023-11-23T12:39:38Z <p>I am trying to implement the Triangular Gregory patch from <a href="https://www2.eecs.berkeley.edu/Pubs/TechRpts/1987/CSD-87-313.pdf" rel="nofollow noreferrer">this</a> paper. The goal is to create a <span class="math-container">$G^1$</span> continuity across the patch boundaries. So that the normal vectors of neighboring triangles are equal.</p> <p>Right now I'm trying to understand how to calculate the Bézier ordinates: <span class="math-container">$b_{i,j,k}$</span> where <span class="math-container">$i,j,k \geq 0$</span> and <span class="math-container">$i+j+k = n$</span></p> <p>The second thing I'm not sure about is the degree <span class="math-container">$n$</span>. How to choose a good <span class="math-container">$n$</span>?</p> https://computergraphics.stackexchange.com/q/13818 0 Issues understanding rotations exported from Blender to gltf C. Dautermann https://computergraphics.stackexchange.com/users/20881 2023-11-22T22:29:24Z 2023-11-22T22:29:24Z <p>I am trying to write a raytracer in Rust that is able to load a .gltf file and render it. To do this I model a scene in Blende, export it to gltf (y up) and use my renderer to render the scene.</p> <p>The Issue I am currently having is that the rotations in Blender and the exported gltf file do not seem to match up. If I for example set a rotation of <code>(0,0.5,0.5,0|XYZW)</code> in Blender, it gets exported as <code>(0,1,0,0|XYZW)</code>. If I however render this Image using my code, yet another rotation seems to be used (an image is produced corresponding to a rotation of (0.5,0,0,0.5|XYZW) in Blender). <code>easy_gltf</code> yields the following transform matrix (world -&gt; camera):</p> <pre><code>camera.transform = Matrix4 [-1.0, 0.0, 0.0, 2.0 0.0, 1.0, 0.0, 10.0 0.0, 0.0, -1.0, -2 0.0, 0.0, 0.0, 1.0] </code></pre> <p>The camera is located at (2,2,10) in Blender, so at least the translational component appears to be working.</p> <p>To load the gltf file, I use <code>easy_gltf</code> in Rust. The following code is used to generate the ray directions:</p> <pre><code>//ray origin in world space let origin_world_space = camera.position(); // the distance from the camera origin to the view plane let z: f32 = height as f32 / (2.0 * fovy.mul(0.5).tan()); //obtain the inverse transformation Matrix let inverse_transform = camera.transform.invert().unwrap_or_else(|| panic!(&quot;Non invertible transform Matrix. giving up.&quot;) ); //TODO: take ray multiplier per pixel into account here let mut rays: Vec&lt;Ray&gt; = Vec::with_capacity(height * width); //generate all rays for this pixel and add them to the rays vector //TODO: use blue noise here to generate multiple rays per pixel rays.push(generate_single_primary_ray( width, height, &amp;inverse_transform, z, pixel_x_coord, pixel_y_coord, origin_world_space)); fn generate_single_primary_ray(image_width: usize, image_height: usize, inverse_transform: &amp;Matrix4&lt;f32&gt;, focal_length: f32, u: usize, v: usize, ray_origin: Vector3&lt;f32&gt;) -&gt; Ray { //calculate the ray direction and translate it to world space let direction_view_space: Vector4&lt;f32&gt; = Vector4::new(u as f32 - (image_width as f32 / 2.0), v as f32 - (image_height as f32 / 2.0), focal_length, 0.0); //TODO: Rotation is fucked //x rotation has sign wrong, y and z are flipped let direction_world_space = inverse_transform * direction_view_space.normalize(); Ray { source: ray_origin, direction: direction_world_space.truncate().normalize() } } </code></pre> <p>As you may see from the code above, to calculate the ray direction I first calculate the distance from the camera origin to the projection plane, take the inverse of the World-to-Camera-Matrix and then map the Camera space coordinates to world space directions using the inverse transform matrix (which I get from the <code>eays_gltf</code> API -&gt; no influence on that).</p> <p>Now I tried debugging this for hours but I cannot seem to pin down the issue. Is the export process wrong? Is easy gltf constructing the Matrix wrongly or do I have an issue in my code?</p> <p>The code, .blend file and .gltf file are available here: <a href="https://git.cdaut.de/CDaut/raytrace-rs" rel="nofollow noreferrer">https://git.cdaut.de/CDaut/raytrace-rs</a></p> https://computergraphics.stackexchange.com/q/13815 1 Convert between screen and world coordinates in isometric 3D Candleout https://computergraphics.stackexchange.com/users/20067 2023-11-19T07:55:01Z 2023-11-20T08:59:52Z <p>I'm working on a a simple 3D scene in WebGL. The purpose is to:</p> <ol> <li>Implement an isometric viewing angle in orthographic 3D</li> <li>Translate between XY screen coordinates and XY world coordinates</li> </ol> <p>Codepen: <a href="https://codepen.io/Candleout/pen/RwvxOJy" rel="nofollow noreferrer">https://codepen.io/Candleout/pen/RwvxOJy</a></p> <p>Sometimes when I load the page the scene appears blank or is not rendered correctly. Not sure why this happens. If this happens to you, refresh the page and/or scene it and it should hopefully work (x = 500 and y = -150 at screen center).</p> <p>In the scene, X (red axis) represent East-West and Y (green axis) represents North-South. X increases to the East and Y increases to the North. Z (blue axis) represents the vertical axis and increases with elevation.</p> <p><a href="https://i.stack.imgur.com/50hDq.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/50hDq.png" alt="enter image description here" /></a></p> <p>Camera setup:</p> <pre><code>cameraPosition = [x + 1, y - 1, 1] cameraTarget = [x, y, 0] up = [0, 0, 1] </code></pre> <p>With this setup, the objects are correctly positioned (or so it appears) in three dimensions. But how do you convert between screen coords and world coords?</p> <p>Below is my current (failed) attempt to converting from screen space to world space. It includes the following steps:</p> <ul> <li>Normalize the screen coordinates</li> <li>Invert the view projection matrix</li> <li>Apply the inverted matrix to the normalized screen coordinates</li> </ul> <p>With this code, only the coordinate in the center of the screen is turning out correct (500, -150). Everything else is skewed in some way. If you follow the y axis with the mouse, the x values will update as well, and vice versa.</p> <p>If anyone can tell me why this is happening and what I should be doing instead it would be very much appreciated.</p> <p>The world coordinates are visible in the bottom left corner of the Codepen.</p> <pre><code>function screenToWorld(screenCoords, viewProjectionMatrix, screenWidth, screenHeight) { // Convert screen coords into clip coords const ndcX = (screenCoords / screenWidth) * 2 - 1; const ndcY = 1 - (screenCoords / screenHeight) * 2; let clipCoords = [ndcX, ndcY, 0, 1]; // Invert view projection matrix const inverseViewProjectionMatrix = m4.inverse(viewProjectionMatrix); // Apply inverted matrix to normalized screen coords let worldCoords = m4.transformMat4([], clipCoords, inverseViewProjectionMatrix); return worldCoords.slice(0, 3); } function inverse(m) { let m00 = m[0 * 4 + 0]; let m01 = m[0 * 4 + 1]; let m02 = m[0 * 4 + 2]; let m03 = m[0 * 4 + 3]; let m10 = m[1 * 4 + 0]; let m11 = m[1 * 4 + 1]; let m12 = m[1 * 4 + 2]; let m13 = m[1 * 4 + 3]; let m20 = m[2 * 4 + 0]; let m21 = m[2 * 4 + 1]; let m22 = m[2 * 4 + 2]; let m23 = m[2 * 4 + 3]; let m30 = m[3 * 4 + 0]; let m31 = m[3 * 4 + 1]; let m32 = m[3 * 4 + 2]; let m33 = m[3 * 4 + 3]; let tmp_0 = m22 * m33; let tmp_1 = m32 * m23; let tmp_2 = m12 * m33; let tmp_3 = m32 * m13; let tmp_4 = m12 * m23; let tmp_5 = m22 * m13; let tmp_6 = m02 * m33; let tmp_7 = m32 * m03; let tmp_8 = m02 * m23; let tmp_9 = m22 * m03; let tmp_10 = m02 * m13; let tmp_11 = m12 * m03; let tmp_12 = m20 * m31; let tmp_13 = m30 * m21; let tmp_14 = m10 * m31; let tmp_15 = m30 * m11; let tmp_16 = m10 * m21; let tmp_17 = m20 * m11; let tmp_18 = m00 * m31; let tmp_19 = m30 * m01; let tmp_20 = m00 * m21; let tmp_21 = m20 * m01; let tmp_22 = m00 * m11; let tmp_23 = m10 * m01; let t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) - (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31); let t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) - (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31); let t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) - (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31); let t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) - (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21); let d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3); return [ d * t0, d * t1, d * t2, d * t3, d * ((tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30) - (tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30)), d * ((tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30) - (tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30)), d * ((tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30) - (tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30)), d * ((tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20) - (tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20)), d * ((tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33) - (tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33)), d * ((tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33) - (tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33)), d * ((tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33) - (tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33)), d * ((tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23) - (tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23)), d * ((tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12) - (tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22)), d * ((tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22) - (tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02)), d * ((tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02) - (tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12)), d * ((tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12) - (tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02)), ]; } function transformMat4(out, vec, mat) { const x = vec; const y = vec; const z = vec || 0; const w = vec || 1; out = mat * x + mat * y + mat * z + mat * w; out = mat * x + mat * y + mat * z + mat * w; out = mat * x + mat * y + mat * z + mat * w; out = mat * x + mat * y + mat * z + mat * w; if (out !== 0) { out /= out; out /= out; out /= out; out /= out; } return out; } </code></pre> https://computergraphics.stackexchange.com/q/13807 1 Nomenclature: Other word for non-closed polygon? Amos Egel https://computergraphics.stackexchange.com/users/7389 2023-11-16T09:43:56Z 2023-11-16T09:59:27Z <p>In Wikipedia, a <a href="https://en.wikipedia.org/wiki/Polygon" rel="nofollow noreferrer">polygon</a> is defined as a <a href="https://en.wikipedia.org/wiki/Polygonal_chain" rel="nofollow noreferrer"> closed polygonal chain</a>. In other words, the term &quot;polygon&quot; implies that the curve is closed.</p> <p>My question is: Is it common to refer to non-closed, piecewise linear curves as &quot;polygons&quot;, too? Otherwise, is there a different term that describes general polygonal chains (other than &quot;polygonal chain&quot; which I find a bit long)?</p> https://computergraphics.stackexchange.com/q/13805 -1 How can I change the dpi of an image? B. Clay Shannon-B. Crow Raven https://computergraphics.stackexchange.com/users/20852 2023-11-12T16:18:55Z 2023-11-12T16:18:55Z <p>I tried <a href="https://clideo.com" rel="nofollow noreferrer">this site</a> to change the dpi of an image, but it didn't really change anything, based on the size of the image and the image properties displayed when I opened the &quot;converted&quot; image in IrfanView (and the fact that kdp still complained about it being a 73 dpi image).</p> <p>Here's the image.</p> <p><a href="https://i.stack.imgur.com/Ma5Gj.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Ma5Gj.jpg" alt="enter image description here" /></a></p> https://computergraphics.stackexchange.com/q/13804 2 Raymarching Refraction Griffin S. https://computergraphics.stackexchange.com/users/20847 2023-11-11T20:11:03Z 2023-11-18T21:19:50Z <p>I'm sorry if this question is imprecise, or violates any guidelines. This is my first post on Stack Exchange, so any feedback is welcome.</p> <p>I am working on a ray-marcher in my spare time, which you can see for reference at <a href="https://replit.com/@GriffinSchreibe/My-First-Raymarcher" rel="nofollow noreferrer">https://replit.com/@GriffinSchreibe/My-First-Raymarcher</a> (Please press view code to see what's happening, as it does not output anything to the console you can see just from viewing the project). Yes, I am working on an online IDE, purely because I do not have sufficient compute power on my laptop. My code is <strong>heavily</strong> based on Ray-tracing in one weekend. I have gradually worked through the first few sections, but one section has been stumping me, namely the refraction section.</p> <p>In my code I have this function that returns the ray color, given a ray shot from the camera:</p> <pre><code>vec3 ray_color(const ray &amp;r, int depth, float current_medium_ior = 1) { // A medium ior of 1 means air. if (depth &lt;= 0) { return vec3(0, 0, 0); } // setup parameters and variables float total_distance_traveled = 0.0; const int NUMBER_OF_STEPS = 64; // 32; const float MAXIMUM_HIT_DISTANCE = 0.001; const float MAXIMUM_TRACE_DISTANCE = 1000.0; vec3 color; // iterate through the max number of steps for (int i = 0; i &lt; NUMBER_OF_STEPS; ++i) { // update the position vec3 current_position = r.origin() + total_distance_traveled * r.direction(); // find the distance Surface closest_surface = map_the_world(current_position); float distance_to_closest = step_size * closest_surface.sd; // if we hit something float abs_dist = abs(distance_to_closest); if (abs_dist &lt; MAXIMUM_HIT_DISTANCE) { vec3 normal = calculate_normal(current_position); vec3 direction; float new_medium_ior = closest_surface.ior; if (closest_surface.surface_type == &quot;REFRACTIVE&quot;) { // Check if the medium has changed if (new_medium_ior != current_medium_ior) { std::clog&lt;&lt;&quot;Medium change!\n&quot;; float ior_ratio = new_medium_ior / current_medium_ior; vec3 direction = refract(r.direction(), normal, ior_ratio); // Recursion color = ray_color(ray(current_position + 0.004 * direction, direction), depth - 1, current_medium_ior); return color; } else { // Continue with loop for further intersections within the medium or other behavior } } else { direction = closest_surface.scatter_direction(r.direction(), normal); // Catch degenerate scatter direction if (direction.near_zero()) direction = normal; // Recursion. color = 0.5 * ray_color(ray(current_position + 0.004 * normal, direction), depth - 1, current_medium_ior); return color; } } // if we have been going for too long if (total_distance_traveled &gt; MAXIMUM_TRACE_DISTANCE) { break; } // update the distance total_distance_traveled += distance_to_closest; } // if we didn't find anything // then we do a blue-white gradient. vec3 unit_direction = unit_vector(r.direction()); auto a = 0.5 * (unit_direction.y() + 1.0); return (1.0 - a) * vec3(1.0, 1.0, 1.0) + a * vec3(0.5, 0.7, 1.0); } </code></pre> <p>As you can see, I attempt to implement refraction, but only when the medium changes. After weeks of toil, I am still perplexed as to how to properly implement ray-marched refraction in the spirit of Ray-tracing in one Weekend (By that I mean no &quot;hacky&quot; solutions).</p> <p>I would be deeply grateful to anyone who could help me solve this problem. Oh, and you can play around with the code in the link above.</p> <p>EDIT: After fixing the medium change check to see if the origin medium was different from the current medium, I am now getting the refracting sphere as blue. I think that what is happening is that the step size is getting tiny inside the material, as I had the Distance Estimator return 0 inside the material. It then ran out of steps, and returned sky color. I am still curious about the best way to stop the ray-marcher running out of steps, though.</p> https://computergraphics.stackexchange.com/q/13803 1 Why does my implementation of a sinusoidally time-varying color work so slowly? Doobius https://computergraphics.stackexchange.com/users/20840 2023-11-11T16:55:51Z 2023-11-11T16:55:51Z <p>I've been following TheCherno's OpenGL tutorials and I got to the point where I could render a square by using an index buffer. Now I wanted to vary the color of the square by using <span class="math-container">$$\frac{\sin(t) + 1}{2}$$</span> as my normalized time-varying function to be used in each of the RGB entries in color. I thought I might proceed as follows: this is my fragment shader.</p> <pre><code>#shader fragment #version 330 core layout(location = 0) out vec4 color; uniform float time; float time_Color(float t) { return (sin(t) + 1) / 2; } void main() { color = vec4(time_Color(time), time_Color(time - 0.2), time_Color(time - 0.4), 1.0f); } </code></pre> <p>in my main loop in main.cpp, I have:</p> <pre><code>int location = glGetUniformLocation(theProgram, &quot;time&quot;); //Main loop glfwSetTime(0); while (!glfwWindowShouldClose(mainWindow)) { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glUniform1f(location, static_cast&lt;float&gt;(glfwGetTime())); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); glfwSwapBuffers(mainWindow); glfwWaitEvents(); } </code></pre> <p>When I run this program, I do see a color-varying square but the change in color becomes slower and slower as the program continues. Initially the change is gradual but then sometime after like 7 secs, I start to get abrupt changes in color that only get updated after a long time. I suspect this is to do with the sin computation in the GPU but I don't actually know since I'm just beginning out. So why is this code working so slowly/inefficiently the longer the program executes?</p> https://computergraphics.stackexchange.com/q/13801 1 k-torus code in C++ shawn_halayka https://computergraphics.stackexchange.com/users/20471 2023-11-08T19:50:09Z 2023-11-11T04:02:21Z <p>I've been trying to implement this k-torus code that I found, but all it does is return a cylinder (torus of outer radius infinity). Is there anything that I'm missing here?</p> <pre><code>#include &quot;main.h&quot; float f(const float x, const int n) { float result = 1.0; for(int i = 1; i &lt;= n; i++) { const float i_float = static_cast&lt;float&gt;(i); result *= (result - (i_float - 1.0f)) * (result - i_float); } return result; } float g(const float x, const float y, const int n) { return f(x, n) + powf(y, 2.0); } float h(const float x, const float y, const float z, const int n, const float r, const float R) { return powf(g(x, y, n), 1.0) + powf(z, 2.0) - powf(r, 2.0); } int main(void) { const float grid_max = 10.0; const float grid_min = -grid_max; const size_t res = 100; const bool make_border = true; const float isovalue = 0.1f; const float border_value = 1.0f + isovalue; const int n = 2; const float radius = 0.1f; const float outer_radius = 1.0f; vector&lt;triangle&gt; triangles; vector&lt;float&gt; xyplane0(res*res, 0); vector&lt;float&gt; xyplane1(res*res, 0); const float step_size = (grid_max - grid_min) / (res - 1); size_t z = 0; vertex_3 pos(grid_min, grid_min, grid_min); // Calculate xy plane 0. for (size_t x = 0; x &lt; res; x++, pos.x += step_size) { pos.y = grid_min; for (size_t y = 0; y &lt; res; y++, pos.y += step_size) { if (true == make_border &amp;&amp; (x == 0 || y == 0 || z == 0 || x == res - 1 || y == res - 1 || z == res - 1)) xyplane0[x * res + y] = border_value; else xyplane0[x * res + y] = h(pos.x, pos.y, pos.z, n, radius, outer_radius); } } // Prepare for xy plane 1. z++; pos.z += step_size; size_t box_count = 0; // Calculate xy planes 1 and greater. for (; z &lt; res; z++, pos.z += step_size) { pos.x = grid_min; cout &lt;&lt; &quot;Calculating triangles from xy-plane pair &quot; &lt;&lt; z &lt;&lt; &quot; of &quot; &lt;&lt; res - 1 &lt;&lt; endl; for (size_t x = 0; x &lt; res; x++, pos.x += step_size) { pos.y = grid_min; for (size_t y = 0; y &lt; res; y++, pos.y += step_size) { if (true == make_border &amp;&amp; (x == 0 || y == 0 || z == 0 || x == res - 1 || y == res - 1 || z == res - 1)) xyplane1[x * res + y] = border_value; else xyplane1[x * res + y] = h(pos.x, pos.y, pos.z, n, radius, outer_radius); } } tesselate_adjacent_xy_plane_pair( box_count, xyplane0, xyplane1, z - 1, triangles, isovalue, grid_min, grid_max, res, grid_min, grid_max, res, grid_min, grid_max, res); xyplane1.swap(xyplane0); } cout &lt;&lt; endl; if (0 &lt; triangles.size()) write_triangles_to_binary_stereo_lithography_file(triangles, &quot;out.stl&quot;); // Print box-counting dimension // Make sure that step_size != 1.0f :) cout &lt;&lt; &quot;Box counting dimension: &quot; &lt;&lt; logf(static_cast&lt;float&gt;(box_count)) / logf(1.0f/step_size) &lt;&lt; endl; return 0; } </code></pre> <p><a href="https://i.stack.imgur.com/iZYnf.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/iZYnf.png" alt="enter image description here" /></a></p> <p>The relevant documents are at:</p> <p><a href="https://computergraphics.stackexchange.com/questions/13794/procedural-generation-of-genus-k-tori-triangle-meshes">Procedural generation of genus $k$ tori triangle meshes</a></p> <p>and</p> <p><a href="https://math.stackexchange.com/questions/152256/implicit-equation-for-double-torus-genus-2-orientable-surface">https://math.stackexchange.com/questions/152256/implicit-equation-for-double-torus-genus-2-orientable-surface</a></p> <p>and</p> <p><a href="https://github.com/sjhalayka/k-torus" rel="nofollow noreferrer">https://github.com/sjhalayka/k-torus</a></p> https://computergraphics.stackexchange.com/q/13797 1 Fixing bias in Specular lobe Consuelo Ugarte https://computergraphics.stackexchange.com/users/20817 2023-11-06T01:27:40Z 2023-11-18T19:46:30Z <p>Im currently making some modifications for a <a href="https://github.com/chunky-dev/chunky" rel="nofollow noreferrer">path tracer for Minecraft</a>, specifically adding glossy refractions. The program currently uses for specular reflections <a href="https://blog.demofox.org/2020/06/06/casual-shadertoy-path-tracing-2-image-improvement-and-glossy-reflections/" rel="nofollow noreferrer">this method</a>, linear interpolation between the diffuse lobe and the perfect specular refection depending on the roughness parameter. However this introduces a direction bias that is quite noticeable in renders. Here I have reproduced in in python, the red line is the mean vector while the green line is the specular refection for roughness values of 1, 0.7, 0.5, 0.3, 0.1 and 0. <a href="https://i.stack.imgur.com/ELDeI.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ELDeI.png" alt="enter image description here" /></a></p> <p>What would be the best way to correct for this bias without introducing substantial computation overhead. I do plan evenly to include more sophisticated BSDF like Cook-Tolerance in the renderer but wanted to have simpler model as an option.</p> https://computergraphics.stackexchange.com/q/13783 0 Constructing half-edges table from triangle list without hash lightxbulb https://computergraphics.stackexchange.com/users/10096 2023-10-28T23:57:11Z 2023-11-28T20:02:05Z <p><strong>Motivation</strong></p> <p>I am trying to refine a mesh such that each triangle gets subdivided into 4 triangles, but I want the vertices to be shared. For that purpose I need a half-edge data structure so I can count and address the vertices on the edges properly. The problem below is formulated a bit more generally - it just assumes a given index list, and doesn't even provide the vertices coordinates. The problem is in 3D, so sorting based on angles for DCEL construction will not work.</p> <p><strong>Problem Statement</strong></p> <p>I am given an index list <span class="math-container">$T = [i_{0}, i_{1}, i_{2}, \ldots, i_{3(n-1)}, t_{3(n-1)+1}, t_{3(n-1)+2}]$</span> of triplets of vertex indices corresponding to a specific triangle. Here <span class="math-container">$i_{3k+j}$</span> is the index of the <span class="math-container">$j$</span>-th vertex in the <span class="math-container">$k$</span>-th triangle (I have <span class="math-container">$n$</span> triangles in the above). I define <span class="math-container">$n(j) = 3\cdot\lfloor j/3\rfloor + \bigl(((j \text{ mod } 3)+1)\text{ mod }3\bigr)$</span>. This cyclically gives me the next index belonging to the same triangle. For example:</p> <p><span class="math-container">$$n(0) = 1, \,n(1) = 2,\, n(2) = 0,\, n(3) = 4, \, n(4) = 5,\, n(5) = 3, \ldots$$</span><br /> I want to build a half-edge table: a table such that <span class="math-container">$(h(j) = k)\land (h(k) = j) \iff (i_j = i_{n(k)})\land (i_{n(j)}=i_k)$</span>. Given a half-edge index <span class="math-container">$j$</span> it returns the index corresponding to the half-edge in the opposite triangle. I am trying to avoid using a hash table since I don't have a nice implementation in C and I don't plan to implement my own (though if you have any good suggestions for hash table code I'll gladly have a look, but that's outside the scope of the question really - I will still be curious about suggestions not using a hash table even if I have one).</p> <p><strong>My Algorithm</strong></p> <p>What I came up with is to iterate over all triangles and count the number of triangles per vertex (meaning I have an array <span class="math-container">$nt(i) = \text{# adjacent triangles to vertex$i$}$</span>, for <span class="math-container">$0\leq i \leq m-1$</span>, where <span class="math-container">$m$</span> is the number of vertices). Once I have the count I can allocate a compressed row storage matrix with <span class="math-container">$nt(i)$</span> elements per vertex (<span class="math-container">$row(i) = nt(i-1) + row(i-1)$</span>), and fill a triangle adjacency matrix <span class="math-container">$A$</span> with the indices of the adjacent triangles. Then for each vertex in the matrix I can go over pairs of its triangles (<span class="math-container">$C^{nt(i)}_{2}$</span> such pairs) and link those that share an edge (in a closed mesh I can even sort them). As long as <span class="math-container">$n(i)$</span> is not too large this is not very problematic. For simplicity one may assume that the mesh is manifold (an edge has no more than two adjacent faces) and that it is orientable (no funny Mobius strip stories), although I think the latter is not as important as I don't care about the orientation of the halfedges, I just need face adjacency.</p> <p><strong>Question</strong></p> <p>My question is whether someone has any better ideas for an algorithm, or suggestions for improvements of the above (or pointing out a mistake)?</p> https://computergraphics.stackexchange.com/q/13766 0 How to correctly handle rendering of ~600000, arbitrary colored 2D squares with WebGL? h4ckthepl4net https://computergraphics.stackexchange.com/users/20720 2023-10-20T08:57:52Z 2023-11-19T11:01:35Z <h2>Information</h2> <p>I have to render a map, that is rendered as a 2d collection of squares of different color, separated by white lines horizontally and vertically. There may be ~600000 squares surrounded by white area, and the actual borders of the map are arbitrary, only one part of map will be visible at a time, so it must not be rendered fully at once (the map is scrollable). The map is interactive, so it must change the color of square when hovering (dark green square) and it is possible to select some rectangle area (purple square collection), zoom in zoom out + a minimap to quickly move from one point to another. There are blue squares that are owned, and they have borders like in images. As an addition there can be images attached to any owned rectangular area.</p> <h2>Actual Implementation</h2> <p>Below is the current implementation which is based on html canvases, and it is not as performant as I want, so I decided to use webgl for rendering.</p> <p><a href="https://i.stack.imgur.com/UxyzB.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/UxyzB.png" alt="enter image description here" /></a></p> <p><a href="https://i.stack.imgur.com/Mn3fO.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Mn3fO.png" alt="enter image description here" /></a></p> <p><a href="https://i.stack.imgur.com/URJfH.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/URJfH.png" alt="enter image description here" /></a></p> <h2>What I've Tried / Research</h2> <p>I tried using ThreeJS to achieve this, but I think it is mostly 3d oriented and also it has many unwanted functionality that I will not use, so I decided to go with bare minimum. I've tried to write some fragment shaders, and achieved some functionality (selected area, hovered object). I am quite new to WebGL/OpenGL, I've read somewhere that it is possible to pass buffer to fragment shader as a texture, and I was thinking about forming a buffer of UInt8 from whole map (even the empty area, for shader to be able to correctly draw borders) and passing it to fragment shader, which will distinguish the state by number of each element and draw the squares accordingly. But then I realized that even before adding images functionality much load will be offloaded to fragment shader, and it was not clear will the fragment shader be able to handle all this much load alone. Doing some research I found out that it is possible to use points and their size parameter to achieve this, and I think that it could be beneficial to split some of work to vertex shader, instead of doing everything in fragment shader.</p> <h2>What I want to achieve</h2> <p>I want to be able to render this map on nearly every device, because in my opinion current hardware is able to do this kind of work very efficiently and very performant. I understand that it is very dependent on implementation, so here are my questions:</p> <h2>Question</h2> <p>Will it give some performance improvements or will it be worse to offload this type of work to vertex shader and draw each square as a point? What abilities of WebGL or techniques can I use (or are mostly used) to handle this kind of situation? How can I achieve performant rendering in case when there are multiple images?</p> https://computergraphics.stackexchange.com/q/13696 1 Is it possible to read arbitrary data at arbitrary array offset in glsl? Tare https://computergraphics.stackexchange.com/users/7008 2023-09-07T11:11:29Z 2023-11-15T18:03:20Z <p><em><strong>TL;DR</strong></em></p> <p>In a Vulkan / GLSL ray tracing program, I have several shader files, all accessing the same material buffer of arbitrary data. All materials have an arbitrary layout, e.g. one might be a float, one might contain two vec3s and a float. Can I access a buffer (i.e. an array of uint type) with just an offset <em>within the shader (i.e. the same buffer binding is shared, I cannot use dynamic offsets set on the CPU side)</em> and read out a struct without having to read every member of the struct individually? I am aware of not being able to read a vec3 from a buffer as just 3 values, but that is not my problem. Just assume I only read good data types that don't waste space.</p> <p>See in the image, I want to access at the given green position with just knowing the size of the struct that will follow at that position.</p> <p><a href="https://i.stack.imgur.com/27ZwK.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/27ZwK.png" alt="Image of buffer data and where to access it" /></a></p> <p>In C++ it would be something like this:</p> <pre><code>uint32_t* buffer; //assume this has all the data in it struct mat2 { glm::vec3 data1; float data2; } //the following line is what I try to achieve mat2 matData = *((mat2)(buffer+offset); </code></pre> <p><em><strong>Long explanation</strong></em></p> <p>I am trying to setup a buffer that contains material parameters. The problem is that I have to support a large number of materials, that may differ drastically in number of parameters, e.g. there might be an entry with two uints and then an entry with five floats.</p> <p>Since I assume using one buffer per material is bad (due to the number of layouts bindings I'd have to use) I wanted to tightly pack the material parameters into a single byte buffer and readout from the shader with a known offset to the material for the hit geometry. I have a shader file per material, so no material is aware of other material structs - it just knows the offset into the array for its own data.</p> <p>While I have basically set up the buffer (though apperantly the smallest chunks I am allowed to use are 4 bytes), I have trouble actually reading out of this buffer in GLSL. Given a simple struct for one material:</p> <pre><code>struct BlinnPhongParams { vec3 diffuse; vec3 specular; float specIntensity; }; </code></pre> <p>And the material buffer:</p> <pre><code>layout(binding = 123, set = 0) readonly buffer MaterialParamsBuffer { uint[] data; }uMaterialParamsBuffer; </code></pre> <p>Currently I am reading every member from the buffer individually:</p> <pre><code>BlinnPhongParams getMaterialParams(uint offset) { BlinnPhongParams bpParams = BlinnPhongParams( //DiffuseCol vec3( uintBitsToFloat(uMaterialParamsUintBuffer.data[offset]), uintBitsToFloat(uMaterialParamsUintBuffer.data[offset+1]), uintBitsToFloat(uMaterialParamsUintBuffer.data[offset+2])), //SpecularCol vec3( uintBitsToFloat(uMaterialParamsUintBuffer.data[offset+3]), uintBitsToFloat(uMaterialParamsUintBuffer.data[offset+4]), uintBitsToFloat(uMaterialParamsUintBuffer.data[offset+5])), //SpecIntensity uintBitsToFloat(uMaterialParamsUintBuffer.data[offset+6]) ); return bpParams; } </code></pre> <p>I would like to make reading from this buffer as easy as possible, ideally just say &quot;at this offset, I have a struct that looks like this&quot;, e.g. I would like to have something like this:</p> <pre><code>BlinnPhongParams getMaterialParams(uint offset) { // here is the problem BlinnPhongParams params = BlinnPhongParams(&amp;uMaterialParamsBuffer.data[offset]); } </code></pre> <p>Is this possible?</p> https://computergraphics.stackexchange.com/q/13562 0 Storing array of floats within shader user20154 https://computergraphics.stackexchange.com/users/20154 2023-06-29T07:51:38Z 2023-11-28T15:05:00Z <p>I am about to implement a framerate histogramm chart for a DirectX Renderer.</p> <p>Ideally I would do this in pure shader code, but for a a histogramm I need to store the timestamps of the last <code>x</code> frames. I guess I could store these to a texture, but I was wondering if there is a more appropriate way to achieve that?</p> <p>Thanks!</p> https://computergraphics.stackexchange.com/q/13554 0 Triangle Rasterization Shaking Issues Serilena https://computergraphics.stackexchange.com/users/18064 2023-06-25T17:35:32Z 2023-11-22T19:03:40Z <p>I am making a Software renderer, and I noticed that there is a screen shaking like effect happening. shown in the first <a href="https://ufile.io/uov1de8z" rel="nofollow noreferrer">video</a>:</p> <p>I tried doing filling without clipping against the small square, and the result is much better, yet, there is some sort of shaking on the edges as shown in the second <a href="https://ufile.io/hkcymcii" rel="nofollow noreferrer">video</a></p> <p>Finally I tried drawing the clipped triangles outline, and the shaking is more apparent as shown in the third <a href="https://ufile.io/uexgf1wk" rel="nofollow noreferrer">video</a></p> <p>My initial assumption was the line drawing was not accurate enough, so I tried both DDA and Bresenham line drawing without any success.</p> <p>Additionally, I tried different triangulation schemes, I noticed that when I increase the number of created triangles (such as when I triangulate a square using the center as a new vertex instead of using one of the corners) the shaking gets worse. That led me to believe to the issue is related to shared edges in the triangles, and indeed in my triangle filling algorithm, I tried to remove the shared edge and got a bit better results (but it introduced different artifacts, some pixels were missing): <a href="https://git.sr.ht/%7Ealiabdulkareem/SoftwareRenderer/tree/FixTrianglulation/item/src/drawing.cpp#L450" rel="nofollow noreferrer">https://git.sr.ht/~aliabdulkareem/SoftwareRenderer/tree/FixTrianglulation/item/src/drawing.cpp#L450</a></p> <p>That did not however remove it entirely (I believe I should remove the shared edges from the triangulation phase as well, not entirely sure how to do that, one idea is when I triangulate the triangles after the first one, I always more pixel in the direction of the two newly formed edges)</p> <p>Also it does not explain entirely the second video shaking when there was a shared edge in the diagonal of a square, but it was fine, while the square edges were shaking despite not sharing an edge.</p> <p>I am a bit puzzled as how to debug this as I can at least think of three different reasons:</p> <p>1- Triangulation is wrong</p> <p>2- Floating point inaccuracy</p> <p>3- Aliasing (I heard that in animations, aliasing becomes very clear, not sure if that is the case)</p> <p>Full source code: <a href="https://git.sr.ht/%7Ealiabdulkareem/SoftwareRenderer/tree/FixTrianglulation" rel="nofollow noreferrer">https://git.sr.ht/~aliabdulkareem/SoftwareRenderer/tree/FixTrianglulation</a></p> https://computergraphics.stackexchange.com/q/13389 2 How to properly use the BRDF from glTF 2.0 specification in path tracing while using metallic/roughness materials? AllenTeehrsie https://computergraphics.stackexchange.com/users/19804 2023-04-04T12:49:53Z 2023-11-18T22:05:15Z <p>I've built a renderer which should render glTF materials, as they are defined in their <a href="https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#materials" rel="nofollow noreferrer">specification</a>. So I should be able to render satisfying (similar to Cycles and Ospray) results just from the base color, metallic and roughness factors. I've implemented their suggested <a href="https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#appendix-b-brdf-implementation" rel="nofollow noreferrer">BRDF</a>, but I'm afraid I'm using it wrong, or I'm making a mistake somewhere else.</p> <p>I'll now describe the steps in my renderer, using the simplest example: light is given by an HDR background and there is one object in the scene with <strong>roughness = 0 and metallic = 1</strong>. I've also attached a sketch of what I'm talking about so it's easier to follow.</p> <p>Steps in bouncing:</p> <ol> <li>Ray is shot from the camera</li> <li>Ray hits object</li> <li>Ray bounces in a mirror-like fashion because of the mentioned material properties</li> <li>Ray hits HDR (hit on the HDR = miss all other objects)</li> <li>Path ends</li> </ol> <p>Reporting works like this:</p> <ol> <li>I have the entire path with all three points (HDR, object, camera).</li> <li>I start from the HDR and assign the path RGB values to the RGB values at the sampled point on the HDR. For example, path.RGB = (0.2, 0.8, 0.9).</li> <li>I continue along the path and come to the point on the object. From the intersection data I get all the necessary information (base color, metallic, roughness and the normal at that point).</li> <li>I provide all that info to the BRDF function and it returns some RGB values.</li> <li>I multiply the RGB values which I got from the BRDF with the current path RGB (which is just the HDR values at this point) and that becomes the new path RGB.</li> <li>I get to the camera point, and save the path RGB for writing to image later.</li> </ol> <p>I simplified some parts which I'm fairly certain are not the cause of the problem, like the distance dependency and sampling and stuff like that.</p> <p>So to get to the <strong>actual problem</strong>,</p> <p>at the second point on the path (object intersection), my <strong>light vector</strong> is pointing towards the point on the HDR and my <strong>view vector</strong> is pointing towards the camera. Since the roughness at this point is 0, these two vectors are mirror images of one another, around the normal vector. So their <strong>half vector</strong> is the same vector as the <strong>normal vector</strong>. And when H (half vector) and N (normal vector) are the same, the BRDF produces a specular highlight, that happens because the D term (Trowbridge-Reitz/GGX microfacet distribution) ends up as a ridiculously large value. Now I'm aware that this should happen, If I were to use a point light source instead of the HDR, I would get the appropriate specular highlight, but that's because the light vector in that case is defined by the position of point light, and only a few points on the surface would fulfill the condition where H and N are the same (or no rays would in case of no roughness and point light with no radius). Problem appears when the light direction is the next point on the path since the direction towards it is the perfect reflection of the incident ray.</p> <p>In the image I've attached, all rays hitting the object would bounce mirror-like, and each point on the object would be considered a specular highlight by the BRDF and it would return RGB values which go up to 8e14. By multiplying the path.RGB with those values, I would break the energy conservation, so currently I normalize them, but that also leads to problems. Black objects report with values around 5e10, and white objects as 8e14, as mentioned. Both end up normalized to (1, 1, 1) and look the same, even though they're opposites.</p> <p>Now I'm not sure where exactly I'm I making a mistake, I've had my implementation of the BRDF checked multiple times, it's exactly like the specification.</p> <p>Is my mistake considering the light vector to be the next (or previous, depends where you start from) point on the path? Or is it something else?</p> <p><a href="https://i.stack.imgur.com/y4qsf.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/y4qsf.jpg" alt="Example" /></a></p> https://computergraphics.stackexchange.com/q/13302 0 How to properly create textures using DSA for ImageTexture in OpenGL Liyuu_ https://computergraphics.stackexchange.com/users/19593 2023-02-17T15:26:08Z 2023-11-19T20:01:35Z <p>For the old approach, generating a texture for the ImageTexture for compute shaders would look like this:</p> <pre><code>glGenTextures(1, &amp;m_texture); glBindTexture(GL_TEXTURE_2D, m_texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, (GLsizei)m_width, (GLsizei)m_height, 0, GL_RGBA, GL_FLOAT, nullptr); </code></pre> <p>However, in DSA, glTexImage2D is no longer a thing and we need to use <code>glTextureStorage2D</code> and <code>glTextureSubImage2D</code> to replace it. Yet, the new DSA functions don't work with ImageTextures, when I try to create texture for the ImageTextures, the texture returns black. Here is the code:</p> <pre><code>glCreateTextures(GL_TEXTURE_2D, 1, &amp;m_texture); glTextureStorage2D(m_texture, 0, m_internalFormat, (GLsizei)width, (GLsizei)height); glTextureParameteri(m_texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTextureParameteri(m_texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTextureParameteri(m_texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTextureParameteri(m_texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTextureSubImage2D(m_texture, 0, 0, 0, (GLsizei)width, (GLsizei)height, m_dataFormat, GL_UNSIGNED_BYTE, nullptr); </code></pre> <p>I've read about that the new DSA functions are immutable textures and maybe that causes this problem? If that is the case, what is the DSA counterpart for creating mutable textures?</p> https://computergraphics.stackexchange.com/q/13250 4 cosine term in rendering equation Rahn https://computergraphics.stackexchange.com/users/3242 2023-01-31T08:39:39Z 2023-11-14T11:06:45Z <p>Rendering equation's value can be estimated with Monte Carlo (<a href="https://www.pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection" rel="nofollow noreferrer">Physically Based Rendering: Light Transport I: Surface Reflection</a>):</p> <p><span class="math-container">$\begin{equation} \begin{split} L_o(p, \omega_o) &amp;= \int_{S^2}f(p, \omega_o, \omega_i) L_i(p, \omega_i) |\cos\theta_i| \mathrm{d}\omega_i\\ &amp; = \frac{1}{N} \sum_{j=1}^{N} \frac{f(p, \omega_o, \omega_i) L_i(p, \omega_j) |\cos\theta_j|}{p(\omega_j)} \end{split} \end{equation}$</span></p> <p>So if the hit surface is a mirror and <span class="math-container">$\omega_j$</span> is the correct direction (only 1 sample is needed and <span class="math-container">$p(\omega_j)=1$</span>) then this equation becomes:</p> <p><span class="math-container">$\begin{equation} \begin{split} L_o(p, \omega_o) &amp; = f(p, \omega_o, \omega_i) L_i(p, \omega_j) |\cos\theta_j| \end{split} \end{equation}$</span></p> <p>For a ideal mirror that reflect without any energe loss, <span class="math-container">$f(p, \omega_o, \omega_i)$</span> is 1.</p> <p>Yet I couldn't find term <span class="math-container">$\cos\theta_j$</span> when reading code from Ray Tracing Weekend and smallpt.</p> <p>In Ray Tracing Weekend, the <a href="https://github.com/RayTracing/raytracing.github.io/blob/master/src/TheRestOfYourLife/main.cc#L25" rel="nofollow noreferrer">ray tracing function</a> is written as</p> <pre class="lang-cpp prettyprint-override"><code>color ray_color( const ray&amp; r, const color&amp; background, const hittable&amp; world, shared_ptr&lt;hittable&gt; lights, int depth ) { hit_record rec; // If we've exceeded the ray bounce limit, no more light is gathered. if (depth &lt;= 0) return color(0,0,0); // If the ray hits nothing, return the background color. if (!world.hit(r, 0.001, infinity, rec)) return background; scatter_record srec; color emitted = rec.mat_ptr-&gt;emitted(r, rec, rec.u, rec.v, rec.p); if (!rec.mat_ptr-&gt;scatter(r, rec, srec)) return emitted; if (srec.is_specular) { return srec.attenuation * ray_color(srec.specular_ray, background, world, lights, depth-1); } ... </code></pre> <p>The last part</p> <pre><code> if (srec.is_specular) { return srec.attenuation * ray_color(srec.specular_ray, background, world, lights, depth-1); } </code></pre> <p>implies that when hitting a specular object, the result (color) got attenuated by <code>srec.attenuation</code> but the cosine term is gone.</p> <p>Similarly, neither <a href="https://www.kevinbeason.com/smallpt/" rel="nofollow noreferrer">smallpt</a> (line 61, 62) include cosine term when handling scatterring for specular object:</p> <pre><code>else if (obj.refl == SPEC) // Ideal SPECULAR reflection return obj.e + f.mult(radiance(Ray(x,r.d-n*2*n.dot(r.d)),depth,Xi)); </code></pre> <p>it shoots a ray to a new direction without having <span class="math-container">$\cos(\theta)$</span> after reflection.</p> <p>So, how does <span class="math-container">$\cos(\theta)$</span> got cancelled for both renderer? Or did I misunderstand the equation?</p> https://computergraphics.stackexchange.com/q/12470 0 OpenGL ignores glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); ahoffer https://computergraphics.stackexchange.com/users/17868 2022-01-18T02:21:04Z 2023-11-12T00:07:45Z <p>I'm learning OpenGL for a personal project. I need to draw a triangle mesh as a wireframe. From what I've read, I can do this using glPolygonMode. However, the program always draws my polygons filled. Is is a bad driver? I'm using the linux subsystem on a chromebook. It's basically debian in a container. How do I get an wireframe triangle?</p> <p>Here is my program, with all the windowing functions and the shader compilation pulled into their own .cpp file.</p> <pre><code>#include &lt;glad/glad.h&gt; #include &lt;GLFW/glfw3.h&gt; #include &lt;glm/glm.hpp&gt; #include &lt;iostream&gt; #include &quot;ah_graphics.h&quot; #include &quot;ah_window.h&quot; const char *vertexShaderSource(); const char *fragmentShaderSource(); // set up vertex data (and buffer(s)) and configure vertex attributes // ------------------------------------------------------------------ float positions[] = { -1.0f, 1.0f, 0.0f, // left -1.0f, 0.0f, 0.0f, // right 0.0f, 1.0f, 0.0f // top }; int main() { GLFWwindow *window = ahCreateWindow(800, 600); ahLoadGlFunctionPointers(); GLuint program = ahCreateGlProgram(vertexShaderSource(), fragmentShaderSource()); unsigned int VBO_pos, VAO; glGenVertexArrays(1, &amp;VAO); glBindVertexArray(VAO); glGenBuffers(1, &amp;VBO_pos); glBindBuffer(GL_ARRAY_BUFFER, VBO_pos); glBufferData(GL_ARRAY_BUFFER, sizeof(positions), positions, GL_STATIC_DRAW); int numComponents = 3; // (x,y,z) and (r,g,b) std::size_t stride = numComponents * sizeof(float); glVertexAttribPointer(0, numComponents, GL_FLOAT, GL_FALSE, stride, (void *) 0); glEnableVertexAttribArray(0); while (!glfwWindowShouldClose(window)) { // input ahProcessInput(window); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(program); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDrawArrays(GL_TRIANGLES, 0, 3); glfwSwapBuffers(window); glfwPollEvents(); } return 0; } const char *vertexShaderSource() { return &quot;#version 330 core\n&quot; &quot;layout (location = 0) in vec3 aPos;\n&quot; &quot;void main()\n&quot; &quot;{\n&quot; &quot; gl_Position = vec4(aPos, 1.0);\n&quot; &quot;}\0&quot;; } const char *fragmentShaderSource() { return &quot;#version 330 core\n&quot; &quot;void main()\n&quot; &quot;{\n&quot; &quot; gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n&quot; &quot;}\n\0&quot;; } </code></pre> <p>And this is the scene it renders: <a href="https://i.stack.imgur.com/u4YIk.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/u4YIk.png" alt="enter image description here" /></a></p> https://computergraphics.stackexchange.com/q/12457 1 Opengl GLSL binding locations confusion Thomas https://computergraphics.stackexchange.com/users/13273 2022-01-13T09:29:31Z 2023-11-17T09:49:11Z <p>The background of this question is that I am trying to write an automatic binding system, where for each uniform variable I want to declare in my GLSL code, I call a method <code>declareUniform</code> which is counting up the location value, saving the type and name of the uniform to a list which will be saved within my shaderobject...</p> <p>I already did something similar with varyings, where I save the varying information (location, type, name, shader stage from, shader stage to, isarray, arraycount) and of cause also generating glsl string which is working fine.</p> <p>I am trying to bind several things to a shader, which does not work right now. I've read, that uniform block binding indices have nothing to do with sampler binding locations <a href="https://stackoverflow.com/questions/49097947/glsl-uniform-layout-binding-and-textures">here</a>, which is totally confusing me... I also read the <code>Explicit_uniform_location</code> site from khronos <a href="https://www.khronos.org/opengl/wiki/Layout_Qualifier_(GLSL)#Explicit_uniform_location" rel="nofollow noreferrer">here</a>. I am trying to bind some sampler2D, image2D and other uniforms in one shader.</p> <pre><code>layout(location = 0) in vec2 texCoordIn; //value from VBO layout(binding = 0, rgba32f) uniform image2D writeColorTexture; layout(binding = 1) uniform sampler2D readColorTexture; layout(location = 0) uniform float u_apature; layout(location = 1) uniform float u_focalDistance; ... </code></pre> <p>On CPU it looks like this:</p> <pre><code>GLint readColorTextureLoc = glGetUniformLocation(glShaderHandle, &quot;readColorTexture&quot;); GLint writeColorTextureLoc = glGetUniformLocation(glShaderHandle, &quot;writeColorTexture&quot;); </code></pre> <p>trying to bind the samper2D:</p> <pre><code>glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); glUniform1i(readColorTextureLoc, 0); glBindTexture(GL_TEXTURE_2D, colorTexture-&gt;id()); </code></pre> <p>trying to bind the image2D:</p> <pre><code>glBindImageTexture(writeColorTextureLoc, colorImage-&gt;id(), 0, GL_TRUE, 0, GL_WRITE_ONLY, GL_RGBA32F); </code></pre> <p>when using <code>glGetUniformLocation(glShaderHandle, &quot;readColorTexture&quot;);</code> I get the value 31 which also confuses me. This brought me to understand it to the following way: <code>layout(location = ...) uniform</code> is the value which will be returned by <code>glGetUniformLocation</code>.</p> <p>The binding qualifier maps the uniform variable to a (I'll call it) &quot;background list&quot;, which can be addressed by <code>glActiveTexture</code> for example if it is a sampler. As far as I understood (please correct me if I am wrong!) there are several of these &quot;background lists&quot;. One for samplers, one for block bindings, one for images... and each of them starts with 0.</p> <p>Now my question: Am I right? Did I understand it correctly? If so: which &quot;background lists&quot; are available and how can I bind a sampler together with an Image?</p> https://computergraphics.stackexchange.com/q/12448 2 vulkan perspective matrix vs opengl perspective matrix VersesDev https://computergraphics.stackexchange.com/users/6064 2022-01-10T11:39:02Z 2023-11-16T15:09:53Z <p>Hi I have a slight confusion in using the opengl perspective matrix in vulkan. glm's perspective matrix works directly in vulkan just by multiplying the &quot;[1,1 term by -1 but when I compared the formula for creation of perspective matrix for both the apis.</p> <p>opengl one here:<a href="http://www.songho.ca/opengl/gl_projectionmatrix.html" rel="nofollow noreferrer">http://www.songho.ca/opengl/gl_projectionmatrix.html</a></p> <p>vulkan here:<a href="https://www.youtube.com/watch?v=U0_ONQQ5ZNM" rel="nofollow noreferrer">https://www.youtube.com/watch?v=U0_ONQQ5ZNM</a>( at 12:10)</p> <p>and I see 2 differences: 1st at 1,1 2nd at 2,3: here is my doubt(opengl's is 2 times the one in vulkan.</p> <p>So how does glm's matrix works for my vulkan program just by correcting [1,1 location? Please do correct me if I am making some mistake in understanding the differences in matrix.</p> <p>openglMarix talking about:<a href="https://i.stack.imgur.com/hcIFm.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/hcIFm.jpg" alt="enter image description here" /></a></p> https://computergraphics.stackexchange.com/q/10537 3 How to determine RGB values given a display spectral response curve? Elad Maimoni https://computergraphics.stackexchange.com/users/9154 2021-01-03T22:36:28Z 2023-11-28T16:08:46Z <p>I am reading Physically Based Rendering <a href="http://www.pbr-book.org/3ed-2018/Color_and_Radiometry/The_SampledSpectrum_Class.html#RGBColor" rel="nofollow noreferrer">section 2.2.2 on RGB color</a>.</p> <p>I am trying to understand how, given a display spectral response curves for rgb intensities, we can choose the intensities so that the display will emit an equivalent spectrum (a CIE xyz metamer)</p> <p>It is my understanding that the following section tries to explain exactly that.</p> <blockquote> <p>Given an <em>(x,y,z)</em> representation of an SPD, we can convert it to corresponding RGB coefficients, given the choice of a particular set of SPDs that define red, green, and blue for a display of interest. Given the spectral response curves <em>R(lambda)</em>, <em>G(lambda)</em>, and <em>B(lambda)</em>, for a particular display, RGB coefficients can be computed by integrating the response curves with the SPD <em>S(lambda)</em> and using the tristimulus theory of color perception:</p> </blockquote> <p><span class="math-container">$$r = \int R(\lambda) S(\lambda) d\lambda$$</span></p> <p>I can't understand this formula. Why it is considered correct? Why choosing <em>r</em> this way makes the display emit the correct / equivalent SPD?</p> <p>Can someone break it down for me?</p> https://computergraphics.stackexchange.com/q/8131 1 Normal Artifacts On Grazing Angles Brady Jessup https://computergraphics.stackexchange.com/users/8893 2018-10-09T05:19:14Z 2023-11-29T09:00:40Z <p>I am currently experiencing a very obvious artifact that occurs when looking at objects on very grazing angles</p> <p>Here is a picture of the artifact: <a href="https://i.stack.imgur.com/ZNQL3.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ZNQL3.png" alt="artifact"></a></p> <p>I noticed that the issue was coming from my implementation of Cook-Torrance's Specular BRDF. </p> <p>Here is the equation for the Cook-Torrance Specular BRDF: <a href="https://i.stack.imgur.com/0wcIZ.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/0wcIZ.jpg" alt="Cook-Torrance Specular BRDF"></a></p> <p>More specifically, calculating the denominator is causing the issue:</p> <pre><code>float denominator = 4 * max(dot(viewDir, normal), 0.0) * max(dot(lightDir, normal), 0.0) + 0.001; // Prevents any division by zero </code></pre> <p>When I change the calculation of dot(viewDir, normal) to dot(halfway, normal), the artifact disappears:</p> <pre><code>float denominator = 4 * max(dot(halfway, normal), 0.0) * max(dot(lightDir, normal), 0.0) + 0.001; // Prevents any division by zero </code></pre> <p>But this equation is no longer correct. I was wondering if anyone knows why my implementation causes these artifacts?</p> <p>If you want to see my fragment shader you can find the code here:</p> <p><a href="https://github.com/Ershany/Arcane-Engine/blob/WIP_PBR/Arcane%20Engine%20Core/src/shaders/pbr_model.frag" rel="nofollow noreferrer">https://github.com/Ershany/Arcane-Engine/blob/WIP_PBR/Arcane%20Engine%20Core/src/shaders/pbr_model.frag</a></p> <p>Thank you!</p> https://computergraphics.stackexchange.com/q/2246 5 Which interpolation algorithm does MS Paint on Windows 7 use for image rescaling? dialer https://computergraphics.stackexchange.com/users/3019 2016-03-29T12:48:44Z 2023-11-28T14:03:25Z <p>I was about to scale this image down to 64x64 pixels:</p> <p><a href="https://i.stack.imgur.com/jAk2Z.jpg" rel="noreferrer"><img src="https://i.stack.imgur.com/jAk2Z.jpg" alt="this"></a></p> <p>The result I got on MS Paint on Windows 7 was surprisingly good (i.e. crisp edges):</p> <p><a href="https://i.stack.imgur.com/RaQLu.png" rel="noreferrer"><img src="https://i.stack.imgur.com/RaQLu.png" alt="ms paint rescaled"></a> , whereas scaling it with GIMP resulted in <a href="https://i.stack.imgur.com/8rPmx.png" rel="noreferrer"><img src="https://i.stack.imgur.com/8rPmx.png" alt="cubic GIMP"></a> for cubic and <a href="https://i.stack.imgur.com/EQ33f.png" rel="noreferrer"><img src="https://i.stack.imgur.com/EQ33f.png" alt="lanczos3 GIMP"></a> for Lanczos3 interpolation, both of which look significantly worse to me. Linear and nearest-neighbor was obviously much worse still.</p> <p>I have also written a small program to check all of the interpolation modes available <a href="https://msdn.microsoft.com/en-us/library/system.drawing.drawing2d.interpolationmode.aspx" rel="noreferrer">in the System.Drawing.Drawing2D.InterpolationMode enumeration</a>, to no avail. Unfortunately, most web search results on the topic of interpolation in MS Paint are still from the days before Vista, when nearest neighbor was the only option.</p> <p>Does anyone know which interpolation algorithm the Windows 7 version of MS Paint uses?</p> https://computergraphics.stackexchange.com/q/1470 15 Problem with definition of BSDF and radiance tom https://computergraphics.stackexchange.com/users/1613 2015-09-10T08:28:52Z 2023-11-23T16:54:09Z <p>When I was reading theory behind physical based rendering I noticed that definition of BSDF and radiance has some problems. For example BSDF of purely specular surfaces is zero almost everywhere and infinite in one point or radiance of directional light is zero for almost all directions except for one where it is again infinite.</p> <p>This causes problems in rendering equation.</p> <p>$$L_0(x, \omega_0)= \int_{S^2}{\rho(x, \omega_i,\omega_0)L(x, \omega_i)\,\mathrm{d}\sigma_\perp(\omega_i)}$$</p> <p>For purely specular surface this integral has to be zero, from strict mathematical point of view. This is because the BSDF is zero (solid angle)-almost everywhere. You can argue that BSDF is infinite in one point and you have to take this point into account. But how do you know what is the reflectance of the surface at that point? From the infinity you can really tell. Furthermore from mathematical standpoint of view you cannot integrate infinite valued function, even if you could than the only sensible answers would be zero or infinity.</p> <p>I know these are subtle problems and in practice can be solved with few <code>if</code>s but I would like to have theory without holes. I believe that if you embrace these problems in theory than it helps you with placing those <code>if</code>s in the right place.</p> <hr> <p>How to deal with this problem? </p> <p>Not sure entirely but as I can remember Erich Veach <a href="https://graphics.stanford.edu/papers/veach_thesis/" rel="noreferrer">in his thesis</a> address this problem only slightly and tries to get away with it by saying that BSDF and radiance are <a href="https://en.wikipedia.org/wiki/Distribution_(mathematics)" rel="noreferrer">distributions</a>. This is problematic, you cannot multiply two distributions, which is needed in rendering equation. For example when a light from directional light hits specular surface than you need to multiply two Dirac delta functions together.</p> <p>The question is: Is there any work which reformulates rendering equation, BSDF and radiance in such a way that it does not suffer from mentioned problems?</p> <p>What is the state of the art theory behind raytracing? Is is still Erich Veach's thesis?</p> <p>(I'm only aware of <a href="http://cybertron.cg.tu-berlin.de/lessig/projects/dissertation/index.html" rel="noreferrer">work</a> of Christian Lessig, but his work is still beyond my mathematical reach.)</p> <hr> <p>I already have <a href="http://tomsmathjourneys.blogspot.cz/2015/09/better-code-with-radiance-and-bsdf-as.html" rel="noreferrer">proposal</a> how to deal with this problem. I define BSDF and radiance as measure. The basic idea works fine, but the whole theory of light transport needs to be redone to find out if it really works.</p> <p>The main purpose of this question is to find out if someone else already did it, so I can read it and then focus my energy somewhere else.</p>