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

Сообщения
1,297
Лучшие ответы
38
Реакции
216
Версия Minecraft
1.7.10
Добрый день.
Хочу узнать как рисовать текстуру за границами модели? например сделать некое "свечение" модели.
Речь заходила о майновском фреймбуффере, но чет "ничера" не понял
 
Сообщения
50
Лучшие ответы
3
Реакции
3
Тоже сейчас хотел задать этот вопрос, надеюсь кто-то ответит :)
 
Сообщения
1,856
Лучшие ответы
49
Реакции
342
Просто берешь и биндишь текстуру, ставишь вершины в тесселяторе, рисуешь(Tesselator#draw).
 
Сообщения
1,011
Лучшие ответы
9
Реакции
98
Мне тоже интересно как рисовать чисто "на камере" всякие свечения или эффекты
 
Сообщения
2,450
Лучшие ответы
75
Реакции
343
Хайпанул видосик, походу.

Конь же кидал ссылку. Проще, чем там, никто не разжуёт.
 
Сообщения
960
Лучшие ответы
45
Реакции
294
Ааа что за видосик? Почему уже 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,981
Лучшие ответы
18
Реакции
90
Ааа что за видосик?
Видосик я кидал тут. Там же есть ссылка на статью, где можно подсмотреть довольно популярную и простую реализацию блума.

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

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

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

** Есть версии, которые сразу на ходу складывают различные уровни блума, в итоге избавляемся от composite-шейдера и оверхеда по памяти, возможно такая техника даёт результат получше приведенного мной. Видел такую реализацию в UE4 и в пейперах майкрософта.
 
Последнее редактирование:
Сообщения
1,446
Лучшие ответы
12
Реакции
171
Что за пейперы? Я заинтересован
 
Сообщения
1,952
Лучшие ответы
65
Реакции
186
@JustAGod, убери ARB .-.
Говорили же его не использовать.
 
Сообщения
1,952
Лучшие ответы
65
Реакции
186
Сообщения
1,446
Лучшие ответы
12
Реакции
171
А что, неуважаемый человек не может правды сказать?
Расширения огл работают не везде одинаково
 
Сообщения
960
Лучшие ответы
45
Реакции
294
А что, неуважаемый человек не может правды сказать?
Расширения огл работают не везде одинаково
Может, но если гарик что нить такое скажет я скорее просто проигнорю и забью. Кстати Майн использует ARB, что интересно.
 
Сообщения
1,981
Лучшие ответы
18
Реакции
90
Я где-то наверное пытался написать довольно объёмное сообщение про использование экстеншен функций, а потом его стёр (или нет).

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