Текстура за пределами объекта

Версия Minecraft
1.7.10
1,417
44
594
Добрый день.
Хочу узнать как рисовать текстуру за границами модели? например сделать некое "свечение" модели.
Речь заходила о майновском фреймбуффере, но чет "ничера" не понял
 
1,111
47
420
Ааа что за видосик? Почему уже 5 раз за сегодня я о нем слышу? Да и не думаю что из-за него это ибо я уже всех в конфе затеребонькал со своим стремлением сделать блум.

Scala:
import java.io.{BufferedReader, InputStreamReader}

import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.OpenGlHelper
import net.minecraft.client.renderer.texture.{TextureManager, TextureUtil}
import net.minecraft.util.ResourceLocation
import org.lwjgl.opengl.ARBShaderObjects._
import org.lwjgl.opengl.GL11.{GL_DEPTH_COMPONENT, GL_TEXTURE_2D, glBindTexture}
import org.lwjgl.opengl._
import ru.justagod.ogl.render.shader.ShaderException

/**
  * Created by JustAGod on 20.01.2018.
  */
object OGLHelper {
  def bindItemsTexture(): Unit = {
    val manager = Minecraft.getMinecraft.renderEngine
    manager.bindTexture(manager.getResourceLocation(1))
  }

  def bindBlocksTexture(): Unit = {
    val manager = Minecraft.getMinecraft.renderEngine
    manager.bindTexture(manager.getResourceLocation(0))
  }

  def createProgram(vertex: Option[ResourceLocation], fragment: Option[ResourceLocation], geometric: Option[ResourceLocation] = None): Int = {
    val program = glCreateProgramObjectARB()
    if (program == 0) throw new ShaderException("Can't create program")
    if (vertex.nonEmpty) {
      val vertexShader = loadShader(ARBVertexShader.GL_VERTEX_SHADER_ARB, loadShader(vertex.get))
      glAttachObjectARB(program, vertexShader)
    }
    if (fragment.nonEmpty) {
      val fragmentShader = loadShader(ARBFragmentShader.GL_FRAGMENT_SHADER_ARB, loadShader(fragment.get))
      glAttachObjectARB(program, fragmentShader)
    }
    // TODO: Разобраться с геометрическими шейдерами
    /*if (geometric.nonEmpty) {
      val fragmentShader = loadShader(ARBFragmentShader.GL_FRAGMENT_SHADER_ARB, loadShader(fragment.get))
      glAttachObjectARB(program, fragmentShader)
    }*/
    glLinkProgramARB(program)
    if (glGetObjectParameteriARB(program, GL_OBJECT_LINK_STATUS_ARB) == GL11.GL_FALSE) {
      val log = getLogInfo(program)
      glDeleteObjectARB(program)
      throw new ShaderException(s"Can't link program. \n$log")
    }
    program
  }

  def createProgramI(vertex: Option[Int], fragment: Option[Int], geometric: Option[Int] = None): Int = {
    val program = glCreateProgramObjectARB()
    if (program == 0) throw new ShaderException("Can't create program")
    if (vertex.nonEmpty) {
      glAttachObjectARB(program, vertex.get)
    }
    if (fragment.nonEmpty) {
      glAttachObjectARB(program, fragment.get)
    }
    // TODO: Разобраться с геометрическими шейдерами
    /*if (geometric.nonEmpty) {
      val fragmentShader = loadShader(ARBFragmentShader.GL_FRAGMENT_SHADER_ARB, loadShader(fragment.get))
      glAttachObjectARB(program, fragmentShader)
    }*/
    glLinkProgramARB(program)
    if (glGetObjectParameteriARB(program, GL_OBJECT_LINK_STATUS_ARB) == GL11.GL_FALSE) {
      val log = getLogInfo(program)
      glDeleteObjectARB(program)
      throw new ShaderException(s"Can't link program. \n$log")
    }
    program
  }

  def checkObject(obj: Int): Int = if (obj == 0) throw new RuntimeException("Not valid OpenGL object" ) else obj


  def framebufferStatus: Int = {
    checkFbo()
    OpenGlHelper.func_153167_i(GL30.GL_FRAMEBUFFER)
  }

  def loadShader(enum: Int, name: ResourceLocation): Int = loadShader(enum, loadShader(name))

  def loadShader(enum: Int, source: String): Int = {
    val shader = glCreateShaderObjectARB(enum)
    if (shader == 0) {
      throw new ShaderException("Can't create shader")
    }
    glShaderSourceARB(shader, source)
    glCompileShaderARB(shader)
    if (glGetObjectParameteriARB(shader, GL_OBJECT_COMPILE_STATUS_ARB) == GL11.GL_FALSE) {
      val log = getLogInfo(shader)
      glDeleteObjectARB(shader)
      throw new ShaderException(s"Can't compile shader. \n$log")
    }
    shader
  }

  def loadShader(name: ResourceLocation): String = {
    val in = new BufferedReader(new InputStreamReader(Minecraft.getMinecraft.mcResourceManager.getResource(name).getInputStream))
    val builder = new StringBuilder
    while (in.ready()) {
      builder.append(in.readLine()).append('\n')
    }
    builder.toString()
  }

  def deleteFramebuffer(fbo: Int): Unit = {
    checkFbo()
    OpenGlHelper.func_153174_h(fbo)
  }

  def deleteRenderBuffer(buffer: Int): Unit = {
    checkFbo()
    OpenGlHelper.func_153184_g(buffer)
  }

  def deleteTexture(texture: Int): Unit = TextureUtil.deleteTexture(texture)

  def fboSupported: Boolean = OpenGlHelper.framebufferSupported

  def createFbo(): Int = {
    checkFbo()
    OpenGlHelper.func_153165_e
  }

  def bindFbo(fbo: Int): Unit = {
    checkFbo()
    glBindTexture(GL_TEXTURE_2D, 0)
    OpenGlHelper.func_153171_g(OpenGlHelper.field_153198_e, fbo)
  }

  def unbindFbo(): Unit = {
    checkFbo()
    if (OpenGlHelper.isFramebufferEnabled) {
      Minecraft.getMinecraft.getFramebuffer.bindFramebuffer(false)
    } else {
      OpenGlHelper.func_153171_g(OpenGlHelper.field_153198_e, 0)
    }
  }

  def bindFboTexture(fbo: Int, texture: Int): Unit = {
    checkFbo()
    OpenGlHelper.func_153188_a(OpenGlHelper.field_153198_e, OpenGlHelper.field_153200_g, GL11.GL_TEXTURE_2D, texture, 0)
  }

  def createRenderBuffer(): Int = {
    checkFbo()
    OpenGlHelper.func_153185_f
  }

  def bindRenderBuffer(buffer: Int): Unit = {
    checkFbo()
    OpenGlHelper.func_153176_h(OpenGlHelper.field_153199_f, buffer)
  }

  def framebufferRenderBuffer(buffer: Int): Unit = {
    checkFbo()
    OpenGlHelper.func_153190_b(OpenGlHelper.field_153198_e, OpenGlHelper.field_153201_h, OpenGlHelper.field_153199_f, buffer)
  }

  def renderBufferStorage(width: Int, height: Int): Unit = {
    checkFbo()
    OpenGlHelper.func_153186_a(OpenGlHelper.field_153199_f, GL_DEPTH_COMPONENT, width, height)
  }

  private def checkFbo(): Unit = if (!fboSupported) throw new RuntimeException("Frame buffers not supported")

  private def getLogInfo(obj: Int) = glGetInfoLogARB(obj, glGetObjectParameteriARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB))

}

Так вот, видимо я совсем плохой объяснятель. Зачем ты зациклился на майновском фрэйм буффере? Давай пройдемся пошагово.
Создаешь свой фрэйм буффер( ARBFramebufferObject.glGenFramebuffers();) как и все прочие OpenGL штуки фрэймбуффер это просто цифра грубо говоря. Тебе это нужно чтобы получить alpha оболочку вокруг твоей текстуры.
Далее тебе необходимо привязать текстуру к фрэймбуфферу. Сделать тебе это нужно потому что сам по себе фрэйм буффер текстурой не является, а прост фигулька в которую OpenGL рендер отправляет всю инфу о результатах своей работы. Фреймбуффер просто сортирует по полочкам. А полочки бывают разные, но нас интересует только картинка. Делаем мы это так:
Scala:
    val texture = glGenTextures()
    OGLHelper.bindFbo(fbo)
    glBindTexture(GL_TEXTURE_2D, texture)
    GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, null.asInstanceOf[ByteBuffer])
    OGLHelper.bindFboTexture(fbo, texture)
    OGLHelper.checkObject(texture)
width и height это ширина и высота вашей новой текстуры. То есть, допустим у вас есть квадрат 20х20 пикселей и вам нужно вокруг него alpha оболочку забацать => ширина и высота будут 25х25(больше чем 20х20)
Далее я буду скорее всего нести бред, но я его все же принесу.
После этого вписываете glClearColor(0, 0, 0, 0) потом glClear(GL_COLOR_BUFFER_BIT) а после просто рисуете свою загагулину как обычно(только не 1х1 а width x height) затем отвязываете ваш фбо(здесь и далее Frame Buffer Object) OGLHelper.unbindFbo(). Что ж крута теперь вернемся к нашей текстуре. Теперь в ней будет то что вы отрисовали(я где-то мог ошибиться, но это норма, и вы сами захотели это прочитать(скорее всего нужно настроить glViewport(не верьте мне я тупой))).
Привязываем значит текстуру glBindTexture(GL_TEXTURE_2D, texture) далее попробуйте нарисовать текстурированый квадрат и удивитесь. glUniform1i(getUniform("texture"), 0) - так вот передаем нашу текстуру в шейдер, ну а дальше сами разберетесь я думаю.
P.S. Сорян что на Scala, но переписывать код мне лень. Вы уж извините.
P.P.S. Для копипастников val это final переменая, в object перед всеми методами добавьте static, Unit это void, а def это функция.
 
Последнее редактирование:
1,990
18
105
Ааа что за видосик?
Видосик я кидал тут. Там же есть ссылка на статью, где можно подсмотреть довольно популярную и простую реализацию блума.

То есть, допустим у вас есть квадрат 20х20 пикселей и вам нужно вокруг него alpha оболочку забацать => ширина и высота будут 25х25(больше чем 20х20)
Вообще не так. Ты же не будешь на каждый светящийся на сцене элемент создавать отдельный рендер таргет 'примерно нужного' размера?
Для этих дел обычно используют полноэкранный буфер.

Блум, по сути - постпроцесс техника. Приведенная по ссылке реализация предполагает такой ход действий:
1) Рисуем сцену в наш фбо
*2) Применяем bright-pass фильтр, который выделяет яркие участки сцены, и обрезает остальные
**3) В несколько проходов размываем получившуюся текстуру, с каждым проходом увеличиваем радиус размытия, храним все замыленные версии
4) Через composite-шейдер собираем (я складывал, например) все уровни блума воедино и аддитивно рисуем поверх сцены
Собственно, всё.

* Мне лично такой подход не нравится, так как даёт сильно нереалистичный, или, зачастую, просто нежеланный результат. В своей реализации я использую MRT, и всё, что на сцене светится - рисуется в отдельный буфер цвета. В итоге получаем полностью контроллируемый блум, который художник сможет настроить как угодно.

** Есть версии, которые сразу на ходу складывают различные уровни блума, в итоге избавляемся от composite-шейдера и оверхеда по памяти, возможно такая техника даёт результат получше приведенного мной. Видел такую реализацию в UE4 и в пейперах майкрософта.
 
Последнее редактирование:
1,111
47
420
А что, неуважаемый человек не может правды сказать?
Расширения огл работают не везде одинаково
Может, но если гарик что нить такое скажет я скорее просто проигнорю и забью. Кстати Майн использует ARB, что интересно.
 
1,111
47
420
V4ieVB94MzFRUkaEnnvulNsF9y7_7nfGFJXyGaOqYeB1YmRX5q2D6iFG333ZMoCoVuj0w6dJhcBSt08PNRD1uQ%3D%3D
Как то так
 
1,990
18
105
Я где-то наверное пытался написать довольно объёмное сообщение про использование экстеншен функций, а потом его стёр (или нет).

Майн использует всякие ARB и прочее (что видно на твоём же скриншоте), только если нет соответствующего функционала в доступной версии ядра GL. Иначе надо использовать core-функционал, что очень рекомендуют делать, потому что vendor совсем не обязан поддерживать все эти экстеншны, и может просто на них забить. Доходит вплоть до того, что этот функционал реализован по-разному в ядре и не в ядре (из примеров - фреймбуферы, и, вроде, шейдеры).
 

CumingSoon

Местный стендапер
1,634
12
269
Майн использует ARB, что интересно.
Майн много чего использует, что использовать не нужно. Например, рендербуфер. Да, быстро. Да, нужен костыль для текстуры глубины
 
Сверху