例子来源:Nvidia openGL SDK10——instanced_Tesslation
主要原理:openGL并没有和DX一样,采用硬件方式,而是采用UniformBuffer + EXT_draw_instanced扩展的方式实现Tesslator
1、将模型所有控制点存入UniformBuffer当中
2、绘制时所用顶点位置VB,存的是Tesslation所需的辅助信息,类似DX中SV_TessFactor,而IndexVB形成instance绘制所需的primitive type而已。当然这两个buffer大小都根据tesslation的程度扩展。
3、在绘制时,每个顶点都被绘制了instanceCount次,每次位置都根据instanceID进行相应改变,相当于一 次绘制了instanceCount个顶点。(instanceCount由控制点个数固定,若要模型更细腻,则需有更多的patch * 顶点数每patch * InstanceCount)
下面是VertShader(fragShader和普通类似):
#version 120 #extension GL_EXT_bindable_uniform : enable #extension GL_EXT_gpu_shader4 : enable bindable uniform vec4 vertices[%d]; varying vec3 v_Normal; void main(void) { vec3 p[16]; for (int i = 0; i < 16; i++) { p[i] = vertices[gl_InstanceID * 16 + i].xyz; } vec2 uv = gl_Vertex.xy; vec2 B0 = (1 - uv) * (1 - uv) * (1 - uv); vec2 B1 = 3 * uv * (1 - uv) * (1 - uv); vec2 B2 = 3 * uv * uv * (1 - uv); vec2 B3 = uv * uv * uv; vec3 pos = (B0.x * p[ 0] + B1.x * p[ 1] + B2.x * p[ 2] + B3.x * p[ 3]) * B0.y + (B0.x * p[ 4] + B1.x * p[ 5] + B2.x * p[ 6] + B3.x * p[ 7]) * B1.y + (B0.x * p[ 8] + B1.x * p[ 9] + B2.x * p[10] + B3.x * p[11]) * B2.y + (B0.x * p[12] + B1.x * p[13] + B2.x * p[14] + B3.x * p[15]) * B3.y; vec2 T0 = (1 - uv) * (1 - uv); vec2 T1 = 2 * uv * (1 - uv); vec2 T2 = uv * uv; vec3 dv = (B0.x * (p[ 4]-p[0]) + B1.x * (p[ 5]-p[1]) + B2.x * (p[ 6]-p[ 2]) + B3.x * (p[ 7]-p[ 3])) * T0.y + (B0.x * (p[ 8]-p[4]) + B1.x * (p[ 9]-p[5]) + B2.x * (p[10]-p[ 6]) + B3.x * (p[11]-p[ 7])) * T1.y + (B0.x * (p[12]-p[8]) + B1.x * (p[13]-p[9]) + B2.x * (p[14]-p[10]) + B3.x * (p[15]-p[11])) * T2.y; vec3 du = (T0.x * (p[ 1]-p[ 0]) + T1.x * (p[ 2]-p[ 1]) + T2.x * (p[ 3]-p[ 2])) * B0.y + (T0.x * (p[ 5]-p[ 4]) + T1.x * (p[ 6]-p[ 5]) + T2.x * (p[ 7]-p[ 6])) * B1.y + (T0.x * (p[ 9]-p[ 8]) + T1.x * (p[10]-p[ 9]) + T2.x * (p[11]-p[10])) * B2.y + (T0.x * (p[13]-p[12]) + T1.x * (p[14]-p[13]) + T2.x * (p[15]-p[14])) * B3.y; gl_Position = gl_ModelViewProjectionMatrix * vec4(pos, 1.0); // gl_TexCoord[0].xy = uv; vec3 nor = cross(du, dv); nor = (length(nor) != 0) ? normalize(nor) : vec3(0.0); v_Normal = gl_NormalMatrix * nor; }