日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

GPU Shader 编程基础

發布時間:2023/12/4 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GPU Shader 编程基础 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自:http://www.cnblogs.com/youthlion/archive/2012/12/07/2807919.html

幾個基本概念:

Vertex buffer:存儲頂點的數組。當構成模型的所有頂點都放進vertex buffer后,就可以把vertex buffer送進GPU,然后GPU就可以渲染模型了。

Index buffer:這個buffer的作用是索引。記錄每個頂點在vertex buffer中的位置。DX SDK里說使用index buffer可以增加頂點數據被緩存在顯存里的概率,所以就效率而言應該使用index buffer。

Vertex Shader:vertex shader是一類小程序,主要用來把vertex buffer里的頂點變換到3D空間中去。也可以用vertex shader干點別的,比如算頂點的法向量。對于每個要處理的頂點,GPU都會調用vertex shader。比如5000個三角形的網格模型,每一幀就得調用vertex shader 15000次,每秒60幀的話,vertex shader還真得寫得靠譜點。

Pixel Shader:是一般用來處理多邊形顏色的小程序。對于場景里每個要畫到屏幕上的可見像素,GPU都會調用Pixel Shader來處理。像著色、光照,還有大多數用在多邊形上的其他效果,都要靠Pixel Shader來搞定。沒錯,這個東西也得寫的靠譜點。效率,效率啊。要不可能GPU還沒有CPU算得快。

HLSL:這就是用來寫各種shader程序的語言了。HLSL程序包括全局變量、類型定義、vertex shaders,pixel shaders還有geometry shaders。

程序的整體結構:

這一次接著上一篇筆記的程序繼續擴展。在這篇筆記中,我們會用shader繪制一個綠色的三角形。這里三角形是要繪制的對象,實際上是一個簡單的多邊形模型,也就是數據,所以把它封裝到一個模型類(ModelClass)中,并集成到文檔類里去。視圖類負責顯示,而顯示的功能是由shader完成的。正如前面說的,shader是一段小程序,上面的圖中集成到視圖類中的ColorShaderClass負責調用shader,也就是讓這段shader小程序運行起來。這就是這篇筆記中程序的最宏觀結構。

第一個shader程序:

在工程中添加一個名為color.fx的源文件,看來shader程序源文件的擴展名是.fx了。這個shader的目的是繪制一個綠色的三角形。

這個shader首先聲明了三個全局矩陣變量,便于其他類從外部訪問,再傳回shader。

/ // GLOBALS // / matrix worldMatrix; matrix viewMatrix; matrix projectionMatrix;

下面幾行代碼里,使用HLSL中的float4類型創建了一個位置向量,包括x、y、z、w,以及一個顏色向量,包括red、green、blue、alpha分量。其中POSITION、COLOR和SV_POSITION是傳遞給GPU的語義信息,讓GPU知道這些變量是干嘛用的。下面的兩個類型貌似作用是一樣的,但是必須分別創建。因為對于vertex shader和pixel shader,需要不同的語義。POSITION是對應vertex shader,SV_POSITION適用于pixel shader,COLOR則是兩者通用。如果需要同一類型的多個成員,就得在類型后面加上個數值后綴,像COLOR0、COLOR1這種。

// // TYPEDEFS // // struct VertexInputType { float4 position : POSITION; float4 color : COLOR; }; ? struct PixelInputType { float4 position : SV_POSITION; float4 color : COLOR; };

?

當vertex buffer中的數據被送進GPU進行處理的時候,GPU會調用vertex shader。下面定義了一個名為ColorVertexShader的函數,該函數在處理vertex buffer中每個頂點的時候都會被調用。vertex shader的輸入必須與vertex buffer緩沖區中的數據以及shader源文件中的類型定義相匹配。這里就是VertexInputType。vertex shader的輸出會被送進pixel shader,這里輸出類型為上面定義的PixelInputType。

下面代碼中的vertex shader流程是這樣的:他先創建一個輸出變量,類型為PixelInputType,然后拿到輸入頂點的坐標,把世界矩陣、視點矩陣、投影矩陣挨個乘上去,對頂點進行變換,最后頂點會被變換到我們視點所觀察的3D空間中的正確位置。然后拿到輸入的顏色值,放進輸出變量里,把輸出變量返回,返回的輸出變量接下來會被送進pixel shader。

// Vertex Shader PixelInputType ColorVertexShader(VertexInputType input) { PixelInputType output; // Change the position vector to be 4 units for proper matrix calculations. input.position.w = 1.0f; ? // Calculate the position of the vertex against the world, view, and projection matrices. output.position = mul(input.position, worldMatrix); output.position = mul(output.position, viewMatrix); output.position = mul(output.position, projectionMatrix); // Store the input color for the pixel shader to use. output.color = input.color; return output; } 接下來就是pixel shader接班,由pixel shader把多邊形上那些要渲染到屏幕上的像素繪制出來。下面的這個pixel shader以PixelInputType作為輸入,返回一個float4類型,這個float4就是最后的像素顏色值。下面這個pixel shader僅僅是把像素著色為輸入的顏色值。重申,vertex shader的輸出是pixel shader的輸入。 // Pixel Shader float4 ColorPixelShader(PixelInputType input) : SV_Target { return input.color; }

下面幾行代碼里的technique才是真正意義的shader。這個東西是用來渲染多邊形、調用vertex shader和pixel shader的,可以把它看做是HLSL的main()函數。在technique里面可以設定多個pass,調用各種vertex shader和pixel shader來組合出想要的效果。這個例子里只使用了一個pass,也只調用了上面寫好的vertex和pixel shader。geometry shader暫時不用,這里也沒有調用。

還有個值得注意的事兒,代碼里用vs_4_0指定vertex shader的版本為4.0,這是SetVertexShader函數的第一個參數。這樣我們才可以使用DX10 HLSL中vertex shader4.0相應的功能。pixel shader也是類似。

// Technique technique10 ColorTechnique { pass pass0 { SetVertexShader(CompileShader(vs_4_0, ColorVertexShader())); SetPixelShader(CompileShader(ps_4_0, ColorPixelShader())); SetGeometryShader(NULL); } }

以上是這個例子的shader部分。也就是負責實際渲染工作的模塊。那么shader渲染的是神馬?恩,模型。

所以要在工程里再添加個模型類:

這個例子里,我們的模型僅僅是個三角形,暫時用原教程給的一個模型類ModelClass,后面如果需要,爭取把這個模型類用CGAL的Polyhedron替換掉。下面先看一下ModelClass的頭文件:

首先在ModelClass中添加頂點類型的定義。這也是vertex buffer的類型。

struct VertexType { D3DXVECTOR3 position; D3DXVECTOR4 color; };

構造和析構函數:

ModelClass(); ModelClass(const ModelClass&); ~ModelClass();

下面的幾個函數負責初始化和釋放模型的vertex和index buffer。Render函數負責把模型的幾何屬性送到顯卡上,準備讓shader繪制。

bool Initialize(ID3D10Device*); void Shutdown(); void Render(ID3D10Device*); ? int GetIndexCount();

上面的幾個公有函數的功能通過調用下面的幾個私有函數實現:

private: bool InitializeBuffers(ID3D10Device*); void ShutdownBuffers(); void RenderBuffers(ID3D10Device*);

添加幾個私有變量,分別作為vertex buffer和index buffer的指針,另外還有兩個整型,用來記錄兩塊buffer的大小。注意DX10里buffer一般用通用的ID3D10Buffer類型,這種類型的變量在創建的時候可以用buffer description進行描述。

private: ID3D10Buffer *m_vertexBuffer, *m_indexBuffer; int m_vertexCount, m_indexCount;

ModelClass類的實現部分,先是構造和析構函數:

ModelClass::ModelClass() { m_vertexBuffer = NULL; m_indexBuffer = NULL; } ? ? ModelClass::ModelClass(const ModelClass& other) { } ? ? ModelClass::~ModelClass() { }

初始化函數:

bool ModelClass::Initialize(ID3D10Device* device) { bool result; ? ? // Initialize the vertex and index buffer that hold the geometry for the triangle. result = InitializeBuffers(device); if(!result) { return false; } ? return true; }

釋放buffer:

void ModelClass::Shutdown() { // Release the vertex and index buffers. ShutdownBuffers(); ? return; }

Render函數實際是在框架的繪制模塊里調用的,也就是我第二篇筆記中的視圖類,再具體點,應該就是在視圖類的OnPaint方法里。

void ModelClass::Render(ID3D10Device* device) { // Put the vertex and index buffers on the graphics pipeline to prepare them for drawing. RenderBuffers(device); ? return; }

GetIndexCount函數返回index的數量:

int ModelClass::GetIndexCount() { return m_indexCount; }

接下來是Initialize、ShutDown和Render對應的幾個私有方法的具體實現,首先是InitializeBuffers,這個函數負責創建vertex buffer和index buffer。在實際的應用里,一般是從數據文件里把模型讀進來(.off,.obj,.ply等等)然后創建buffer,在這個例子里,因為模型只是一個三角形,所以直接在vertex buffer和index buffer里人工設置了三個點。

bool ModelClass::InitializeBuffers(ID3D10Device* device) { VertexType* vertices; unsigned long* indices; D3D10_BUFFER_DESC vertexBufferDesc, indexBufferDesc; D3D10_SUBRESOURCE_DATA vertexData, indexData; HRESULT result;

首先創建兩個數組,用來存儲頂點和索引數據。后面會用這兩個數組去填充最終的buffer。

// Set the number of vertices in the vertex array. m_vertexCount = 3; ? // Set the number of indices in the index array. m_indexCount = 3; ? // Create the vertex array. vertices = new VertexType[m_vertexCount]; if(!vertices) { return false; } ? // Create the index array. indices = new unsigned long[m_indexCount]; if(!indices) { return false; }

然后分別對頂點屬性和頂點索引賦值。留心,下面的代碼是按照順時針的順序創建頂點的。如果逆時針創建的話,程序會認為這個三角形是屁股朝著屏幕。如果恰好又設置了背面剔除的話,程序就不再繪制這個三角形了。所以說,被送進GPU的頂點順序是有講究的。

// Load the vertex array with data. vertices[0].position = D3DXVECTOR3(-1.0f, -1.0f, 0.0f); // Bottom left. vertices[0].color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f); ? vertices[1].position = D3DXVECTOR3(0.0f, 1.0f, 0.0f); // Top middle. vertices[1].color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f); ? vertices[2].position = D3DXVECTOR3(1.0f, -1.0f, 0.0f); // Bottom right. vertices[2].color = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f); ? // Load the index array with data. indices[0] = 0; // Bottom left. indices[1] = 1; // Top middle. indices[2] = 2; // Bottom right.

vetex數組和index數組搞定后,可以用它們來創建vertex buffer和index buffer。兩種buffer的創建方式是一樣的:首先填好buffer的description。在這個description里面ByteWidth(buffer的大小)和BindFlags(buffer類型)必須得填對。填好description后,還要分別填一個subresource指針,這量個指針分別指向前面創建的vertex數組和index數組。description和subresource都填好之后,就可以用D3D device調用CreateBuffer,這個函數會返回指向新創建buffer的指針。

// Set up the description of the vertex buffer. vertexBufferDesc.Usage = D3D10_USAGE_DEFAULT; vertexBufferDesc.ByteWidth = sizeof(VertexType) * m_vertexCount; vertexBufferDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER; vertexBufferDesc.CPUAccessFlags = 0; vertexBufferDesc.MiscFlags = 0; ? // Give the subresource structure a pointer to the vertex data. vertexData.pSysMem = vertices; ? // Now finally create the vertex buffer. result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer); if(FAILED(result)) { return false; } ? // Set up the description of the index buffer. indexBufferDesc.Usage = D3D10_USAGE_DEFAULT; indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount; indexBufferDesc.BindFlags = D3D10_BIND_INDEX_BUFFER; indexBufferDesc.CPUAccessFlags = 0; indexBufferDesc.MiscFlags = 0; ? // Give the subresource structure a pointer to the index data. indexData.pSysMem = indices; ? // Create the index buffer. result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer); if(FAILED(result)) { return false; }

vertex buffer和index buffer創建后,就可以卸磨殺驢,干掉vertex數組和index數組了:

// Release the arrays now that the vertex and index buffers have been created and loaded. delete [] vertices; vertices = 0; ? delete [] indices; indices = 0; ? return true; }

接下來是負責釋放vertex buffer和index buffer的ShutdownBuffers函數:

void ModelClass::ShutdownBuffers() { // Release the index buffer. if(m_indexBuffer) { m_indexBuffer->Release(); m_indexBuffer = 0; } ? // Release the vertex buffer. if(m_vertexBuffer) { m_vertexBuffer->Release(); m_vertexBuffer = 0; } ? return; }

下面是對應Render函數的私有函數RenderBuffers。這個函數的作用是把GPU中input assembler上的vertex buffer和index buffer設置為激活狀態。一旦有了一塊激活的vertex buffer,GPU就可以用我們寫的HLSL shader去渲染這塊buffer。RenderBuffers函數還規定了這些buffer的繪制方式,比如繪制三角形、繪制直線神馬的。這一篇筆記里,我們在input assembler上激活index buffer和vertex buffer,并通過DX10的IASetPrimitiveTopology函數告訴GPU,這塊buffer要以三角形的方式繪制。

void ModelClass::RenderBuffers(ID3D10Device* device) { unsigned int stride; unsigned int offset; ? ? // Set vertex buffer stride and offset. stride = sizeof(VertexType); offset = 0; // Set the vertex buffer to active in the input assembler so it can be rendered. device->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset); ? // Set the index buffer to active in the input assembler so it can be rendered. device->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0); ? // Set the type of primitive that should be rendered from this vertex buffer, in this case triangles. device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); ? return; }

Model類搞定。整理一下宏觀的思路:現在我們有了模型,也有了shader,可以用shader去渲染模型了。

問題在于,shader是怎樣開始運行的呢?

我們用下面這個ColorShaderClass類來調用shader。

這個類的Initialize和Shutdown兩個成員函數完成對shader的初始化和關閉,Render成員函數負責設置shader的參數,然后用shader去繪制模型。

ColorShaderClass類包含的頭文件及類聲明如下:

#include <d3d10.h> #include <d3dx10math.h> #include <fstream> using namespace std; ? class ColorShaderClass { public: ColorShaderClass(); ColorShaderClass(const ColorShaderClass&); ~ColorShaderClass(); ? bool Initialize(ID3D10Device*, HWND); void Shutdown(); void Render(ID3D10Device*, int, D3DXMATRIX, D3DXMATRIX, D3DXMATRIX); ? private: bool InitializeShader(ID3D10Device*, HWND, WCHAR*); void ShutdownShader(); void OutputShaderErrorMessage(ID3D10Blob*, HWND, WCHAR*); ? void SetShaderParameters(D3DXMATRIX, D3DXMATRIX, D3DXMATRIX); void RenderShader(ID3D10Device*, int); ? private: ID3D10Effect* m_effect; ID3D10EffectTechnique* m_technique; ID3D10InputLayout* m_layout; ? ID3D10EffectMatrixVariable* m_worldMatrixPtr; ID3D10EffectMatrixVariable* m_viewMatrixPtr; ID3D10EffectMatrixVariable* m_projectionMatrixPtr; }; 這個類和模型類的結構類似。在Initialize函數里,真正負責shader初始化的是InitializeShader,我們要傳給這個函數三個參數:device、窗口句柄和shader的文件名。 bool ColorShaderClass::Initialize(ID3D10Device* device, HWND hwnd) { bool result; ? ? // Initialize the shader that will be used to draw the triangle. result = InitializeShader(device, hwnd, L"../02_01/color.fx"); if(!result) { return false; } ? return true; }

Shutdown調用ShutdownShader關閉shader:

void ColorShaderClass::Shutdown() { // Shutdown the shader effect. ShutdownShader(); ? return; }

Render函數里做兩件事:1、設置shader參數,通過SetShaderParameters完成;2、用shader繪制綠三角,調用RenderShader完成:

void ColorShaderClass::Render(ID3D10Device* device, int indexCount, D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix) { // Set the shader parameters that it will use for rendering. SetShaderParameters(worldMatrix, viewMatrix, projectionMatrix); ? // Now render the prepared buffers with the shader. RenderShader(device, indexCount); ? return; }

在下面的InitializeShader函數中我們可以看到,shader實際上是在這里加載的。在這個函數里,我們還需要設置一個layout,這個layout需要與模型類及color.fx類中定義的頂點類相匹配:

bool ColorShaderClass::InitializeShader(ID3D10Device* device, HWND hwnd, WCHAR* filename) { HRESULT result; ID3D10Blob* errorMessage; D3D10_INPUT_ELEMENT_DESC polygonLayout[2]; unsigned int numElements; D3D10_PASS_DESC passDesc; ? ? // Initialize the error message. errorMessage = 0;

在D3DX10CreateEffectFromFile函數中,shader程序被編譯為一個effect。這個函數的幾個重要參數包括shader文件名、shader版本(DX10是4.0)、還要制定要把shader編譯到哪個effect里去(對應ColorShaderClass類的m_effect成員)。如果在編譯shader的過程中失敗的話,D3DX10CreateEffectFromFile會把一條錯誤消息放到errorMessage里,我們會把這個字符串塞給另一個函數OutputShaderErrorMessage去輸出錯誤信息。要是編譯失敗了,卻還沒有錯誤信息的話,可能是找不到shader文件,對這種情況我們會彈出一個對話框作為提示。

// Load the shader in from the file. result = D3DX10CreateEffectFromFile(filename, NULL, NULL, "fx_4_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, device, NULL, NULL, &m_effect, &errorMessage, NULL); if(FAILED(result)) { // If the shader failed to compile it should have writen something to the error message. if(errorMessage) { OutputShaderErrorMessage(errorMessage, hwnd, filename); } // If there was nothing in the error message then it simply could not find the shader file itself. else { MessageBox(hwnd, filename, L"Missing Shader File", MB_OK); } ? return false; }

當shader文件成功編譯為effect后,就可以用這個effect找到shader里的那個technique。我們后面用這個technique進行繪制:

// Get a pointer to the technique inside the shader. m_technique = m_effect->GetTechniqueByName("ColorTechnique"); if(!m_technique) { return false; }

下一步,shader所處理的頂點,還需要創建并設置一個layout。在這一篇筆記里,shader使用了一個位置向量和一個顏色向量,所以我們在layout中也要創建對應的元素,用來指明位置和顏色信息的內存占用情況。首先要填充的是語義信息,這樣shader才能知道這個layout元素的用途。對于位置信息,我們使用POSITION,顏色信息用COLOR。另一個重要信息是格式,位置信息我們用DXGI_FORMAT_R32G32B32_FLOAT,顏色信息用DXGI_FORMAT_R32G32B32A32_FLOAT。最后要注意的是AlignedByteOffset,這個字段指定了buffer中數據存儲的起點。對于本例來說,前12個字節是位置,隨后的16個字節是顏色。這個字段可以用D3D10_APPEND_ALIGNED_ELEMENT代替,表示DX10會自動計算。layout的其他字段暫時不會用到,這里使用默認設置:

// Now setup the layout of the data that goes into the shader. // This setup needs to match the VertexType stucture in the ModelClass and in the shader. polygonLayout[0].SemanticName = "POSITION"; polygonLayout[0].SemanticIndex = 0; polygonLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT; polygonLayout[0].InputSlot = 0; polygonLayout[0].AlignedByteOffset = 0; polygonLayout[0].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA; polygonLayout[0].InstanceDataStepRate = 0; ? polygonLayout[1].SemanticName = "COLOR"; polygonLayout[1].SemanticIndex = 0; polygonLayout[1].Format = DXGI_FORMAT_R32G32B32A32_FLOAT; polygonLayout[1].InputSlot = 0; polygonLayout[1].AlignedByteOffset = D3D10_APPEND_ALIGNED_ELEMENT; polygonLayout[1].InputSlotClass = D3D10_INPUT_PER_VERTEX_DATA; polygonLayout[1].InstanceDataStepRate = 0;

layout數組設置好之后,我們計算一下它包含的元素個數,然后用device創建input layout。

// Get a count of the elements in the layout. numElements = sizeof(polygonLayout) / sizeof(polygonLayout[0]); ? // Get the description of the first pass described in the shader technique. m_technique->GetPassByIndex(0)->GetDesc(&passDesc); ? // Create the input layout. result = device->CreateInputLayout(polygonLayout, numElements, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &m_layout); if(FAILED(result)) { return false; }

下面要做的是獲取shader里面那三個矩陣的指針,這樣以后就能用這三個指針設置矩陣的值:

// Get pointers to the three matrices inside the shader so we can update them from this class. m_worldMatrixPtr = m_effect->GetVariableByName("worldMatrix")->AsMatrix(); m_viewMatrixPtr = m_effect->GetVariableByName("viewMatrix")->AsMatrix(); m_projectionMatrixPtr = m_effect->GetVariableByName("projectionMatrix")->AsMatrix(); ? return true; }

ShutdownShader函數負責釋放資源:

void ColorShaderClass::ShutdownShader() { // Release the pointers to the matrices inside the shader. m_worldMatrixPtr = 0; m_viewMatrixPtr = 0; m_projectionMatrixPtr = 0; ? // Release the pointer to the shader layout. if(m_layout) { m_layout->Release(); m_layout = 0; } ? // Release the pointer to the shader technique. m_technique = 0; ? // Release the pointer to the shader. if(m_effect) { m_effect->Release(); m_effect = 0; } ? return; }

在編譯vertex shader或pixelshader時若發生問題,錯誤信息由OutputShaderErrorMessage函數輸出:

void ColorShaderClass::OutputShaderErrorMessage(ID3D10Blob* errorMessage, HWND hwnd, WCHAR* shaderFilename) { char* compileErrors; unsigned long bufferSize, i; ofstream fout; ? ? // Get a pointer to the error message text buffer. compileErrors = (char*)(errorMessage->GetBufferPointer()); ? // Get the length of the message. bufferSize = errorMessage->GetBufferSize(); ? // Open a file to write the error message to. fout.open("shader-error.txt"); ? // Write out the error message. for(i=0; i<bufferSize; i++) { fout << compileErrors[i]; } ? // Close the file. fout.close(); ? // Release the error message. errorMessage->Release(); errorMessage = 0; ? // Pop a message up on the screen to notify the user to check the text file for compile errors. MessageBox(hwnd, L"Error compiling shader. Check shader-error.txt for message.", shaderFilename, MB_OK); ? return; } SetShaderParameters函數便于我們設置shader中的全局變量。這個函數中的三個矩陣是在上一篇筆記中的視圖類里創建的,矩陣被創建之后,負責繪圖的代碼會調用這個函數,把這三個矩陣送進shader。 void ColorShaderClass::SetShaderParameters(D3DXMATRIX worldMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix) { // Set the world matrix variable inside the shader. m_worldMatrixPtr->SetMatrix((float*)&worldMatrix); ? // Set the view matrix variable inside the shader. m_viewMatrixPtr->SetMatrix((float*)&viewMatrix); ? // Set the projection matrix variable inside the shader. m_projectionMatrixPtr->SetMatrix((float*)&projectionMatrix); ? return; }

SetShaderParameters函數執行后,各種參數(這里實際就是那仨矩陣)設置完成,ColorShaderClass類隨后調用RenderShader,RenderShader通過technique指針調用color.fx文件中的shader程序。

RenderShader函數上來先把input layout激活,這樣GPU才能知道vertex buffer里數據的格式。接下來要從shader中獲取technique的描述,這個technique告訴GPU調用哪個vertex shader或pixel shader來繪制vertex buffer里的數據。本例中我們獲取的是color.fx中ColorTechnique的描述,然后通過device調用DrawIndexed函數,循環調用technique中的各個pass來渲染三角形。目前的例子里,shader只有一個pass(pass0)。

void ColorShaderClass::RenderShader(ID3D10Device* device, int indexCount) { D3D10_TECHNIQUE_DESC techniqueDesc; unsigned int i; ? // Set the input layout. device->IASetInputLayout(m_layout); ? // Get the description structure of the technique from inside the shader so it can be used for rendering. m_technique->GetDesc(&techniqueDesc); ? // Go through each pass in the technique (should be just one currently) and render the triangles. for(i=0; i<techniqueDesc.Passes; ++i) { m_technique->GetPassByIndex(i)->Apply(0); device->DrawIndexed(indexCount, 0, 0); } ? return; }

到這里,我們搞定了一個HLSL shader,設置了vertex buffer和index buffer,并了解了如何調用shader繪制兩種buffer中的數據。除此之外,還有一些輔助性的工作要做。第一個問題是,我們繪制的那些內容,是相對于哪個視點的?

好吧,所以我們還需要來個鏡頭類:

鏡頭類告訴DX10,鏡頭是從哪里、以及怎樣去觀察場景的。鏡頭類會始終跟蹤鏡頭的位置及其旋轉,使用位置和旋轉信息生成一個視點矩陣,這個視點矩陣會傳進shader,用于渲染。

鏡頭類聲明如下:

#include <d3dx10math.h> class CameraClass { public: CameraClass(); CameraClass(const CameraClass&); ~CameraClass(); ? void SetPosition(float, float, float); void SetRotation(float, float, float); ? D3DXVECTOR3 GetPosition(); D3DXVECTOR3 GetRotation(); ? void Render(); void GetViewMatrix(D3DXMATRIX&); ? private: float m_positionX, m_positionY, m_positionZ; float m_rotationX, m_rotationY, m_rotationZ; D3DXMATRIX m_viewMatrix; };

其中,SetPosition和SetRotation函數用來設置鏡頭對象的位置和旋轉。Render函數基于位置和旋轉信息創建視點矩陣。GetViewMatrix用來訪問視點矩陣。

構造函數把位置和旋轉設置為場景的原點:

CameraClass::CameraClass() { m_positionX = 0.0f; m_positionY = 0.0f; m_positionZ = 0.0f; ? m_rotationX = 0.0f; m_rotationY = 0.0f; m_rotationZ = 0.0f; } ? ? CameraClass::CameraClass(const CameraClass& other) { } ? ? CameraClass::~CameraClass() { }

兩個set函數:

void CameraClass::SetPosition(float x, float y, float z) { m_positionX = x; m_positionY = y; m_positionZ = z; return; } ? ? void CameraClass::SetRotation(float x, float y, float z) { m_rotationX = x; m_rotationY = y; m_rotationZ = z; return; }

兩個get函數:

D3DXVECTOR3 CameraClass::GetPosition() { return D3DXVECTOR3(m_positionX, m_positionY, m_positionZ); } ? ? D3DXVECTOR3 CameraClass::GetRotation() { return D3DXVECTOR3(m_rotationX, m_rotationY, m_rotationZ); }

Render函數用位置和旋轉信息構造和更新視點矩陣。這里除了位置和旋轉,還需要指定一個“上”方向和鏡頭朝向。接下來,首先在原點處根據x,y,z的值旋轉鏡頭,旋轉之后再把鏡頭移動到三維空間中的指定位置上。當位置、旋轉、方向“上”和所觀察的位置都確定下來后,就可以用DX10中的D3DXMatrixLookAtLH函數創建視點矩陣了:

void CameraClass::Render() { D3DXVECTOR3 up, position, lookAt; float yaw, pitch, roll; D3DXMATRIX rotationMatrix; ? ? // Setup the vector that points upwards. up.x = 0.0f; up.y = 1.0f; up.z = 0.0f; ? // Setup the position of the camera in the world. position.x = m_positionX; position.y = m_positionY; position.z = m_positionZ; ? // Setup where the camera is looking by default. lookAt.x = 0.0f; lookAt.y = 0.0f; lookAt.z = 1.0f; ? // Set the yaw (Y axis), pitch (X axis), and roll (Z axis) rotations in radians. pitch = m_rotationX * 0.0174532925f; yaw = m_rotationY * 0.0174532925f; roll = m_rotationZ * 0.0174532925f; ? // Create the rotation matrix from the yaw, pitch, and roll values. D3DXMatrixRotationYawPitchRoll(&rotationMatrix, yaw, pitch, roll); ? // Transform the lookAt and up vector by the rotation matrix so the view is correctly rotated at the origin. D3DXVec3TransformCoord(&lookAt, &lookAt, &rotationMatrix); D3DXVec3TransformCoord(&up, &up, &rotationMatrix); ? // Translate the rotated camera position to the location of the viewer. lookAt = position + lookAt; ? // Finally create the view matrix from the three updated vectors. D3DXMatrixLookAtLH(&m_viewMatrix, &position, &lookAt, &up); ? return; } GetViewMatrix: void CameraClass::GetViewMatrix(D3DXMATRIX& viewMatrix) { viewMatrix = m_viewMatrix; return; }

至此,我們搞定了負責渲染的shader、負責調用shader的ColorShaderClass、用來存儲模型的ModelClass,以及負責管理視點信息的CamaraClass。

下面的故事是,在MFC的MDI框架中,應該怎樣用這些類?

從功能上看,文檔和視圖分別對應數據和顯示,在這個例子里,模型是數據(ModelClass),ColorShaderClass實現顯示(實際上是shader,color.fx),所以模型嵌入到文檔類,而ColorShaderClass集成進視圖類。

在文檔類中添加ModelClass類指針,這里為了訪問方便,直接設置為public:

#include "ModelClass.h" class CMy02_01Doc : public CDocument { ... public: ModelClass * m_pMesh; ... };

目前文檔類要改的有三處:

構造函數:

CMy02_01Doc::CMy02_01Doc() { // TODO: add one-time construction code here m_pMesh = NULL; }

在新建文檔時創建模型:

BOOL CMy02_01Doc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; ? // TODO: add reinitialization code here // (SDI documents will reuse this document) m_pMesh = new ModelClass(); return TRUE; }

關閉文檔時釋放內存:

CMy02_01Doc::~CMy02_01Doc() { if(m_pMesh) { m_pMesh->Shutdown(); delete m_pMesh; m_pMesh = NULL; } }

接下來是顯示相關的內容。鏡頭類和ColorShaderClass類都集成到視圖類中。

#include <CameraClass.h> #include <Colorshaderclass.h> ? class CMy02_01View : public CView { ... CameraClass * m_Camara; ColorShaderClass * m_ColorShader; ... };

構造函數:

CMy02_01View::CMy02_01View() { // TODO: add construction code here ... ? m_Camara = NULL; m_ColorShader = NULL; }

給視圖類添加一個建立camera、shader對象并進行初始化的函數ShaderInitialize,由于模型是在文檔類里創建和銷毀的,所以這里只要弄一個臨時指針指向模型對象就行了,不需要操心資源管理的事兒:

bool CMy02_01View::ShaderInitialize() { bool result; ? HWND hwnd = GetSafeHwnd(); ? // Create the camera object. m_Camera = new CameraClass(); if(!m_Camera) { return false; } ? // Set the initial position of the camera. m_Camera->SetPosition(0.0f, 0.0f, -10.0f); ? // Create the model object. ModelClass * pmesh = ((CMy02_01Doc *)GetDocument())->m_pMesh; if(!pmesh) { MessageBox(L"NULL Model!!"); return false; } result = pmesh->Initialize(m_device); if(!result) { MessageBox(L"Could not initialize the model object."); return false; } ? // Create the color shader object. m_ColorShader = new ColorShaderClass(); if(!m_ColorShader) { return false; } ? // Initialize the color shader object. result = m_ColorShader->Initialize(m_device, hwnd); if(!result) { MessageBox(L"Could not initialize the color shader object."); return false; } ? return true; }

這個初始化函數在OnInitialUpdate中DX環境初始化后調用:

void CMy02_01View::OnInitialUpdate() { CView::OnInitialUpdate(); ? // TODO: Add your specialized code here and/or call the base class InitDX(); ShaderInitialize(); }

再添加一個相應的資源釋放函數,該函數在視圖類的析構函數中調用:

void CMy02_01View::ShutDownShader() { // Release the color shader object. if(m_ColorShader) { m_ColorShader->Shutdown(); delete m_ColorShader; m_ColorShader = NULL; } ? // Release the camera object. if(m_Camera) { delete m_Camera; m_Camera = 0; } }

最后在OnPaint中完成繪制功能:

void CMy02_01View::OnPaint() { D3DXMATRIX viewMatrix, projectionMatrix, worldMatrix; ? CPaintDC dc(this); // device context for painting // TODO: Add your message handler code here // Do not call CView::OnPaint() for painting messages float color[4]; ? ? // Setup the color to clear the buffer to. color[0] = 1.0f; color[1] = 0.0f; color[2] = 0.0f; color[3] = 1.0f; ? // Clear the back buffer. m_device->ClearRenderTargetView(m_renderTargetView, color); ? // Clear the depth buffer. m_device->ClearDepthStencilView(m_depthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0); ? // Generate the view matrix based on the camera's position. m_Camera->Render(); ? // Get the world, view, and projection matrices from the camera and d3d objects. m_Camera->GetViewMatrix(viewMatrix); GetWorldMatrix(worldMatrix); GetProjectionMatrix(projectionMatrix); ? ModelClass * pmesh = ((CMy02_01Doc *)GetDocument())->m_pMesh; pmesh->Render(m_device); ? // Render the model using the color shader. m_ColorShader->Render(m_device, pmesh->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix); ? if(m_vsync_enabled) { // Lock to screen refresh rate. m_swapChain->Present(1, 0); } else { // Present as fast as possible. m_swapChain->Present(0, 0); } }

運行效果,弱爆了T_T

下面理一理頭緒,回憶一下,上面的shader、ColorShaderClass、ModelClass、CameraClass都是咋回事兒來著?

shader:

(1)它是一個擴展名為.fx的文件

(2)它的入口是technique,這玩意好比main

(3)shader里面還為vertex shader和pixel shader分別定義了頂點類型

(4)分別實現了vertex shader和pixel shader函數

(5)vertex buffer里的數據送進GPU后,會先讓vertex shader處理,然后再送進pixel shader

(6)別忘了類型匹配那些事兒

ModelClass:

(1)這是一個模型類,雖然現在這個模型很簡單

(2)模型類創建了vertex buffer(注意頂點順序)和index buffer,并且設置了具體的值(也就是把三角形的各個頂點坐標和顏色值都寫進了buffer里面)

(3)模型類激活了vertex buffer和index buffer,讓GPU知道,這塊數據可以進行繪制了。

(4)模型類告訴GPU,用三角形的方式繪制buffer里的內容

ColorShaderClass:

(1)ColorShaderClass是用來調用shader的

(2)ColorShaderClass要創建并設置與shader中定義的頂點類型匹配的layout,讓GPU知道vertex buffer中數據的格式

(3)ColorShaderClass會獲取shader中那三個全局矩陣的指針,并設置這三個矩陣的值

(4)ColorShaderClass會獲取technique的描述,讓GPU知道調用哪些shader函數去繪制,然后循環調用technique中的各個pass進行繪制

CameraClass:

(1)它會設置鏡頭位置和旋轉角度

(2)它會根據鏡頭位置和旋轉角度生成視點變換矩陣

最后,還有一幅惡心的大圖,描述了程序的整個流程和關鍵數據的傳輸途徑:

PS:英文原文教程地址http://www.rastertek.com/dx10tut04.html,根據自己的需要進行了小小改動。

總結

以上是生活随笔為你收集整理的GPU Shader 编程基础的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

国产永久网站 | 在线观看网站av | 国产亚洲精品久久久久久久久久 | 亚洲专区在线播放 | 国产福利一区在线观看 | 国产成人av | 男女视频91 | 亚洲欧美日本A∨在线观看 青青河边草观看完整版高清 | 精品国产一二三 | 国产亚洲精品久久久久久久久久久久 | 亚洲国产精品小视频 | 一级淫片在线观看 | 久久久精品久久日韩一区综合 | 国产成人av电影在线观看 | 福利视频网址 | 国产视频久 | 天天曰天天爽 | 在线观看亚洲视频 | 激情综合色综合久久综合 | 国产精品视频内 | www.国产视频 | 在线播放第一页 | 久久久网站 | 国产亚洲婷婷 | 中文字幕欧美日韩va免费视频 | 麻花豆传媒mv在线观看网站 | 国产主播99 | 日韩高清在线一区二区三区 | 亚洲国产精品成人av | 日本中文字幕久久 | 亚洲免费av电影 | 免费看片网站91 | 亚洲三级在线免费观看 | 99精品国产兔费观看久久99 | 日日干干夜夜 | 日本韩国精品在线 | 亚洲天堂网在线视频观看 | 日韩国产欧美视频 | 天天操天天操天天操天天 | 国产91av视频在线观看 | 973理论片235影院9 | 九九涩涩av台湾日本热热 | 亚洲91精品在线观看 | 久久久久久久久久久久电影 | 久久综合九色欧美综合狠狠 | 亚洲视频,欧洲视频 | 狠狠色伊人亚洲综合成人 | 91中文字幕在线播放 | 国产剧情一区二区在线观看 | 国产无限资源在线观看 | 激情小说网站亚洲综合网 | 最近的中文字幕大全免费版 | 天天超碰 | 中文av日韩 | 久久国产精品精品国产色婷婷 | 国产亚洲精品久久19p | 中文字幕视频在线播放 | 天天干,天天射,天天操,天天摸 | 精品中文字幕视频 | 久久看视频| 国产精品1区2区在线观看 | 99久久精品久久亚洲精品 | 亚洲全部视频 | 99精品视频在线播放免费 | 在线观看av不卡 | 成人av免费在线观看 | 亚洲精品视频免费观看 | 精品久久久久久久久久久久久久久久久久 | 色就色,综合激情 | 日韩电影一区二区三区在线观看 | 91久久丝袜国产露脸动漫 | 超碰在线1| 国产精品精品久久久 | 永久免费毛片 | 久久黄色小说视频 | 成人免费在线视频 | 五月在线视频 | 在线看黄网站 | 免费看一级特黄a大片 | 欧美日韩伦理在线 | 成片免费观看视频 | 国产3p视频| 欧美成人h版电影 | 在线观看久草 | 日韩视频 一区 | 久久久污 | 欧美做受高潮电影o | 欧美成人在线免费观看 | 国产在线观看高清视频 | 精品黄色在线观看 | 久久久 激情 | 色综合久久久久久久久五月 | 欧美日韩中文在线视频 | 色视频网站在线观看一=区 a视频免费在线观看 | 日韩av有码在线 | 天天艹天天爽 | 国产麻豆精品一区 | 欧美最猛性xxxx| 成人a视频在线观看 | 中文字幕av电影下载 | 精品国产视频在线观看 | 婷婷六月天综合 | 国产成人av片 | 久久婷亚洲五月一区天天躁 | 精品国产综合区久久久久久 | 国产成人久久精品一区二区三区 | 国产一级三级 | 波多野结衣在线观看视频 | 亚洲成a人片77777潘金莲 | 中文字幕制服丝袜av久久 | 国产手机视频在线观看 | 中文字幕免费在线 | 中文字幕亚洲欧美日韩 | 91精品播放 | 免费网站看v片在线a | 在线视频精品 | 国产91精品一区二区绿帽 | 91精品免费在线观看 | 久草手机视频 | 天天草av | 亚洲天天看 | 欧美不卡视频在线 | av+在线播放在线播放 | 久久久久久久久亚洲精品 | 久久久久久久久久久久久国产精品 | 国产成人精品一区二区三区福利 | 欧美精品久久 | 日本在线视频网址 | 韩国精品视频在线观看 | 人人干在线 | 波多野结衣在线中文字幕 | 国产黄色免费在线观看 | 天天爽天天爽天天爽 | 久久久久色 | 日韩精品一区电影 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 日本在线观看一区 | 九色琪琪久久综合网天天 | 日批视频在线 | 久久免费av| 国产精品视频观看 | 国内精品国产三级国产aⅴ久 | 91九色在线视频 | 中文字幕精品视频 | 国产精品成久久久久三级 | 黄污视频网站大全 | 欧美另类一二三四区 | 最近中文字幕大全 | www色,com| 欧美午夜性生活 | 国产区在线| 国产在线一线 | 成人观看视频 | 在线视频日韩一区 | 日韩欧美一区二区三区在线观看 | 91久久精品一区 | 国产中文字幕一区二区 | 亚洲一级片在线看 | 黄在线免费观看 | 九九热国产视频 | 激情久久久 | 国产成人av电影在线 | 国产一区二区网址 | 在线成人观看 | 亚洲精品字幕在线观看 | 嫩草av在线| 国产视频资源在线观看 | 一区二区精品在线视频 | 人人看97| 日韩高清www| 中文字幕精品视频 | 日韩理论视频 | 成人四虎| 午夜a区 | 成人黄色国产 | 91成人短视频在线观看 | 国产原厂视频在线观看 | www.久久成人| 国产黄在线 | 97成人在线观看 | 国产午夜麻豆影院在线观看 | 亚洲精品国产高清 | 日韩三级在线观看 | 免费视频成人 | 久久免费美女视频 | 久久国产精品久久精品国产演员表 | 日韩天天干 | 免费视频在线观看网站 | 美腿丝袜一区二区三区 | 人人插人人 | 日韩中文字幕一区 | 国产成人精品福利 | 97视频在线播放 | 免费网站看v片在线a | 网址你懂的在线观看 | 2024国产在线 | 免费观看av | 久久女同性恋中文字幕 | 欧美性脚交 | 国产一区二区三区免费在线 | 一区二区三区四区五区在线 | 亚洲无吗视频在线 | 色视频网站免费观看 | 日韩高清一 | 97视频免费在线 | 亚洲 欧美 另类人妖 | 欧美va电影 | 2023av| 在线观看不卡的av | 国产乱码精品一区二区三区介绍 | 天天综合91 | 欧美一级电影免费观看 | 色就干| 99视频在线免费观看 | 日本在线观看中文字幕 | 国产精品h在线观看 | 九九99| 精品日韩在线 | 日韩综合精品 | 国产精品入口传媒 | 国产精品专区在线观看 | 久久伊人婷婷 | 在线观看免费一区 | 中文在线a∨在线 | 欧美综合色 | 色婷婷啪啪免费在线电影观看 | 国产精品综合久久久久久 | 久久天| 中文字幕免费一区二区 | av大全在线免费观看 | 亚洲香蕉在线观看 | 一本色道久久精品 | 91在线中文 | 麻豆视频免费在线 | 国产精品久久久久久久久久久久 | 亚洲激情国产精品 | 丁香久久五月 | 亚洲视频,欧洲视频 | 欧美性精品| 色偷偷网站视频 | 98久久 | 日韩精品欧美专区 | 综合网久久| 久草影视在线 | 在线播放 一区 | 日韩欧美视频一区二区 | 少妇超碰在线 | 91人人射 | 免费观看v片在线观看 | 国产精品一区二区av | 在线欧美a| 亚洲狠狠 | 日韩特级毛片 | 91在线91 | 日韩电影在线视频 | 欧洲成人免费 | 精品视频 | av黄色免费在线观看 | 婷婷色在线视频 | 奇米四色影狠狠爱7777 | av在线最新 | 欧美日韩国产一区二区三区 | 6699私人影院| 特黄特色特刺激视频免费播放 | 日本69hd | 波多野结衣在线视频免费观看 | 欧美亚洲国产一卡 | 欧美日本不卡视频 | 波多野结衣精品在线 | se视频网址 | www.夜夜夜| 97超碰在线资源 | 91亚洲国产成人久久精品网站 | 久久在线观看 | av福利网址导航大全 | 亚洲三区在线 | 国产日韩欧美精品在线观看 | 久久久久国产一区二区三区 | www.亚洲精品在线 | 中中文字幕av在线 | 91爱爱中文字幕 | 九九九九精品 | 91大神精品视频在线观看 | 一区二区激情 | 国产精品不卡在线播放 | 久久久精品电影 | 国产在线精品区 | 国内免费久久久久久久久久久 | 中字幕视频在线永久在线观看免费 | 蜜臀av免费一区二区三区 | 日本激情视频中文字幕 | 亚洲理论片 | 在线视频你懂得 | 国产三级视频在线 | 午夜视频播放 | av短片在线观看 | 国产美女网 | 在线观看日韩精品 | 在线观看视频免费播放 | 激情五月婷婷 | 中文字幕黄网 | 综合精品久久 | 一级片免费在线 | 国产精品久久久久久久久免费看 | 少妇bbw搡bbbb搡bbbb | 国产精品v欧美精品v日韩 | 久热色超碰 | 国产精品一区二区在线观看免费 | 成人h在线播放 | 久久99在线视频 | 人人草人 | 久久草在线视频国产 | 欧美日韩国产在线一区 | 一级黄色片在线播放 | 在线观看国产日韩欧美 | 日韩高清在线观看 | 国产美女精品视频免费观看 | 色多多视频在线观看 | 亚洲视频网站在线观看 | 久久精品国产v日韩v亚洲 | 97超碰在线视 | 国产一二三在线视频 | 中文字幕在线观看免费观看 | 国产精品久久久久久久久大全 | 日日日爽爽爽 | 欧美日韩超碰 | 久久亚洲综合国产精品99麻豆的功能介绍 | 久久精品免费观看 | 天堂在线成人 | 国产免费大片 | 色视频在线观看 | 999一区二区三区 | 中文字幕有码在线播放 | 国产精品国产亚洲精品看不卡 | 久久97精品 | 99久久久国产免费 | av中文字幕不卡 | 私人av| 国产视频2区 | 国产手机视频在线观看 | 中文字幕av在线 | 99久久超碰中文字幕伊人 | av一本久道久久波多野结衣 | 成人资源在线观看 | 青青河边草观看完整版高清 | 亚洲综合网站在线观看 | 日韩欧美高清 | 欧美欧美 | 国产精品日韩高清 | 亚洲一级黄色片 | 成人在线播放视频 | 国产精品女同一区二区三区久久夜 | 亚洲aⅴ一区二区三区 | 久草资源在线 | 天天综合精品 | 中文字幕欧美日韩va免费视频 | 国产精品正在播放 | 香蕉久草| 五月综合婷 | 中文字幕黄色网 | 四虎海外影库www4hu | 激情综合网五月婷婷 | 波多野结衣在线中文字幕 | 久久久久国产精品午夜一区 | 91爱在线| 国产精品99久久久久久武松影视 | 91大神一区二区三区 | 91视频在线国产 | 久久免费国产电影 | 午夜av一区 | 日韩乱色精品一区二区 | 午夜精品一二区 | 国产裸体视频网站 | 国产一级在线看 | 在线观看一级片 | 国产精品久久久久久五月尺 | 奇米影视777影音先锋 | 天天操夜夜看 | www.天天成人国产电影 | 视频99爱 | 三级在线国产 | 精品91| 亚洲精品一区二区久 | 97天天干 | 玖玖精品在线 | av免费看电影 | 久久亚洲精品国产亚洲老地址 | 在线精品视频免费观看 | 最新av免费在线 | av一区二区在线观看中文字幕 | 国产精品手机在线观看 | 婷婷丁香av | 97在线免费观看 | 国产 欧美 日产久久 | 国产亚洲精品久久久久秋 | 青青河边草免费直播 | 国产免费激情久久 | 国产美女搞久久 | 美女网站色| 国产一卡在线 | 国产在线观看你懂的 | 天天综合婷婷 | 欧美日韩在线观看视频 | 日日夜夜婷婷 | 91精品伦理 | 亚洲视频免费在线观看 | 国产一级做a| 韩国一区二区三区视频 | 免费看黄色大全 | 97超碰国产精品女人人人爽 | 天天操天天干天天 | 亚洲精品在线一区二区 | 国产午夜剧场 | 4438全国亚洲精品在线观看视频 | 成人av av在线| 欧洲亚洲女同hd | 看片在线亚洲 | 亚洲精品乱码久久久久久9色 | 国内精品久久久久久久久久清纯 | 美女视频黄在线 | 国产1区2区3区在线 亚洲自拍偷拍色图 | 在线视频成人 | 国产69精品久久久久99 | 久久久精品视频网站 | 日本最新中文字幕 | www.天天成人国产电影 | 在线之家免费在线观看电影 | 在线观看理论 | 全久久久久久久久久久电影 | 免费视频成人 | 亚洲黄色在线 | 黄a在线观看| 国产96在线观看 | 美国av大片 | 日韩精品一区二区三区中文字幕 | 最新国产精品亚洲 | 亚洲精品日韩一区二区电影 | 久久久久久久福利 | 日韩精选在线 | 狠狠色狠狠色综合日日小说 | 激情五月在线观看 | 久久激情电影 | 欧美日韩在线观看一区二区 | 国产精品国产三级国产aⅴ入口 | 亚洲激情p | 99色视频 | 91精品国产乱码久久桃 | 婷婷色综合色 | 中文乱码视频在线观看 | 区一区二区三区中文字幕 | 欧美成人理伦片 | 草久久久久久久 | 日韩精品亚洲专区在线观看 | www.久草视频 | av丝袜制服| 在线视频第一页 | 午夜av在线电影 | 婷婷www | 精品视频久久久久久 | 久久免费看视频 | 午夜精品一区二区三区可下载 | 欧美日韩另类视频 | 国产精品久久久久四虎 | 久久精品一区二区三区中文字幕 | 91黄色成人 | 十八岁免进欧美 | 久久精品999| 99se视频在线观看 | 日韩丝袜视频 | 91看片成人 | 超碰97成人 | 免费一级特黄录像 | 一级黄色免费 | 99热这里只有精品国产首页 | 日韩精品一区二区在线观看 | 夜夜爽夜夜操 | 99精品视频免费看 | 免费电影一区二区三区 | 中文av影院| 成人国产综合 | 久久网页 | av免费观看高清 | 中文在线亚洲 | 在线看的av网站 | 免费人人干 | 成人毛片一区 | 一级黄色在线免费观看 | 欧美日韩免费一区 | 久久久精品国产一区二区电影四季 | 97夜夜澡人人爽人人免费 | 国产精品黄色在线观看 | 在线精品国产 | 在线国产不卡 | 国产专区视频 | 日韩美女免费线视频 | 中文字幕第一 | 激情视频免费在线观看 | 日韩在线观看第一页 | 日韩久久久久久久久久 | 日本久久中文字幕 | 日韩精品专区在线影院重磅 | 黄色aaaaa| 亚洲一区精品二人人爽久久 | 久草视频国产 | 久久久免费精品视频 | 国产69精品久久久久9999apgf | 日韩精品在线一区 | 中文字幕在线看人 | 午夜婷婷在线播放 | 国内精品视频一区二区三区八戒 | 不卡日韩av | 国产视频2区 | 麻豆国产视频 | 午夜国产福利视频 | 亚洲精品美女久久 | 欧美最猛性xxxxx免费 | 人成午夜视频 | 992tv又爽又黄的免费视频 | 五月天婷婷在线观看视频 | 婷婷六月久久 | 国产精品黄色影片导航在线观看 | 91香蕉视频好色先生 | 精品一区电影 | 精品国产一区二区三区不卡 | 精品国精品自拍自在线 | 91九色在线观看 | 丁香婷婷久久久综合精品国产 | 丰满少妇一级 | 国产成人av一区二区三区在线观看 | 亚洲视频在线观看网站 | 久久人人艹| 日批视频在线 | 99精品视频在线免费观看 | 国产精品久久久久久a | 日本黄色免费在线 | 久久久亚洲国产精品麻豆综合天堂 | 亚洲国产剧情 | 久久这里精品视频 | 人人干狠狠操 | 亚洲国产精品久久久久婷婷884 | 日韩精品欧美精品 | 波多野结衣精品视频 | 夜色成人av | 国产精品午夜av | 国产精品嫩草影院9 | 欧美激情精品久久久久久变态 | 国产精品一区二区果冻传媒 | av先锋中文字幕 | 久草线 | 精品免费| 国产在线精品一区二区三区 | 91cn国产在线| 国产99自拍 | 欧美一级片免费观看 | 美女一级毛片视频 | 亚洲国产视频网站 | 日韩av在线小说 | 天天操夜夜操夜夜操 | 国产午夜精品久久久久久久久久 | 亚州视频在线 | 大胆欧美gogo免费视频一二区 | 国产永久免费高清在线观看视频 | 97精品国自产拍在线观看 | 国产成人精品久久久久蜜臀 | 亚洲成年人免费网站 | 欧美另类高清 | 亚洲午夜久久久久久久久电影网 | 久久五月精品 | 91视频a| 国产 中文 日韩 欧美 | 日韩色综合| 久久国产品| 国产精品网红直播 | 三级性生活视频 | 成人免费在线观看av | 狠狠操天天操 | 色诱亚洲精品久久久久久 | 日本深夜福利视频 | 日韩欧美高清 | 国产精品久久久久影院 | 91在线亚洲 | 免费97视频 | 中文av网| 日韩免费高清在线观看 | 色综合久久精品 | 免费看污片| 久久久久久高潮国产精品视 | 成人久久久久久久久 | av一区二区在线观看中文字幕 | 99久久99视频| 亚洲专区欧美专区 | 91精品国自产在线观看欧美 | 亚洲精品合集 | 日本中出在线观看 | 欧美一区二区三区四区夜夜大片 | 黄色成人91 | 很黄很污的视频网站 | 最近最新mv字幕免费观看 | 国产在线不卡一区 | 久久久久久久久综合 | 色人久久 | 中文字幕久久网 | 日韩午夜精品福利 | 91在线入口 | 欧美福利视频一区 | 9在线观看免费高清完整 | 中文字幕第一页在线视频 | 精品国产一区二区三区久久久 | 亚洲久草网 | 韩国精品福利一区二区三区 | 日韩av在线网站 | 国产成人久久精品77777 | www.国产在线观看 | 日韩视频免费播放 | 午夜日b视频 | 亚洲精品午夜久久久久久久 | 亚洲精品美女久久 | 久久狠狠一本精品综合网 | 天天骚夜夜操 | 99高清视频有精品视频 | 深爱激情开心 | 成人影片在线免费观看 | 午夜视频在线观看一区二区 | 在线观看av片 | 欧美日本不卡高清 | 四虎www| 国产视频每日更新 | 国产97在线视频 | 久久久精品国产一区二区电影四季 | 天天插一插 | 欧美二区视频 | 亚洲 欧洲 国产 精品 | 国产亚洲午夜高清国产拍精品 | 色综合久久网 | 欧美激精品 | 国产欧美精品xxxx另类 | 美女免费电影 | 欧美日韩视频在线观看一区二区 | 国产精品扒开做爽爽的视频 | 天天干夜夜操视频 | 一区二区三区精品在线 | 91av在线免费播放 | 国语久久| 国产日韩精品一区二区 | 日韩精品2区 | 成人一区电影 | 国产一区福利在线 | 国产韩国精品一区二区三区 | 欧美成人a在线 | 日韩久久精品一区二区三区 | 久久久久久毛片精品免费不卡 | 国产精品一区二区三区在线看 | 国产精品嫩草55av | 欧美色图88 | 国产一区麻豆 | 亚洲最大免费成人网 | 午夜.dj高清免费观看视频 | 国产精品久久久久久久久蜜臀 | 欧洲色吧 | 99国产在线观看 | 精品在线免费视频 | 日韩免费观看av | 国产精品久久久久久吹潮天美传媒 | 在线观看视频你懂得 | 国产综合香蕉五月婷在线 | 欧美日韩中文字幕视频 | 麻豆 videos| 就操操久久 | 欧美日韩视频在线 | 黄色软件在线观看视频 | 久久久 激情 | 亚洲成aⅴ人片久久青草影院 | 在线观看91网站 | 国产精品99久久久久久武松影视 | 女人高潮特级毛片 | 精品久久久久久久久久久院品网 | 国产精品一区二区三区在线播放 | 天天色天天操天天爽 | 91免费高清视频 | 国产精品mm| 日韩在线免费观看视频 | 日韩午夜电影院 | 成人av一区二区兰花在线播放 | 亚洲精选国产 | 亚洲精品www.| 天天射天天爱天天干 | 99欧美 | 天天操天天拍 | 九九热在线观看视频 | 精品欧美在线视频 | 亚洲欧洲成人精品av97 | 日韩a级免费视频 | 中文字幕在线观看一区二区三区 | 国产在线理论片 | 1000部18岁以下禁看视频 | 色停停五月天 | 国产 日韩 中文字幕 | 免费看久久久 | 婷婷色网址 | 国产裸体永久免费视频网站 | 国内成人精品视频 | 久草在线欧美 | 中文视频在线播放 | 免费av成人在线 | 91九色网站| 99精品久久久久久久久久综合 | 中文字幕久久精品一区 | 中文字幕 在线 一 二 | 99精品免费在线观看 | 在线观看国产日韩 | 正在播放国产精品 | 超碰免费公开 | 青草视频在线 | 日韩在线免费播放 | 国产麻豆电影在线观看 | 久久精品精品电影网 | av高清不卡 | 欧美精品一区二区三区一线天视频 | 久久免费视频7 | 美女在线免费视频 | 西西人体www444 | 久久久久国产免费免费 | 国产精品第54页 | 玖草在线观看 | 国产中文字幕在线视频 | 国产精品久久久久久久婷婷 | 日日干天天爽 | 精品免费观看视频 | 成人免费 在线播放 | 久草国产在线 | 一区av在线播放 | 精品少妇一区二区三区在线 | 成人av观看| 狠狠色丁香婷综合久久 | 欧美精品久久99 | 国产精在线 | 99麻豆视频 | 亚洲免费国产视频 | 99久热精品 | 国产成人在线免费观看 | 在线观看视频在线观看 | 国产成人61精品免费看片 | 国产精品av在线免费观看 | 久久国产麻豆 | 国产aa免费视频 | 玖玖国产精品视频 | 亚洲精品一区中文字幕乱码 | 亚洲精品xxx | 久久一区精品 | 久久久www成人免费精品 | 日韩伦理片一区二区三区 | 激情综合国产 | 日韩电影在线观看一区 | 三上悠亚在线免费 | 婷婷网五月天 | 亚洲区另类春色综合小说校园片 | 久久久久久黄 | 久久精品视频免费观看 | 色婷婷亚洲精品 | 免费麻豆| 国产 日韩 在线 亚洲 字幕 中文 | 亚洲国产欧美在线人成大黄瓜 | 超碰在97 | 日韩在线视频观看 | 成人a免费 | 四川妇女搡bbbb搡bbbb搡 | 在线观看免费成人 | 国产中文字幕久久 | a视频在线播放 | 在线观看视频福利 | 制服丝袜成人在线 | 国产视频一区在线免费观看 | 国产精品嫩草在线 | 在线成人免费电影 | 国产成人精品a | 国产精品12 | 美女免费视频一区二区 | 久久在草 | 国内精品久久久久久久久久清纯 | 国产精品毛片一区二区 | zzijzzij日本成熟少妇 | 日韩成人免费在线 | 国产一区不卡在线 | 中文字幕在线播出 | 综合色婷婷 | 国产专区视频在线 | 亚洲免费精品一区二区 | 日韩一区正在播放 | 香蕉久草 | 天天色天天骑天天射 | 操操操com| 亚洲少妇影院 | 久久久久在线观看 | 久久免费在线 | 超碰在线最新地址 | 久久国产精品免费 | 久久国产一区二区三区 | 中文字幕在线观看免费高清电影 | 久久影视一区 | 中文字幕在线观看视频网站 | 在线a亚洲视频播放在线观看 | 在线免费中文字幕 | 天天操天天操天天爽 | 激情综合色图 | 国产精品中文字幕在线 | 欧美另类z0zx | 日本性高潮视频 | 亚洲天堂网站 | 午夜精品久久久久久久爽 | 亚洲国产美女精品久久久久∴ | 欧美做受xxx | 黄色大片视频网站 | 亚洲国产电影在线观看 | 超碰在线天天 | 国产精品成人一区二区 | 黄色片网站大全 | 99精品一区二区三区 | 国产精国产精品 | 国产成人精品久久久 | 国产91免费在线 | 91传媒在线播放 | 国产精品对白一区二区三区 | 97网站| 超碰97国产 | 激情久久五月天 | 国产精品va在线观看入 | 欧美精品一区二区免费 | 韩国精品福利一区二区三区 | 91一区在线观看 | 久久久影片| 欧美乱码精品一区 | 久久久久久欧美二区电影网 | 午夜在线看片 | 免费在线视频一区二区 | 五月婷婷电影网 | 国产精品免费在线播放 | 91污在线观看 | 国产69精品久久99不卡的观看体验 | 激情中文在线 | 伊人网av | 亚洲欧美日韩精品久久奇米一区 | 欧美日韩国语 | 免费观看版 | av免费观看在线 | 亚洲一区网 | 久久 一区 | 久久精品福利视频 | 中文字幕 在线看 | 免费在线看v | 97国产大学生情侣白嫩酒店 | 久久视频中文字幕 | 久久伊人八月婷婷综合激情 | 依人成人综合网 | 久久国产精品第一页 | 亚洲国产一区在线观看 | 四虎在线永久免费观看 | 一区二区三区不卡在线 | 中国一级片在线观看 | 午夜精品久久久99热福利 | 亚洲国产免费网站 | 欧美亚洲专区 | 国产一级久久久 | 黄色一级大片免费看 | 婷婷去俺也去六月色 | 成人免费大片黄在线播放 | www黄免费| 日韩精品视频免费在线观看 | 国产精品亚洲片在线播放 | 特级西西444www大胆高清无视频 | 国产在线观看99 | 久久婷婷色综合 | 亚洲香蕉视频 | 波多野结衣视频在线 | 亚洲黄网站 | av不卡免费在线观看 | 亚洲美女视频网 | 国产偷国产偷亚洲清高 | 亚洲色图激情文学 | 国产免费中文字幕 | 日韩免费视频播放 | 国产91免费看 | 久久久久激情电影 | 在线播放av网址 | 国产无遮挡又黄又爽在线观看 | 成人少妇影院yyyy | a黄色片| av大全免费在线观看 | 久草视频免费 | 久久激情片 | 99视频网址 | 青草草在线视频 | 天天操夜夜曰 | 在线观看免费av网 | 色综合天天干 | 麻豆一级视频 | 国精产品999国精产品视频 | 综合色在线观看 | 久久久久久久久久久福利 | 主播av在线 | 精品国产乱码久久久久久1区2匹 | 中文在线字幕免 | 天天射网 | 99精品黄色片免费大全 | 麻豆视频免费在线观看 | 久久久精品网站 | 亚洲片在线 | 日韩一级电影网站 | 91九色精品国产 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 日日夜夜人人精品 | 欧美日韩在线免费观看 | 免费看国产精品 | 91麻豆精品国产91久久久使用方法 | 国产老太婆免费交性大片 | 亚洲精品白浆高清久久久久久 | 国产三级视频 | 亚洲精品乱码 | 精品国产乱码久久久久久久 | av日韩在线网站 | 五月婷婷综合网 | 亚洲精品在线观看中文字幕 | 日韩理论影院 | 久久久av电影 | 在线91色 | 中字幕视频在线永久在线观看免费 | 日韩国产高清在线 | 欧美日韩国产精品爽爽 | 日韩h在线观看 | 国产青草视频在线观看 | 欧美精品三级在线观看 | 亚洲精品乱码久久久久 | 国产精品日韩高清 | 91精品资源| 玖玖在线资源 | 国产一区成人 | 美女在线观看网站 | 嫩草伊人久久精品少妇av | 欧美一区二区三区在线观看 | 激情五月综合 | 黄网av在线| 一本色道久久精品 | 亚洲国产三级 | 国产一区在线播放 | 久久久久国产视频 | 插综合网 | 久久久久在线 | 亚洲黄色一级视频 | 国产麻豆视频免费观看 | 日日麻批40分钟视频免费观看 | 96亚洲精品久久久蜜桃 | 欧美日韩在线视频一区 | 中文字幕黄网 | 色午夜 | 在线观看成年人 | 国产精品porn| 夜夜操综合网 | 天堂在线视频中文网 | www.久久久com | 992tv成人免费看片 | 久久精品视频网 | 午夜精品99久久免费 | 97狠狠操 | 2023av在线| 激情五月综合 | 成在线播放 | 欧美日韩精品在线观看视频 | 日韩精品一区二区三区在线播放 | 丁香花在线观看免费完整版视频 | 国产精品四虎 | 日本三级大片 | 中文字幕视频一区 | 亚洲精品女人久久久 | 人人玩人人添人人澡超碰 | 激情综合网在线观看 | 不卡的av在线播放 | 久久1区| 亚洲欧美综合 | 激情综合六月 | 免费黄色在线网站 | 一区二区三区在线播放 | 中文字幕免费一区 | 草久热 | 成年人在线视频观看 | 在线观看日韩视频 | 精品中文字幕在线播放 | 午夜91视频 | 激情丁香综合 | 中文字幕视频免费观看 | 日韩字幕| 成人在线观看av | 日韩免费电影网 | 在线欧美国产 | 69国产成人综合久久精品欧美 | 中文字幕一区二区三区精华液 | 亚洲成人av片 | 91九色国产| 亚洲精品乱码久久久久久久久久 | 国产在线精品国自产拍影院 |