private void BuildQuad() { VertexPt4[] Vertices = new VertexPt4[] { new VertexPt4() { Pt = new float4(-1, +1, 0, 1) }, new VertexPt4() { Pt = new float4(-1, -1, 0, 1) }, new VertexPt4() { Pt = new float4(+1, +1, 0, 1) }, new VertexPt4() { Pt = new float4(+1, -1, 0, 1) }, }; ByteBuffer VerticesBuffer = VertexPt4.FromArray(Vertices); Reg(m_Prim_Quad = new Primitive(m_Device, Vertices.Length, VerticesBuffer, null, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.Pt4)); }
private void BuildQuad() { VertexPt4[] Vertices = new VertexPt4[4]; Vertices[0] = new VertexPt4() { Pt = new float4(-1, +1, 0, 1) }; // Top-Left Vertices[1] = new VertexPt4() { Pt = new float4(-1, -1, 0, 1) }; // Bottom-Left Vertices[2] = new VertexPt4() { Pt = new float4(+1, +1, 0, 1) }; // Top-Right Vertices[3] = new VertexPt4() { Pt = new float4(+1, -1, 0, 1) }; // Bottom-Right ByteBuffer VerticesBuffer = VertexPt4.FromArray(Vertices); m_Prim_Quad = new Primitive(m_Device, Vertices.Length, VerticesBuffer, null, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.Pt4); }
void BuildPrimitives() { { // Post-process quad List <VertexPt4> Vertices = new List <VertexPt4>(); Vertices.Add(new VertexPt4() { Pt = new float4(-1, +1, 0, 1) }); Vertices.Add(new VertexPt4() { Pt = new float4(-1, -1, 0, 1) }); Vertices.Add(new VertexPt4() { Pt = new float4(+1, +1, 0, 1) }); Vertices.Add(new VertexPt4() { Pt = new float4(+1, -1, 0, 1) }); m_Prim_Quad = new Primitive(m_Device, 4, VertexPt4.FromArray(Vertices.ToArray()), null, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.Pt4); } { // Sphere Primitive List <VertexP3N3G3T2> Vertices = new List <VertexP3N3G3T2>(); List <uint> Indices = new List <uint>(); const int SUBDIVS_THETA = 80; const int SUBDIVS_PHI = 160; for (int Y = 0; Y <= SUBDIVS_THETA; Y++) { double Theta = Y * Math.PI / SUBDIVS_THETA; float CosTheta = (float)Math.Cos(Theta); float SinTheta = (float)Math.Sin(Theta); for (int X = 0; X <= SUBDIVS_PHI; X++) { double Phi = X * 2.0 * Math.PI / SUBDIVS_PHI; float CosPhi = (float)Math.Cos(Phi); float SinPhi = (float)Math.Sin(Phi); float3 N = new float3(SinTheta * SinPhi, CosTheta, SinTheta * CosPhi); float3 T = new float3(CosPhi, 0.0f, -SinPhi); float2 UV = new float2((float)X / SUBDIVS_PHI, (float)Y / SUBDIVS_THETA); Vertices.Add(new VertexP3N3G3T2() { P = N, N = N, T = T, UV = UV }); } } for (int Y = 0; Y < SUBDIVS_THETA; Y++) { int CurrentLineOffset = Y * (SUBDIVS_PHI + 1); int NextLineOffset = (Y + 1) * (SUBDIVS_PHI + 1); for (int X = 0; X <= SUBDIVS_PHI; X++) { Indices.Add((uint)(CurrentLineOffset + X)); Indices.Add((uint)(NextLineOffset + X)); } if (Y < SUBDIVS_THETA - 1) { Indices.Add((uint)(NextLineOffset - 1)); // Degenerate triangle to end the line Indices.Add((uint)NextLineOffset); // Degenerate triangle to start the next line } } m_Prim_Sphere = new Primitive(m_Device, Vertices.Count, VertexP3N3G3T2.FromArray(Vertices.ToArray()), Indices.ToArray(), Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.P3N3G3T2); } { // Build the cube float3[] Normals = new float3[6] { -float3.UnitX, float3.UnitX, -float3.UnitY, float3.UnitY, -float3.UnitZ, float3.UnitZ, }; float3[] Tangents = new float3[6] { float3.UnitZ, -float3.UnitZ, float3.UnitX, -float3.UnitX, -float3.UnitX, float3.UnitX, }; VertexP3N3G3T2[] Vertices = new VertexP3N3G3T2[6 * 4]; uint[] Indices = new uint[2 * 6 * 3]; for (int FaceIndex = 0; FaceIndex < 6; FaceIndex++) { float3 N = Normals[FaceIndex]; float3 T = Tangents[FaceIndex]; float3 B = N.Cross(T); Vertices[4 * FaceIndex + 0] = new VertexP3N3G3T2() { P = N - T + B, N = N, T = T, // B = B, UV = new float2(0, 0) }; Vertices[4 * FaceIndex + 1] = new VertexP3N3G3T2() { P = N - T - B, N = N, T = T, // B = B, UV = new float2(0, 1) }; Vertices[4 * FaceIndex + 2] = new VertexP3N3G3T2() { P = N + T - B, N = N, T = T, // B = B, UV = new float2(1, 1) }; Vertices[4 * FaceIndex + 3] = new VertexP3N3G3T2() { P = N + T + B, N = N, T = T, // B = B, UV = new float2(1, 0) }; Indices[2 * 3 * FaceIndex + 0] = (uint)(4 * FaceIndex + 0); Indices[2 * 3 * FaceIndex + 1] = (uint)(4 * FaceIndex + 1); Indices[2 * 3 * FaceIndex + 2] = (uint)(4 * FaceIndex + 2); Indices[2 * 3 * FaceIndex + 3] = (uint)(4 * FaceIndex + 0); Indices[2 * 3 * FaceIndex + 4] = (uint)(4 * FaceIndex + 2); Indices[2 * 3 * FaceIndex + 5] = (uint)(4 * FaceIndex + 3); } ByteBuffer VerticesBuffer = VertexP3N3G3T2.FromArray(Vertices); m_Prim_Cube = new Primitive(m_Device, Vertices.Length, VerticesBuffer, Indices, Primitive.TOPOLOGY.TRIANGLE_LIST, VERTEX_FORMAT.P3N3G3T2); } }
private void BuildQuad() { VertexPt4[] Vertices = new VertexPt4[] { new VertexPt4() { Pt = new float4( -1, +1, 0, 1 ) }, new VertexPt4() { Pt = new float4( -1, -1, 0, 1 ) }, new VertexPt4() { Pt = new float4( +1, +1, 0, 1 ) }, new VertexPt4() { Pt = new float4( +1, -1, 0, 1 ) }, }; ByteBuffer VerticesBuffer = VertexPt4.FromArray( Vertices ); Reg( m_Prim_Quad = new Primitive( m_Device, Vertices.Length, VerticesBuffer, null, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.Pt4 ) ); }
private void BuildPrimitives() { { VertexPt4[] Vertices = new VertexPt4[4]; Vertices[0] = new VertexPt4() { Pt = new float4(-1, +1, 0, 1) }; // Top-Left Vertices[1] = new VertexPt4() { Pt = new float4(-1, -1, 0, 1) }; // Bottom-Left Vertices[2] = new VertexPt4() { Pt = new float4(+1, +1, 0, 1) }; // Top-Right Vertices[3] = new VertexPt4() { Pt = new float4(+1, -1, 0, 1) }; // Bottom-Right ByteBuffer VerticesBuffer = VertexPt4.FromArray(Vertices); m_Prim_Quad = new Primitive(m_Device, Vertices.Length, VerticesBuffer, null, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.Pt4); } { VertexP3N3G3B3T2[] Vertices = new VertexP3N3G3B3T2[4]; Vertices[0] = new VertexP3N3G3B3T2() { P = new float3(-1, +1, 0), N = new float3(0, 0, 1), T = new float3(1, 0, 0), B = new float3(0, 1, 0), UV = new float2(0, 0) }; // Top-Left Vertices[1] = new VertexP3N3G3B3T2() { P = new float3(-1, -1, 0), N = new float3(0, 0, 1), T = new float3(1, 0, 0), B = new float3(0, 1, 0), UV = new float2(0, 1) }; // Bottom-Left Vertices[2] = new VertexP3N3G3B3T2() { P = new float3(+1, +1, 0), N = new float3(0, 0, 1), T = new float3(1, 0, 0), B = new float3(0, 1, 0), UV = new float2(1, 0) }; // Top-Right Vertices[3] = new VertexP3N3G3B3T2() { P = new float3(+1, -1, 0), N = new float3(0, 0, 1), T = new float3(1, 0, 0), B = new float3(0, 1, 0), UV = new float2(1, 1) }; // Bottom-Right ByteBuffer VerticesBuffer = VertexP3N3G3B3T2.FromArray(Vertices); m_Prim_Rectangle = new Primitive(m_Device, Vertices.Length, VerticesBuffer, null, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.P3N3G3B3T2); } { // Build the sphere const int W = 41; const int H = 22; VertexP3N3G3B3T2[] Vertices = new VertexP3N3G3B3T2[W * H]; for (int Y = 0; Y < H; Y++) { double Theta = Math.PI * Y / (H - 1); float CosTheta = (float)Math.Cos(Theta); float SinTheta = (float)Math.Sin(Theta); for (int X = 0; X < W; X++) { double Phi = 2.0 * Math.PI * X / (W - 1); float CosPhi = (float)Math.Cos(Phi); float SinPhi = (float)Math.Sin(Phi); float3 N = new float3(SinTheta * SinPhi, CosTheta, SinTheta * CosPhi); float3 T = new float3(CosPhi, 0.0f, -SinPhi); float3 B = N.Cross(T); Vertices[W * Y + X] = new VertexP3N3G3B3T2() { P = N, N = N, T = T, B = B, UV = new float2(2.0f * X / W, 1.0f * Y / H) }; } } ByteBuffer VerticesBuffer = VertexP3N3G3B3T2.FromArray(Vertices); uint[] Indices = new uint[(H - 1) * (2 * W + 2) - 2]; int IndexCount = 0; for (int Y = 0; Y < H - 1; Y++) { for (int X = 0; X < W; X++) { Indices[IndexCount++] = (uint)((Y + 0) * W + X); Indices[IndexCount++] = (uint)((Y + 1) * W + X); } if (Y < H - 2) { Indices[IndexCount++] = (uint)((Y + 1) * W - 1); Indices[IndexCount++] = (uint)((Y + 1) * W + 0); } } m_Prim_Sphere = new Primitive(m_Device, Vertices.Length, VerticesBuffer, Indices, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.P3N3G3B3T2); } { // Build the cube float3[] Normals = new float3[6] { -float3.UnitX, float3.UnitX, -float3.UnitY, float3.UnitY, -float3.UnitZ, float3.UnitZ, }; float3[] Tangents = new float3[6] { float3.UnitZ, -float3.UnitZ, float3.UnitX, -float3.UnitX, -float3.UnitX, float3.UnitX, }; VertexP3N3G3B3T2[] Vertices = new VertexP3N3G3B3T2[6 * 4]; uint[] Indices = new uint[2 * 6 * 3]; for (int FaceIndex = 0; FaceIndex < 6; FaceIndex++) { float3 N = Normals[FaceIndex]; float3 T = Tangents[FaceIndex]; float3 B = N.Cross(T); Vertices[4 * FaceIndex + 0] = new VertexP3N3G3B3T2() { P = N - T + B, N = N, T = T, B = B, UV = new float2(0, 0) }; Vertices[4 * FaceIndex + 1] = new VertexP3N3G3B3T2() { P = N - T - B, N = N, T = T, B = B, UV = new float2(0, 1) }; Vertices[4 * FaceIndex + 2] = new VertexP3N3G3B3T2() { P = N + T - B, N = N, T = T, B = B, UV = new float2(1, 1) }; Vertices[4 * FaceIndex + 3] = new VertexP3N3G3B3T2() { P = N + T + B, N = N, T = T, B = B, UV = new float2(1, 0) }; Indices[2 * 3 * FaceIndex + 0] = (uint)(4 * FaceIndex + 0); Indices[2 * 3 * FaceIndex + 1] = (uint)(4 * FaceIndex + 1); Indices[2 * 3 * FaceIndex + 2] = (uint)(4 * FaceIndex + 2); Indices[2 * 3 * FaceIndex + 3] = (uint)(4 * FaceIndex + 0); Indices[2 * 3 * FaceIndex + 4] = (uint)(4 * FaceIndex + 2); Indices[2 * 3 * FaceIndex + 5] = (uint)(4 * FaceIndex + 3); } ByteBuffer VerticesBuffer = VertexP3N3G3B3T2.FromArray(Vertices); m_Prim_Cube = new Primitive(m_Device, Vertices.Length, VerticesBuffer, Indices, Primitive.TOPOLOGY.TRIANGLE_LIST, VERTEX_FORMAT.P3N3G3B3T2); } }
/* // float Theta = 0.5 * _UV.x * PI; // float3 ToLight = float3( sin( Theta ), 0, cos( Theta ) ); // float3 ToView = float3( -sin( Theta ), 0, cos( Theta ) ); // // float Albedo = 0.0; // const int THETA_COUNT = 64; // * $alwaysOne; // warning X4008: floating point division by zero // const float dTheta = HALFPI / THETA_COUNT; // const float dPhi = PI / THETA_COUNT; // for ( int i=0; i < THETA_COUNT; i++ ) // { // Theta = HALFPI * (0.5 + i) / THETA_COUNT; // for ( int j=0; j < THETA_COUNT; j++ ) // { // float Phi = PI * j / THETA_COUNT; // // ToView = float3( sin( Theta ) * cos( Phi ), sin( Theta ) * sin( Phi ), cos( Theta ) ); // // float3 Half = normalize( ToLight + ToView ); // // // "True" and expensive evaluation of the Ward BRDF // float alpha = Roughness; // // float CosDelta = Half.z; // dot( Half, _wsNormal ); // float delta = acos( CosDelta ); // float CosThetaL = ToLight.z; // float SinThetaL = sqrt( 1.0 - CosThetaL*CosThetaL ); // float PhiL = atan2( ToLight.y, ToLight.x ); // float CosThetaV = ToView.z; // float SinThetaV = sqrt( 1.0 - CosThetaV*CosThetaV ); // float PhiV = atan2( ToView.y, ToView.x ); // // float BRDF = 1.0 / square(alpha) * exp( -square( tan( delta ) / alpha ) ) * 2.0 * (1.0 + CosThetaL*CosThetaV + SinThetaL*SinThetaV*cos( PhiV - PhiL )) / pow4( CosThetaL + CosThetaV ); // // Albedo += BRDF * cos( Theta ) * sin( Theta ) * dTheta * dPhi; // } // } // // Albedo *= 2.0; // Since we integrate on half a hemisphere... // Albedo *= INVPI; // Since we forgot that in the main loop // // ========================================================================== // arkDebugBRDFAlbedo // // Displays the true and theoretical BRDF albedos // // ========================================================================== // renderProg PostFX/Debug/WardBRDFAlbedo { newstyle hlsl_prefix { #include <ward> // Displays the BRDF albedo in 2 small screen insets showing how the albedo varies with roughness // The albedo is computed by integrating the BRDF over an entire hemisphere of view directions for a // single light direction that varies with U in [0,1] corresponding to Theta_Light in [0,PI/2]. // // The goal here is to demonstrate the albedo is correctly bounded (i.e. never > 1). // The especially important part is when the light is at grazing angles (i.e. U -> 1) // // Just call this function in the finalizer post-process, providing the screen UVs and the final color // void DEBUG_DisplayWardBRDFAlbedo( float2 _UV, inout float3 _Color ) { float Roughness = lerp( 0.01, 1.0, 0.5 * (1.0 + sin( $time.x )) ); // Roughness is varying with time here... if ( _UV.x < 0.2 && _UV.y > 0.8 ) { // This version integrates the "true" BRDF // The formula comes from eq. (15) from http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.169.9908&rep=rep1&type=pdf // _UV.x /= 0.2; _UV.y = (_UV.y - 0.8) / 0.2; float Theta = 0.5 * _UV.x * PI; float3 ToLight = float3( sin( Theta ), 0, cos( Theta ) ); float3 ToView = float3( -sin( Theta ), 0, cos( Theta ) ); float Albedo = 0.0; const int THETA_COUNT = 64; // * $alwaysOne; // warning X4008: floating point division by zero const float dTheta = HALFPI / THETA_COUNT; const float dPhi = PI / THETA_COUNT; for ( int i=0; i < THETA_COUNT; i++ ) { Theta = HALFPI * (0.5 + i) / THETA_COUNT; for ( int j=0; j < THETA_COUNT; j++ ) { float Phi = PI * j / THETA_COUNT; ToView = float3( sin( Theta ) * cos( Phi ), sin( Theta ) * sin( Phi ), cos( Theta ) ); float3 Half = normalize( ToLight + ToView ); // "True" and expensive evaluation of the Ward BRDF float alpha = Roughness; float CosDelta = Half.z; // dot( Half, _wsNormal ); float delta = acos( CosDelta ); float CosThetaL = ToLight.z; float SinThetaL = sqrt( 1.0 - CosThetaL*CosThetaL ); float PhiL = atan2( ToLight.y, ToLight.x ); float CosThetaV = ToView.z; float SinThetaV = sqrt( 1.0 - CosThetaV*CosThetaV ); float PhiV = atan2( ToView.y, ToView.x ); float BRDF = 1.0 / square(alpha) * exp( -square( tan( delta ) / alpha ) ) * 2.0 * (1.0 + CosThetaL*CosThetaV + SinThetaL*SinThetaV*cos( PhiV - PhiL )) / pow4( CosThetaL + CosThetaV ); Albedo += BRDF * cos( Theta ) * sin( Theta ) * dTheta * dPhi; } } Albedo *= 2.0; // Since we integrate on half a hemisphere... Albedo *= INVPI; // Since we forgot that in the main loop _Color = 1.0 - _UV.y < 0.8 * Albedo ? 1 : 0; if ( _UV.x < 0.01 ) _Color = Roughness; } else if ( _UV.x > 0.25 && _UV.x < 0.45 && _UV.y > 0.8 ) { // And this version uses our implementation of the Ward BRDF // The formula comes from eq. (23) of the same paper. // Both renderings should be equal and albedo should NEVER be > 1! // _UV.x = (_UV.x - 0.25) / 0.2; _UV.y = (_UV.y - 0.8) / 0.2; WardContext ctx; CreateWardContext( ctx, Roughness, 0.0, 0.0, float3( 1, 0, 0 ), float3( 0, 1, 0 ) ); float Theta = 0.5 * _UV.x * PI; float3 ToLight = float3( sin( Theta ), 0, cos( Theta ) ); float3 ToView = float3( -sin( Theta ), 0, cos( Theta ) ); float Albedo = 0.0; const int THETA_COUNT = 64; // * $alwaysOne; // Allows to prevent unrolling and lenghty shader compilation! const float dTheta = HALFPI / THETA_COUNT; const float dPhi = PI / THETA_COUNT; for ( int i=0; i < THETA_COUNT; i++ ) { Theta = HALFPI * (0.5 + i) / THETA_COUNT; for ( int j=0; j < THETA_COUNT; j++ ) { float Phi = PI * j / THETA_COUNT; ToView = float3( sin( Theta ) * cos( Phi ), sin( Theta ) * sin( Phi ), cos( Theta ) ); Albedo += ctx.ComputeWardTerm( float3( 0, 0, 1 ), ToLight, ToView ) * cos( Theta ) * sin( Theta ) * dTheta * dPhi; } } Albedo *= 2.0; // Since we integrate on half a hemisphere... Albedo *= INVPI; // Since we forgot that in the main loop _Color = (1.0 - _UV.y < 0.8 * Albedo ? 1 : 0) * float3( 1, 0, 0 ); if ( _UV.x < 0.01 ) _Color = Roughness; } } } } * / /* struct WardContext { float3 anisoTangentDivRoughness; float3 anisoBitangentDivRoughness; float specularNormalization; float isotropicRoughness; // Original normalized isotropic roughness // float diffuseRoughness; // ARKANE: bmayaux (2013-10-14) Disney diffuse roughness Fresnel term // Computes the Ward normal distribution // _wsNormal, surface normal // _wsToLight, world space light vector // _wsView, world space view vector // float ComputeWardTerm( float3 _wsNormal, float3 _wsToLight, float3 _wsView ) { float3 Half = _wsToLight + _wsView; // Half = normalize(Half); // not normalized on purpose, HdotH would be 1 if normalized, nonsense float HdotN = dot( Half, _wsNormal ); HdotN = max( 1e-4f, HdotN ); float invHdotN_2 = 1.0 / square( HdotN ); float invHdotN_4 = square( invHdotN_2 ); float HdotT = dot( Half, anisoTangentDivRoughness ); float HdotB = dot( Half, anisoBitangentDivRoughness ); float HdotH = dot( Half, Half ); float exponent = -invHdotN_2 * (square( HdotT ) + square( HdotB )); return specularNormalization * exp( exponent ) * HdotH * invHdotN_4; } }; void CreateWardContext( out WardContext wardContext, float _Roughness, float _Anisotropy, float _AnisotropyAngle, float3 _Tangent, float3 _BiTangent ) { // Tweak roughness so the user feels it's a linear parameter float Roughness = _Roughness * _Roughness; // Roughness squared seems to give a nice linear feel... // People at Disney seem to agree with me! (cf ยง5.4 http://blog.selfshadow.com/publications/s2012-shading-course/burley/s2012_pbs_disney_brdf_notes_v2.pdf) // Keep an average normalized roughness value for other people who require it (e.g. IBL) wardContext.isotropicRoughness = Roughness; // Build anisotropic roughness along tangent/bitangent float2 anisotropicRoughness = float2( Roughness, Roughness * saturate( 1.0 - _Anisotropy ) ); anisotropicRoughness = max( 0.01, anisotropicRoughness ); // Make sure we don't go below 0.01 otherwise specularity is unnatural for our poor lights (only IBL with many samples would solve that!) // Tangent/Ax, Bitangent/Ay float2 sinCosAnisotropy; sincos( _AnisotropyAngle, sinCosAnisotropy.x, sinCosAnisotropy.y ); float2 invRoughness = 1.0 / (1e-5 + anisotropicRoughness); wardContext.anisoTangentDivRoughness = (sinCosAnisotropy.y * _Tangent + sinCosAnisotropy.x * _BiTangent) * invRoughness.x; wardContext.anisoBitangentDivRoughness = (sinCosAnisotropy.y * _BiTangent - sinCosAnisotropy.x * _Tangent) * invRoughness.y; wardContext.specularNormalization = INVPI * invRoughness.x * invRoughness.y; // ARKANE: bmayaux (2014-02-05) Sheen is not tied to roughness anymore (for better or for worse?) so it doesn't need to be tied to Ward anymore either! // // ARKANE: bmayaux (2013-10-14) Disney diffuse roughness Fresnel term // // Diffuse roughness starts increasing for ward roughness > 0.35 and reaches 1 for ward roughness = 0.85 // // this to make sure only very diffuse and rough objects have a sheen... // // wardContext.diffuseRoughness = _Sheen * saturate( 2.0 * _Roughness - 0.7 ); // wardContext.diffuseRoughness = _Sheen; // Use direct sheen value, at the risk of making it strange on smooth materials... } */ #endregion #region Primitives private void BuildPrimitives() { { VertexPt4[] Vertices = new VertexPt4[4]; Vertices[0] = new VertexPt4() { Pt = new float4( -1, +1, 0, 1 ) }; // Top-Left Vertices[1] = new VertexPt4() { Pt = new float4( -1, -1, 0, 1 ) }; // Bottom-Left Vertices[2] = new VertexPt4() { Pt = new float4( +1, +1, 0, 1 ) }; // Top-Right Vertices[3] = new VertexPt4() { Pt = new float4( +1, -1, 0, 1 ) }; // Bottom-Right ByteBuffer VerticesBuffer = VertexPt4.FromArray( Vertices ); m_Prim_Quad = new Primitive( m_Device, Vertices.Length, VerticesBuffer, null, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.Pt4 ); } { VertexP3N3G3B3T2[] Vertices = new VertexP3N3G3B3T2[4]; Vertices[0] = new VertexP3N3G3B3T2() { P = new float3( -1, +1, 0 ), N = new float3( 0, 0, 1 ), T = new float3( 1, 0, 0 ), B = new float3( 0, 1, 0 ), UV = new float2( 0, 0 ) }; // Top-Left Vertices[1] = new VertexP3N3G3B3T2() { P = new float3( -1, -1, 0 ), N = new float3( 0, 0, 1 ), T = new float3( 1, 0, 0 ), B = new float3( 0, 1, 0 ), UV = new float2( 0, 1 ) }; // Bottom-Left Vertices[2] = new VertexP3N3G3B3T2() { P = new float3( +1, +1, 0 ), N = new float3( 0, 0, 1 ), T = new float3( 1, 0, 0 ), B = new float3( 0, 1, 0 ), UV = new float2( 1, 0 ) }; // Top-Right Vertices[3] = new VertexP3N3G3B3T2() { P = new float3( +1, -1, 0 ), N = new float3( 0, 0, 1 ), T = new float3( 1, 0, 0 ), B = new float3( 0, 1, 0 ), UV = new float2( 1, 1 ) }; // Bottom-Right ByteBuffer VerticesBuffer = VertexP3N3G3B3T2.FromArray( Vertices ); m_Prim_Rectangle = new Primitive( m_Device, Vertices.Length, VerticesBuffer, null, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.P3N3G3B3T2 ); } { // Build the sphere const int W = 41; const int H = 22; VertexP3N3G3B3T2[] Vertices = new VertexP3N3G3B3T2[W*H]; for ( int Y=0; Y < H; Y++ ) { double Theta = Math.PI * Y / (H-1); float CosTheta = (float) Math.Cos( Theta ); float SinTheta = (float) Math.Sin( Theta ); for ( int X=0; X < W; X++ ) { double Phi = 2.0 * Math.PI * X / (W-1); float CosPhi = (float) Math.Cos( Phi ); float SinPhi = (float) Math.Sin( Phi ); float3 N = new float3( SinTheta * SinPhi, CosTheta, SinTheta * CosPhi ); float3 T = new float3( CosPhi, 0.0f, -SinPhi ); float3 B = N.Cross( T ); Vertices[W*Y+X] = new VertexP3N3G3B3T2() { P = N, N = N, T = T, B = B, UV = new float2( 2.0f * X / W, 1.0f * Y / H ) }; } } ByteBuffer VerticesBuffer = VertexP3N3G3B3T2.FromArray( Vertices ); uint[] Indices = new uint[(H-1) * (2*W+2)-2]; int IndexCount = 0; for ( int Y=0; Y < H-1; Y++ ) { for ( int X=0; X < W; X++ ) { Indices[IndexCount++] = (uint) ((Y+0) * W + X); Indices[IndexCount++] = (uint) ((Y+1) * W + X); } if ( Y < H-2 ) { Indices[IndexCount++] = (uint) ((Y+1) * W - 1); Indices[IndexCount++] = (uint) ((Y+1) * W + 0); } } m_Prim_Sphere = new Primitive( m_Device, Vertices.Length, VerticesBuffer, Indices, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.P3N3G3B3T2 ); } { // Build the cube float3[] Normals = new float3[6] { -float3.UnitX, float3.UnitX, -float3.UnitY, float3.UnitY, -float3.UnitZ, float3.UnitZ, }; float3[] Tangents = new float3[6] { float3.UnitZ, -float3.UnitZ, float3.UnitX, -float3.UnitX, -float3.UnitX, float3.UnitX, }; VertexP3N3G3B3T2[] Vertices = new VertexP3N3G3B3T2[6*4]; uint[] Indices = new uint[2*6*3]; for ( int FaceIndex=0; FaceIndex < 6; FaceIndex++ ) { float3 N = Normals[FaceIndex]; float3 T = Tangents[FaceIndex]; float3 B = N.Cross( T ); Vertices[4*FaceIndex+0] = new VertexP3N3G3B3T2() { P = N - T + B, N = N, T = T, B = B, UV = new float2( 0, 0 ) }; Vertices[4*FaceIndex+1] = new VertexP3N3G3B3T2() { P = N - T - B, N = N, T = T, B = B, UV = new float2( 0, 1 ) }; Vertices[4*FaceIndex+2] = new VertexP3N3G3B3T2() { P = N + T - B, N = N, T = T, B = B, UV = new float2( 1, 1 ) }; Vertices[4*FaceIndex+3] = new VertexP3N3G3B3T2() { P = N + T + B, N = N, T = T, B = B, UV = new float2( 1, 0 ) }; Indices[2*3*FaceIndex+0] = (uint) (4*FaceIndex+0); Indices[2*3*FaceIndex+1] = (uint) (4*FaceIndex+1); Indices[2*3*FaceIndex+2] = (uint) (4*FaceIndex+2); Indices[2*3*FaceIndex+3] = (uint) (4*FaceIndex+0); Indices[2*3*FaceIndex+4] = (uint) (4*FaceIndex+2); Indices[2*3*FaceIndex+5] = (uint) (4*FaceIndex+3); } ByteBuffer VerticesBuffer = VertexP3N3G3B3T2.FromArray( Vertices ); m_Prim_Cube = new Primitive( m_Device, Vertices.Length, VerticesBuffer, Indices, Primitive.TOPOLOGY.TRIANGLE_LIST, VERTEX_FORMAT.P3N3G3B3T2 ); } }
private void BuildQuad() { VertexPt4[] Vertices = new VertexPt4[4]; Vertices[0] = new VertexPt4() { Pt = new float4( -1, +1, 0, 1 ) }; // Top-Left Vertices[1] = new VertexPt4() { Pt = new float4( -1, -1, 0, 1 ) }; // Bottom-Left Vertices[2] = new VertexPt4() { Pt = new float4( +1, +1, 0, 1 ) }; // Top-Right Vertices[3] = new VertexPt4() { Pt = new float4( +1, -1, 0, 1 ) }; // Bottom-Right ByteBuffer VerticesBuffer = VertexPt4.FromArray( Vertices ); m_Prim_Quad = new Primitive( m_Device, Vertices.Length, VerticesBuffer, null, Primitive.TOPOLOGY.TRIANGLE_STRIP, VERTEX_FORMAT.Pt4 ); }