【问题标题】:Real Time Change of Texture in BlenderBlender中纹理的实时变化
【发布时间】:2021-11-02 12:24:28
【问题描述】:

我是 Blender 和 Python 的新手,需要实时更改飞机的纹理。我有一个处理草图,它不断保存来自 USB 相机的黑白静止图像,这些静止图像用作 Blender 上平面的位移纹理。

在同一个文件夹中,我有处理草图、Blender 文件和来自 USB 相机的 20 帧,这些帧不断更新。我已经设法在 Processing 和 Blender 之间创建了一个串行链接。

在保存静止帧时,我基本上需要纹理文件的名称不断从 1 更改为 20。理想情况下,我也可以通过它导出动画序列。但正如我所说,我是一个完全的初学者!

我在网上找到了类似的东西,但我认为这是 Python 的旧版本,因为它不起作用!

import Blender
from Blender import Image
from Blender import Texture
from Blender import Material
from Blender import Object
from Blender import Window
from Blender import Modifier
from Blender import Scene
import serial
myPort = serial.Serial('COM11', 9600)

texture=Texture.Get('Textura')
texture.setType('Image')
scene=Scene.getCurrent()
plane=Object.Get('Plane')
modifier=plane.modifiers[0] 
myPort.flushInput()

for i in range(1, 301):
    y = ord(myPort.read(size=1))
    name=str(y)+".png"
    image=Image.Load(name)
    texture.image=image
    modifier[Modifier.Settings.TEXTURE] = texture
    Window.EditMode(1)
    Window.EditMode(0)
    Window.Redraw()

【问题讨论】:

  • 您应该指定您使用的 Blender 版本。事实上,Blender Python 看起来像是 2.4x 或更早版本。如果你在处理中有平面位移会不会更简单? (我试图弄清楚,除了一种简单的方法来应用置换贴图,如果在这种特定情况下还有其他需要 Blender 的东西)
  • 使用 Blender 2.92 和 Python 3.7.7。我将在 Processing 中尝试平面置换,因为这可能是产生一些结果的好一步,谢谢!

标签: python processing blender real-time-data


【解决方案1】:

我从一个非常强烈的假设开始:如果可以取代,您将单独使用 Processing,从而完全消除了 Processing 与 Blender 和 Blender 之间串行通信的需要。 (题外话:为了便于进程间通信,我发现 OSC 协议更易于使用。Checkout Processing 的 oscP5 库和示例以及您选择的 Python OSC 模块)

通过快速搜索,我发现了this post,其中包含一个代码示例,说明如何生成一个被柏林噪声取代的细分平面。这是 Cedric 代码的调整版本:

float noiseScale= .12;


int meshSize = 10;
int resX = 50;
int resY = 50;
float[][] val = new float[resX][resY];

void setup() {
  size(900, 600, P3D);
  smooth();
  background(255);
}

void draw() {
  // sample perline noise
  noiseScale= mouseX*.0002;

  float xoff = 0.0;
  for (int x =0; x<resX; x++) {
    xoff +=noiseScale;
    float yoff = 0.0;
    for (int y =0; y<resY; y++) {

      yoff +=noiseScale;

      val[x][y] = noise(xoff, yoff)*255;
    }
  }
  // render displaced subdivided plane
  background(0);
  translate(width / 2, height / 2);
  rotateY(map(mouseX, 0, width, -PI, PI));
  rotateX(map(mouseY, 0, height, PI, -PI));
  translate(-resX/2*meshSize, -resY/2*meshSize);
  
  beginShape(QUADS);
  colorMode(HSB, 255);

  for (int x =0; x<resX-1; x++) {
    for (int y =0; y<resY-1; y++) {
      fill( val[x][y], 255, 255);

      vertex(x*meshSize, y*meshSize, val[x][y] );
      vertex((x+1)*meshSize, y*meshSize, val[x+1][y] );
      vertex((x+1)*meshSize, (y+1)*meshSize, val[x+1][y+1] );
      vertex(x*meshSize, (y+1)*meshSize, val[x][y+1] );
    }
  }

  endShape();


}

在这种情况下,50x50 是网络摄像头图像的大小,val 是等效的像素数据。

调整它以使用来自网络摄像头的像素亮度如下所示:

import processing.video.*;

int meshSize = 10;
int resX = 64;
int resY = 48;


Capture webcam;

void setup(){
 size(640, 480, P3D); 
 
 webcam = new Capture(this, resX, resY);
 webcam.start();
}

void draw(){
  background(0);
  // 2D
  image(webcam, 0, 0);
  // 3D : isolate coordinate space using push/pop matrix
  pushMatrix();
  translate(width / 2, height / 2);
  rotateY(map(mouseX, 0, width, -PI, PI));
  rotateX(map(mouseY, 0, height, PI, -PI));
  
  drawWebcamDisplacement(webcam);
  popMatrix();
}

void drawWebcamDisplacement(PImage frame){
  // prep. pixels for reading
  frame.loadPixels();
  // isolate coordinate space
  pushMatrix();
  translate(-resX/2*meshSize, -resY/2*meshSize);
  
  // start pairing 4 vergices as quads
  beginShape(QUADS);
  colorMode(HSB, 255);
  // for each  x,y subdivision
  for (int x =0; x < resX-1; x++) {
    for (int y =0; y < resY-1; y++) {
      // sample 4 neighbouring pixels (current (top left), to the right (TR), bellow (BL) and bellow diagonally (BR)
      color pixelTL = frame.pixels[x + (y * resX)];
      color pixelTR = frame.pixels[(x + 1) + (y * resX)];
      color pixelBR = frame.pixels[(x + 1) + ((y + 1) * resX)];
      color pixelBL = frame.pixels[x + ((y + 1) * resX)];
      // extract brightness
      float brigthnessTL = brightness(pixelTL);
      float brigthnessTR = brightness(pixelTR);
      float brigthnessBR = brightness(pixelBR);
      float brigthnessBL = brightness(pixelBL);
      
      
      fill( brigthnessTL, 255, 255);

      vertex(x*meshSize    , y*meshSize    , brigthnessTL );
      vertex((x+1)*meshSize, y*meshSize    , brigthnessTR );
      vertex((x+1)*meshSize, (y+1)*meshSize, brigthnessBR );
      vertex(x*meshSize    , (y+1)*meshSize, brigthnessBL );
    }
  }

  endShape();
  // restore coordinate space
  popMatrix();
}

void captureEvent(Capture cam){
  cam.read(); 
}

很遗憾,我现在无法访问网络摄像头,因此可能存在错误,但希望注释代码说明了这个想法。 (仔细检查您的网络摄像头是否真的支持此分辨率/纵横比,如果不调整并尝试使用单独的 PImage(例如webcam.get()),那么您可以使用resize())。 (HSB 颜色模式是可选的/从 Cedric 的示例中提升。当然可以根据需要随意调整)。

(应该可以将置换贴图实现为 GLSL 着色器(在处理中实现为 PShader),但这可能对新手不友好)

更新

为了提高性能,可以使用PShape 缓存几何图形,稍后在draw() 中简单地更新现有(预分配的)顶点。这是上面使用PShape的修改版本:

import processing.video.*;

Capture webcam;

int meshSize = 15;
int resX = 64;
int resY = 48;
PShape grid;

boolean sampleZ = true;

void settings(){
 size(640, 480, P3D);
 //fullScreen();
}

void setup(){
 textAlign(RIGHT);
 colorMode(HSB, 255);
 
 webcam = new Capture(this, resX, resY);
 webcam.start();
 
 grid = createPShapeGrid(resX, resY, meshSize);
}

void draw(){
  // update
  if(sampleZ) gridSampleBrightness(grid, webcam);
  else        gridSamplePixels(grid, webcam);
  // render
  background(0);
  // 2D
  //image(webcam, 0, 0);
  text((int)frameRate+"fps\npress any key to change sampling\nmode: " + (sampleZ ? "Z" : "pixels")+"\nmouse press for lights", width - 10, 15);
  // 3D : isolate coordinate space using push/pop matrix
  if(mousePressed) lights();
  else noLights();
  pushMatrix();
    translate(width * 0.5, height * 0.5, -(resX + resY) * 5);
    rotateY(map(mouseX, 0, width, -PI,  PI));
    rotateX(map(mouseY, 0, height, PI, -PI));
    pushMatrix();
      // offset to centre
      translate(-resX * 0.5 * meshSize, -resY * 0.5 * meshSize);
      shape(grid);
    popMatrix();
  popMatrix();
}

void keyPressed(){
  sampleZ = !sampleZ;
}

void captureEvent(Capture cam){
  cam.read(); 
}

PShape createPShapeGrid(int resX, int resY, int meshSize){
  PShape grid = createShape(PShape.GEOMETRY);
  
  grid.setStroke(false);
  
  for (int x =0; x < resX-1; x++) {
    for (int y =0; y < resY-1; y++) {
      grid.beginShape(QUAD);
      grid.vertex(x*meshSize    , y*meshSize    , 0 );
      grid.vertex((x+1)*meshSize, y*meshSize    , 0 );
      grid.vertex((x+1)*meshSize, (y+1)*meshSize, 0 );
      grid.vertex(x*meshSize    , (y+1)*meshSize, 0 );
      grid.endShape();
    }
  }
  
  return grid;
}

// sample pixels, map birghtness to Z, colour from Z (usually HSB)
void gridSampleBrightness(PShape grid, PImage frame){
  frame.loadPixels();
  // start pairing 4 vertices as quads
  // for each  x,y subdivision
  int vertexIndex = 0;
  for (int x =0; x < resX-1; x++) {
    for (int y =0; y < resY-1; y++) {
      // sample 4 neighbouring pixels (current (top left), to the right (TR), bellow (BL) and bellow diagonally (BR)
      color pixelTL = frame.pixels[x + (y * resX)];
      color pixelTR = frame.pixels[(x + 1) + (y * resX)];
      color pixelBR = frame.pixels[(x + 1) + ((y + 1) * resX)];
      color pixelBL = frame.pixels[x + ((y + 1) * resX)];
      // extract brightness
      float brigthnessTL = brightness(pixelTL);
      float brigthnessTR = brightness(pixelTR);
      float brigthnessBR = brightness(pixelBR);
      float brigthnessBL = brightness(pixelBL);
      
      color brigthnessTLHSB = color(brigthnessTL, 255, 255);
      
      grid.setFill(vertexIndex    , brigthnessTLHSB);
      grid.setFill(vertexIndex + 1, brigthnessTLHSB);
      grid.setFill(vertexIndex + 2, brigthnessTLHSB);
      grid.setFill(vertexIndex + 3, brigthnessTLHSB);
      
      grid.setVertex(vertexIndex++,x*meshSize    , y*meshSize    , brigthnessTL );
      grid.setVertex(vertexIndex++,(x+1)*meshSize, y*meshSize    , brigthnessTR );
      grid.setVertex(vertexIndex++,(x+1)*meshSize, (y+1)*meshSize, brigthnessBR );
      grid.setVertex(vertexIndex++,x*meshSize    , (y+1)*meshSize, brigthnessBL );
    }
  }
}

// sample pixels, map birghtness to Z, colour from pixels
void gridSamplePixels(PShape grid, PImage frame){
  frame.loadPixels();
  // start pairing 4 vertices as quads
  // for each  x,y subdivision
  int vertexIndex = 0;
  for (int x =0; x < resX-1; x++) {
    for (int y =0; y < resY-1; y++) {
      // sample 4 neighbouring pixels (current (top left), to the right (TR), bellow (BL) and bellow diagonally (BR)
      color pixelTL = frame.pixels[x + (y * resX)];
      color pixelTR = frame.pixels[(x + 1) + (y * resX)];
      color pixelBR = frame.pixels[(x + 1) + ((y + 1) * resX)];
      color pixelBL = frame.pixels[x + ((y + 1) * resX)];
      // extract brightness
      float brigthnessTL = brightness(pixelTL);
      float brigthnessTR = brightness(pixelTR);
      float brigthnessBR = brightness(pixelBR);
      float brigthnessBL = brightness(pixelBL);
      
      grid.setFill(vertexIndex    , pixelTL);
      grid.setFill(vertexIndex + 1, pixelTR);
      grid.setFill(vertexIndex + 2, pixelBR);
      grid.setFill(vertexIndex + 3, pixelBL);
      
      grid.setVertex(vertexIndex++,x*meshSize    , y*meshSize    , brigthnessTL );
      grid.setVertex(vertexIndex++,(x+1)*meshSize, y*meshSize    , brigthnessTR );
      grid.setVertex(vertexIndex++,(x+1)*meshSize, (y+1)*meshSize, brigthnessBR );
      grid.setVertex(vertexIndex++,x*meshSize    , (y+1)*meshSize, brigthnessBL );
    }
  }
}

使用这种方法,最好注意网格分辨率:顶点越多,初始化过程就越慢。主要危险是如果PShape 被创建并填充到setup() 中:如果P3D 需要超过15 秒来初始化这可能会出现问题。解决此问题的方法可能是使用布尔标志从 draw() 只进行一次函数调用,例如:

if(!isPShapeReady){
  setupPShape();
  isPShapeReady = true;
}

【讨论】:

  • 谢谢!将检查并让您知道。我想我会首先使用 Blender,这样我就有能力用纹理等渲染它,但我现在会尝试这样做以获得一些初步结果!谢谢!
  • 我理解您为什么选择使用 Blender 进行原型设计。如果答案有帮助,请记得投票,如果它是您问题的解决方案,请用绿色复选标记标记它。谢谢你:)
  • 再次感谢 - 也是第一次使用这个平台! :)
猜你喜欢
  • 2015-06-13
  • 2016-08-03
  • 2022-01-10
  • 2014-06-04
  • 2018-12-23
  • 2020-06-27
  • 2011-10-05
  • 2013-10-07
  • 2013-10-31
相关资源
最近更新 更多