public void CreateProgram(string name) { // Assemble program if (program == 0) { program = OpenGL.glCreateProgram(); } else { uint prevpr = program; program = OpenGL.glCreateProgram(); OpenGL.glDeleteProgram(prevpr); } foreach (ShaderInfo si in compiledbox.Values) { si.glid = CompileShaderObject(si.type, si.name); if (si.glid > 0) { AddWatcher(si.name, ShaderTypeToFileExt(si.type)); OpenGL.glAttachShader(program, si.glid); OpenGL.glDeleteShader(si.glid); } } //можно экономить на этих командах glBindAttribLocation, убрать отсюда и перенес и в сам файл vert от шейдера // разметить эти позиции через layout(location=0) in vec4 aVertexPosition - означает привязка к 0 позиции формата вертбуфера // к аргументу aVertexPosition в шейдере. OpenGL.glLinkProgram(program); int success; OpenGL.glGetProgramiv(program, OpenGL.GL_LINK_STATUS, out success); if (success == OpenGL.GL_FALSE) { int len; OpenGL.glGetProgramiv(program, OpenGL.GL_INFO_LOG_LENGTH, out len); var log = new StringBuilder(len); int length; OpenGL.glGetProgramInfoLog(program, len, out length, log); Log.Write("graphics", "GL Info Log:\n{0}", log.ToString()); throw new InvalidProgramException("Link error in shader program '{0}'".F(name)); } OpenGL.glUseProgram(program); int numUniforms; OpenGL.glGetProgramiv(program, OpenGL.GL_ACTIVE_UNIFORMS, out numUniforms); // забираем все переменные из shader и потом используем для связи с ними текстур var nextTexUnit = 0; samplers.Clear(); for (var i = 0; i < numUniforms; i++) { int length, size; int type; var sb = new StringBuilder(128); OpenGL.glGetActiveUniform(program, i, 128, out length, out size, out type, sb); var sampler = sb.ToString(); if (type == OpenGL.GL_SAMPLER_2D) { samplers.Add(sampler, nextTexUnit); var loc = OpenGL.glGetUniformLocation(program, sampler); OpenGL.glUniform1i(loc, nextTexUnit); nextTexUnit++; } if (type == OpenGL.GL_SAMPLER_2D_ARRAY) { samplers.Add(sampler, nextTexUnit); var loc = OpenGL.glGetUniformLocation(program, sampler); OpenGL.glUniform1i(loc, nextTexUnit); nextTexUnit++; } } }