//Add vertex to mesh, normalize position to be on unit sphere. private ushort AddNormalizedVertex(float3 p) { p = p.Normalize(); _sphereVertices.Add(p); return(_newVertIndex++); }
public void GetSamplingDirection(float _U1, float _U2, ref float3 _direction) { float theta = Mathf.Asin(Mathf.Sqrt(_U1)); // float theta = Mathf.Acos( Mathf.Sqrt( _U1 ) ); float phi = Mathf.TWOPI * _U2; float3 D = new float3(Mathf.Sin(theta) * Mathf.Cos(phi), Mathf.Sin(theta) * Mathf.Sin(phi), Mathf.Cos(theta)); Transform(M, D, ref _direction); _direction.Normalize(); }
public void GetSamplingDirection(float _U1, float _U2, ref float3 _direction) { // float theta = Mathf.Asin( Mathf.Sqrt( _U1 ) ); float theta = Mathf.Acos(Mathf.Sqrt(_U1)); float phi = Mathf.TWOPI * _U2; // #if FIT_TRANSPOSED // Transform( new float3( Mathf.Sin(theta)*Mathf.Cos(phi), Mathf.Sin(theta)*Mathf.Sin(phi), Mathf.Cos(theta) ), M, ref _direction ); // #else Transform(M, new float3(Mathf.Sin(theta) * Mathf.Cos(phi), Mathf.Sin(theta) * Mathf.Sin(phi), Mathf.Cos(theta)), ref _direction); // #endif _direction.Normalize(); }
/// <summary> /// Calculates the vertex position so that it is parallel to the x-y plane. /// </summary> /// <param name="vertPos">Original vertex position.</param> /// <param name="normal">The normal of the polygon the vertex belongs to. Used as new Z axis.</param> /// <returns></returns> internal static float3 Reduce2D(this float3 vertPos, float3 normal) { normal = normal.Normalize(); //New z axis //If the normal equals the z axis of the world coodrinate system: reflect the point on the y axis. if (normal == float3.UnitZ) { var rot = new float3x3(-1, 0, 0, 0, 1, 0, 0, 0, 1); return(vertPos * rot); } //If the normal equals the negative z axis of the world coodrinate system: use the original coordinates. if (normal == float3.UnitZ * -1) { return(vertPos); } var v2 = float3.Cross(normal, float3.UnitZ); //rotation axis - new x axis v2 = v2.Normalize(); var v3 = float3.Cross(normal, v2); //new y axis v3 = v3.Normalize(); //Calculate change-of-basis matrix (orthonormal matrix). var row1 = new float3(v3.x, v2.x, normal.x); var row2 = new float3(v3.y, v2.y, normal.y); var row3 = new float3(v3.z, v2.z, normal.z); //vector in new basis * changeOfBasisMat = vector in old basis var changeOfBasisMat = new float3x3(row1, row2, row3); //In an orthonomal matrix the inverse equals the transpose, thus the transpose can be used to calculate vector in new basis (transpose * vector = vector in new basis). var transposeMat = new float3x3(changeOfBasisMat.Row0, changeOfBasisMat.Row1, changeOfBasisMat.Row2); transposeMat = transposeMat.Transpose(); var newVert = transposeMat * vertPos; //Round, to get rid of potential exponent representation. var vecX = System.Math.Round(newVert.x, 5); var vecY = System.Math.Round(newVert.y, 5); var vecZ = System.Math.Round(newVert.z, 5); newVert = new float3((float)vecX, (float)vecY, (float)vecZ); return(newVert); }
void LoadNormalMap(System.IO.FileInfo _normalMapFileName) { try { ImageFile tempImageNormal = new ImageFile(_normalMapFileName); // Make sure we accept the image double isPOT = Math.Log(tempImageNormal.Width) / Math.Log(2.0); if (tempImageNormal.Width != tempImageNormal.Height || (int)isPOT != isPOT) { throw new Exception("The converter only supports square power-of-two textures!\r\nThis image is " + tempImageNormal.Width + "x" + tempImageNormal.Height); } // Replace existing if (m_imageNormal != null) { m_imageNormal.Dispose(); m_imageNormal = null; } m_imageNormal = tempImageNormal; imagePanelNormal.Bitmap = m_imageNormal.AsBitmap; // Read normals m_size = m_imageNormal.Width; nx = new Complex[m_size, m_size]; ny = new Complex[m_size, m_size]; const float pipo = 1.0f; // Amplification test => no real change! float3 normal = float3.Zero; m_imageNormal.ReadPixels((uint X, uint Y, ref float4 _color) => { normal.Set(pipo * (2.0f * _color.x - 1.0f), pipo * (2.0f * _color.y - 1.0f), 2.0f * _color.z - 1.0f); normal.Normalize(); double fact = normal.z != 0.0 ? 1.0 / normal.z : 0.0; nx[X, Y].Set(fact * normal.x, 0); ny[X, Y].Set(fact * normal.y, 0); }); // Enable conversion buttonConvert.Enabled = true; buttonConvertOneSided.Enabled = true; } catch (Exception _e) { MessageBox("An error occurred while loading the normal map:\r\n\r\n" + _e.Message, MessageBoxButtons.OK, MessageBoxIcon.Error); } }
//Newell's Method - see Graphics Gems III, p. 232. /// <summary> /// Calculates a face normal from three vertices. The vertices have to be coplanar and part of the face. /// </summary> /// <param name="faceOuterVertices">All vertices of the outer boundary of the face.</param> /// <returns></returns> public static float3 CalculateFaceNormal(IList <Vertex> faceOuterVertices) { var normal = new float3(); for (var i = 0; i < faceOuterVertices.Count; i++) { var vCur = faceOuterVertices[i].VertData.Pos; var vNext = faceOuterVertices[(i + 1) % faceOuterVertices.Count].VertData.Pos; normal.x += (vCur.y - vNext.y) * (vCur.z + vNext.z); normal.y += (vCur.z - vNext.z) * (vCur.x + vNext.x); normal.z += (vCur.x - vNext.x) * (vCur.y + vNext.y); } normal = normal * -1; normal = normal.Normalize(); return(normal); }
private void RenderWithLights(Mesh rm, ShaderEffect effect) { if (_lights.Count > 0) { foreach (LightInfo li in _lights) { // SetupLight(li); effect.RenderMesh(rm); } } else { // No light present - switch on standard light effect.SetEffectParam(ShaderCodeBuilder.LightColorName, new float3(1, 1, 1)); // float4 lightDirHom = new float4(0, 0, -1, 0); float4 lightDirHom = _rc.InvModelView * new float4(0, 0, -1, 0); // float4 lightDirHom = _rc.TransModelView * new float4(0, 0, -1, 0); float3 lightDir = lightDirHom.xyz; lightDir.Normalize(); effect.SetEffectParam(ShaderCodeBuilder.LightDirectionName, lightDir); effect.SetEffectParam(ShaderCodeBuilder.LightIntensityName, (float)1); effect.RenderMesh(rm); } }
bool Scatter(Material mat, Ray r_in, Hit rec, out float3 attenuation, out Ray scattered, out float3 outLightE, ref int inoutRayCount, ref uint state) { outLightE = new float3(0, 0, 0); if (mat.type == Material.Type.Lambert) { // random point inside unit sphere that is tangent to the hit point float3 target = rec.pos + rec.normal + MathUtil.RandomUnitVector(ref state); scattered = new Ray(rec.pos, float3.Normalize(target - rec.pos)); attenuation = mat.albedo; // sample lights #if DO_LIGHT_SAMPLING for (int i = 0; i < s_Spheres.Length; ++i) { if (!s_SphereMats[i].HasEmission) { continue; // skip non-emissive } //@TODO if (&mat == &smat) // continue; // skip self var s = s_Spheres[i]; // create a random direction towards sphere // coord system for sampling: sw, su, sv float3 sw = Normalize(s.center - rec.pos); float3 su = Normalize(Cross(MathF.Abs(sw.x) > 0.01f ? new float3(0, 1, 0) : new float3(1, 0, 0), sw)); float3 sv = Cross(sw, su); // sample sphere by solid angle float cosAMax = MathF.Sqrt(MathF.Max(0.0f, 1.0f - s.radius * s.radius / (rec.pos - s.center).SqLength)); float eps1 = RandomFloat01(ref state), eps2 = RandomFloat01(ref state); float cosA = 1.0f - eps1 + eps1 * cosAMax; float sinA = MathF.Sqrt(1.0f - cosA * cosA); float phi = 2 * PI * eps2; float3 l = su * MathF.Cos(phi) * sinA + sv * MathF.Sin(phi) * sinA + sw * cosA; l.Normalize(); // shoot shadow ray Hit lightHit = default(Hit); int hitID = 0; ++inoutRayCount; if (HitWorld(new Ray(rec.pos, l), kMinT, kMaxT, ref lightHit, ref hitID) && hitID == i) { float omega = 2 * PI * (1 - cosAMax); float3 rdir = r_in.dir; Debug.Assert(rdir.IsNormalized); float3 nl = Dot(rec.normal, rdir) < 0 ? rec.normal : -rec.normal; outLightE += (mat.albedo * s_SphereMats[i].emissive) * (MathF.Max(0.0f, Dot(l, nl)) * omega / PI); } } #endif return(true); } else if (mat.type == Material.Type.Metal) { Debug.Assert(r_in.dir.IsNormalized); Debug.Assert(rec.normal.IsNormalized); float3 refl = Reflect(r_in.dir, rec.normal); // reflected ray, and random inside of sphere based on roughness scattered = new Ray(rec.pos, Normalize(refl + mat.roughness * RandomInUnitSphere(ref state))); attenuation = mat.albedo; return(Dot(scattered.dir, rec.normal) > 0); } else if (mat.type == Material.Type.Dielectric) { Debug.Assert(r_in.dir.IsNormalized); Debug.Assert(rec.normal.IsNormalized); float3 outwardN; float3 rdir = r_in.dir; float3 refl = Reflect(rdir, rec.normal); float nint; attenuation = new float3(1, 1, 1); float3 refr; float reflProb; float cosine; if (Dot(rdir, rec.normal) > 0) { outwardN = -rec.normal; nint = mat.ri; cosine = mat.ri * Dot(rdir, rec.normal); } else { outwardN = rec.normal; nint = 1.0f / mat.ri; cosine = -Dot(rdir, rec.normal); } if (Refract(rdir, outwardN, nint, out refr)) { reflProb = Schlick(cosine, mat.ri); } else { reflProb = 1; } if (RandomFloat01(ref state) < reflProb) { scattered = new Ray(rec.pos, Normalize(refl)); } else { scattered = new Ray(rec.pos, Normalize(refr)); } } else { attenuation = new float3(1, 0, 1); scattered = default(Ray); return(false); } return(true); }
/// <summary> /// Extrudes a given Face along a specified Vector. /// </summary> /// <param name="geometry"></param> /// <param name="faceHandle"></param> /// <param name="offset"></param> /// <param name="extrusionVector"></param> /// <returns></returns> public static Geometry ExtrudeFace(this Geometry geometry, int faceHandle, float offset, float3 extrusionVector) { extrusionVector = extrusionVector.Normalize(); return(ExtrudeFaceByHandle(geometry, faceHandle, offset, extrusionVector)); }
public void Normalize_Instance(float3 vec, float3 expected) { var actual = vec.Normalize(); Assert.Equal(expected, actual); }
public static Mesh CreateTorus(float segradius, float sliceradius, int segments, int slices) { float3[] verts = new float3[4 * segments * slices]; // one vertex per segment and one extra for the center point float3[] norms = new float3[verts.Length]; // one normal at each vertex ushort[] tris = new ushort[3 * 2 * segments * slices]; // a triangle per segment. Each triangle is made of three indices float deltaSegment = 2 * M.Pi / segments; float deltaSlice = 2 * M.Pi / slices; int triCount = 0; for (int i = 0; i < segments; i++) { for (int j = 0; j < slices; j++) { float3 slicePoint = new float3(sliceradius * M.Cos(j * deltaSlice), sliceradius * M.Sin(j * deltaSlice), 0); verts[4 * i * slices + 4 * j] = new float3((segradius + slicePoint.x) * M.Cos(i * deltaSegment), slicePoint.y, (segradius + slicePoint.x) * M.Sin(i * deltaSegment)); verts[4 * i * slices + 4 * j + 1] = new float3((segradius + slicePoint.x) * M.Cos(i * deltaSegment), slicePoint.y, (segradius + slicePoint.x) * M.Sin(i * deltaSegment)); verts[4 * i * slices + 4 * j + 2] = new float3((segradius + slicePoint.x) * M.Cos(i * deltaSegment), slicePoint.y, (segradius + slicePoint.x) * M.Sin(i * deltaSegment)); verts[4 * i * slices + 4 * j + 3] = new float3((segradius + slicePoint.x) * M.Cos(i * deltaSegment), slicePoint.y, (segradius + slicePoint.x) * M.Sin(i * deltaSegment)); tris[triCount++] = (ushort)(4 * i * slices + 4 * j + 3); tris[triCount++] = (ushort)(4 * ((i + 1) % segments) * slices + (4 * ((j + 1) % slices))); tris[triCount++] = (ushort)(4 * i * slices + (4 * ((j + 1) % slices) + 1)); tris[triCount++] = (ushort)(4 * i * slices + 4 * j + 3); tris[triCount++] = (ushort)(4 * ((i + 1) % segments) * slices + (4 * j + 2)); tris[triCount++] = (ushort)(4 * ((i + 1) % segments) * slices + (4 * ((j + 1) % slices))); float3 sliceMidVecA = new float3(sliceradius * M.Cos((j + 0.5f) * deltaSlice), sliceradius * M.Sin((j + 0.5f) * deltaSlice), 0); float3 sliceMidVecB = new float3(sliceradius * M.Cos((j - 0.5f) * deltaSlice), sliceradius * M.Sin((j - 0.5f) * deltaSlice), 0); float3 segMidVecA = new float3(segradius * M.Cos((i + 0.5f) * deltaSegment), 0, segradius * M.Sin((i + 0.5f) * deltaSegment)); float3 segMidVecB = new float3(segradius * M.Cos((i - 0.5f) * deltaSegment), 0, segradius * M.Sin((i - 0.5f) * deltaSegment)); float3 point1 = new float3((segradius + sliceMidVecB.x) * M.Cos((i - 0.5f) * deltaSegment), sliceMidVecB.y, (segradius + sliceMidVecB.x) * M.Sin((i - 0.5f) * deltaSegment)); float3 point2 = new float3((segradius + sliceMidVecB.x) * M.Cos((i + 0.5f) * deltaSegment), sliceMidVecB.y, (segradius + sliceMidVecB.x) * M.Sin((i + 0.5f) * deltaSegment)); float3 point3 = new float3((segradius + sliceMidVecA.x) * M.Cos((i - 0.5f) * deltaSegment), sliceMidVecA.y, (segradius + sliceMidVecA.x) * M.Sin((i - 0.5f) * deltaSegment)); float3 point4 = new float3((segradius + sliceMidVecA.x) * M.Cos((i + 0.5f) * deltaSegment), sliceMidVecA.y, (segradius + sliceMidVecA.x) * M.Sin((i + 0.5f) * deltaSegment)); float3 v1 = (point1 - (segMidVecB)); float3 v2 = (point2 - (segMidVecA)); float3 v3 = (point3 - (segMidVecB)); float3 v4 = (point4 - (segMidVecA)); v1.Normalize(); v2.Normalize(); v3.Normalize(); v4.Normalize(); norms[4 * i * slices + 4 * j] = v1; norms[4 * i * slices + 4 * j + 1] = v2; norms[4 * i * slices + 4 * j + 2] = v3; norms[4 * i * slices + 4 * j + 3] = v4; } } return(new Mesh { Vertices = verts, Normals = norms, Triangles = tris, }); }
void Application_Idle(object sender, EventArgs e) { if (m_device == null) { return; } // Setup global data m_CB_Main.m.iResolution = new float2(panelOutput.Width, panelOutput.Height); m_CB_Main.m.tanHalfFOV = Mathf.Tan(0.5f * Mathf.ToRad(FOV_DEGREES)); m_CB_Main.m.iGlobalTime = GetGameTime() - m_startTime; m_CB_Main.UpdateData(); // Setup light data float3 wsLightPosition = new float3(floatTrackbarControlLightPosX.Value, floatTrackbarControlLightPosY.Value, floatTrackbarControlLightPosZ.Value); float3 at = (m_wsLightTargetPosition - wsLightPosition).Normalized; if (radioButtonNegativeFreeTarget.Checked) { at = -at; } else if (radioButtonHorizontalTarget.Checked) { at.y = 0; at.Normalize(); } float roll = Mathf.ToRad(floatTrackbarControlLightRoll.Value); float3 left, up; at.OrthogonalBasis(out left, out up); float3 axisX = Mathf.Cos(roll) * left + Mathf.Sin(roll) * up; float3 axisY = -Mathf.Sin(roll) * left + Mathf.Cos(roll) * up; float radiusX = floatTrackbarControlLightScaleX.Value; float radiusY = floatTrackbarControlLightScaleY.Value; m_CB_Light.m._luminance = floatTrackbarControlLuminance.Value; m_CB_Light.m._wsLight2World.r0.Set(axisX, radiusX); m_CB_Light.m._wsLight2World.r1.Set(axisY, radiusY); m_CB_Light.m._wsLight2World.r2.Set(at, Mathf.PI * radiusX * radiusY); // Disk area in W m_CB_Light.m._wsLight2World.r3.Set(wsLightPosition, 1); m_CB_Light.UpdateData(); // Upload FGD & LTC tables m_tex_MSBRDF_E.SetPS(2); m_tex_MSBRDF_Eavg.SetPS(3); m_tex_LTC.SetPS(4); m_tex_MS_LTC.SetPS(5); // =========== Render scene =========== m_device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.READ_WRITE_DEPTH_LESS, BLEND_STATE.DISABLED); if (!checkBoxShowDiff.Checked) { m_device.SetRenderTarget(m_device.DefaultTarget, m_device.DefaultDepthStencil); m_device.Clear(m_device.DefaultTarget, float4.Zero); m_device.ClearDepthStencil(m_device.DefaultDepthStencil, 1.0f, 0, true, false); if (checkBoxShowReference.Checked) { // Use expensive reference if (m_shader_RenderScene_Reference.Use()) { m_device.RenderFullscreenQuad(m_shader_RenderScene_Reference); } } else { if (m_shader_RenderScene.Use()) { m_device.RenderFullscreenQuad(m_shader_RenderScene); } } } else { // Render reference in RT0 m_device.SetRenderTarget(m_RT_temp0, m_device.DefaultDepthStencil); m_device.ClearDepthStencil(m_device.DefaultDepthStencil, 1.0f, 0, true, false); if (m_shader_RenderScene_Reference.Use()) { m_device.RenderFullscreenQuad(m_shader_RenderScene_Reference); } // Render LTC in RT1 m_device.SetRenderTarget(m_RT_temp1, m_device.DefaultDepthStencil); m_device.ClearDepthStencil(m_device.DefaultDepthStencil, 1.0f, 0, true, false); if (m_shader_RenderScene.Use()) { m_device.RenderFullscreenQuad(m_shader_RenderScene); } // Render difference m_device.SetRenderStates(RASTERIZER_STATE.NOCHANGE, DEPTHSTENCIL_STATE.DISABLED, BLEND_STATE.DISABLED); m_device.SetRenderTarget(m_device.DefaultTarget, null); if (m_shader_RenderDiff.Use()) { m_RT_temp0.SetPS(0); m_RT_temp1.SetPS(1); m_tex_FalseColors.SetPS(2); m_device.RenderFullscreenQuad(m_shader_RenderDiff); } } // =========== Render Light Disk =========== m_device.SetRenderTarget(m_device.DefaultTarget, m_device.DefaultDepthStencil); if (!checkBoxDebugMatrix.Checked) { m_device.SetRenderStates(RASTERIZER_STATE.CULL_NONE, DEPTHSTENCIL_STATE.READ_WRITE_DEPTH_LESS, BLEND_STATE.DISABLED); if (m_shader_RenderLight.Use()) { m_prim_disk.Render(m_shader_RenderLight); } } else { if (m_shader_RenderTestQuad.Use()) { m_CB_TestQuad.m._wsLight2World.r0.Set(radiusX * axisX, 0); m_CB_TestQuad.m._wsLight2World.r1.Set(radiusY * axisY, 0); m_CB_TestQuad.m._wsLight2World.r2.Set(at, 0); m_CB_TestQuad.m._wsLight2World.r3.Set(wsLightPosition, 1); // Upload the full matrix, although we only really need the 4 non trivial coefficients at indices m11, m13, m31 and m33... int roughnessIndex = (int)Mathf.Floor(63.99f * Mathf.Sqrt(floatTrackbarControlRoughness.Value)); int thetaIndex = (int)Mathf.Floor(63.99f * Mathf.Sqrt(1.0f - Mathf.Cos(Mathf.ToRad(floatTrackbarControlViewAngle.Value)))); int matrixIndex = roughnessIndex + 64 * thetaIndex; double[,] LTC = radioButtonGGX.Checked ? LTCAreaLight.s_LtcMatrixData_GGX : LTCAreaLight.s_LtcMatrixData_OrenNayar; // NOTE: The LTC inverse matrices stored in the tables are transposed: columns are stored first // So in order to use them in the shaders, we need to compute P * M^-1^T instead of the paper's formulation M^-1 * P // m_CB_TestQuad.m._invM_transposed_r0.Set((float)LTC[matrixIndex, 0], (float)LTC[matrixIndex, 1], (float)LTC[matrixIndex, 2], 0); m_CB_TestQuad.m._invM_transposed_r1.Set((float)LTC[matrixIndex, 3], (float)LTC[matrixIndex, 4], (float)LTC[matrixIndex, 5], 0); m_CB_TestQuad.m._invM_transposed_r2.Set((float)LTC[matrixIndex, 6], (float)LTC[matrixIndex, 7], (float)LTC[matrixIndex, 8], 0); m_CB_TestQuad.UpdateData(); m_device.RenderFullscreenQuad(m_shader_RenderTestQuad); } } // Show! m_device.Present(false); }